//-----------------------------------------------------------------------------
// Purpose: Spawn the entity
//-----------------------------------------------------------------------------
void CNPC_CeilingTurret::Spawn( void )
{ 
	Precache();

	SetModel( CEILING_TURRET_MODEL );
	
	BaseClass::Spawn();

	m_HackedGunPos	= Vector( 0, 0, 12.75 );
	SetViewOffset( EyeOffset( ACT_IDLE ) );
	m_flFieldOfView	= 0.0f;
	m_takedamage	= DAMAGE_YES;
	m_iHealth		= 1000;
	m_bloodColor	= BLOOD_COLOR_MECH;
	
	SetSolid( SOLID_BBOX );
	AddSolidFlags( FSOLID_NOT_STANDABLE );

	SetHeight( CEILING_TURRET_RETRACT_HEIGHT );

	AddFlag( FL_AIMTARGET );
	AddEFlags( EFL_NO_DISSOLVE );

	SetPoseParameter( m_poseAim_Yaw, 0 );
	SetPoseParameter( m_poseAim_Pitch, 0 );

	m_iAmmoType = GetAmmoDef()->Index( "AR2" );

	//Create our eye sprite
	m_pEyeGlow = CSprite::SpriteCreate( CEILING_TURRET_GLOW_SPRITE, GetLocalOrigin(), false );
	m_pEyeGlow->SetTransparency( kRenderTransAdd, 255, 0, 0, 128, kRenderFxNoDissipation );
	m_pEyeGlow->SetAttachment( this, 2 );

	//Set our autostart state
	m_bAutoStart = !!( m_spawnflags & SF_CEILING_TURRET_AUTOACTIVATE );
	m_bEnabled	 = ( ( m_spawnflags & SF_CEILING_TURRET_STARTINACTIVE ) == false );

	//Do we start active?
	if ( m_bAutoStart && m_bEnabled )
	{
		SetThink( &CNPC_CeilingTurret::AutoSearchThink );
		SetEyeState( TURRET_EYE_DORMANT );
	}
	else
	{
		SetEyeState( TURRET_EYE_DISABLED );
	}

	//Stagger our starting times
	SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.1f, 0.3f ) );

	// Don't allow us to skip animation setup because our attachments are critical to us!
	SetBoneCacheFlags( BCF_NO_ANIMATION_SKIP );
}
//-----------------------------------------------------------------------------
// Purpose: Retract and stop attacking
//-----------------------------------------------------------------------------
void CNPC_CeilingTurret::Retire( void )
{
	if ( PreThink( TURRET_RETIRING ) )
		return;

	//Level out the turret
	m_vecGoalAngles = GetAbsAngles();
	SetNextThink( gpGlobals->curtime );

	//Set ourselves to close
	if ( GetActivity() != ACT_CEILING_TURRET_CLOSE )
	{
		//Set our visible state to dormant
		SetEyeState( TURRET_EYE_DORMANT );

		SetActivity( (Activity) ACT_CEILING_TURRET_OPEN_IDLE );
		
		//If we're done moving to our desired facing, close up
		if ( UpdateFacing() == false )
		{
			SetActivity( (Activity) ACT_CEILING_TURRET_CLOSE );
			EmitSound( "NPC_CeilingTurret.Retire" );

			//Notify of the retraction
			m_OnRetire.FireOutput( NULL, this );
		}
	}
	else if ( IsActivityFinished() )
	{	
		SetHeight( CEILING_TURRET_RETRACT_HEIGHT );

		m_bActive		= false;
		m_flLastSight	= 0;

		SetActivity( (Activity) ACT_CEILING_TURRET_CLOSED_IDLE );

		//Go back to auto searching
		if ( m_bAutoStart )
		{
			SetThink( &CNPC_CeilingTurret::AutoSearchThink );
			SetNextThink( gpGlobals->curtime + 0.05f );
		}
		else
		{
			//Set our visible state to dormant
			SetEyeState( TURRET_EYE_DISABLED );
			SetThink( &CNPC_CeilingTurret::SUB_DoNothing );
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: Target doesn't exist or has eluded us, so search for one
//-----------------------------------------------------------------------------
void CNPC_CombineCamera::SearchThink()
{
	// Allow descended classes a chance to do something before the think function
	if (PreThink(CAMERA_SEARCHING))
		return;

	SetNextThink( gpGlobals->curtime + 0.05f );

	SetIdealActivity((Activity) ACT_COMBINE_CAMERA_OPEN_IDLE);

	if ( !GetTarget() )
	{
		// Try to acquire a new target
		if (MaintainEnemy())
		{
			SetThink( &CNPC_CombineCamera::ActiveThink );
			return;
		}
	}

	// Display that we're scanning
	m_vecGoalAngles.x = 15.0f;
	m_vecGoalAngles.y = GetAbsAngles().y + (sin(gpGlobals->curtime * 2.0f) * 45.0f);

	// Turn and ping
	UpdateFacing();
	Ping();

	SetEyeState(CAMERA_EYE_IDLE);
}
//-----------------------------------------------------------------------------
// Purpose: When we become angry, we make an angry sound and start photographing
//			whatever target we are tracking.
//-----------------------------------------------------------------------------
void CNPC_CombineCamera::SetAngry(bool bAngry)
{
	if ((bAngry) && (!m_bAngry))
	{
		m_bAngry = true;
		m_nClickCount = 0;
		m_flClickTime = gpGlobals->curtime + 0.4;
		EmitSound("NPC_CombineCamera.Angry");
		SetEyeState(CAMERA_EYE_ANGRY);
	}
	else if ((!bAngry) && (m_bAngry))
	{
		m_bAngry = false;

		// make sure the flash is off (we might be in mid-flash)
		m_pEyeFlash->SetBrightness(0);
		SetEyeState(GetTarget() ? CAMERA_EYE_SEEKING_TARGET : CAMERA_EYE_IDLE);
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &info - 
//-----------------------------------------------------------------------------
void CNPC_Assassin::Event_Killed( const CTakeDamageInfo &info )
{
	BaseClass::Event_Killed( info );

	// Turn off the eye
	SetEyeState( ASSASSIN_EYE_DEAD );
	
	// Turn off the pistols
	SetBodygroup( 1, 0 );

	// Spawn her guns
}
//-----------------------------------------------------------------------------
// Purpose: Translate base class activities into combot activites
//-----------------------------------------------------------------------------
Activity CNPC_CombineAce::NPC_TranslateActivity( Activity eNewActivity )
{
	// If the special ep2_outland_05 "use march" flag is set, use the more casual marching anim.
	if ( m_iUseMarch && eNewActivity == ACT_WALK )
	{
		eNewActivity = ACT_WALK_MARCH;
	}
	else if (eNewActivity == ACT_IDLE)
	{
		SetEyeState(ACE_EYE_DORMANT);

		if (!IsCrouching() && (m_NPCState == NPC_STATE_COMBAT || m_NPCState == NPC_STATE_ALERT))
		{
			SetEyeState(ACE_EYE_ACTIVATE);
			eNewActivity = ACT_IDLE_ANGRY;
		}
	}
	else if (eNewActivity == ACT_RANGE_ATTACK1)
	{
		SetEyeState(ACE_EYE_ACTIVATE);
	}
	else if (eNewActivity == ACT_RANGE_ATTACK2)
	{
		SetEyeState(ACE_EYE_ACTIVATE);

		// grunt is going to a secondary long range attack. This may be a thrown 
		// grenade or fired grenade, we must determine which and pick proper sequence
		if (Weapon_OwnsThisType("weapon_grenadelauncher"))
		{
			return (Activity)ACT_COMBINE_LAUNCH_GRENADE;
		}
		else
		{
			return (Activity)ACT_COMBINE_THROW_GRENADE;
		}
	}

	return BaseClass::NPC_TranslateActivity( eNewActivity );
}
//-----------------------------------------------------------------------------
// Purpose: Make a pinging noise so the player knows where we are
//-----------------------------------------------------------------------------
void CNPC_CeilingTurret::Ping( void )
{
	//See if it's time to ping again
	if ( m_flPingTime > gpGlobals->curtime )
		return;

	//Ping!
	EmitSound( "NPC_CeilingTurret.Ping" );

	SetEyeState( TURRET_EYE_SEEKING_TARGET );

	m_flPingTime = gpGlobals->curtime + CEILING_TURRET_PING_TIME;
}
//-----------------------------------------------------------------------------
// Purpose: The turret is not doing anything at all
//-----------------------------------------------------------------------------
void CNPC_Portal_FloorTurret::DisabledThink( void )
{
	LaserOff();
	RopesOff();

	SetNextThink( gpGlobals->curtime + 0.5 );
	if ( OnSide() )
	{
		m_OnTipped.FireOutput( this, this );
		SetEyeState( TURRET_EYE_DEAD );
		//SetCollisionGroup( COLLISION_GROUP_DEBRIS_TRIGGER );
		SetThink( NULL );
	}

}
//-----------------------------------------------------------------------------
// Purpose: Deploy and start searching for targets.
//-----------------------------------------------------------------------------
void CNPC_CombineCamera::Deploy()
{
	m_vecGoalAngles = GetAbsAngles();

	SetNextThink( gpGlobals->curtime );

	SetEyeState(CAMERA_EYE_IDLE);
	m_bActive = true;

	SetHeight(COMBINE_CAMERA_DEPLOY_HEIGHT);
	SetIdealActivity((Activity) ACT_COMBINE_CAMERA_OPEN_IDLE);
	m_flPlaybackRate = 0;
	SetThink(&CNPC_CombineCamera::SearchThink);

	EmitSound("NPC_CombineCamera.Move");
}
//-----------------------------------------------------------------------------
// Purpose: Deploy and start attacking
//-----------------------------------------------------------------------------
void CNPC_CeilingTurret::Deploy( void )
{
	if ( PreThink( TURRET_DEPLOYING ) )
		return;

	m_vecGoalAngles = GetAbsAngles();

	SetNextThink( gpGlobals->curtime );

	//Show we've seen a target
	SetEyeState( TURRET_EYE_SEE_TARGET );

	//Open if we're not already
	if ( GetActivity() != ACT_CEILING_TURRET_OPEN )
	{
		m_bActive = true;
		SetActivity( (Activity) ACT_CEILING_TURRET_OPEN );
		EmitSound( "NPC_CeilingTurret.Deploy" );

		//Notify we're deploying
		m_OnDeploy.FireOutput( NULL, this );
	}

	//If we're done, then start searching
	if ( IsActivityFinished() )
	{
		SetHeight( CEILING_TURRET_DEPLOY_HEIGHT );

		SetActivity( (Activity) ACT_CEILING_TURRET_OPEN_IDLE );

		m_flShotTime  = gpGlobals->curtime + 1.0f;

		m_flPlaybackRate = 0;
		SetThink( &CNPC_CeilingTurret::SearchThink );

		EmitSound( "NPC_CeilingTurret.Move" );
	}

	SetLastSightTime();
}
//---------------------------------------------------------
// Purpose: 
//---------------------------------------------------------
void CNPC_Assassin::StartTask( const Task_t *pTask )
{
	switch( pTask->iTask )
	{
	case TASK_ASSASSIN_SET_EYE_STATE:
		{
			SetEyeState( (eyeState_t) ( (int) pTask->flTaskData ) );
			TaskComplete();
		}
		break;

	case TASK_ASSASSIN_EVADE:
		{
			Activity flipAct = ACT_INVALID;

			const Vector *avoidPos = ( GetEnemy() != NULL ) ? &(GetEnemy()->GetAbsOrigin()) : NULL;

			for ( int i = FLIP_LEFT; i < NUM_FLIP_TYPES; i++ )
			{
				if ( CanFlip( i, flipAct, avoidPos ) )
				{
					// Don't flip back to where we just were
					if ( ( ( i == FLIP_LEFT ) && ( m_nLastFlipType == FLIP_RIGHT ) ) ||
						 ( ( i == FLIP_RIGHT ) && ( m_nLastFlipType == FLIP_LEFT ) ) ||
						 ( ( i == FLIP_FORWARD ) && ( m_nLastFlipType == FLIP_BACKWARD ) ) ||
						 ( ( i == FLIP_BACKWARD ) && ( m_nLastFlipType == FLIP_FORWARD ) ) )
					{
						flipAct = ACT_INVALID;
						continue;
					}

					m_nNumFlips--;
					ResetIdealActivity( flipAct );
					m_flNextFlipTime = gpGlobals->curtime + 2.0f;
					m_nLastFlipType = i;
					break;
				}
			}

			if ( flipAct == ACT_INVALID )
			{
				m_nNumFlips = 0;
				m_nLastFlipType = -1;
				m_flNextFlipTime = gpGlobals->curtime + 2.0f;
				TaskFail( "Unable to find flip evasion direction!\n" );
			}
		}
		break;

	case TASK_ASSASSIN_GET_PATH_TO_VANTAGE_POINT:
		{
			assert( GetEnemy() != NULL );
			if ( GetEnemy() == NULL )
				break;

			Vector	goalPos;

			CHintCriteria	hint;

			// Find a disadvantage node near the player, but away from ourselves
			hint.SetHintType( HINT_TACTICAL_ENEMY_DISADVANTAGED );
			hint.AddExcludePosition( GetAbsOrigin(), 256 );
			hint.AddExcludePosition( GetEnemy()->GetAbsOrigin(), 256 );

			if ( ( m_pSquad != NULL ) && ( m_pSquad->NumMembers() > 1 ) )
			{
				AISquadIter_t iter;
				for ( CAI_BaseNPC *pSquadMember = m_pSquad->GetFirstMember( &iter ); pSquadMember; pSquadMember = m_pSquad->GetNextMember( &iter ) )
				{
					if ( pSquadMember == NULL )
						continue;

					hint.AddExcludePosition( pSquadMember->GetAbsOrigin(), 128 );
				}
			}
	
			hint.SetFlag( bits_HINT_NODE_NEAREST );

			CAI_Hint *pHint = CAI_HintManager::FindHint( this, GetEnemy()->GetAbsOrigin(), &hint );

			if ( pHint == NULL )
			{
				TaskFail( "Unable to find vantage point!\n" );
				break;
			}

			pHint->GetPosition( this, &goalPos );

			AI_NavGoal_t goal( goalPos );
			
			//Try to run directly there
			if ( GetNavigator()->SetGoal( goal ) == false )
			{
				TaskFail( "Unable to find path to vantage point!\n" );
				break;
			}
			
			TaskComplete();
		}
		break;

	default:
		BaseClass::StartTask( pTask );
		break;
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_CombineAce::Spawn( void )
{
	Precache();

	SetModel( "models/combine_ace_soldier.mdl" );

	//Give him a random amount of grenades on spawn
	if (combine_ace_spawnwithgrenades.GetBool())
	{
		if (g_pGameRules->IsSkillLevel(SKILL_HARD))
		{
			m_iNumGrenades = random->RandomInt(2, 3);
		}
		else if (g_pGameRules->IsSkillLevel(SKILL_VERYHARD))
		{
			m_iNumGrenades = random->RandomInt(4, 6);
		}
		else if (g_pGameRules->IsSkillLevel(SKILL_NIGHTMARE))
		{
			m_iNumGrenades = random->RandomInt(8, 12);
		}
		else
		{
			m_iNumGrenades = random->RandomInt(0, 2);
		}
	}

	m_fIsElite = true;
	m_fIsAce = true;

	// Stronger, tougher.
	SetHealth(sk_combine_ace_health.GetFloat());
	SetMaxHealth(sk_combine_ace_health.GetFloat());
	SetKickDamage(sk_combine_ace_kick.GetFloat());

	CapabilitiesAdd( bits_CAP_ANIMATEDFACE );
	CapabilitiesAdd( bits_CAP_MOVE_SHOOT );
	CapabilitiesAdd( bits_CAP_MOVE_JUMP );
	CapabilitiesAdd( bits_CAP_DOORS_GROUP );

	int attachment = LookupAttachment("eyes");

	// Start up the eye glow
	m_pEyeSprite = CSprite::SpriteCreate("sprites/redglow1.vmt", GetLocalOrigin(), false);

	if (m_pEyeSprite != NULL)
	{
		m_pEyeSprite->SetAttachment(this, attachment);
		m_pEyeSprite->SetTransparency(kRenderTransAdd, 255, 255, 255, 200, kRenderFxNone);
		m_pEyeSprite->SetScale(0.25f);
	}

	// Start up the eye trail
	m_pEyeTrail = CSpriteTrail::SpriteTrailCreate("sprites/bluelaser1.vmt", GetLocalOrigin(), false);

	if (m_pEyeTrail != NULL)
	{
		m_pEyeTrail->SetAttachment(this, attachment);
		m_pEyeTrail->SetTransparency(kRenderTransAdd, 255, 0, 0, 200, kRenderFxNone);
		m_pEyeTrail->SetStartWidth(8.0f);
		m_pEyeTrail->SetLifeTime(0.75f);
	}

	SetEyeState(ACE_EYE_DORMANT);

	if (combine_ace_shieldspawnmode.GetInt() == 1)
	{
		SpawnArmorPieces();
	}
	else if (combine_ace_shieldspawnmode.GetInt() > 1)
	{
		int iShieldRandom = random->RandomInt(0, 3);
		if (iShieldRandom == 0)
		{
			SpawnArmorPieces();
		}
		else
		{
			pArmor = NULL;
			m_bNoArmor = true;
		}
	}
	else
	{
		pArmor = NULL;
		m_bNoArmor = true;
	}

	BaseClass::Spawn();

#if HL2_EPISODIC
	if (m_iUseMarch && !HasSpawnFlags(SF_NPC_START_EFFICIENT))
	{
		Msg( "Soldier %s is set to use march anim, but is not an efficient AI. The blended march anim can only be used for dead-ahead walks!\n", GetDebugName() );
	}
#endif
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &info - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
void CNPC_CombineAce::Event_Killed( const CTakeDamageInfo &info )
{
	if (!(g_Language.GetInt() == LANGUAGE_GERMAN || UTIL_IsLowViolence()) && info.GetDamageType() & (DMG_BLAST | DMG_CRUSH) && !(info.GetDamageType() & (DMG_DISSOLVE)) && !PlayerHasMegaPhysCannon())
	{
		Vector vecDamageDir = info.GetDamageForce();
		SpawnBlood(GetAbsOrigin(), g_vecAttackDir, BloodColor(), info.GetDamage());
		DispatchParticleEffect("headshotspray", GetAbsOrigin(), GetAbsAngles(), this);
		EmitSound("Gore.Headshot");
		float flFadeTime = 25.0;

		CGib::SpawnSpecificGibs(this, 1, 750, 1500, "models/gibs/soldier_ace_head.mdl", flFadeTime);

		Vector vecRagForce;
		vecRagForce.x = random->RandomFloat(-400, 400);
		vecRagForce.y = random->RandomFloat(-400, 400);
		vecRagForce.z = random->RandomFloat(0, 250);

		Vector vecRagDmgForce = (vecRagForce + vecDamageDir);

		CBaseEntity *pLeftArmGib = CreateRagGib("models/gibs/soldier_ace_left_arm.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire());
		if (pLeftArmGib)
		{
			color32 color = pLeftArmGib->GetRenderColor();
			pLeftArmGib->SetRenderColor(color.r, color.g, color.b, color.a);
		}

		CBaseEntity *pRightArmGib = CreateRagGib("models/gibs/soldier_ace_right_arm.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire());
		if (pRightArmGib)
		{
			color32 color = pRightArmGib->GetRenderColor();
			pRightArmGib->SetRenderColor(color.r, color.g, color.b, color.a);
		}

		CBaseEntity *pTorsoGib = CreateRagGib("models/gibs/soldier_ace_torso.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire());
		if (pTorsoGib)
		{
			color32 color = pTorsoGib->GetRenderColor();
			pTorsoGib->SetRenderColor(color.r, color.g, color.b, color.a);
		}

		CBaseEntity *pPelvisGib = CreateRagGib("models/gibs/soldier_ace_pelvis.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire());
		if (pPelvisGib)
		{
			color32 color = pPelvisGib->GetRenderColor();
			pPelvisGib->SetRenderColor(color.r, color.g, color.b, color.a);
		}

		CBaseEntity *pLeftLegGib = CreateRagGib("models/gibs/soldier_ace_left_leg.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire());
		if (pLeftLegGib)
		{
			color32 color = pLeftLegGib->GetRenderColor();
			pLeftLegGib->SetRenderColor(color.r, color.g, color.b, color.a);
		}

		CBaseEntity *pRightLegGib = CreateRagGib("models/gibs/soldier_ace_right_leg.mdl", GetAbsOrigin(), GetAbsAngles(), vecRagDmgForce, flFadeTime, IsOnFire());
		if (pRightLegGib)
		{
			color32 color = pRightLegGib->GetRenderColor();
			pRightLegGib->SetRenderColor(color.r, color.g, color.b, color.a);
		}

		//now add smaller gibs.
		CGib::SpawnSpecificGibs(this, 3, 750, 1500, "models/gibs/pgib_p3.mdl", flFadeTime);
		CGib::SpawnSpecificGibs(this, 3, 750, 1500, "models/gibs/pgib_p4.mdl", flFadeTime);

		if (!m_bNoArmor && combine_ace_shieldspawnmode.GetInt() > 0)
		{
			pArmor->Remove();
			DropItem("item_shield", WorldSpaceCenter() + RandomVector(-4, 4), RandomAngle(0, 360));
		}

		Vector forceVector = CalcDamageForceVector(info);

		// Drop any weapon that I own
		if (VPhysicsGetObject())
		{
			Vector weaponForce = forceVector * VPhysicsGetObject()->GetInvMass();
			Weapon_Drop(m_hActiveWeapon, NULL, &weaponForce);
		}
		else
		{
			Weapon_Drop(m_hActiveWeapon);
		}

		if (info.GetAttacker()->IsPlayer())
		{
			((CSingleplayRules*)GameRules())->NPCKilled(this, info);
		}

		UTIL_Remove(this);
		SetThink(NULL);
		return;
	}

	// Don't bother if we've been told not to, or the player has a megaphyscannon
	if ( combine_ace_spawn_health.GetBool() == false || PlayerHasMegaPhysCannon() )
	{
		BaseClass::Event_Killed( info );
		return;
	}

	SetEyeState(ACE_EYE_DEAD);

	if (!m_bNoArmor && combine_ace_shieldspawnmode.GetInt() > 0)
	{
		pArmor->Remove();
	}

	CBasePlayer *pPlayer = ToBasePlayer( info.GetAttacker() );

	if ( !pPlayer )
	{
		CPropVehicleDriveable *pVehicle = dynamic_cast<CPropVehicleDriveable *>( info.GetAttacker() ) ;
		if ( pVehicle && pVehicle->GetDriver() && pVehicle->GetDriver()->IsPlayer() )
		{
			pPlayer = assert_cast<CBasePlayer *>( pVehicle->GetDriver() );
		}
	}

	if ( pPlayer != NULL )
	{
		// Elites drop alt-fire ammo, so long as they weren't killed by dissolving.
#ifdef HL2_EPISODIC
		if (HasSpawnFlags(SF_COMBINE_NO_AR2DROP) == false)
#endif
		{
			if (FClassnameIs(GetActiveWeapon(), "weapon_ar2"))
			{
				CBaseEntity *pItem = DropItem("item_ammo_ar2_altfire", WorldSpaceCenter() + RandomVector(-4, 4), RandomAngle(0, 360));

				if (pItem)
				{
					IPhysicsObject *pObj = pItem->VPhysicsGetObject();

					if (pObj)
					{
						Vector			vel = RandomVector(-64.0f, 64.0f);
						AngularImpulse	angImp = RandomAngularImpulse(-300.0f, 300.0f);

						vel[2] = 0.0f;
						pObj->AddVelocity(&vel, &angImp);
					}

					if (info.GetDamageType() & DMG_DISSOLVE)
					{
						CBaseAnimating *pAnimating = dynamic_cast<CBaseAnimating*>(pItem);

						if (pAnimating)
						{
							pAnimating->Dissolve(NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL);
						}
					}
					else
					{
						WeaponManager_AddManaged(pItem);
					}
				}
			}
			else if (FClassnameIs(GetActiveWeapon(), "weapon_smg1"))
			{
				CBaseEntity *pItem = DropItem("item_ammo_smg1_grenade", WorldSpaceCenter() + RandomVector(-4, 4), RandomAngle(0, 360));

				if (pItem)
				{
					IPhysicsObject *pObj = pItem->VPhysicsGetObject();

					if (pObj)
					{
						Vector			vel = RandomVector(-64.0f, 64.0f);
						AngularImpulse	angImp = RandomAngularImpulse(-300.0f, 300.0f);

						vel[2] = 0.0f;
						pObj->AddVelocity(&vel, &angImp);
					}

					if (info.GetDamageType() & DMG_DISSOLVE)
					{
						CBaseAnimating *pAnimating = dynamic_cast<CBaseAnimating*>(pItem);

						if (pAnimating)
						{
							pAnimating->Dissolve(NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL);
						}
					}
					else
					{
						WeaponManager_AddManaged(pItem);
					}
				}
			}
		}

		CHalfLife2 *pHL2GameRules = static_cast<CHalfLife2 *>(g_pGameRules);

		// Attempt to drop health
		if ( pHL2GameRules->NPC_ShouldDropHealth( pPlayer ) )
		{
			DropItem( "item_healthvial", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) );
			pHL2GameRules->NPC_DroppedHealth();
		}

		if (!m_bNoArmor && combine_ace_shieldspawnmode.GetInt() > 0)
		{
			DropItem("item_shield", WorldSpaceCenter() + RandomVector(-4, 4), RandomAngle(0, 360));
		}
	}

	BaseClass::Event_Killed( info );
}
//-----------------------------------------------------------------------------
// Purpose: Target doesn't exist or has eluded us, so search for one
//-----------------------------------------------------------------------------
void CNPC_Portal_FloorTurret::SearchThink( void )
{
	//Allow descended classes a chance to do something before the think function
	if ( PreThink( TURRET_SEARCHING ) )
		return;

	SetNextThink( gpGlobals->curtime + 0.05f );

	SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE );

	//If our enemy has died, pick a new enemy
	if ( ( GetEnemy() != NULL ) && ( GetEnemy()->IsAlive() == false ) )
	{
		SetEnemy( NULL );
	}

	//Acquire the target
	if ( GetEnemy() == NULL )
	{
		HackFindEnemy();
	}

	LaserOn();

	CBaseEntity *pEnemy = GetEnemy();

	//If we've found a target, spin up the barrel and start to attack
	if ( pEnemy != NULL )
	{
		//Get our shot positions
		Vector vecMid = EyePosition();
		Vector vecMidEnemy = pEnemy->BodyTarget( vecMid );

		//Look for our current enemy
		bool bEnemyInFOV = FInViewCone( pEnemy );
		bool bEnemyVisible = FVisible( pEnemy );

		//Calculate dir and dist to enemy
		Vector	vecDirToEnemy = vecMidEnemy - vecMid;	
		m_flDistToEnemy = VectorNormalize( vecDirToEnemy );

		// If the enemy isn't in the normal fov, check the fov through portals
		CProp_Portal *pPortal = NULL;
		pPortal = FInViewConeThroughPortal( pEnemy );

		if ( pPortal && FVisibleThroughPortal( pPortal, pEnemy ) )
		{
			// Translate our target across the portal
			Vector vecMidEnemyTransformed;
			UTIL_Portal_PointTransform( pPortal->m_hLinkedPortal->MatrixThisToLinked(), vecMidEnemy, vecMidEnemyTransformed );

			//Calculate dir and dist to enemy
			Vector	vecDirToEnemyTransformed = vecMidEnemyTransformed - vecMid;	
			float	flDistToEnemyTransformed = VectorNormalize( vecDirToEnemyTransformed );

			// If it's not visible through normal means or the enemy is closer through the portal, use the translated info
			if ( !bEnemyInFOV || !bEnemyVisible || flDistToEnemyTransformed < m_flDistToEnemy )
			{
				bEnemyInFOV = true;
				bEnemyVisible = true;
				vecMidEnemy = vecMidEnemyTransformed;
				vecDirToEnemy = vecDirToEnemyTransformed;
				m_flDistToEnemy = flDistToEnemyTransformed;
			}
		}

		// Give enemies that are farther away a longer grace period
		float fDistanceRatio = m_flDistToEnemy / PORTAL_FLOOR_TURRET_RANGE;
		m_flShotTime = gpGlobals->curtime + fDistanceRatio * fDistanceRatio * PORTAL_FLOOR_TURRET_MAX_SHOT_DELAY;

		m_flLastSight = 0;
		SetThink( &CNPC_FloorTurret::ActiveThink );
		SetEyeState( TURRET_EYE_SEE_TARGET );

		SpinUp();

		if ( gpGlobals->curtime > m_flNextActivateSoundTime )
		{
			EmitSound( "NPC_FloorTurret.Activate" );
			m_flNextActivateSoundTime = gpGlobals->curtime + 3.0;
		}
		return;
	}

	//Are we out of time and need to retract?
	if ( gpGlobals->curtime > m_flLastSight )
	{
		//Before we retrace, make sure that we are spun down.
		m_flLastSight = 0;
		SetThink( &CNPC_FloorTurret::Retire );
		return;
	}

	//Display that we're scanning
	m_vecGoalAngles.x = GetAbsAngles().x + ( sin( ( m_flLastSight + gpGlobals->curtime * m_fSearchSpeed ) * 1.5f ) * 20.0f );
	m_vecGoalAngles.y = GetAbsAngles().y + ( sin( ( m_flLastSight + gpGlobals->curtime * m_fSearchSpeed ) * 2.5f ) * 20.0f );

	//Turn and ping
	UpdateFacing();
	Ping();

	// Update rope positions
	for ( int iRope = 0; iRope < PORTAL_FLOOR_TURRET_NUM_ROPES; ++iRope )
	{
		if ( m_hRopes[ iRope ] )
		{
			m_hRopes[ iRope ]->EndpointsChanged();
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: The turret has been tipped over and will thrash for awhile
//-----------------------------------------------------------------------------
void CNPC_Portal_FloorTurret::TippedThink( void )
{
	PreThink( TURRET_TIPPED );

	SetNextThink( gpGlobals->curtime + 0.05f );
	SetEnemy( NULL );

	StudioFrameAdvance();
	// If we're not on side anymore, stop thrashing
	if ( !OnSide() && VPhysicsGetObject()->GetContactPoint( NULL, NULL ) )
	{
		ReturnToLife();
		return;
	}

	LaserOn();
	RopesOn();

	//See if we should continue to thrash
	if ( gpGlobals->curtime < m_flThrashTime && !IsDissolving() )
	{
		if ( m_flShotTime < gpGlobals->curtime )
		{
			if( m_bOutOfAmmo )
			{
				SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE );
				DryFire();
			}
			else
			{
				Vector vecMuzzle, vecMuzzleDir;
				GetAttachment( m_iMuzzleAttachment, vecMuzzle, &vecMuzzleDir );

				SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE );
				SetActivity( (Activity)( ( m_bShootWithBottomBarrels ) ? ( ACT_FLOOR_TURRET_FIRE2 ) : ( ACT_FLOOR_TURRET_FIRE ) ) );

#if !DISABLE_SHOT
				Shoot( vecMuzzle, vecMuzzleDir );
#endif
			}

			m_flShotTime = gpGlobals->curtime + 0.05f;
		}

		m_vecGoalAngles.x = GetAbsAngles().x + random->RandomFloat( -60, 60 );
		m_vecGoalAngles.y = GetAbsAngles().y + random->RandomFloat( -60, 60 );

		UpdateFacing();
	}
	else
	{
		//Face forward
		m_vecGoalAngles = GetAbsAngles();

		//Set ourselves to close
		if ( GetActivity() != ACT_FLOOR_TURRET_CLOSE )
		{
			SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE );

			//If we're done moving to our desired facing, close up
			if ( UpdateFacing() == false )
			{
				//Make any last death noises and anims
				EmitSound( "NPC_FloorTurret.Die" );
				EmitSound( GetTurretTalkName( PORTAL_TURRET_DISABLED ) );
				SpinDown();

				SetActivity( (Activity) ACT_FLOOR_TURRET_CLOSE );
				EmitSound( "NPC_FloorTurret.Retract" );

				CTakeDamageInfo	info;
				info.SetDamage( 1 );
				info.SetDamageType( DMG_CRUSH );
				Event_Killed( info );
			}
		}
		else if ( IsActivityFinished() )
		{	
			m_bActive		= false;
			m_flLastSight	= 0;

			SetActivity( (Activity) ACT_FLOOR_TURRET_CLOSED_IDLE );

			// Don't need to store last NPC anymore, because I've been knocked over
			if ( m_hLastNPCToKickMe )
			{
				m_hLastNPCToKickMe = NULL;
				m_flKnockOverFailedTime = 0;
			}

			//Try to look straight
			if ( UpdateFacing() == false )
			{
				m_OnTipped.FireOutput( this, this );
				SetEyeState( TURRET_EYE_DEAD );
				//SetCollisionGroup( COLLISION_GROUP_DEBRIS_TRIGGER );

				// Start thinking slowly to see if we're ever set upright somehow
				SetThink( &CNPC_FloorTurret::InactiveThink );
				SetNextThink( gpGlobals->curtime + 1.0f );
				RopesOff();
			}
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: Spawn the entity
//-----------------------------------------------------------------------------
void CNPC_CombineCamera::Spawn()
{
	Precache();

	SetModel(COMBINE_CAMERA_MODEL);

	m_pEyeFlash = CSprite::SpriteCreate(COMBINE_CAMERA_FLASH_SPRITE, GetLocalOrigin(), FALSE);
	m_pEyeFlash->SetTransparency(kRenderGlow, 255, 255, 255, 0, kRenderFxNoDissipation);
	m_pEyeFlash->SetAttachment(this, 2);
	m_pEyeFlash->SetBrightness(0);
	m_pEyeFlash->SetScale(1.0);

	BaseClass::Spawn();

	m_HackedGunPos	= Vector(0, 0, 12.75);
	SetViewOffset(EyeOffset(ACT_IDLE));
	m_flFieldOfView	= CAMERA_FOV_WIDE;
	m_takedamage	= DAMAGE_YES;
	m_iHealth		= 50;
	m_bloodColor	= BLOOD_COLOR_MECH;
	
	SetSolid(SOLID_BBOX);
	AddSolidFlags(FSOLID_NOT_STANDABLE);

	SetHeight(COMBINE_CAMERA_RETRACT_HEIGHT);

	AddFlag(FL_AIMTARGET);

	SetPoseParameter(COMBINE_CAMERA_BC_YAW, 0);
	SetPoseParameter(COMBINE_CAMERA_BC_PITCH, 0);

	m_iAmmoType = GetAmmoDef()->Index("Pistol");

	// Create our eye sprite
	m_pEyeGlow = CSprite::SpriteCreate(COMBINE_CAMERA_GLOW_SPRITE, GetLocalOrigin(), false);
	m_pEyeGlow->SetTransparency(kRenderWorldGlow, 255, 0, 0, 128, kRenderFxNoDissipation);
	m_pEyeGlow->SetAttachment(this, 2);

	// Set our enabled state
	m_bEnabled = ((m_spawnflags & SF_COMBINE_CAMERA_STARTINACTIVE) == false);

	// Make sure the radii are sane.
	if (m_nOuterRadius <= 0)
	{
		m_nOuterRadius = 300;
	}

	if (m_nInnerRadius <= 0)
	{
		m_nInnerRadius = 450;
	}

	if (m_nOuterRadius < m_nInnerRadius)
	{
		swap(m_nOuterRadius, m_nInnerRadius);
	}

	// Do we start active?
	if (m_bEnabled)
	{
		Deploy();
	}
	else
	{
		SetEyeState(CAMERA_EYE_DISABLED);
	}

	//Adrian: No shadows on these guys.
	AddEffects( EF_NOSHADOW );

	// Stagger our starting times
	SetNextThink( gpGlobals->curtime + random->RandomFloat(0.1f, 0.3f) );

	// Don't allow us to skip animation setup because our attachments are critical to us!
	SetBoneCacheFlags( BCF_NO_ANIMATION_SKIP );
}
//-----------------------------------------------------------------------------
// Purpose: Target doesn't exist or has eluded us, so search for one
//-----------------------------------------------------------------------------
void CNPC_CeilingTurret::SearchThink( void )
{
	//Allow descended classes a chance to do something before the think function
	if ( PreThink( TURRET_SEARCHING ) )
		return;

	SetNextThink( gpGlobals->curtime + 0.05f );

	SetActivity( (Activity) ACT_CEILING_TURRET_OPEN_IDLE );

	//If our enemy has died, pick a new enemy
	if ( ( GetEnemy() != NULL ) && ( GetEnemy()->IsAlive() == false ) )
	{
		SetEnemy( NULL );
	}

	//Acquire the target
 	if ( GetEnemy() == NULL )
	{
		GetSenses()->Look( CEILING_TURRET_RANGE );
		CBaseEntity *pEnemy = BestEnemy();
		if ( pEnemy )
		{
			SetEnemy( pEnemy );
		}
	}

	//If we've found a target, spin up the barrel and start to attack
	if ( GetEnemy() != NULL )
	{
		//Give players a grace period
		if ( GetEnemy()->IsPlayer() )
		{
			m_flShotTime  = gpGlobals->curtime + 0.5f;
		}
		else
		{
			m_flShotTime  = gpGlobals->curtime + 0.1f;
		}

		m_flLastSight = 0;
		SetThink( &CNPC_CeilingTurret::ActiveThink );
		SetEyeState( TURRET_EYE_SEE_TARGET );

		SpinUp();
		EmitSound( "NPC_CeilingTurret.Active" );
		return;
	}

	//Are we out of time and need to retract?
 	if ( gpGlobals->curtime > m_flLastSight )
	{
		//Before we retrace, make sure that we are spun down.
		m_flLastSight = 0;
		SetThink( &CNPC_CeilingTurret::Retire );
		return;
	}
	
	//Display that we're scanning
	m_vecGoalAngles.x = 15.0f;
	m_vecGoalAngles.y = GetAbsAngles().y + ( sin( gpGlobals->curtime * 2.0f ) * 45.0f );

	//Turn and ping
	UpdateFacing();
	Ping();
}
//-----------------------------------------------------------------------------
// Purpose: Think while actively tracking a target.
//-----------------------------------------------------------------------------
void CNPC_CombineCamera::ActiveThink()
{
	// Allow descended classes a chance to do something before the think function
	if (PreThink(CAMERA_ACTIVE))
		return;

	// No active target, look for suspicious characters.
	CBaseEntity *pTarget = MaintainEnemy();
	if ( !pTarget )
	{
		// Nobody suspicious. Go back to being idle.
		m_hEnemyTarget = NULL;
		EmitSound("NPC_CombineCamera.BecomeIdle");
		SetAngry(false);
		SetThink(&CNPC_CombineCamera::SearchThink);
		SetNextThink( gpGlobals->curtime );
		return;
	}

	// Examine the target until it reaches our inner radius
	if ( pTarget != m_hEnemyTarget )
	{
		Vector vecDelta = pTarget->GetAbsOrigin() - GetAbsOrigin();
		float flDist = vecDelta.Length();
		if ( (flDist < m_nInnerRadius) && FInViewCone(pTarget) )
		{
			m_OnFoundEnemy.Set(pTarget, pTarget, this);

			// If it's a citizen, it's ok. If it's the player, it's not ok.
			if ( pTarget->IsPlayer() )
			{
				SetEyeState(CAMERA_EYE_FOUND_TARGET);

				if (HasSpawnFlags(SF_COMBINE_CAMERA_BECOMEANGRY))
				{
					SetAngry(true);
				}
				else
				{
					EmitSound("NPC_CombineCamera.Active");
				}

				m_OnFoundPlayer.Set(pTarget, pTarget, this);
				m_hEnemyTarget = pTarget;
			}
			else
			{
				SetEyeState(CAMERA_EYE_HAPPY);
				m_flEyeHappyTime = gpGlobals->curtime + 2.0;

				// Now forget about this target forever
				AddEntityRelationship( pTarget, D_NU, 99 );
			}
		}
		else
		{
			// If we get angry automatically, we get un-angry automatically
			if ( HasSpawnFlags(SF_COMBINE_CAMERA_BECOMEANGRY) && m_bAngry )
			{
				SetAngry(false);
			}
			m_hEnemyTarget = NULL;

			// We don't quite see this guy, but we sense him.
			SetEyeState(CAMERA_EYE_SEEKING_TARGET);
		}
	}

	// Update our think time
	SetNextThink( gpGlobals->curtime + 0.1f );

	TrackTarget(pTarget);
	MaintainEye();
}