//-----------------------------------------------------------------------------
// Purpose: Avoid aiming/drawing beams while opening and closing
// Input  :  - 
//-----------------------------------------------------------------------------
void CNPC_RocketTurret::OpeningThink()
{
	StudioFrameAdvance();

	// Require these poses for this animation
	QAngle vecNeutralAngles ( 0, 90, 0 );
	m_vecGoalAngles = m_vecCurrentAngles = vecNeutralAngles;
	SyncPoseToAimAngles();

	// Start following player after we're fully opened
	float flCurProgress = GetCycle();
	if ( flCurProgress >= 0.99f )
	{
		
		LaserOn();
		SetThink( &CNPC_RocketTurret::FollowThink );
	}

	SetNextThink( gpGlobals->curtime + 0.1f );
}
void EffectManager :: Poll
(
    unsigned long                                   time,
    bool                                            offHook
)
{
    static bool runEffects = false;
    static unsigned short effectCount = 0;
    static bool laserMode = false;
    PollLaser(time);        
    if ((time - m_pollDelay) > EFFECT_POLL_DELAY_MS)
    {
        //EM_DEBUG("BEGIN POLL");
        //EM_DEBUG(effectCount);
        //static int ringer = 0;
        //ringer++;
        
        m_pollDelay = time;
        bool switchEffect = (effectCount == 0);

        // Which index are we in the array of effects for this mode:
        //static char *currentEffect; // 0 in case it is not specified

        //static Effect * effects;
        switch (m_mode)
        {
        case EM_MODE_RING:
        case EM_MODE_IDLE:
            if (m_disablePanels)
            {
                SetMode(EM_MODE_DISABLE);
                m_panelsDisabled = false;
            }
            if
            (
                digitalRead(PHONE_PIN_RING_DETECT)
            //||  (ringer & 32)
            )
            {
                SetMode(EM_MODE_RING);
                if (switchEffect)
                {
                    m_currentRing++;
                    if (m_currentRing >= m_sizeRing)
                    {
                        m_currentRing = 0;
                    }
                    effectCount = m_effectsRing[m_currentRing].duration;
                }
            } else {
                SetMode(EM_MODE_IDLE);
                if (switchEffect)
                {
                    m_currentIdle++;
                    if (m_currentIdle >= m_sizeIdle)
                    {
                        m_currentIdle = 0;
                    }
                    effectCount = m_effectsIdle[m_currentIdle].duration;
                }
            }
            
            if (offHook)
            {
                SetMode(EM_MODE_CALL);
            }
            break;
        case EM_MODE_CALL:
            if (m_laserCallCount == 0)
            {
                LaserOff();
                m_laserCallCount = -1;
            }
            else if (m_laserCallCount > 0)
            {
                m_laserCallCount--;
            }
                
            if (switchEffect)
            {
                m_currentCall++;
                if (m_currentCall >= m_sizeCall)
                {
                    m_currentCall = 0;
                }
                effectCount = m_effectsCall[m_currentCall].duration;

            }
            //currentEffect = m_currentCall;
            if (!offHook)
            {
                SetMode(EM_MODE_CALLENDED);
            }
            if ((time - m_duration) > MAX_CALL_DURATION_MS)
            {
                EM_DEBUG("EM:   Call went overtime.");
                SetMode(EM_MODE_CALL_OVERTIME);
            }
            break;
        case EM_MODE_CALL_OVERTIME:
            // Whoops, the person was on the line too long:
            if (switchEffect)
            {
                m_currentOver++;
                if (m_currentOver >= m_sizeOver)
                {
                    m_currentOver = 0;
                }
                effectCount = m_effectsOver[m_currentOver].duration;
            }            
            if (!offHook)
            {
                SetMode(EM_MODE_CALLENDED);
            }
            break;
        case EM_MODE_CALLENDED_REBOOTED:
            if (RebootComplete())
            {
                SetMode(EM_MODE_IDLE);
            }
            break;
        case EM_MODE_DISABLE_STANDBY:
            if (m_disablePanels == false)
            {
                m_panelsDisabled = false;
                RebootPanels();
                SetMode(EM_MODE_CALLENDED_REBOOTED);
            }
            
            // Do nothing.
            m_pollDelay += EM_FADE_DELAY_MS; // To reduce poll time.

            break;
        default:
            break;

        }

        if (m_modePrevious != m_mode)
        {
            m_modePrevious = m_mode;

            // All variables in this section must be persistent
            runEffects = false;
            // Triggered once per mode change.
            switch(m_mode)
            {
            case EM_MODE_IDLE:
                EM_DEBUG("EM:   State: IDLE");
                LaserOff();
                SET_EFFECT(m_effectsIdle, &m_currentIdle);
                break;
            case EM_MODE_RING:
                EM_DEBUG("EM:   State: RING");
                m_canvas.ClearCeiling(0);
                LaserOn();
                m_currentRing++;
                if (m_currentRing >= m_sizeRing)
                {
                    m_currentRing = 0;
                }
                effectCount = m_effectsRing[m_currentRing].duration;

                SET_EFFECT(m_effectsRing, &m_currentRing);
                break;
            case EM_MODE_CALL:
                EM_DEBUG("EM:   State: CALL");
                // The current time so we can shut down the effects if the
                // person is taking too long
                m_duration = time;
                m_currentCall++;
                if (m_currentCall >= m_sizeCall)
                {
                    m_currentCall = 0;
                }
                effectCount = m_effectsCall[m_currentCall].duration;
                LaserOn();
                m_laserCallCount = EM_LASER_CALL_COUNT;
                // Restore the lights!
                m_canvas.ClearCeiling(0);
                SET_EFFECT(m_effectsCall, &m_currentCall);
                break;               
            case EM_MODE_CALL_OVERTIME:
                EM_DEBUG("EM:   State: OVER");
                LaserOff();
                // The current time so we can shut down the effects if the
                // person is taking too long
                effectCount = 0;
                // Restore the lights!
                SET_EFFECT(m_effectsOver, &m_currentOver);
                break;             
            case EM_MODE_CALLENDED_REBOOTED:
                EM_DEBUG("EM:   State: CALLENDED_REBOOTED");
                break;  
            case EM_MODE_CALLENDED:
                EM_DEBUG("EM:   State: CALLENDED");
                LaserOff();
                // The call ended, fade those panels out.
                m_canvas.FadeToBlack();

                //EM_DEBUG2("EM:   State: CALLENDED: time: ");
                //EM_DEBUG((unsigned long)time);
                //EM_DEBUG2("EM:   State: CALLENDED: poll: ");
                //EM_DEBUG((unsigned long)m_pollDelay);

                m_pollDelay += EM_FADE_DELAY_MS;
                //EM_DEBUG2("EM:   State: CALLENDED: poll: ");
                //EM_DEBUG((unsigned long)m_pollDelay);
                //EM_DEBUG("EM:   State: CALLENDED (fading command issued)");
                
                SetMode(EM_MODE_CALLENDED_FADE_END);
                //EM_DEBUG("EM:   State: CALLENDED - FINISH");
                break;
            case EM_MODE_CALLENDED_FADE_END:
                EM_DEBUG("EM:   State: CALLENDED FADEEND");
                // Wait until the power manager is ready, and then
                // reboot the panels:
                RebootPanels();
                SetMode(EM_MODE_CALLENDED_REBOOTED);
                /*if (m_pm->Ready())
                {
                    if (m_pm->GetPowerStatus() == PM_POWER_ON)
                    {
                        m_pm->PowerDown();
                    } else {
                        m_pm->PowerUp();
                        // Idea: wait another bit before switching mode?
                        SetMode(EM_MODE_IDLE);
                    }
                }*/
                break;
            case EM_MODE_DISABLE:
                EM_DEBUG("EM:   State: DISABLE - Fading panels");
                LaserOff();
                // Fade out
                m_canvas.FadeToBlack();
                m_pollDelay += EM_FADE_DELAY_MS; // 2 seconds delay
                SetMode(EM_MODE_DISABLE_FADE_END);
                break;
            case EM_MODE_DISABLE_FADE_END:
                EM_DEBUG("EM:   State: DISABLE_FADEEND");
                // We're all faded out, terminate power.  The only way out of 
                // this mode is a call to EnableEffects().
                m_pm->PowerDown();
                SetMode(EM_MODE_DISABLE_STANDBY);
                break;
            case EM_MODE_DISABLE_STANDBY:
                EM_DEBUG("EM:   State: DISABLE_STANDBY - Low power mode activated.");
                break;
            default:
                EM_DEBUG("EM:   State: UNKNOWN!");
                break;
            };
        }
        if (runEffects)
        {
            m_spectrum.ReadSpectrum();
            switch(m_mode)
            {
            case EM_MODE_IDLE:
                m_effectsIdle[m_currentIdle].func
                (
                    &m_canvas, 
                    const_cast<EffectManager *>(this), 
                    EFFECTMODE_LOOP
                );
                break;
            case EM_MODE_RING:
                m_effectsRing[m_currentRing].func
                (
                    &m_canvas, 
                    const_cast<EffectManager *>(this), 
                    EFFECTMODE_LOOP
                );
                break;
            case EM_MODE_CALL:
                m_effectsCall[m_currentCall].func
                (
                    &m_canvas, 
                    const_cast<EffectManager *>(this), 
                    EFFECTMODE_LOOP
                );
                break;
            case EM_MODE_CALL_OVERTIME:
                m_effectsOver[m_currentOver].func
                (
                    &m_canvas, 
                    const_cast<EffectManager *>(this), 
                    EFFECTMODE_LOOP
                );
                break;
            default:
                EM_DEBUG("EM:   ERROR MODE");
                break;
            }
            
            //EM_DEBUG("runEffects");
            //EM_DEBUG((int)(*currentEffect));
            //EM_DEBUG("ringer");
            //EM_DEBUG((int)(ringer));
            //Effect *theEffect = (effects + (*currentEffect));
            
#ifndef EM_DEBUG_NOBLIT
            m_canvas.BlitToPanels();
#endif
        }
        if (effectCount > 0)
        {
            effectCount--;
        }

    }
}
//-----------------------------------------------------------------------------
// 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();
		}
	}
}
void CNPC_Portal_FloorTurret::ActiveThink( void )
{
	LaserOn();

	//Allow descended classes a chance to do something before the think function
	if ( PreThink( TURRET_ACTIVE ) )
		return;

	HackFindEnemy();

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

	CBaseEntity *pEnemy = GetEnemy();

	//If we've become inactive, go back to searching
	if ( ( m_bActive == false ) || ( pEnemy == NULL ) )
	{
		SetEnemy( NULL );
		m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_MAX_WAIT;
		SetThink( &CNPC_FloorTurret::SearchThink );
		m_vecGoalAngles = GetAbsAngles();
		return;
	}

	//Get our shot positions
	Vector vecMid = EyePosition();
	Vector vecMidEnemy = pEnemy->BodyTarget( vecMid );

	// Store off our last seen location so we can suppress it later
	m_vecEnemyLKP = vecMidEnemy;

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

	//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;
	if ( pEnemy->IsAlive() )
	{
		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;
			}
			else
			{
				pPortal = NULL;
			}
		}
		else
		{
			pPortal = NULL;
		}
	}

	//Draw debug info
	if ( g_debug_turret.GetBool() )
	{
		NDebugOverlay::Cross3D( vecMid, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 );
		NDebugOverlay::Cross3D( GetEnemy()->WorldSpaceCenter(), -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 );
		NDebugOverlay::Line( vecMid, GetEnemy()->WorldSpaceCenter(), 0, 255, 0, false, 0.05 );

		NDebugOverlay::Cross3D( vecMid, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 );
		NDebugOverlay::Cross3D( vecMidEnemy, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05 );
		NDebugOverlay::Line( vecMid, vecMidEnemy, 0, 255, 0, false, 0.05f );
	}

	//See if they're past our FOV of attack
	if ( bEnemyInFOV == false )
	{
		// Should we look for a new target?
		ClearEnemyMemory();
		SetEnemy( NULL );

		if ( m_spawnflags & SF_FLOOR_TURRET_FASTRETIRE )
		{
			// Retire quickly in this case. (The case where we saw the player, but he hid again).
			m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_SHORT_WAIT;
		}
		else
		{
			m_flLastSight = gpGlobals->curtime + FLOOR_TURRET_MAX_WAIT;
		}

		SetThink( &CNPC_FloorTurret::SearchThink );
		m_vecGoalAngles = GetAbsAngles();

		SpinDown();

		return;
	}

	//Current enemy is not visible
	if ( ( bEnemyVisible == false ) || ( m_flDistToEnemy > PORTAL_FLOOR_TURRET_RANGE ))
	{
		m_flLastSight = gpGlobals->curtime + 2.0f;

		ClearEnemyMemory();
		SetEnemy( NULL );
		SetThink( &CNPC_FloorTurret::SuppressThink );

		return;
	}

	if ( g_debug_turret.GetBool() )
	{
		Vector vecMuzzle, vecMuzzleDir;

		UpdateMuzzleMatrix();
		MatrixGetColumn( m_muzzleToWorld, 0, vecMuzzleDir );
		MatrixGetColumn( m_muzzleToWorld, 3, vecMuzzle );

		// Visualize vertical firing ranges
		for ( int i = 0; i < 4; i++ )
		{
			QAngle angMaxDownPitch = GetAbsAngles();

			switch( i )
			{
			case 0:	angMaxDownPitch.x -= 15; break;
			case 1:	angMaxDownPitch.x += 15; break;
			case 2:	angMaxDownPitch.x -= 25; break;
			case 3:	angMaxDownPitch.x += 25; break;
			default:
				break;
			}

			Vector vecMaxDownPitch;
			AngleVectors( angMaxDownPitch, &vecMaxDownPitch );
			NDebugOverlay::Line( vecMuzzle, vecMuzzle + (vecMaxDownPitch*256), 255, 255, 255, false, 0.1 );
		}
	}

	if ( m_flShotTime < gpGlobals->curtime )
	{
		Vector vecMuzzle, vecMuzzleDir;

		UpdateMuzzleMatrix();
		MatrixGetColumn( m_muzzleToWorld, 0, vecMuzzleDir );
		MatrixGetColumn( m_muzzleToWorld, 3, vecMuzzle );

		Vector2D vecDirToEnemy2D = vecDirToEnemy.AsVector2D();
		Vector2D vecMuzzleDir2D = vecMuzzleDir.AsVector2D();

		bool bCanShoot = true;
		float minCos3d = DOT_10DEGREE; // 10 degrees slop

		if ( m_flDistToEnemy < 60.0 )
		{
			vecDirToEnemy2D.NormalizeInPlace();
			vecMuzzleDir2D.NormalizeInPlace();

			bCanShoot = ( vecDirToEnemy2D.Dot(vecMuzzleDir2D) >= DOT_10DEGREE );
			minCos3d = 0.7071; // 45 degrees
		}

		//Fire the gun
		if ( bCanShoot ) // 10 degree slop XY
		{
			float dot3d = DotProduct( vecDirToEnemy, vecMuzzleDir );

			if( m_bOutOfAmmo )
			{
				DryFire();
			}
			else
			{
				if ( dot3d >= minCos3d ) 
				{
					SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE );
					SetActivity( (Activity)( ( m_bShootWithBottomBarrels ) ? ( ACT_FLOOR_TURRET_FIRE2 ) : ( ACT_FLOOR_TURRET_FIRE ) ) );

					//Fire the weapon
#if !DISABLE_SHOT
					Shoot( vecMuzzle, vecMuzzleDir, (dot3d < DOT_10DEGREE) );
#endif
				}
			}
		} 
	}
	else
	{
		SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE );
	}

	//If we can see our enemy, face it
	if ( bEnemyVisible )
	{
		//We want to look at the enemy's eyes so we don't jitter
		Vector vEnemyWorldSpaceCenter = pEnemy->WorldSpaceCenter();
		if ( pPortal && pPortal->IsActivedAndLinked() )
		{
			// Translate our target across the portal
			UTIL_Portal_PointTransform( pPortal->m_hLinkedPortal->MatrixThisToLinked(), vEnemyWorldSpaceCenter, vEnemyWorldSpaceCenter );
		}

		Vector	vecDirToEnemyEyes = vEnemyWorldSpaceCenter - vecMid;
		VectorNormalize( vecDirToEnemyEyes );

		QAngle vecAnglesToEnemy;
		VectorAngles( vecDirToEnemyEyes, vecAnglesToEnemy );

		m_vecGoalAngles.y = vecAnglesToEnemy.y;
		m_vecGoalAngles.x = vecAnglesToEnemy.x;
	}

	//Turn to face
	UpdateFacing();
}
void CNPC_Portal_FloorTurret::Retire( void )
{
	LaserOn();

	BaseClass::Retire();
}
void CNPC_Portal_FloorTurret::SuppressThink( void )
{
	LaserOn();

	BaseClass::SuppressThink();
}
//-----------------------------------------------------------------------------
// 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();
			}
		}
	}
}