//------------------------------------------------------------------------------
// Purpose :
// Input   :
// Output  :
//------------------------------------------------------------------------------
void CNPC_CombineDropship::Hunt( void )
{
	// If we have a pickup target, fly to it
	if ( m_hPickupTarget )
	{
		UpdatePickupNavigation();
	}
	else if ( m_iLandState == LANDING_NO )
	{
		UpdateTrackNavigation();
	}

	// look for enemy
	GetSenses()->Look( 4092 );
	ChooseEnemy();

	// don't face player ever, only face nav points
	Vector desiredDir = GetDesiredPosition() - GetAbsOrigin();
	VectorNormalize( desiredDir ); 
	// Face our desired position.
	m_vecDesiredFaceDir = desiredDir;

	Flight();

	UpdatePlayerDopplerShift( );

}
//------------------------------------------------------------------------------
// Updates the facing direction
//------------------------------------------------------------------------------
void CBaseHelicopter::UpdateFacingDirection()
{
	if ( 1 )
	{
		Vector targetDir = m_vecTargetPosition - GetAbsOrigin();
		Vector desiredDir = GetDesiredPosition() - GetAbsOrigin();

		VectorNormalize( targetDir ); 
		VectorNormalize( desiredDir ); 

		if ( !IsCrashing() && m_flLastSeen + 5 > gpGlobals->curtime ) //&& DotProduct( targetDir, desiredDir) > 0.25)
		{
			// If we've seen the target recently, face the target.
			//Msg( "Facing Target \n" );
			m_vecDesiredFaceDir = targetDir;
		}
		else
		{
			// Face our desired position.
			// Msg( "Facing Position\n" );
			m_vecDesiredFaceDir = desiredDir;
		}
	}
	else
	{
		// Face the way the path corner tells us to.
		//Msg( "Facing my path corner\n" );
		m_vecDesiredFaceDir = GetGoalOrientation();
	}

}
//-----------------------------------------------------------------------------
// Purpose: Override base class to add display of fly direction
// Input  :
// Output : 
//-----------------------------------------------------------------------------
void CBaseHelicopter::DrawDebugGeometryOverlays(void) 
{
	if (m_pfnThink!= NULL)
	{
		// ------------------------------
		// Draw route if requested
		// ------------------------------
		if (m_debugOverlays & OVERLAY_NPC_ROUTE_BIT)
		{
			NDebugOverlay::Line(GetAbsOrigin(), GetDesiredPosition(), 0,0,255, true, 0);
		}
	}
	BaseClass::DrawDebugGeometryOverlays();
}
//------------------------------------------------------------------------------
// Updates the enemy
//------------------------------------------------------------------------------
void CBaseHelicopter::UpdateEnemy()
{
	if( HasCondition( COND_ENEMY_DEAD ) )
	{
		SetEnemy( NULL );
	}

	// Look for my best enemy. If I change enemies, 
	// be sure and change my prevseen/lastseen timers.
	if( m_lifeState == LIFE_ALIVE )
	{
		GetSenses()->Look( (int)EnemySearchDistance() );

		GetEnemies()->RefreshMemories();
		ChooseEnemy();

		if( HasEnemy() )
		{
			CBaseEntity *pEnemy = GetEnemy();
			GatherEnemyConditions( pEnemy );
			if ( FVisible( pEnemy ) )
			{
				if (m_flLastSeen < gpGlobals->curtime - 2)
				{
					m_flPrevSeen = gpGlobals->curtime;
				}

				m_flLastSeen = gpGlobals->curtime;
				m_vecTargetPosition = pEnemy->WorldSpaceCenter();
			}
		}
		else
		{
			// look at where we're going instead
			m_vecTargetPosition = GetDesiredPosition();
		}
	}
	else
	{
		// If we're dead or dying, forget our enemy and don't look for new ones(sjb)
		SetEnemy( NULL );
	}

}
//-----------------------------------------------------------------------------
// Computes the actual position to fly to
//-----------------------------------------------------------------------------
void CBaseHelicopter::ComputeActualTargetPosition( float flSpeed, float flTime, float flPerpDist, Vector *pDest, bool bApplyNoise )
{
	// This is used to make the helicopter drift around a bit.
	if ( bApplyNoise && m_flRandomOffsetTime <= gpGlobals->curtime )
	{
		m_vecRandomOffset.Random( -25.0f, 25.0f );
		m_flRandomOffsetTime = gpGlobals->curtime + 1.0f;
	}

	if ( IsLeading() && GetEnemy() && IsOnPathTrack() )
	{
		ComputePointAlongCurrentPath( flSpeed * flTime, flPerpDist, pDest );
		*pDest += m_vecRandomOffset;
		return;
	}

	*pDest = GetDesiredPosition() - GetAbsOrigin();
	float flDistToDesired = pDest->Length();
	if (flDistToDesired > flSpeed * flTime)
	{
		float scale = flSpeed * flTime / flDistToDesired;
		*pDest *= scale;
	}
	else if ( IsOnPathTrack() )
	{
		// Blend in a fake destination point based on the dest velocity 
		Vector vecDestVelocity;
		ComputeNormalizedDestVelocity( &vecDestVelocity );
		vecDestVelocity *= flSpeed;

		float flBlendFactor = 1.0f - flDistToDesired / (flSpeed * flTime);
		VectorMA( *pDest, flTime * flBlendFactor, vecDestVelocity, *pDest );
	}

	*pDest += GetAbsOrigin();

	if ( bApplyNoise )
	{
		//	ComputePointAlongCurrentPath( flSpeed * flTime, flPerpDist, pDest );
		*pDest += m_vecRandomOffset;
	}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void CBaseHelicopter::Flight( void )
{
	if( GetFlags() & FL_ONGROUND )
	{
		//This would be really bad.
		SetGroundEntity( NULL );
	}

	// Generic speed up
	if (m_flGoalSpeed < GetMaxSpeed())
	{
		m_flGoalSpeed += GetAcceleration();
	}
	
	//NDebugOverlay::Line(GetAbsOrigin(), m_vecDesiredPosition, 0,0,255, true, 0.1);

	// tilt model 5 degrees (why?! sjb)
	QAngle vecAdj = QAngle( 5.0, 0, 0 );

	// estimate where I'll be facing in one seconds
	Vector forward, right, up;
	AngleVectors( GetLocalAngles() + GetLocalAngularVelocity() * 2 + vecAdj, &forward, &right, &up );

	// Vector vecEst1 = GetLocalOrigin() + GetAbsVelocity() + up * m_flForce - Vector( 0, 0, 384 );
	// float flSide = DotProduct( m_vecDesiredPosition - vecEst1, right );
	QAngle angVel = GetLocalAngularVelocity();
	float flSide = DotProduct( m_vecDesiredFaceDir, right );
	if (flSide < 0)
	{
		if (angVel.y < 60)
		{
			angVel.y += 8;
		}
	}
	else
	{
		if (angVel.y > -60)
		{
			angVel.y -= 8;
		}
	}

	angVel.y *= ( 0.98 ); // why?! (sjb)

	// estimate where I'll be in two seconds
	AngleVectors( GetLocalAngles() + angVel * 1 + vecAdj, NULL, NULL, &up );
	Vector vecEst = GetAbsOrigin() + GetAbsVelocity() * 2.0 + up * m_flForce * 20 - Vector( 0, 0, 384 * 2 );

	// add immediate force
	AngleVectors( GetLocalAngles() + vecAdj, &forward, &right, &up );
	
	Vector vecImpulse( 0, 0, 0 );
	vecImpulse.x += up.x * m_flForce;
	vecImpulse.y += up.y * m_flForce;
	vecImpulse.z += up.z * m_flForce;

	// add gravity
	vecImpulse.z -= 38.4; // 32ft/sec
	ApplyAbsVelocityImpulse( vecImpulse );

	float flSpeed = GetAbsVelocity().Length();
	float flDir = DotProduct( Vector( forward.x, forward.y, 0 ), Vector( GetAbsVelocity().x, GetAbsVelocity().y, 0 ) );
	if (flDir < 0)
	{
		flSpeed = -flSpeed;
	}

	float flDist = DotProduct( GetDesiredPosition() - vecEst, forward );

	// float flSlip = DotProduct( GetAbsVelocity(), right );
	float flSlip = -DotProduct( GetDesiredPosition() - vecEst, right );

	// fly sideways
	if (flSlip > 0)
	{
		if (GetLocalAngles().z > -30 && angVel.z > -15)
			angVel.z -= 4;
		else
			angVel.z += 2;
	}
	else
	{
		if (GetLocalAngles().z < 30 && angVel.z < 15)
			angVel.z += 4;
		else
			angVel.z -= 2;
	}

	// These functions contain code Ken wrote that used to be right here as part of the flight model,
	// but we want different helicopter vehicles to have different drag characteristics, so I made
	// them virtual functions (sjb)
	ApplySidewaysDrag( right );
	ApplyGeneralDrag();
	
	// apply power to stay correct height
	// FIXME: these need to be per class variables
#define MAX_FORCE		80
#define FORCE_POSDELTA	12	
#define FORCE_NEGDELTA	8

	if (m_flForce < MAX_FORCE && vecEst.z < GetDesiredPosition().z) 
	{
		m_flForce += FORCE_POSDELTA;
	}
	else if (m_flForce > 30)
	{
		if (vecEst.z > GetDesiredPosition().z) 
			m_flForce -= FORCE_NEGDELTA;
	}
	
	// pitch forward or back to get to target
	//-----------------------------------------
	// Pitch is reversed since Half-Life! (sjb)
	//-----------------------------------------
	if (flDist > 0 && flSpeed < m_flGoalSpeed /* && flSpeed < flDist */ && GetLocalAngles().x + angVel.x < 40)
	{
		// ALERT( at_console, "F " );
		// lean forward
		angVel.x += 12.0;
	}
	else if (flDist < 0 && flSpeed > -50 && GetLocalAngles().x + angVel.x  > -20)
	{
		// ALERT( at_console, "B " );
		// lean backward
		angVel.x -= 12.0;
	}
	else if (GetLocalAngles().x + angVel.x < 0)
	{
		// ALERT( at_console, "f " );
		angVel.x += 4.0;
	}
	else if (GetLocalAngles().x + angVel.x > 0)
	{
		// ALERT( at_console, "b " );
		angVel.x -= 4.0;
	}

	SetLocalAngularVelocity( angVel );
	// ALERT( at_console, "%.0f %.0f : %.0f %.0f : %.0f %.0f : %.0f\n", GetAbsOrigin().x, GetAbsVelocity().x, flDist, flSpeed, GetLocalAngles().x, m_vecAngVelocity.x, m_flForce ); 
	// ALERT( at_console, "%.0f %.0f : %.0f %0.f : %.0f\n", GetAbsOrigin().z, GetAbsVelocity().z, vecEst.z, m_vecDesiredPosition.z, m_flForce ); 
}
//------------------------------------------------------------------------------
// Purpose :
// Input   :
// Output  :
//------------------------------------------------------------------------------
void CBaseHelicopter::Hunt( void )
{
	UpdateTrackNavigation( );

	if( HasCondition( COND_ENEMY_DEAD ) )
	{
		SetEnemy( NULL );
	}

	// Look for my best enemy. If I change enemies, 
	// be sure and change my prevseen/lastseen timers.
	if( m_lifeState == LIFE_ALIVE )
	{
		GetSenses()->Look( 4092 );

		GetEnemies()->RefreshMemories();
		ChooseEnemy();

		if( HasEnemy() )
		{
			GatherEnemyConditions( GetEnemy() );

			if (FVisible( GetEnemy() ))
			{
				if (m_flLastSeen < gpGlobals->curtime - 2)
				{
					m_flPrevSeen = gpGlobals->curtime;
				}

				m_flLastSeen = gpGlobals->curtime;
				m_vecTargetPosition = GetEnemy()->WorldSpaceCenter();
			}
		}
		else
		{
			// look at where we're going instead
			m_vecTargetPosition = GetDesiredPosition();
		}
	}
	else
	{
		// If we're dead or dying, forget our enemy and don't look for new ones(sjb)
		SetEnemy( NULL );
	}

	if ( 1 )
	{
		Vector targetDir = m_vecTargetPosition - GetAbsOrigin();
		Vector desiredDir = GetDesiredPosition() - GetAbsOrigin();

		VectorNormalize( targetDir ); 
		VectorNormalize( desiredDir ); 

		if ( !IsCrashing() && m_flLastSeen + 5 > gpGlobals->curtime ) //&& DotProduct( targetDir, desiredDir) > 0.25)
		{
			// If we've seen the target recently, face the target.
			//Msg( "Facing Target \n" );
			m_vecDesiredFaceDir = targetDir;
		}
		else
		{
			// Face our desired position.
			// Msg( "Facing Position\n" );
			m_vecDesiredFaceDir = desiredDir;
		}
	}
	else
	{
		// Face the way the path corner tells us to.
		//Msg( "Facing my path corner\n" );
		m_vecDesiredFaceDir = GetGoalOrientation();
	}

	Flight();

	UpdatePlayerDopplerShift( );

	// ALERT( at_console, "%.0f %.0f %.0f\n", gpGlobals->curtime, m_flLastSeen, m_flPrevSeen );
	if (m_fHelicopterFlags & BITS_HELICOPTER_GUN_ON)
	{
		//if ( (m_flLastSeen + 1 > gpGlobals->curtime) && (m_flPrevSeen + 2 < gpGlobals->curtime) )
		{
			if (FireGun( ))
			{
				// slow down if we're firing
				if (m_flGoalSpeed > m_flMaxSpeedFiring )
				{
					m_flGoalSpeed = m_flMaxSpeedFiring;
				}
			}
		}
	}

	if (m_fHelicopterFlags & BITS_HELICOPTER_MISSILE_ON)
	{
		AimRocketGun();
	}

	// Finally, forget dead enemies.
	if( GetEnemy() != NULL && (!GetEnemy()->IsAlive() || GetEnemy()->GetFlags() & FL_NOTARGET) )
	{
		SetEnemy( NULL );
	}
}
//------------------------------------------------------------------------------
// Purpose : 
// Input   :
// Output  :
//------------------------------------------------------------------------------
void CNPC_CombineDropship::PrescheduleThink( void )
{
	BaseClass::PrescheduleThink();
	
	// keep track of think time deltas for burn calc below
	float dt = gpGlobals->curtime - m_flLastTime;
	m_flLastTime = gpGlobals->curtime;

	switch( m_iLandState )
	{
	case LANDING_NO:
		{
			if ( IsActivityFinished() && (GetActivity() != ACT_DROPSHIP_FLY_IDLE_EXAGG && GetActivity() != ACT_DROPSHIP_FLY_IDLE_CARGO) )
			{
				if ( m_hContainer )
				{
					SetIdealActivity( (Activity)ACT_DROPSHIP_FLY_IDLE_CARGO );
				}
				else
				{
					SetIdealActivity( (Activity)ACT_DROPSHIP_FLY_IDLE_EXAGG );
				}
			}

			DoRotorWash();
		}
		break;

	case LANDING_LEVEL_OUT:
		{
			// Approach the drop point
			Vector vecToTarget = (GetDesiredPosition() - GetAbsOrigin());
			float flDistance = vecToTarget.Length();

			// If we're slowing, make it look like we're slowing
			/*
			if ( IsActivityFinished() && GetActivity() != ACT_DROPSHIP_DESCEND_IDLE )
			{
				SetActivity( (Activity)ACT_DROPSHIP_DESCEND_IDLE );
			}
			*/

			// Are we there yet?
			float flSpeed = GetAbsVelocity().Length();
			if ( flDistance < 70 && flSpeed < 100 )
			{
				m_flLandingSpeed = flSpeed;
				m_iLandState = LANDING_DESCEND;
				// save off current angles so we can work them out over time
				QAngle angles = GetLocalAngles();
				m_existPitch = angles.x;
				m_existRoll = angles.z;

			}

			DoRotorWash();
		}
		break;

	case LANDING_DESCEND:
		{
			float	flAltitude;

			SetLocalAngularVelocity( vec3_angle );

			// Ensure we land on the drop point
			Vector vecToTarget = (GetDesiredPosition() - GetAbsOrigin());
			float flDistance = vecToTarget.Length();
			float flRampedSpeed = m_flLandingSpeed * (flDistance / 70);
			Vector vecVelocity = (flRampedSpeed / flDistance) * vecToTarget;
			vecVelocity.z = -75;
			SetAbsVelocity( vecVelocity );

			flAltitude = GetAltitude();			

			if ( IsActivityFinished() && GetActivity() != ACT_DROPSHIP_DESCEND_IDLE )
			{
				SetActivity( (Activity)ACT_DROPSHIP_DESCEND_IDLE );
			}

			if ( flAltitude < 72 )
			{
				QAngle angles = GetLocalAngles();

				// Level out quickly.
				angles.x = UTIL_Approach( 0.0, angles.x, 0.2 );
				angles.z = UTIL_Approach( 0.0, angles.z, 0.2 );

				SetLocalAngles( angles );
			}
			else
			{
				// randomly move as if buffeted by ground effects
				// gently flatten ship from starting pitch/yaw
				m_existPitch = UTIL_Approach( 0.0, m_existPitch, 1 );
				m_existRoll = UTIL_Approach( 0.0, m_existRoll, 1 );

				QAngle angles = GetLocalAngles();
				angles.x = m_existPitch + ( sin( gpGlobals->curtime * 3.5f ) * DROPSHIP_MAX_LAND_TILT );
				angles.z = m_existRoll + ( sin( gpGlobals->curtime * 3.75f ) * DROPSHIP_MAX_LAND_TILT );
				SetLocalAngles( angles );

				// figure out where to face (nav point)
				Vector targetDir = GetDesiredPosition() - GetAbsOrigin();
//				NDebugOverlay::Cross3D( m_pGoalEnt->GetAbsOrigin(), -Vector(2,2,2), Vector(2,2,2), 255, 0, 0, false, 20 );

				QAngle targetAngles = GetAbsAngles();
				targetAngles.y += UTIL_AngleDiff(UTIL_VecToYaw( targetDir ), targetAngles.y);
				// orient ship towards path corner on the way down
				angles = GetAbsAngles();
				angles.y = UTIL_Approach(targetAngles.y, angles.y, 2 );
				SetAbsAngles( angles );
			}

			if ( flAltitude <= 0.5f )
			{
				m_iLandState = LANDING_TOUCHDOWN;

				// upon landing, make sure ship is flat
				QAngle angles = GetLocalAngles();
				angles.x = 0;
				angles.z = 0;
				SetLocalAngles( angles );

				// TODO: Release cargo anim
				SetActivity( (Activity)ACT_DROPSHIP_DESCEND_IDLE );
			}

			DoRotorWash();

			// place danger sounds 1 foot above ground to get troops to scatter if they are below dropship
			Vector vecBottom = GetAbsOrigin();
			vecBottom.z += WorldAlignMins().z;
			Vector vecSpot = vecBottom + Vector(0, 0, -1) * (GetAltitude() - 12 );
			CSoundEnt::InsertSound( SOUND_DANGER, vecSpot, 400, 0.2, this, 0 );
			CSoundEnt::InsertSound( SOUND_PHYSICS_DANGER, vecSpot, 400, 0.2, this, 1 );
//			NDebugOverlay::Cross3D( vecSpot, -Vector(4,4,4), Vector(4,4,4), 255, 0, 255, false, 10.0f );

			// now check to see if player is below us, if so, cause heat damage to them (i.e. get them to move)
			trace_t tr;
			Vector vecBBoxMin = CRATE_BBOX_MIN;		// use flat box for check
			vecBBoxMin.z = -5;
			Vector vecBBoxMax = CRATE_BBOX_MAX;
			vecBBoxMax.z = 5;
			Vector pEndPoint = vecBottom + Vector(0, 0, -1) * ( GetAltitude() - 12 );
			AI_TraceHull( vecBottom, pEndPoint, vecBBoxMin, vecBBoxMax, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );

			if ( tr.fraction < 1.0f )
			{
				if ( tr.GetEntityIndex() == 1 )			// player???
				{
					CTakeDamageInfo info( this, this, 20 * dt, DMG_BURN );
					CBasePlayer *pPlayer = UTIL_PlayerByIndex(1);
					pPlayer->TakeDamage( info );
				}
			}

		}
		break;

	case LANDING_TOUCHDOWN:
		{
			if ( IsActivityFinished() && ( GetActivity() != ACT_DROPSHIP_DESCEND_IDLE ) )
			{
				SetActivity( (Activity)ACT_DROPSHIP_DESCEND_IDLE );
			}

			m_iLandState = LANDING_UNLOADING;
			m_flTroopDeployPause = gpGlobals->curtime + DROPSHIP_PAUSE_B4_TROOP_UNLOAD;
			m_flTimeTakeOff = m_flTroopDeployPause + DROPSHIP_DEPLOY_TIME;
		}
		break;

	case LANDING_UNLOADING:
		{
			// pause before dropping troops
			if ( gpGlobals->curtime > m_flTroopDeployPause )
			{
				if ( m_hContainer )	// don't drop troops if we don't have a crate any more
				{
					SpawnTroops();
					m_flTroopDeployPause = m_flTimeTakeOff + 2;	// only drop once
				}
			}
			// manage engine wash and volume
			if ( m_flTimeTakeOff - gpGlobals->curtime < 0.5f )
			{
				m_engineThrust = UTIL_Approach( 1.0f, m_engineThrust, 0.1f );
				DoRotorWash();
			}
			else
			{
				float idleVolume = 0.2f;
				m_engineThrust = UTIL_Approach( idleVolume, m_engineThrust, 0.04f );
				if ( m_engineThrust > idleVolume ) 
				{
					DoRotorWash();				// make sure we're kicking up dust/water as long as engine thrust is up
				}
			}

			if( gpGlobals->curtime > m_flTimeTakeOff )
			{
				m_iLandState = LANDING_LIFTOFF;
				SetActivity( (Activity)ACT_DROPSHIP_LIFTOFF );
				m_engineThrust = 1.0f;			// ensure max volume once we're airborne
				if ( m_bIsFiring )
				{
					StopCannon();				// kill cannon sounds if they are on
				}

				// detach container from ship
				if ( m_hContainer && m_leaveCrate )
				{
					m_hContainer->SetParent(NULL);
					m_hContainer->SetMoveType( (MoveType_t)m_iContainerMoveType );

					// If the container has a physics object, remove it's shadow
					IPhysicsObject *pPhysicsObject = m_hContainer->VPhysicsGetObject();
					if ( pPhysicsObject )
					{
						pPhysicsObject->RemoveShadowController();
					}

					m_hContainer = NULL;
				}
			}
		}
		break;

	case LANDING_LIFTOFF:
		{
			// give us some clearance before changing back to larger hull -- keeps ship from getting stuck on
			// things like the player, etc since we "pop" the hull...
			if ( GetAltitude() > 120 )		
			{
				m_OnFinishedDropoff.FireOutput( this, this );

				m_iLandState = LANDING_NO;

				// change bounding box back to normal ship hull
				Vector vecBBMin, vecBBMax;
				ExtractBbox( SelectHeaviestSequence( ACT_DROPSHIP_DEPLOY_IDLE ), vecBBMin, vecBBMax ); 
				UTIL_SetSize( this, vecBBMin, vecBBMax );
				Relink();
			}
		}
		break;

	case LANDING_SWOOPING:
		{
			// Did we lose our pickup target?
			if ( !m_hPickupTarget )
			{
				m_iLandState = LANDING_NO;
			}
			else
			{
				// Decrease altitude and speed to hit the target point.
				Vector vecToTarget = (GetDesiredPosition() - GetAbsOrigin());
				float flDistance = vecToTarget.Length();

				// Start cheating when we get near it
				if ( flDistance < 50 )
				{
					/*
					if ( flDistance > 10 )
					{
						// Cheat and ensure we touch the target
						float flSpeed = GetAbsVelocity().Length();
						Vector vecVelocity = vecToTarget;
						VectorNormalize( vecVelocity );
						SetAbsVelocity( vecVelocity * min(flSpeed,flDistance) );
					}
					else
					*/
					{
						// Grab the target
						m_hContainer = m_hPickupTarget;
						m_hPickupTarget = NULL;
						m_iContainerMoveType = m_hContainer->GetMoveType();

						// If the container has a physics object, move it to shadow
						IPhysicsObject *pPhysicsObject = m_hContainer->VPhysicsGetObject();
						if ( pPhysicsObject )
						{
							pPhysicsObject->SetShadow( Vector(1e4,1e4,1e4), AngularImpulse(1e4,1e4,1e4), false, false );
							pPhysicsObject->UpdateShadow( GetAbsOrigin(), GetAbsAngles(), false, 0 );
						}

						int iIndex = 0;//LookupAttachment("Cargo");
						/*
						Vector vecOrigin;
						QAngle vecAngles;
						GetAttachment( iIndex, vecOrigin, vecAngles );
						m_hContainer->SetAbsOrigin( vecOrigin );
						m_hContainer->SetAbsAngles( vec3_angle );
						*/
						m_hContainer->SetAbsOrigin( GetAbsOrigin() );
						m_hContainer->SetParent(this, iIndex);
						m_hContainer->SetMoveType( MOVETYPE_PUSH );
						m_hContainer->RemoveFlag( FL_ONGROUND );
						m_hContainer->Relink();
						m_hContainer->SetAbsAngles( vec3_angle );

						m_OnFinishedPickup.FireOutput( this, this );
						m_iLandState = LANDING_NO;
					}
				}
			}

			DoRotorWash();
		}
		break;
	}

	DoCombatStuff();

	if ( GetActivity() != GetIdealActivity() )
	{
		//Msg( "setactivity" );
		SetActivity( GetIdealActivity() );
	}
}
//------------------------------------------------------------------------------
// Purpose : 
// Input   :
// Output  :
//------------------------------------------------------------------------------
void CNPC_CombineDropship::Flight( void )
{
	// Only run pose params in some flight states
	bool bRunPoseParams = ( m_iLandState == LANDING_NO || 
							m_iLandState == LANDING_LEVEL_OUT || 
							m_iLandState == LANDING_LIFTOFF ||
							m_iLandState == LANDING_SWOOPING );

	if ( bRunPoseParams )
	{
		if( GetFlags() & FL_ONGROUND )
		{
			//This would be really bad.
			RemoveFlag( FL_ONGROUND );
		}

		// NDebugOverlay::Line(GetLocalOrigin(), GetDesiredPosition(), 0,0,255, true, 0.1);

		Vector deltaPos = GetDesiredPosition() - GetLocalOrigin();

		// calc desired acceleration
		float dt = 1.0f;

		Vector	accel;
		float	accelRate = DROPSHIP_ACCEL_RATE;
		float	maxSpeed = m_flMaxSpeed;

		if ( m_lifeState == LIFE_DYING )
		{
			accelRate *= 5.0;
			maxSpeed *= 5.0;
		}

		float flDist = min( GetAbsVelocity().Length() + accelRate, maxSpeed );

		// Only decelerate to our goal if we're going to hit it
		if ( deltaPos.Length() > flDist * dt )
		{
			float scale = flDist * dt / deltaPos.Length();
			deltaPos = deltaPos * scale;
		}
		
		// If we're swooping, floor it
		if ( m_iLandState == LANDING_SWOOPING )
		{
			VectorNormalize( deltaPos );
			deltaPos *= maxSpeed;
		}
		
		// calc goal linear accel to hit deltaPos in dt time.
		accel.x = 2.0 * (deltaPos.x - GetAbsVelocity().x * dt) / (dt * dt);
		accel.y = 2.0 * (deltaPos.y - GetAbsVelocity().y * dt) / (dt * dt);
		accel.z = 2.0 * (deltaPos.z - GetAbsVelocity().z * dt + 0.5 * 384 * dt * dt) / (dt * dt);
		
		//NDebugOverlay::Line(GetLocalOrigin(), GetLocalOrigin() + deltaPos, 255,0,0, true, 0.1);
		//NDebugOverlay::Line(GetLocalOrigin(), GetLocalOrigin() + accel, 0,255,0, true, 0.1);

		// don't fall faster than 0.2G or climb faster than 2G
		if ( m_iLandState != LANDING_SWOOPING )
		{
			accel.z = clamp( accel.z, 384 * 0.2, 384 * 2.0 );
		}

		Vector forward, right, up;
		GetVectors( &forward, &right, &up );

		Vector goalUp = accel;
		VectorNormalize( goalUp );

		// calc goal orientation to hit linear accel forces
		float goalPitch = RAD2DEG( asin( DotProduct( forward, goalUp ) ) );
		float goalYaw = UTIL_VecToYaw( m_vecDesiredFaceDir );
		float goalRoll = RAD2DEG( asin( DotProduct( right, goalUp ) ) );

		// clamp goal orientations
		goalPitch = clamp( goalPitch, -45, 60 );
		goalRoll = clamp( goalRoll, -45, 45 );

		// calc angular accel needed to hit goal pitch in dt time.
		dt = 0.6;
		QAngle goalAngAccel;
		goalAngAccel.x = 2.0 * (AngleDiff( goalPitch, AngleNormalize( GetLocalAngles().x ) ) - GetLocalAngularVelocity().x * dt) / (dt * dt);
		goalAngAccel.y = 2.0 * (AngleDiff( goalYaw, AngleNormalize( GetLocalAngles().y ) ) - GetLocalAngularVelocity().y * dt) / (dt * dt);
		goalAngAccel.z = 2.0 * (AngleDiff( goalRoll, AngleNormalize( GetLocalAngles().z ) ) - GetLocalAngularVelocity().z * dt) / (dt * dt);

		goalAngAccel.x = clamp( goalAngAccel.x, -300, 300 );
		//goalAngAccel.y = clamp( goalAngAccel.y, -60, 60 );
		goalAngAccel.y = clamp( goalAngAccel.y, -120, 120 );
		goalAngAccel.z = clamp( goalAngAccel.z, -300, 300 );

		// limit angular accel changes to simulate mechanical response times
		dt = 0.1;
		QAngle angAccelAccel;
		angAccelAccel.x = (goalAngAccel.x - m_vecAngAcceleration.x) / dt;
		angAccelAccel.y = (goalAngAccel.y - m_vecAngAcceleration.y) / dt;
		angAccelAccel.z = (goalAngAccel.z - m_vecAngAcceleration.z) / dt;

		angAccelAccel.x = clamp( angAccelAccel.x, -1000, 1000 );
		angAccelAccel.y = clamp( angAccelAccel.y, -1000, 1000 );
		angAccelAccel.z = clamp( angAccelAccel.z, -1000, 1000 );

		m_vecAngAcceleration += angAccelAccel * 0.1;

		// Msg( "pitch %6.1f (%6.1f:%6.1f)  ", goalPitch, GetLocalAngles().x, m_vecAngVelocity.x );
		// Msg( "roll %6.1f (%6.1f:%6.1f) : ", goalRoll, GetLocalAngles().z, m_vecAngVelocity.z );
		// Msg( "%6.1f %6.1f %6.1f  :  ", goalAngAccel.x, goalAngAccel.y, goalAngAccel.z );
		// Msg( "%6.0f %6.0f %6.0f\n", angAccelAccel.x, angAccelAccel.y, angAccelAccel.z );

		ApplySidewaysDrag( right );
		ApplyGeneralDrag();
		
		QAngle angVel = GetLocalAngularVelocity();
		angVel += m_vecAngAcceleration * 0.1;

		//angVel.y = clamp( angVel.y, -60, 60 );
		//angVel.y = clamp( angVel.y, -120, 120 );
		angVel.y = clamp( angVel.y, -120, 120 );

		SetLocalAngularVelocity( angVel );

		m_flForce = m_flForce * 0.8 + (accel.z + fabs( accel.x ) * 0.1 + fabs( accel.y ) * 0.1) * 0.1 * 0.2;

		Vector vecImpulse = m_flForce * up;
		
		if ( m_lifeState == LIFE_DYING )
		{
			vecImpulse.z = -38.4;  // 64ft/sec
		}
		else
		{
			vecImpulse.z -= 38.4;  // 32ft/sec
		}
		
		// Find our acceleration direction
		Vector	vecAccelDir = vecImpulse;
		VectorNormalize( vecAccelDir );

		// Find our current velocity
		Vector	vecVelDir = GetAbsVelocity();
		VectorNormalize( vecVelDir );

		// Level out our plane of movement
		vecAccelDir.z	= 0.0f;
		vecVelDir.z		= 0.0f;
		forward.z		= 0.0f;
		right.z			= 0.0f;

		// Find out how "fast" we're moving in relation to facing and acceleration
		float speed = m_flForce * DotProduct( vecVelDir, vecAccelDir );// * DotProduct( forward, vecVelDir );

		// Use the correct pose params
		char *sBodyAccel;
		char *sBodySway;
		if ( m_hContainer || m_iLandState == LANDING_SWOOPING )
		{
			sBodyAccel = "cargo_body_accel";
			sBodySway = "cargo_body_sway";
			SetPoseParameter( "body_accel", 0 );
			SetPoseParameter( "body_sway", 0 );
		}
		else
		{
			sBodyAccel = "body_accel";
			sBodySway = "body_sway";
			SetPoseParameter( "cargo_body_accel", 0 );
			SetPoseParameter( "cargo_body_sway", 0 );
		}

		// Apply the acceleration blend to the fins
		float finAccelBlend = SimpleSplineRemapVal( speed, -60, 60, -1, 1 );
		float curFinAccel = GetPoseParameter( sBodyAccel );
		
		curFinAccel = UTIL_Approach( finAccelBlend, curFinAccel, 0.5f );

		SetPoseParameter( sBodyAccel, curFinAccel );

		speed = m_flForce * DotProduct( vecVelDir, right );

		// Apply the spin sway to the fins
		float finSwayBlend = SimpleSplineRemapVal( speed, -60, 60, -1, 1 );
		float curFinSway = GetPoseParameter( sBodySway );

		curFinSway = UTIL_Approach( finSwayBlend, curFinSway, 0.5f );
		SetPoseParameter( sBodySway, curFinSway );

		// Add in our velocity pulse for this frame
		ApplyAbsVelocityImpulse( vecImpulse );

		//Msg("FinAccel: %f, Finsway: %f\n", curFinAccel, curFinSway );
	}
	else
	{
		SetPoseParameter( "body_accel", 0 );
		SetPoseParameter( "body_sway", 0 );
		SetPoseParameter( "cargo_body_accel", 0 );
		SetPoseParameter( "cargo_body_sway", 0 );
	}
}