//----------------------------------------------------------------------------- // 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: Charge up, deal damage along our facing direction. //----------------------------------------------------------------------------- void CNPC_RocketTurret::FiringThink( void ) { //Allow descended classes a chance to do something before the think function if ( PreThink() ) return; SetNextThink( gpGlobals->curtime + ROCKET_TURRET_THINK_RATE ); CRocket_Turret_Projectile* pRocket = dynamic_cast<CRocket_Turret_Projectile*>(m_hCurRocket.Get()); if ( pRocket ) { // If this rocket has been out too long, detonate it and launch a new one if ( (gpGlobals->curtime - m_flTimeLastFired) > ROCKET_PROJECTILE_DEFAULT_LIFE ) { pRocket->ShotDown(); m_flTimeLastFired = gpGlobals->curtime; SetThink( &CNPC_RocketTurret::FollowThink ); } } else { // Set Locked sprite UpdateSkin( ROCKET_SKIN_IDLE ); // Rocket dead, or never created. Revert to follow think m_flTimeLastFired = gpGlobals->curtime; SetThink( &CNPC_RocketTurret::FollowThink ); } }
//----------------------------------------------------------------------------- // 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: Watch for a target to wander into our view //----------------------------------------------------------------------------- void CNPC_CeilingTurret::AutoSearchThink( void ) { //Allow descended classes a chance to do something before the think function if ( PreThink( TURRET_AUTO_SEARCHING ) ) return; //Spread out our thinking SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.2f, 0.4f ) ); //If the enemy is dead, find a new one if ( ( GetEnemy() != NULL ) && ( GetEnemy()->IsAlive() == false ) ) { SetEnemy( NULL ); } //Acquire Target if ( GetEnemy() == NULL ) { GetSenses()->Look( CEILING_TURRET_RANGE ); SetEnemy( BestEnemy() ); } //Deploy if we've got an active target if ( GetEnemy() != NULL ) { SetThink( &CNPC_CeilingTurret::Deploy ); EmitSound( "NPC_CeilingTurret.Alert" ); } }
//----------------------------------------------------------------------------- // 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(); }
void CWeaponPortalgun::Think( void ) { //Allow descended classes a chance to do something before the think function if ( PreThink() ) return; SetNextThink( gpGlobals->curtime + 0.1f ); CPortal_Player *pPlayer = ToPortalPlayer( GetOwner() ); if ( !pPlayer || pPlayer->GetActiveWeapon() != this ) { m_fCanPlacePortal1OnThisSurface = 1.0f; m_fCanPlacePortal2OnThisSurface = 1.0f; return; } // Test portal placement m_fCanPlacePortal1OnThisSurface = ( ( m_bCanFirePortal1 ) ? ( FirePortal( false, 0, 1 ) ) : ( 0.0f ) ); m_fCanPlacePortal2OnThisSurface = ( ( m_bCanFirePortal2 ) ? ( FirePortal( true, 0, 2 ) ) : ( 0.0f ) ); // Draw obtained portal color chips int iSlot1State = ( ( m_bCanFirePortal1 ) ? ( 0 ) : ( 1 ) ); // FIXME: Portal gun might have only red but not blue; int iSlot2State = ( ( m_bCanFirePortal2 ) ? ( 0 ) : ( 1 ) ); SetBodygroup( 1, iSlot1State ); SetBodygroup( 2, iSlot2State ); if ( pPlayer->GetViewModel() ) { pPlayer->GetViewModel()->SetBodygroup( 1, iSlot1State ); pPlayer->GetViewModel()->SetBodygroup( 2, iSlot2State ); } // HACK HACK! Used to make the gun visually change when going through a cleanser! if ( m_fEffectsMaxSize1 > 4.0f ) { m_fEffectsMaxSize1 -= gpGlobals->frametime * 400.0f; if ( m_fEffectsMaxSize1 < 4.0f ) m_fEffectsMaxSize1 = 4.0f; } if ( m_fEffectsMaxSize2 > 4.0f ) { m_fEffectsMaxSize2 -= gpGlobals->frametime * 400.0f; if ( m_fEffectsMaxSize2 < 4.0f ) m_fEffectsMaxSize2 = 4.0f; } }
//----------------------------------------------------------------------------- // 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: 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_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); } }
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(); }
//----------------------------------------------------------------------------- // 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: 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 ); } } } }
//----------------------------------------------------------------------------- // 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: 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(); }
//----------------------------------------------------------------------------- // 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(); }