//----------------------------------------------------------------------------- // Purpose: Charge up, prepare to fire and give player time to dodge //----------------------------------------------------------------------------- void CNPC_RocketTurret::LockingThink( void ) { //Allow descended classes a chance to do something before the think function if ( PreThink() ) return; //Turn to face UpdateFacing(); SetNextThink( gpGlobals->curtime + ROCKET_TURRET_THINK_RATE ); if ( m_flTimeLocking == 0.0f ) { // Play lockon sound EmitSound ( ROCKET_TURRET_SOUND_LOCKING ); EmitSound ( ROCKET_TURRET_SOUND_LOCKING, gpGlobals->curtime + ROCKET_TURRET_QUARTER_LOCKON_TIME ); EmitSound ( ROCKET_TURRET_SOUND_LOCKED, gpGlobals->curtime + ROCKET_TURRET_HALF_LOCKON_TIME ); ResetSequence(LookupSequence("load")); // Change lockon sprite UpdateSkin( ROCKET_SKIN_LOCKING ); } m_flTimeLocking += ROCKET_TURRET_THINK_RATE; if ( m_flTimeLocking > ROCKET_TURRET_LOCKON_TIME ) { // Set Locked sprite to 'rocket out' color UpdateSkin( ROCKET_SKIN_LOCKED ); FireRocket(); SetThink ( &CNPC_RocketTurret::FiringThink ); m_flTimeLocking = 0.0f; } }
//----------------------------------------------------------------------------- // 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: 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: //----------------------------------------------------------------------------- void CNPC_RocketTurret::SearchThink() { if ( PreThink() || GetEnemy() == NULL ) return; SetSequence ( LookupSequence( "idle" ) ); UpdateAimPoint(); //Update our think time SetNextThink( gpGlobals->curtime + ROCKET_TURRET_THINK_RATE ); // Still can't see enemy, zip around frantically if ( !m_bHasSightOfEnemy ) { if ( m_flTimeSpentPaused >= m_flPauseLength ) { float flOffsetX = RandomFloat( -5.0f, 5.0f ); float flOffsetY = RandomFloat( -5.0f, 5.0f ); if ( fabs(m_flTotalDivergenceX) <= MAX_DIVERGENCE_X || SignDiffers( m_flTotalDivergenceX, flOffsetX ) ) { m_flTotalDivergenceX += flOffsetX; m_vecGoalAngles.x += flOffsetX; } if ( fabs(m_flTotalDivergenceY) <= MAX_DIVERGENCE_Y || SignDiffers( m_flTotalDivergenceY, flOffsetY ) ) { m_flTotalDivergenceY += flOffsetY; m_vecGoalAngles.y += flOffsetY; } // Reset pause timer m_flTimeSpentPaused = 0.0f; m_flPauseLength = RandomFloat( 0.3f, 2.5f ); } m_flTimeSpentPaused += ROCKET_TURRET_THINK_RATE; } else { // Found target, go back to following it SetThink( &CNPC_RocketTurret::FollowThink ); SetNextThink( gpGlobals->curtime + ROCKET_TURRET_THINK_RATE ); } // Move beam towards goal angles UpdateFacing(); }
//----------------------------------------------------------------------------- // Purpose: The turret has been tipped over and will thrash for awhile //----------------------------------------------------------------------------- void CNPC_Portal_FloorTurret::HeldThink( void ) { PreThink( (turretState_e)PORTAL_TURRET_PICKUP ); SetNextThink( gpGlobals->curtime + 0.05f ); SetEnemy( NULL ); StudioFrameAdvance(); IPhysicsObject *pTurretPhys = VPhysicsGetObject(); // If we're not held anymore, stop thrashing if ( !(pTurretPhys->GetGameFlags() & FVPHYSICS_PLAYER_HELD) ) { m_fNextTalk = gpGlobals->curtime + 1.25f; if ( m_lifeState == LIFE_ALIVE ) SetThink( &CNPC_FloorTurret::ActiveThink ); else SetThink( &CNPC_FloorTurret::InactiveThink ); } LaserOn(); RopesOn(); //See if we should continue to thrash if ( !IsDissolving() ) { if ( m_flShotTime < gpGlobals->curtime ) { SetActivity( (Activity) ACT_FLOOR_TURRET_OPEN_IDLE ); DryFire(); m_flShotTime = gpGlobals->curtime + RandomFloat( 0.25f, 0.75f ); m_vecGoalAngles.x = GetAbsAngles().x + RandomFloat( -15, 15 ); m_vecGoalAngles.y = GetAbsAngles().y + RandomFloat( -40, 40 ); } UpdateFacing(); } }
//----------------------------------------------------------------------------- // Purpose: // Input : pTarget - //----------------------------------------------------------------------------- void CNPC_CombineCamera::TrackTarget( CBaseEntity *pTarget ) { if (!pTarget) return; // Calculate direction to target Vector vecMid = EyePosition(); Vector vecMidTarget = pTarget->BodyTarget(vecMid); Vector vecDirToTarget = vecMidTarget - vecMid; // We want to look at the target's eyes so we don't jitter Vector vecDirToTargetEyes = pTarget->WorldSpaceCenter() - vecMid; VectorNormalize(vecDirToTargetEyes); QAngle vecAnglesToTarget; VectorAngles(vecDirToTargetEyes, vecAnglesToTarget); // Draw debug info if (g_debug_combine_camera.GetBool()) { NDebugOverlay::Cross3D(vecMid, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05); NDebugOverlay::Cross3D(pTarget->WorldSpaceCenter(), -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05); NDebugOverlay::Line(vecMid, pTarget->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(vecMidTarget, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, false, 0.05); NDebugOverlay::Line(vecMid, vecMidTarget, 0, 255, 0, false, 0.05f); } Vector vecMuzzle, vecMuzzleDir; QAngle vecMuzzleAng; GetAttachment("eyes", vecMuzzle, &vecMuzzleDir); SetIdealActivity((Activity) ACT_COMBINE_CAMERA_OPEN_IDLE); m_vecGoalAngles.y = vecAnglesToTarget.y; m_vecGoalAngles.x = vecAnglesToTarget.x; // Turn to face UpdateFacing(); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CNPC_CombineCamera::DeathThink() { if (PreThink(CAMERA_DEAD)) return; // Level out our angles m_vecGoalAngles = GetAbsAngles(); SetNextThink( gpGlobals->curtime + 0.1f ); if (m_lifeState != LIFE_DEAD) { m_lifeState = LIFE_DEAD; EmitSound("NPC_CombineCamera.Die"); // lots of smoke Vector pos; CollisionProp()->RandomPointInBounds( vec3_origin, Vector( 1, 1, 1 ), &pos ); CBroadcastRecipientFilter filter; te->Smoke(filter, 0.0, &pos, g_sModelIndexSmoke, 2.5, 10); g_pEffects->Sparks(pos); SetActivity((Activity) ACT_COMBINE_CAMERA_CLOSE); } StudioFrameAdvance(); if (IsActivityFinished() && (UpdateFacing() == false)) { SetHeight(COMBINE_CAMERA_RETRACT_HEIGHT); m_flPlaybackRate = 0; SetThink(NULL); } }
//----------------------------------------------------------------------------- // Purpose: Avoid aiming/drawing beams while opening and closing // Input : - //----------------------------------------------------------------------------- void CNPC_RocketTurret::ClosingThink() { LaserOff(); // Require these poses for this animation QAngle vecNeutralAngles ( 0, 90, 0 ); m_vecGoalAngles = vecNeutralAngles; // Once we're within 10 degrees of the neutral pose, start close animation. if ( UpdateFacing() <= 10.0f ) { StudioFrameAdvance(); } SetNextThink( gpGlobals->curtime + ROCKET_TURRET_THINK_RATE ); // Start following player after we're fully opened float flCurProgress = GetCycle(); if ( flCurProgress >= 0.99f ) { SetThink( NULL ); SetNextThink( TICK_NEVER_THINK ); } }
void GamepadController::Update() { UpdateFacing(); UpdateButtons(); }
//----------------------------------------------------------------------------- // 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::FireBullet( const char *pTargetName ) { CBaseEntity *pEnemy = gEntList.FindEntityByName( NULL, pTargetName ); if ( !pEnemy ) 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; //Calculate dir and dist to enemy Vector vecDirToEnemy = vecMidEnemy - vecMid; m_flDistToEnemy = VectorNormalize( vecDirToEnemy ); //We want to look at the enemy's eyes so we don't jitter Vector vecDirToEnemyEyes = vecMidEnemy - vecMid; VectorNormalize( vecDirToEnemyEyes ); QAngle vecAnglesToEnemy; VectorAngles( vecDirToEnemyEyes, vecAnglesToEnemy ); Vector vecMuzzle, vecMuzzleDir; GetAttachment( m_iMuzzleAttachment, vecMuzzle, &vecMuzzleDir ); if ( m_flShotTime < gpGlobals->curtime ) { Vector2D vecDirToEnemy2D = vecDirToEnemy.AsVector2D(); Vector2D vecMuzzleDir2D = vecMuzzleDir.AsVector2D(); if ( m_flDistToEnemy < 60.0 ) { vecDirToEnemy2D.NormalizeInPlace(); vecMuzzleDir2D.NormalizeInPlace(); } //Fire the gun if( m_bOutOfAmmo ) { DryFire(); } else { 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, vecDirToEnemy, true ); #endif } //If we can see our enemy, face it m_vecGoalAngles.y = vecAnglesToEnemy.y; m_vecGoalAngles.x = vecAnglesToEnemy.x; //Turn to face UpdateFacing(); EmitSound( "NPC_FloorTurret.Alert" ); SetThink( &CNPC_FloorTurret::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(); } } } }
//----------------------------------------------------------------------------- // 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: Allows the turret to fire on targets if they're visible //----------------------------------------------------------------------------- void CNPC_CeilingTurret::ActiveThink( void ) { //Allow descended classes a chance to do something before the think function if ( PreThink( TURRET_ACTIVE ) ) return; //Update our think time SetNextThink( gpGlobals->curtime + 0.1f ); //If we've become inactive, go back to searching if ( ( m_bActive == false ) || ( GetEnemy() == NULL ) ) { SetEnemy( NULL ); SetLastSightTime(); SetThink( &CNPC_CeilingTurret::SearchThink ); m_vecGoalAngles = GetAbsAngles(); return; } //Get our shot positions Vector vecMid = EyePosition(); Vector vecMidEnemy = GetEnemy()->GetAbsOrigin(); //Store off our last seen location UpdateEnemyMemory( GetEnemy(), vecMidEnemy ); //Look for our current enemy bool bEnemyVisible = FInViewCone( GetEnemy() ) && FVisible( GetEnemy() ) && GetEnemy()->IsAlive(); //Calculate dir and dist to enemy Vector vecDirToEnemy = vecMidEnemy - vecMid; float flDistToEnemy = VectorNormalize( vecDirToEnemy ); //We want to look at the enemy's eyes so we don't jitter Vector vecDirToEnemyEyes = GetEnemy()->WorldSpaceCenter() - vecMid; VectorNormalize( vecDirToEnemyEyes ); QAngle vecAnglesToEnemy; VectorAngles( vecDirToEnemyEyes, vecAnglesToEnemy ); //Draw debug info if ( g_debug_turret_ceiling.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 ); } //Current enemy is not visible if ( ( bEnemyVisible == false ) || ( flDistToEnemy > CEILING_TURRET_RANGE )) { if ( m_flLastSight ) { m_flLastSight = gpGlobals->curtime + 0.5f; } else if ( gpGlobals->curtime > m_flLastSight ) { // Should we look for a new target? ClearEnemyMemory(); SetEnemy( NULL ); SetLastSightTime(); SetThink( &CNPC_CeilingTurret::SearchThink ); m_vecGoalAngles = GetAbsAngles(); SpinDown(); return; } bEnemyVisible = false; } Vector vecMuzzle, vecMuzzleDir; QAngle vecMuzzleAng; GetAttachment( "eyes", vecMuzzle, vecMuzzleAng ); AngleVectors( vecMuzzleAng, &vecMuzzleDir ); if ( m_flShotTime < gpGlobals->curtime ) { //Fire the gun if ( DotProduct( vecDirToEnemy, vecMuzzleDir ) >= 0.9848 ) // 10 degree slop { if ( m_spawnflags & SF_CEILING_TURRET_OUT_OF_AMMO ) { SetActivity( (Activity) ACT_CEILING_TURRET_DRYFIRE ); } else { SetActivity( (Activity) ACT_CEILING_TURRET_FIRE ); } //Fire the weapon Shoot( vecMuzzle, vecMuzzleDir ); } } else { SetActivity( (Activity) ACT_CEILING_TURRET_OPEN_IDLE ); } //If we can see our enemy, face it if ( bEnemyVisible ) { m_vecGoalAngles.y = vecAnglesToEnemy.y; m_vecGoalAngles.x = vecAnglesToEnemy.x; } //Turn to face UpdateFacing(); }
//----------------------------------------------------------------------------- // Purpose: Allows the turret to fire on targets if they're visible //----------------------------------------------------------------------------- void CNPC_RocketTurret::FollowThink( void ) { // Default to player as enemy if ( GetEnemy() == NULL ) { SetEnemy( UTIL_GetLocalPlayer() ); } SetSequence ( LookupSequence( "idle" ) ); //Allow descended classes a chance to do something before the think function if ( PreThink() || GetEnemy() == NULL ) { return; } //Update our think time SetNextThink( gpGlobals->curtime + ROCKET_TURRET_THINK_RATE ); UpdateAimPoint(); m_vecGoalAngles = m_vecAnglesToEnemy; // Chase enemy if ( !m_bHasSightOfEnemy ) { // Aim at the last known location m_vecGoalAngles = m_vecCurrentAngles; // Lost sight, move to search think SetThink( &CNPC_RocketTurret::SearchThink ); } //Turn to face UpdateFacing(); // If our facing direction hits our enemy, fire the beam Ray_t rayDmg; Vector vForward; AngleVectors( m_vecCurrentAngles, &vForward, NULL, NULL ); Vector vEndPoint = EyePosition() + vForward*ROCKET_TURRET_RANGE; rayDmg.Init( EyePosition(), vEndPoint ); rayDmg.m_IsRay = true; trace_t traceDmg; // This version reorients through portals CTraceFilterSimple subfilter( this, COLLISION_GROUP_NONE ); CTraceFilterTranslateClones filter ( &subfilter ); float flRequiredParameter = 2.0f; CProp_Portal* pFirstPortal = UTIL_Portal_FirstAlongRay( rayDmg, flRequiredParameter ); UTIL_Portal_TraceRay_Bullets( pFirstPortal, rayDmg, MASK_VISIBLE_AND_NPCS, &filter, &traceDmg, false ); if ( traceDmg.m_pEnt ) { // This thing we're hurting is our enemy if ( traceDmg.m_pEnt == GetEnemy() ) { // If we're past the cooldown time, fire another rocket if ( (gpGlobals->curtime - m_flTimeLastFired) > ROCKET_TURRET_ROCKET_FIRE_COOLDOWN_TIME ) { SetThink( &CNPC_RocketTurret::LockingThink ); } } } }