#include "precompiled.h" #pragma hdrstop #include "prey_local.h" const idEventDef EV_PlayCycle( "", "ds" ); CLASS_DECLARATION( hhAnimatedEntity, hhAnimDriven ) EVENT( EV_PlayCycle, hhAnimDriven::Event_PlayCycle ) END_CLASS //============== // hhAnimDriven::Spawn //============== void hhAnimDriven::Spawn() { passenger = NULL; hadPassenger = false; spawnTime = gameLocal.time; // We are gonna move the guy manually, turn off having the anim move him GetAnimator()->RemoveOriginOffset( true ); // How do we deal with our owner? physicsAnim.SetSelf( this ); if( spawnArgs.GetBool( "solid", "0" ) ) { fl.takedamage = true; physicsAnim.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f ); GetPhysics()->SetContents( CONTENTS_SOLID ); } else { fl.takedamage = false; GetPhysics()->SetContents( 0 ); physicsAnim.SetClipModel( new idClipModel( GetPhysics()->GetClipModel() ), 1.0f ); GetPhysics()->UnlinkClip(); } // move up to make sure the monster is at least an epsilon above the floor physicsAnim.SetOrigin( GetOrigin() + idVec3( 0, 0, CM_CLIP_EPSILON ) ); SetPhysics( &physicsAnim ); //? Have this start at a set time afterwards? int animLength = PlayAnim( ANIMCHANNEL_ALL, "initial" ); PostEventMS( &EV_PlayCycle, animLength, ANIMCHANNEL_ALL, "move" ); float delta_min = spawnArgs.GetFloat( "delta_scale_min", "1.0" ); float delta_max = spawnArgs.GetFloat( "delta_scale_max", "1.0" ); if ( delta_min != 1.0f || delta_max != 1.0f ) { deltaScale.x = idMath::ClampFloat( delta_min, delta_max, gameLocal.random.RandomFloat() ); deltaScale.y = idMath::ClampFloat( delta_min, delta_max, gameLocal.random.RandomFloat() ); deltaScale.z = idMath::ClampFloat( delta_min, delta_max, gameLocal.random.RandomFloat() ); } else { deltaScale = idVec3( 1.0f, 1.0f, 1.0f ); } BecomeActive( TH_TICKER ); } void hhAnimDriven::Save(idSaveGame *savefile) const { savefile->WriteStaticObject( physicsAnim ); passenger.Save(savefile); savefile->WriteInt( spawnTime ); savefile->WriteBool( hadPassenger ); } void hhAnimDriven::Restore( idRestoreGame *savefile ) { savefile->ReadStaticObject( physicsAnim ); passenger.Restore(savefile); savefile->ReadInt( spawnTime ); savefile->ReadBool( hadPassenger ); } //============= // hhAnimDriven::SetPassenger //============= void hhAnimDriven::SetPassenger( idEntity *newPassenger, bool orientFromPassenger ) { idVec3 origin; idMat3 axis; //?! Right now handle only 1 passenger. If we have one, warn and exit. if ( passenger.IsValid() ) { const char *oldName = passenger->GetName(); const char *newName = "NULL"; if ( newPassenger ) { newName = newPassenger->GetName(); } gameLocal.Warning( "Error: hhAnimDriven::SetPassenger tried to add passenger %s but already had %s\n", newName, oldName ); return; } passenger = newPassenger; hadPassenger = true; fl.takedamage = true; if ( orientFromPassenger ) { origin = passenger->GetOrigin(); axis = passenger->GetAxis(); } GetPhysics()->SetClipModel( new idClipModel( passenger->GetPhysics()->GetClipModel() ), 1.0f ); GetPhysics()->SetContents( passenger->GetPhysics()->GetContents() ); GetPhysics()->SetClipMask( passenger->GetPhysics()->GetClipMask() ); if ( orientFromPassenger ) { SetOrigin( origin ); SetAxis( axis ); } passenger->Bind( this, true ); } //============== // hhAnimDriven::Think //============== void hhAnimDriven::Think() { idVec3 delta; // Done move unless we have a passenger. (Give us like 10 secs to get one) if ( !passenger.IsValid() ) { // If we had a passenger, they removed themselves, and so should we :) if ( hadPassenger ) { PostEventMS( &EV_Remove, 0 ); } // If never had a passenger for a second, remove ourselves else if ( gameLocal.time - spawnTime > 1000 ) { PostEventMS( &EV_Remove, 0 ); gameLocal.Warning( "hhAnimDriven %s existed for a second w/out a passenger. Removing.", GetName() ); } return; } // Move them based on their anim GetAnimator()->GetDelta( gameLocal.time - gameLocal.msec, gameLocal.time, delta ); delta *= GetAxis(); delta.x *= deltaScale.x; delta.y *= deltaScale.y; delta.z *= deltaScale.z; physicsAnim.SetDelta( delta ); // gameLocal.Printf( "%d Doing %s\n", gameLocal.GetTime(), delta.ToString() ); hhAnimatedEntity::Think(); } //============ // //============ int hhAnimDriven::PlayAnim( int channel, const char *animName ) { int animIndex; int length; animIndex = GetAnimator()->GetAnim( animName ); if ( !animIndex ) { return( 0 ); } //gameLocal.Printf( "Playing Anim %s\n", animName ); GetAnimator()->PlayAnim( channel, animIndex, gameLocal.GetTime(), 0 ); length = GetAnimator()->CurrentAnim( channel )->GetEndTime() - gameLocal.GetTime(); return( length ); } //============ // hhAnimDrive::Event_PlayCycle() //============ void hhAnimDriven::Event_PlayCycle( int channel, const char *animName ) { PlayCycle( channel, animName ); } //============ // //============ bool hhAnimDriven::PlayCycle( int channel, const char *animName ) { int animIndex; animIndex = GetAnimator()->GetAnim( animName ); if ( !animIndex ) { return( false ); } //gameLocal.Printf( "Cycling Anim %s\n", animName ); GetAnimator()->CycleAnim( channel, animIndex, gameLocal.GetTime(), 0 ); return( true ); } /* ================ hhAnimDriven::ClearAllAnims ================ */ void hhAnimDriven::ClearAllAnims() { GetAnimator()->ClearAllAnims( gameLocal.GetTime(), 0 ); } //=========== // //============ bool hhAnimDriven::Collide( const trace_t &collision, const idVec3 &velocity ) { // If we hit something, and have a passenger, pass along the message if( passenger.IsValid() ) { if( !passenger->Collide(collision, velocity) ) { return( false ); } passenger->Unbind(); } //. We have a valid passenger // If we made it this far, assume the collision is for real, and // remove ourselves from interacting with the world fl.takedamage = false; GetPhysics()->SetContents( 0 ); GetPhysics()->UnlinkClip(); ClearAllAnims(); PostEventMS( &EV_Remove, 0 ); return( true ); } bool hhAnimDriven::AllowCollision( const trace_t& collision ) { if ( !spawnArgs.GetBool( "projectile_collision", "1" ) ) { idEntity* ent = gameLocal.entities[ collision.c.entityNum ]; if ( !ent || ent->IsType( idProjectile::Type ) ) { return false; } } return true; } void hhAnimDriven::UpdateAnimation( void ) { PROFILE_SCOPE("Animation", PROFMASK_NORMAL); // HUMANHEAD pdm // don't do animations if they're not enabled if ( !( thinkFlags & TH_ANIMATE ) ) { return; } // is the model an MD5? if ( !animator.ModelHandle() ) { // no, so nothing to do return; } // call any frame commands that have happened in the past frame if ( !fl.hidden ) { animator.ServiceAnims( gameLocal.previousTime, gameLocal.time ); } // if the model is animating then we have to update it if ( !animator.FrameHasChanged( gameLocal.time ) ) { // still fine the way it was return; } // update the renderEntity UpdateVisuals(); // the animation is updated animator.ClearForceUpdate(); }