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