//---------------------------------------------------------------------------- // // ROUTINE: CAIHumanStateCatch::HandleSetupCatch() // // PURPOSE: // //---------------------------------------------------------------------------- void CAIHumanStateCatch::HandleSetupCatch() { // All of the sequence animations MUST be set by the time we start // the initialization process UBER_ASSERT( m_eAnimProp1 != kAP_None, "CAIHumanStateCatch::UpdateAnimation Goal failed to set m_eAnimProp1"); UBER_ASSERT( m_eAnimProp2 != kAP_None, "CAIHumanStateCatch::UpdateAnimation Goal failed to set m_eAnimProp2"); UBER_ASSERT( m_eAnimProp3 != kAP_None, "CAIHumanStateCatch::UpdateAnimation Goal failed to set m_eAnimProp3"); // Be sure that we retrieved a MaxCatch value.. UBER_ASSERT( m_fMaxCatchDuration > 0.0000001, "SetupCatch: MaxCatchDuration not set" ); CAnimationProps Props; Props.Set(kAPG_Posture, kAP_Stand); Props.Set(kAPG_WeaponPosition, kAP_Up); Props.Set(kAPG_Weapon, GetAI()->GetCurrentWeaponProp()); Props.Set(kAPG_WeaponAction, m_eAnimProp2); if ( GetAI()->HasTarget() ) { // Setting a target push speed allows the AI to knock the // player back if they collide while the AI Catching GetAI()->GetTarget()->SetPushSpeed( GetAI()->GetSpeed() * 2.f ); } // Advance to the first phase.. m_eStateStatus = kSStat_TriplePhaseOne; }
void CAIActionReload::ActivateAction( CAI* pAI, CAIWorldState& wsWorldStateGoal ) { super::ActivateAction( pAI, wsWorldStateGoal ); // Reload our randed weapon. pAI->SetCurrentWeapon( kAIWeaponType_Ranged ); // Set animate state. pAI->SetState( kState_Animate ); // Set reload animation. CAnimationProps animProps; animProps.Set( kAPG_Posture, m_ePosture ); animProps.Set( kAPG_Weapon, pAI->GetAIBlackBoard()->GetBBPrimaryWeaponProp() ); animProps.Set( kAPG_WeaponPosition, kAP_WPOS_Up ); animProps.Set( kAPG_Action, kAP_ACT_Reload ); CAIStateAnimate* pStateAnimate = (CAIStateAnimate*)( pAI->GetState() ); pStateAnimate->SetAnimation( animProps, !LOOP ); // Torso tracking. pAI->GetAIBlackBoard()->SetBBTargetTrackerFlags( kTrackerFlag_AimAt ); pAI->GetAIBlackBoard()->SetBBFaceTarget( true ); }
void CAIGoalAlert::SetWSSatisfaction( CAIWorldState& WorldState ) { // Bail if the Goal's SmartObject record does not exist. AIDB_SmartObjectRecord* pSmartObjectRecord = g_pAIDB->GetAISmartObjectRecord( m_pGoalRecord->eSmartObjectID ); if( !pSmartObjectRecord ) { return; } // Bail if animation does not exist. CAnimationProps Props; Props = pSmartObjectRecord->Props; Props.Set( kAPG_Weapon, m_pAI->GetAIBlackBoard()->GetBBPrimaryWeaponProp() ); HMODELANIM hAni = m_pAI->GetAnimationContext()->GetAni( Props ); if( hAni == INVALID_MODEL_ANIM ) { return; } // Goal is satisfied by looping the alert animation. WorldState.SetWSProp( kWSK_AnimLooped, m_pAI->m_hObject, kWST_int, (int)hAni ); }
void CAIActionIdle::ActivateAction( CAI* pAI, CAIWorldState& wsWorldStateGoal ) { super::ActivateAction( pAI, wsWorldStateGoal ); // Added an assert when an AI goes into the idle goal with an animation // that is currently locked. This suggests that the previous behavior // did not perform the expected cleanup. // If this assumption isn't valid, this assert can safely be removed. AIASSERT( !pAI->GetAnimationContext()->IsLocked(), pAI->GetHOBJECT(), "CAIActionIdle::ActivateAction : AIs animation is still locked and will be looped. This may indicate the previous action failed to clean itself up properly." ); // If AI is not in any state, set Idle state. // Otherwise, the AIActionIdle does not affect the current state. if( ( pAI->GetState() == NULL ) || ( pAI->GetAnimationContext()->WasLocked() ) || ( pAI->GetAnimationContext()->WasPlayingSpecial() ) || ( pAI->GetAIBlackBoard()->GetBBDestStatus() != kNav_Unset ) ) { // Set animate state. pAI->SetState( kState_Animate ); // Set idle animation. EnumAnimProp ePosture = pAI->GetAnimationContext()->GetCurrentProp( kAPG_Posture ); if( ePosture == kAP_None || ePosture == kAP_POS_Mounted) { ePosture = kAP_POS_Stand; } CAnimationProps animProps; animProps.Set( kAPG_Posture, ePosture ); animProps.Set( kAPG_Weapon, pAI->GetAIBlackBoard()->GetBBPrimaryWeaponProp() ); animProps.Set( kAPG_WeaponPosition, kAP_WPOS_Down ); CAIStateAnimate* pStateAnimate = (CAIStateAnimate*)( pAI->GetState() ); pStateAnimate->SetAnimation( animProps, LOOP ); } // Head tracking. if( pAI->HasTarget( kTarget_Character | kTarget_Object | kTarget_Interest ) && AIWeaponUtils::HasWeaponType( pAI, kAIWeaponType_Ranged, !AIWEAP_CHECK_HOLSTER ) && AIWeaponUtils::HasAmmo( pAI, kAIWeaponType_Ranged, !AIWEAP_CHECK_HOLSTER ) ) { pAI->GetAIBlackBoard()->SetBBTargetTrackerFlags( kTrackerFlag_AimAt ); pAI->GetAIBlackBoard()->SetBBFaceTarget( true ); } else { pAI->GetAIBlackBoard()->SetBBTargetTrackerFlags( kTrackerFlag_LookAt ); pAI->GetAIBlackBoard()->SetBBFaceTarget( false ); } }
void CAIActionFaceNode::ActivateAction( CAI* pAI, CAIWorldState& wsWorldStateGoal ) { super::ActivateAction( pAI, wsWorldStateGoal ); // Find which node we are facing from the goal world state. SAIWORLDSTATE_PROP* pProp = wsWorldStateGoal.GetWSProp( kWSK_UsingObject, pAI->m_hObject ); if( !pProp ) { return; } // Set animate state. pAI->SetState( kState_Animate ); CAnimationProps animProps; animProps.Set( kAPG_Posture, kAP_POS_Stand ); animProps.Set( kAPG_WeaponPosition, kAP_WPOS_Up ); animProps.Set( kAPG_Action, kAP_ACT_Alert ); CAIStateAnimate* pStateAnimate = (CAIStateAnimate*)( pAI->GetState() ); pStateAnimate->SetAnimation( animProps, LOOP ); // Face the node. pAI->GetAIBlackBoard()->SetBBFaceObject( pProp->hWSValue ); // We are departing a previous node. pAI->GetAIWorldState()->SetWSProp( kWSK_UsingObject, pAI->m_hObject, kWST_HOBJECT, 0 ); // We have a new destination. pAI->GetAIBlackBoard()->SetBBDestStatus( kNav_Set ); // Loop turning sound. HRECORD hRecord = g_pAIDB->GetMiscRecordLink( TURNING_SOUND ); const char* pszSoundFile = g_pLTDatabase->GetRecordName( hRecord ); HRECORD hSR = g_pSoundDB->GetSoundDBRecord( pszSoundFile ); HLTSOUND hLoopSound = g_pServerSoundMgr->PlayDBSoundFromObject( pAI->m_hObject, hSR, -1.0f, SOUNDPRIORITY_MISC_LOW, PLAYSOUND_LOOP | PLAYSOUND_GETHANDLE, SMGR_DEFAULT_VOLUME, 1.0f, -1.0f, DEFAULT_SOUND_CLASS, PLAYSOUND_MIX_OBJECTS); pAI->GetAIBlackBoard()->SetBBLoopingSound( hLoopSound ); // Head tracking. pAI->GetAIBlackBoard()->SetBBTargetTrackerFlags( kTrackerFlag_None ); pAI->GetAIBlackBoard()->SetBBFaceTarget( false ); }
void CAIActionAttackGrenade::ActivateAction( CAI* pAI, CAIWorldState& wsWorldStateGoal ) { super::ActivateAction( pAI, wsWorldStateGoal ); // Set grenade as current weapon. pAI->SetCurrentWeapon( kAIWeaponType_Thrown ); // Set animate state. pAI->SetState( kState_Animate ); // Set throw animation. CAnimationProps animProps; animProps.Set( kAPG_Posture, kAP_POS_Stand ); animProps.Set( kAPG_Weapon, pAI->GetAIBlackBoard()->GetBBPrimaryWeaponProp() ); animProps.Set( kAPG_Action, kAP_ACT_Throw ); CAIStateAnimate* pStateAnimate = (CAIStateAnimate*)( pAI->GetState() ); pStateAnimate->SetAnimation( animProps, !LOOP ); // Get the target. HOBJECT hTarget = NULL; if( pAI->HasTarget( kTarget_Character | kTarget_Object ) ) { hTarget = pAI->GetAIBlackBoard()->GetBBTargetObject(); } // Play grenade attack sound. if( g_pAICoordinator->FindAlly( pAI->m_hObject, NULL ) ) { g_pAISoundMgr->RequestAISound( pAI->m_hObject, kAIS_Grenade, kAISndCat_Always, hTarget, 0.f ); } // Coordinate frequency of grenade attacks across all AIs. SetNextThrowTime( pAI ); // Torso tracking. pAI->GetAIBlackBoard()->SetBBTargetTrackerFlags( kTrackerFlag_AimAt ); pAI->GetAIBlackBoard()->SetBBFaceTarget( true ); }
//---------------------------------------------------------------------------- // // ROUTINE: CAIHumanStateCatch::HandleStartCatch() // // PURPOSE: // //---------------------------------------------------------------------------- void CAIHumanStateCatch::HandleStartCatch() { // Set up the direction and duration of the Catch if ( m_hObjectToCatch != LTNULL ) { // Reset the facing direction GetAI()->FacePos( m_vIncomingPosition ); } // If we are done with the previous animation (locking is off) // then we can enter the next phase if( !GetAnimationContext()->IsLocked() ) { LTVector vOrigin = GetAI()->GetPosition(); // Set up the direction and duration of the Catch if ( m_hObjectToCatch != LTNULL ) { // If we have a specific object, then orient ourselves to face it g_pLTServer->GetObjectPos( m_hObjectToCatch, &m_vIncomingPosition ); } // Find the length of the fly animation. CAnimationProps Props; Props.Set(kAPG_Posture, kAP_Stand); Props.Set(kAPG_WeaponPosition, kAP_Up); Props.Set(kAPG_Weapon, GetAI()->GetCurrentWeaponProp()); Props.Set(kAPG_WeaponAction, m_eAnimProp2); // Advance to the next phase.. m_eStateStatus = kSStat_TriplePhaseTwo; } // Decide if we ought to abort this phase -- we might not want // to hold the catch for the animations duration if( ShouldDropCatch() ) { // Advance to the last phase.. m_eStateStatus = kSStat_TriplePhaseThree; } }
void CAIActionFinishBlockNormal::ActivateAction( CAI* pAI, CAIWorldState& wsWorldStateGoal ) { super::ActivateAction( pAI, wsWorldStateGoal ); // Bail if the Action's SmartObject record does not exist. AIDB_SmartObjectRecord* pSmartObjectRecord = g_pAIDB->GetAISmartObjectRecord( m_pActionRecord->eSmartObjectID ); if( !pSmartObjectRecord ) { return; } // Set the state. pAI->SetState( kState_Animate ); CAIStateAnimate* pStateAnimate = (CAIStateAnimate*)( pAI->GetState() ); CAnimationProps props = pSmartObjectRecord->Props; props.Set( kAPG_Weapon, pAI->GetAIBlackBoard()->GetBBPrimaryWeaponProp() ); pStateAnimate->SetAnimation( props, !LOOP ); }
HMODELANIM CAIGoalAbstractUseObject::GetAlternateDeathAnimation() { // Were killed in the middle of an activity? // jrg - 7/29/02 - don't count the activity if we haven't fully transitioned yet. if( ( m_pAI->GetState()->GetStateType() == kState_HumanUseObject ) && ( m_pAI->GetState()->GetStateStatus() == kSStat_PathComplete ) && (!m_pAI->GetAnimationContext()->IsTransitioning()) ) { CAIHumanStateUseObject* pStateUseObject = (CAIHumanStateUseObject*)m_pAI->GetState(); EnumAnimProp eActivity = pStateUseObject->GetActivity(); CAIHuman* pAIHuman = (CAIHuman*)m_pAI; CAnimationProps animProps; animProps.Set( kAPG_Posture, pStateUseObject->GetPose() ); animProps.Set( kAPG_Weapon, pAIHuman->GetCurrentWeaponProp() ); animProps.Set( kAPG_WeaponPosition, kAP_Lower ); animProps.Set( kAPG_Awareness, eActivity ); animProps.Set( kAPG_Action, kAP_Death ); // Find a death animation for this activity. if( m_pAI->GetAnimationContext()->AnimationExists( animProps )) { m_bPlayedSpecialDeathAnim = LTTRUE; return m_pAI->GetAnimationContext()->GetAni( animProps ); } } // No alternate. return INVALID_ANI; }
LTBOOL CAIGoalWork::HandleWorkInterruptionDeactivation() { // Were interrupted while in the middle of an activity? if( ( m_pAI->GetState()->GetStateType() == kState_HumanUseObject ) && ( m_pAI->GetState()->GetStateStatus() == kSStat_PathComplete ) ) { CAIHumanStateUseObject* pStateUseObject = (CAIHumanStateUseObject*)m_pAI->GetState(); EnumAnimProp eActivity = pStateUseObject->GetActivity(); CAnimationProps animProps; animProps.Set( kAPG_Posture, pStateUseObject->GetPose() ); animProps.Set( kAPG_Weapon, kAP_Weapon3 ); animProps.Set( kAPG_WeaponPosition, kAP_Lower ); animProps.Set( kAPG_Awareness, eActivity ); animProps.Set( kAPG_Action, kAP_Interrupt ); // If this activity has an interruption animation, // play it and lock deactivation until complete. if( m_pAI->GetAnimationContext()->AnimationExists( animProps ) ) { m_pAI->SetState( kState_HumanAnimate ); CAIHumanStateAnimate* pStateAnimate = (CAIHumanStateAnimate*)(m_pAI->GetState()); pStateAnimate->SetAnimation( animProps, LTFALSE ); m_eDeactivationState = kWDS_Interrupting; m_pGoalMgr->LockGoal(this); return LTTRUE; } } return LTFALSE; }
void CAIActionDismountVehicle::ActivateAction( CAI* pAI, CAIWorldState& wsWorldStateGoal ) { super::ActivateAction( pAI, wsWorldStateGoal ); // Sanity check. if( !pAI ) { return; } // Bail if AI is not attached to anything. HOBJECT hVehicle = pAI->GetAIBlackBoard()->GetBBAttachedTo(); if( !hVehicle ) { return; } // Detach the AI from the vehicle. std::string strCmd = "DETACH "; strCmd += pAI->GetName(); g_pCmdMgr->QueueMessage( pAI, g_pLTServer->HandleToObject(hVehicle), strCmd.c_str() ); // Record the vehicle the AI was attached to from the Blackboard. pAI->GetAIBlackBoard()->SetBBAttachedTo( NULL ); // Get vehicle animProp. SAIWORLDSTATE_PROP* pProp = pAI->GetAIWorldState()->GetWSProp( kWSK_RidingVehicle, pAI->m_hObject ); if( !pProp ) { return; } EnumAnimProp eVehicle = pProp->eAnimPropWSValue; // Set animate state. pAI->SetState( kState_Animate ); // Set idle animation. CAnimationProps animProps; animProps.Set( kAPG_Posture, kAP_POS_Stand ); animProps.Set( kAPG_Weapon, pAI->GetAIBlackBoard()->GetBBPrimaryWeaponProp() ); animProps.Set( kAPG_WeaponPosition, kAP_WPOS_Lower ); animProps.Set( kAPG_Action, kAP_ACT_Dismount ); animProps.Set( kAPG_Activity, eVehicle ); CAIStateAnimate* pStateAnimate = (CAIStateAnimate*)( pAI->GetState() ); pStateAnimate->SetAnimation( animProps, !LOOP ); // Torso tracking. pAI->GetAIBlackBoard()->SetBBTargetTrackerFlags( kTrackerFlag_None ); pAI->GetAIBlackBoard()->SetBBFaceTarget( false ); }
void CAIActionReactToDanger::ActivateAction( CAI* pAI, CAIWorldState& wsWorldStateGoal ) { super::ActivateAction( pAI, wsWorldStateGoal ); // Bail if we are not aware of danger. CAIWMFact factQuery; factQuery.SetFactType( kFact_Danger ); CAIWMFact* pFact = pAI->GetAIWorkingMemory()->FindWMFact( factQuery ); if( !pFact ) { return; } // Set animate state. pAI->SetState( kState_Animate ); // Set flinch animation. CAnimationProps animProps; animProps.Set( kAPG_Posture, kAP_POS_Crouch ); animProps.Set( kAPG_Weapon, pAI->GetAIBlackBoard()->GetBBPrimaryWeaponProp() ); animProps.Set( kAPG_WeaponPosition, kAP_WPOS_Up ); animProps.Set( kAPG_Activity, kAP_ATVT_Distress ); animProps.Set( kAPG_Action, kAP_ACT_Idle ); CAIStateAnimate* pStateAnimate = (CAIStateAnimate*)( pAI->GetState() ); pStateAnimate->SetAnimation( animProps, !LOOP ); // Do NOT play a threat sound if threatened by a Turret. // Instead, allow turret targeting to play something appropriate. if( IsPlayer( pFact->GetSourceObject() ) ) { CPlayerObj* pPlayer = (CPlayerObj*)g_pLTServer->HandleToObject( pFact->GetSourceObject() ); if( pPlayer && pPlayer->GetTurret() ) { return; } } // Play threat sound. // "Fire!" if( IsAINode( pFact->GetSourceObject() ) ) { EnumAISoundType eAISound = kAIS_Danger; AINode* pNode = (AINode*)g_pLTServer->HandleToObject( pFact->GetSourceObject() ); if( pNode && pNode->GetType() == kNode_Stimulus ) { AINodeStimulus* pNodeStim = (AINodeStimulus*)pNode; if( pNodeStim ) { eAISound = pNodeStim->GetAISoundType(); } } g_pAISoundMgr->RequestAISound( pAI->m_hObject, eAISound, kAISndCat_Event, NULL, 0.f ); } // "Watch out grenade!" // "Shit!" else if( IsKindOf( pFact->GetSourceObject(), "CProjectile" ) ) { // Don't say anything if ally threw grenade. CProjectile* pProjectile = (CProjectile*)g_pLTServer->HandleToObject( pFact->GetSourceObject() ); if( pProjectile && IsCharacter( pProjectile->GetFiredFrom() ) ) { CCharacter *pChar = (CCharacter*)g_pLTServer->HandleToObject( pProjectile->GetFiredFrom() ); if( pChar && kCharStance_Like != g_pCharacterDB->GetStance( pAI->GetAlignment(), pChar->GetAlignment() ) ) { ENUM_AI_SQUAD_ID eSquad = g_pAICoordinator->GetSquadID( pAI->m_hObject ); CAISquad* pSquad = g_pAICoordinator->FindSquad( eSquad ); if( pSquad && pSquad->GetNumSquadMembers() > 1 ) { g_pAISoundMgr->RequestAISound( pAI->m_hObject, kAIS_GrenadeThreat, kAISndCat_Event, NULL, 0.f ); } else { g_pAISoundMgr->RequestAISound( pAI->m_hObject, kAIS_GrenadeThreatAlone, kAISndCat_Event, NULL, 0.f ); } } } } // "Shit" else { g_pAISoundMgr->RequestAISound( pAI->m_hObject, kAIS_GrenadeThreatAlone, kAISndCat_Event, NULL, 0.f ); } // Search for the source of the danger. LTVector vDangerPos = pFact->GetPos(); SearchForDangerOrigin( pAI, vDangerPos ); }
void CAIActionSurpriseAttackLaunch::ActivateAction( CAI* pAI, CAIWorldState& wsWorldStateGoal ) { super::ActivateAction( pAI, wsWorldStateGoal ); // Verify we selected a valid action. EnumAnimProp eAction = GetAtNodeAttackProp( *pAI->GetAIWorldState(), pAI->GetHOBJECT(), pAI->GetAIBlackBoard()->GetBBTargetObject() ); if ( kAP_Invalid == eAction ) { AIASSERT( 0, pAI->GetHOBJECT(), "CAIActionSurpriseAttackLaunch::ActivateAction: Failed to find an action despite passing precondition test." ); return; } // Verify the node specifies a smartobject. const AIDB_SmartObjectRecord* pSmartObject = GetAtNodeSmartObjectRecord( *pAI->GetAIWorldState(), pAI->GetHOBJECT() ); if ( !pSmartObject ) { AIASSERT( 0, pAI->GetHOBJECT(), "CAIActionSurpriseAttackLaunch::ActivateAction: Failed to smartobject for node despite passing precondition test." ); return; } // Notify the surprise node that it has been used. AINodeSurprise* pSurprise = GetSurpriseNode( *pAI->GetAIWorldState(), pAI->GetHOBJECT() ); if ( pSurprise ) { pSurprise->HandleSurpriseAttack(); } // Depart from a node (this must be done AFTER we get the node) SAIWORLDSTATE_PROP* pProp = pAI->GetAIWorldState()->GetWSProp( kWSK_AtNode, pAI->m_hObject ); if( pProp && pProp->hWSValue ) { AINode* pNode = (AINode*)g_pLTServer->HandleToObject( pProp->hWSValue ); if( pNode ) { pNode->HandleAIDeparture( pAI ); // Insure we call the PostActivate to fire off any commands/to // reset the activation time/to dispatch any post activate commands. AINodeSmartObject* pNodeSmartObject = AINodeSmartObject::DynamicCast( pNode->GetHOBJECT() ); if( pNodeSmartObject ) { pNodeSmartObject->PostActivate(); } } } // Get the nodes smartobject and replace the action with the action // determined dynamically. The activity specifies the direction/etc. CAnimationProps Props = pSmartObject->Props; Props.Set( kAPG_Action, eAction ); // Set the animation to play. pAI->SetState( kState_Animate ); CAIStateAnimate* pAnimate = (CAIStateAnimate*)pAI->GetState(); pAnimate->SetAnimation( Props, !LOOP ); // Torso tracking. pAI->GetAIBlackBoard()->SetBBTargetTrackerFlags( kTrackerFlag_AimAt ); pAI->GetAIBlackBoard()->SetBBFaceTarget( false ); // Ignore the AIs radius when validating movement encoding, as this // animation should be fit to the geometry by level designers. pAI->GetAIBlackBoard()->SetBBMovementEncodeUseRadius( false ); }
LTBOOL CAIGoalWork::HandleSpecialDamageDeactivation() { // No special damage applied. if( !m_pAI->GetDamageFlags() ) { return LTFALSE; } // Get the anim prop for the damage type. EnumAnimProp eDamage = kAP_None; switch( DamageFlagToType( m_pAI->GetDamageFlags() ) ) { case DT_SLEEPING: eDamage = kAP_DamageSleeping; break; case DT_STUN: eDamage = kAP_DamageStunned; break; case DT_BEAR_TRAP: eDamage = kAP_DamageTrapped; break; case DT_GLUE: eDamage = kAP_DamageGlued; break; case DT_LAUGHING: eDamage = kAP_DamageLaughing; break; case DT_SLIPPERY: eDamage = kAP_DamageSlipping; break; } // Check if a damage animation exists for the current activity. if( ( m_pAI->GetState()->GetStateType() == kState_HumanUseObject ) && ( m_pAI->GetState()->GetStateStatus() == kSStat_PathComplete ) ) { CAIHumanStateUseObject* pStateUseObject = (CAIHumanStateUseObject*)m_pAI->GetState(); EnumAnimProp eActivity = pStateUseObject->GetActivity(); CAnimationProps animProps; animProps.Set( kAPG_Posture, pStateUseObject->GetPose() ); animProps.Set( kAPG_Weapon, kAP_Weapon3 ); animProps.Set( kAPG_WeaponPosition, kAP_Lower ); animProps.Set( kAPG_Awareness, eActivity ); animProps.Set( kAPG_Action, kAP_Idle ); animProps.Set( kAPG_Mood, eDamage ); // This activity has a special damage animation, if( m_pAI->GetAnimationContext()->AnimationExists( animProps ) ) { return LTTRUE; } } // This activity does not have a special damage animation, return LTFALSE; }