void CAIHumanStateAttackMove::UpdateAnimation()
{
	super::UpdateAnimation();

	GetAnimationContext()->SetProp(kAPG_Posture, kAP_Stand);
	GetAnimationContext()->SetProp(kAPG_WeaponPosition, kAP_Up);

	switch( m_eAttackMove )
	{
		// Step.

		case kAP_ShuffleRight:
		case kAP_ShuffleLeft:
			GetAnimationContext()->SetProp( kAPG_Evasive, m_eAttackMove );
			GetAnimationContext()->Lock();
			break;

		// BackUp.

		case kAP_BackUp:
		case kAP_FlankLeft:
		case kAP_FlankRight:
			m_pStrategyShoot->UpdateAnimation();
			m_pStrategyFollowPath->UpdateAnimation();
			break;

		default: AIASSERT( 0, GetAI()->m_hObject, "CAIHumanStateAttackMove::UpdateAnimation: Unexpected attack move." );
	}
}
void CAIHumanStateLaunch::UpdateAnimation()
{
	super::UpdateAnimation();

	GetAnimationContext()->SetProp( kAPG_Posture, kAP_Stand );
	GetAnimationContext()->SetProp( kAPG_WeaponPosition, kAP_Down );
	GetAnimationContext()->SetProp( kAPG_Movement, m_eLaunchMovement );
}
void CAIHumanStateAttackProne::UpdateAnimation()
{
	super::UpdateAnimation();

	GetAnimationContext()->SetProp(kAPG_Posture, kAP_Prone);
	GetAnimationContext()->SetProp(kAPG_WeaponPosition, kAP_Up);

	m_pStrategyShoot->UpdateAnimation();
}
//----------------------------------------------------------------------------
//              
//	ROUTINE:	CAIHumanStateResurrecting::GetDeathAni()
//              
//	PURPOSE:	
//              
//----------------------------------------------------------------------------
/*virtual*/ HMODELANIM CAIHumanStateResurrecting::GetDeathAni(LTBOOL bFront)
{
	if ( !GetAnimationContext() )
		return INVALID_MODEL_ANIM;

	if ( !GetAnimationContext()->IsPropSet(kAPG_Action, kAP_Resurrecting ) )
		return INVALID_MODEL_ANIM;

	return g_pLTServer->GetAnimIndex(GetAI()->GetObject(), "PrUn");
}
//----------------------------------------------------------------------------
//              
//	ROUTINE:	CAIHumanStateObstruct::UpdateAnimation()
//              
//	PURPOSE:	Sets the Props for the given animation
//              
//----------------------------------------------------------------------------
void CAIHumanStateObstruct::UpdateAnimation(void)
{
	super::UpdateAnimation();

	GetAnimationContext()->SetProp(kAPG_Posture, kAP_Stand);
	GetAnimationContext()->SetProp(kAPG_WeaponPosition, kAP_Up);

	if( IsNodeStillValid() && CanUpdatePath() )
	{
		m_pStrategyFollowPath->UpdateAnimation();
	}
}
//----------------------------------------------------------------------------
//              
//	ROUTINE:	CAIHumanStateCatch::UpdateAnimation()
//              
//	PURPOSE:	Sets animation flags depending on state, then locks the 
//				animation in place.  Here and only here do we handle setting
//				the props.
//              
//----------------------------------------------------------------------------
void CAIHumanStateCatch::UpdateAnimation(void)
{
	CAIHumanState::UpdateAnimation();

	// Set the common flags..
	GetAnimationContext()->SetProp( kAPG_Posture, kAP_Stand );
	GetAnimationContext()->SetProp( kAPG_WeaponPosition, kAP_Up );

	switch( m_eStateStatus )
	{
		case kSStat_TriplePhaseOne:
		{
			GetAnimationContext()->SetProp( kAPG_WeaponAction, m_eAnimProp1 );
			break;
		}
		case kSStat_TriplePhaseTwo:
		{
			GetAnimationContext()->SetProp( kAPG_WeaponAction, m_eAnimProp2 );
			break;
		}
		case kSStat_TriplePhaseThree:
		{
			GetAnimationContext()->SetProp( kAPG_WeaponAction, m_eAnimProp3 );
			break;
		}
		case kSStat_StateComplete:
		{
			break;
		}
	}

	// Always lock the animation.  Let the caller handle unlocking later
	// if the animation ends.
	GetAnimationContext()->Lock();
}
//----------------------------------------------------------------------------
//              
//	ROUTINE:	CAIHumanStateCatch::Update()
//              
//	PURPOSE:	
//              
//----------------------------------------------------------------------------
void CAIHumanStateCatch::Update(void)
{
	CAIHumanState::Update();

	// Remember the entry status so we can see if the status changed
	// over the course of this run.
	EnumAIStateStatus eEntryStatus = m_eStateStatus;

	switch( m_eStateStatus )
	{
		case kSStat_Initialized:
		{
			HandleSetupCatch();
			break;
		}
		case kSStat_TriplePhaseOne:
		{
			HandleStartCatch();
			break;
		}
		case kSStat_TriplePhaseTwo:
		{
			HandleHoldCatch();
			break;
		}
		case kSStat_TriplePhaseThree:
		{
			HandleDropCatch();
			break;
		}
	}

	// If we changed states, force an animation recalculation by locking,
	// and then clearing the lock
	if ( m_eStateStatus != eEntryStatus )
	{
		GetAnimationContext()->Lock();
		GetAnimationContext()->ClearLock();
	}
}
//----------------------------------------------------------------------------
//              
//	ROUTINE:	CAIHumanStateCatch::HandleDropCatch()
//              
//	PURPOSE:	
//              
//----------------------------------------------------------------------------
void CAIHumanStateCatch::HandleDropCatch()
{
	// If we are done with the previous animation (locking is off)
	// then we can enter the next phase
	if( !GetAnimationContext()->IsLocked() )
	{
		// If we have a target, turn to face it now.
		if ( GetAI()->HasTarget() )
		{
			GetAI()->FaceTarget();
		}
		
		m_eStateStatus = kSStat_StateComplete;
	}
}
//----------------------------------------------------------------------------
//              
//	ROUTINE:	CAIHumanStateResurrecting::Update()
//              
//	PURPOSE:	
//              
//----------------------------------------------------------------------------
/*virtual*/ void CAIHumanStateResurrecting::Update()
{
	CAIHumanState::Update();

	AIASSERT( m_fResurrectCompleteTime!=-1, GetAI()->m_hObject,
		"CAIHumanStateResurrecting::Update: m_fResurrectCompleteTime == -1" );

	if ( m_bFirstUpdate )
	{
		GetAI()->KillDlgSnd();

		// TEMP!!
		// Replace this with FXEd effects setup!
		CLIENTDEBRIS cd;
		cd.rRot			= m_pAI->GetRotation();
		cd.vPos			= m_pAI->GetPosition() + LTVector( 0.0f, 10.0f, 0.0f );
		cd.nDebrisId	= 43;
		::CreatePropDebris( cd.vPos, LTVector(0,1,0), 43 );
	}

	switch ( m_eStateStatus )
	{
		case kSStat_Conscious:
		break;

		case kSStat_RegainingConsciousness:
		{
			if ( GetAnimationContext()->IsPropSet(kAPG_Posture, kAP_Stand) )
			{
				m_eStateStatus = kSStat_Conscious;
				GetAI()->SetBlinking(LTTRUE);
			}
		}
		break;

		case kSStat_Resurrecting:
		{
			if ( m_fResurrectCompleteTime < g_pLTServer->GetTime() )
			{
				m_eStateStatus = kSStat_RegainingConsciousness;
			}
		}
		break;
	}
}
//----------------------------------------------------------------------------
//              
//	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;
	}
}
//----------------------------------------------------------------------------
//              
//	ROUTINE:	CAIHumanStrategyShootStream::UpdateAiming()
//              
//	PURPOSE:	
//              
//----------------------------------------------------------------------------
/*virtual*/ void CAIHumanStrategyShootStream::UpdateAiming(HOBJECT hTarget)
{
	if ( m_flStreamTime < g_pLTServer->GetTime() )
	{
		// Don't calculate new stream time until finished firing animation.
		if( !GetAnimationContext()->IsLocked() )
		{
			CalculateStreamTime();
		}

		Aim();
	}
	else
	{
		// We're done waiting, fire if we're at a reasonable angle

		if ( m_bIgnoreFOV )
		{
			Fire();
		}
		else
		{
			LTVector vTargetPos;
			g_pLTServer->GetObjectPos(hTarget, &vTargetPos);

			LTVector vDir = vTargetPos - GetAI()->GetPosition();
			vDir.y = 0.0f;
			vDir.Normalize();

			if ( vDir.Dot(GetAI()->GetTorsoForward()) < 0.70f )
			{
				Aim();
			}
			else
			{
				Fire();
			}
		}
	}
}
void CAIHumanStateAttackMove::Update()
{
	super::Update();

	// Make sure we have a target

	if ( !GetAI()->HasTarget() )
	{
		m_eStateStatus = kSStat_FailedComplete;
		return;
	}

	HOBJECT hTarget = GetAI()->GetTarget()->GetObject();
	HOBJECT hAI = GetAI()->m_hObject;

	// Head and Torso tracking.
	
	if( m_bFirstUpdate )
	{
		GetAI()->SetNodeTrackingTarget( kTrack_AimAt, hTarget, "Head" );
	}

	// Handle update appropriately for the type of move.

	switch( m_eAttackMove )
	{
		// Step.

		case kAP_ShuffleRight:
		case kAP_ShuffleLeft:
			if( m_bFirstUpdate )
			{
				// Snap AI to face the direction of his torso.

				GetAI()->FaceDir( GetAI()->GetTorsoForward() );
				GetAI()->FaceTargetRotImmediately();
				GetAnimationContext()->ClearLock();
			}
			else if( !GetAnimationContext()->IsLocked() )
			{
				m_eStateStatus = kSStat_StateComplete;
			}

			// Head and Torso tracking.

			GetAI()->EnableNodeTracking( kTrack_AimAt, hTarget );
			break;

		// BackUp.

		case kAP_BackUp:
		case kAP_FlankLeft:
		case kAP_FlankRight:
			if( m_pStrategyFollowPath->IsUnset() )
			{
				if( m_eAttackMove == kAP_BackUp )
				{
					m_pStrategyFollowPath->SetMovement( kAP_BackUp );
				}
				else {
					m_pStrategyFollowPath->SetMovement( kAP_Run );
				}

				m_bTurnedAround = LTFALSE;

				if( !m_pStrategyFollowPath->Set( m_vAttackMoveDest, LTFALSE ) )
				{
					m_eStateStatus = kSStat_FailedComplete;
				}
			}

			if( m_pStrategyFollowPath->IsDone() )
			{
				m_eStateStatus = kSStat_StateComplete;
			}
			else if( m_pStrategyFollowPath->IsSet() )
			{
				SelectMoveAnim();
				m_pStrategyFollowPath->Update();
			}

			if( m_pStrategyShoot->ShouldReload() )
			{
				m_pStrategyShoot->Reload(LTTRUE);
			}

			if( m_pStrategyShoot->IsReloading() ||
				m_pStrategyShoot->IsFiring() ||
				GetAI()->GetTarget()->IsVisibleCompletely() )
			{
				m_pStrategyShoot->Update();
			}

			// Head and Torso tracking.

			GetAI()->EnableNodeTracking( kTrack_AimAt, LTNULL );
			break;

		default:
			AIASSERT( 0, GetAI()->m_hObject, "CAIHumanStateAttackMove::Update: Unexpected attack move." );
			m_eStateStatus = kSStat_FailedComplete;
			break;
	}
}
void CAIHumanStateAttackProne::Update()
{
	super::Update();

	// Make sure we have a target

	if ( !GetAI()->HasTarget() )
	{
		m_eStateStatus = kSStat_FailedComplete;
		return;
	}

	HOBJECT hTarget = GetAI()->GetTarget()->GetObject();
	HOBJECT hAI = GetAI()->m_hObject;

	// Ensure that node tracking is disabled.

	m_pAIHuman->DisableNodeTracking();

	// Find the direction to the target.

	LTVector vTargetDir = m_pAI->GetTarget()->GetVisiblePosition() - m_pAI->GetPosition();
	vTargetDir.Normalize();

	// Snap AI to face the direction of his torso.

	if( m_bFirstUpdate )
	{
		GetAI()->FaceDir( vTargetDir );
		GetAI()->FaceTargetRotImmediately();
		GetAnimationContext()->ClearLock();
		return;
	}

	// Do no processing while transitioning into prone position.

	LTFLOAT fCurTime = g_pLTServer->GetTime();
	if( GetAnimationContext()->IsTransitioning() )
	{
		m_fStayProneTime = fCurTime + 3.f;
		return;
	}


	LTFLOAT fDot = GetAI()->GetForwardVector().Dot( vTargetDir );

	// Be sure to stay down at least 3 seconds.

	if( m_fStayProneTime < fCurTime )
	{
		// Bail if the target is outside of fov.
	
		if( fDot < c_fFOV60 ) 
		{
			m_eStateStatus = kSStat_StateComplete;
			return;
		}

		// Bail if target is within half of the minimum prone distance.

		if( m_fHalfMinDistSqr > GetAI()->GetTarget()->GetVisiblePosition().DistSqr( GetAI()->GetPosition() ) )
		{
			m_eStateStatus = kSStat_StateComplete;
			return;
		}
	}

	// Reload.

	if( m_pStrategyShoot->ShouldReload() )
	{
		m_pStrategyShoot->Reload(LTTRUE);
		return;
	}

	// Shoot if we are in the middle of shooting or reloading.

	if( m_pStrategyShoot->IsReloading() ||
		m_pStrategyShoot->IsFiring() )
	{
		m_pStrategyShoot->Update();
		m_fLastFiredTime = fCurTime;
		return;
	}

	// Shoot if target is visible, and within a small fov.

	if(	( GetAI()->GetTarget()->IsVisibleCompletely() ) &&
		( fDot > c_fFOV45 ) )
	{
		m_pStrategyShoot->Update();
		m_fLastFiredTime = fCurTime;
	}

	// Bail if haven't shot in 3 seconds.

	else if( ( m_fLastFiredTime + 3.f < fCurTime ) &&
			 ( m_fStayProneTime < fCurTime ) )
	{
		m_eStateStatus = kSStat_StateComplete;
		return;
	}
}
// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CAIHumanStrategyShoot::UpdateAnimation
//
//	PURPOSE:	Handles any pending AnimationContext specializations.  
//				Extends the base class and makes the following assumptions:
//				1) Animations are being locked by the base class.
//
// ----------------------------------------------------------------------- //
LTBOOL CAIHumanStrategyShootStream::UpdateAnimation()
{
	if( !CAIHumanStrategyShoot::UpdateAnimation() )
	{
		return LTFALSE;
	}

	switch ( m_eFireState )
	{
		case eFireStateStart:
		{
			// If we are in the fire state, and if our animation is not locked, 
			// then make sure it is cleared fully.  Rely on the base class to 
			// handle the initial locking.
			
			if( GetAI()->GetCurrentWeapon() == GetAI()->GetPrimaryWeapon() )
			{
				GetAnimationContext()->SetProp(kAPG_WeaponAction, kAP_FireStreamStart);
			}
			else
			{
				GetAnimationContext()->SetProp(kAPG_WeaponAction, kAP_FireSecondaryStreamStart);
			}
			GetAnimationContext()->Lock();
		}
		break;

		case eFireStateFiring:
		{
			// Streaming attacks are NEVER garenteed to play all the way through -- we want
			// tighter control over them than the animation will give us. BUT we want to also
			// have the ability to kick out when the animation ends UNLESS the animation is
			// looping.

			if( GetAI()->GetCurrentWeapon() == GetAI()->GetPrimaryWeapon() )
			{
				GetAnimationContext()->SetProp(kAPG_WeaponAction, kAP_FireStream);
			}
			else
			{
				GetAnimationContext()->SetProp(kAPG_WeaponAction, kAP_FireSecondaryStream);
			}
			GetAnimationContext()->Lock();
		}
		break;

		case eFireStateEnding:
		{
			if( GetAI()->GetCurrentWeapon() == GetAI()->GetPrimaryWeapon() )
			{
				GetAnimationContext()->SetProp(kAPG_WeaponAction, kAP_FireStreamEnd);
			}
			else
			{
				GetAnimationContext()->SetProp(kAPG_WeaponAction, kAP_FireSecondaryStreamEnd);
			}
			GetAnimationContext()->Lock();
		}
		break;

		case eFireStateInvalid:
		{
			// we are not in one of the basic firing states, so don't do anything special
			;
		}
		break;

		default:
		{
			AIASSERT( 0, GetAI()->GetHOBJECT(), "CAIHumanStrategyShootStream::UpdateAnimation: Unexpected m_eFireState" );
		}
		break;
	}

	return LTTRUE;
}