//----------------------------------------------------------------------------- // 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(); }
int CE_Cycler_Fix::OnTakeDamage_Alive(const CTakeDamageInfo& info) { #if 0 return BaseClass::OnTakeDamage_Alive(info); #endif Forget( bits_MEMORY_INCOVER ); if ( !CCombatCharacter::FAKE_OnTakeDamage_Alive( info ) ) return 0; if ( GetSleepState() == AISS_WAITING_FOR_THREAT ) Wake(); CEntity *attacker = CEntity::Instance(info.GetAttacker()); // NOTE: This must happen after the base class is called; we need to reduce // health before the pain sound, since some NPCs use the final health // level as a modifier to determine which pain sound to use. // REVISIT: Combine soldiers shoot each other a lot and then talk about it // this improves that case a bunch, but it seems kind of harsh. if ( !GetSquad() || !GetSquad()->SquadIsMember( attacker ) ) { PainSound( info );// "Ouch!" } // See if we're running a dynamic interaction that should break when I am damaged. if ( IsActiveDynamicInteraction() ) { ScriptedNPCInteraction_t *pInteraction = GetRunningDynamicInteraction(); if ( pInteraction->iLoopBreakTriggerMethod & SNPCINT_LOOPBREAK_ON_DAMAGE ) { CEAI_ScriptedSequence *_m_hCine = Get_m_hCine(); // Can only break when we're in the action anim if ( _m_hCine->IsPlayingAction() ) { _m_hCine->StopActionLoop( true ); } } } // If we're not allowed to die, refuse to die // Allow my interaction partner to kill me though if ( m_iHealth <= 0 && HasInteractionCantDie() && attacker != m_hInteractionPartner ) { m_iHealth = 1; } // ----------------------------------- // Fire outputs // ----------------------------------- if ( m_flLastDamageTime != gpGlobals->curtime ) { // only fire once per frame m_OnDamaged->FireOutput( attacker, this); if( attacker && attacker->IsPlayer() ) { m_OnDamagedByPlayer->FireOutput( attacker, this ); // This also counts as being harmed by player's squad. m_OnDamagedByPlayerSquad->FireOutput( attacker, this ); } else { // See if the person that injured me is an NPC. CAI_NPC *pAttacker = dynamic_cast<CAI_NPC *>( attacker ); if( pAttacker && pAttacker->IsAlive() ) { if( pAttacker->GetSquad() != NULL && pAttacker->IsInPlayerSquad() ) { m_OnDamagedByPlayerSquad->FireOutput( attacker, this ); } } } } if( (info.GetDamageType() & DMG_CRUSH) && !(info.GetDamageType() & DMG_PHYSGUN) && info.GetDamage() >= MIN_PHYSICS_FLINCH_DAMAGE ) { SetCondition( COND_PHYSICS_DAMAGE ); } if ( m_iHealth <= ( m_iMaxHealth / 2 ) ) { m_OnHalfHealth->FireOutput( attacker, this ); } // react to the damage (get mad) if ( ( (GetFlags() & FL_NPC) == 0 ) || !attacker ) return 1; // If the attacker was an NPC or client update my position memory if ( attacker->GetFlags() & (FL_NPC | FL_CLIENT) ) { // ------------------------------------------------------------------ // DO NOT CHANGE THIS CODE W/O CONSULTING // Only update information about my attacker I don't see my attacker // ------------------------------------------------------------------ if ( !FInViewCone_Entity( info.GetAttacker() ) || !FVisible_Entity( info.GetAttacker() ) ) { // ------------------------------------------------------------- // If I have an inflictor (enemy / grenade) update memory with // position of inflictor, otherwise update with an position // estimate for where the attack came from // ------------------------------------------------------ Vector vAttackPos; CEntity *inflictor = CEntity::Instance(info.GetInflictor()); if (inflictor) { vAttackPos = inflictor->GetAbsOrigin(); } else { vAttackPos = (GetAbsOrigin() + ( *g_vecAttackDir * 64 )); } // ---------------------------------------------------------------- // If I already have an enemy, assume that the attack // came from the enemy and update my enemy's position // unless I already know about the attacker or I can see my enemy // ---------------------------------------------------------------- if ( GetEnemy() != NULL && !GetEnemies()->HasMemory( info.GetAttacker() ) && !HasCondition(COND_SEE_ENEMY) ) { UpdateEnemyMemory(GetEnemy_CBase(), vAttackPos, GetEnemy_CBase()); } // ---------------------------------------------------------------- // If I already know about this enemy, update his position // ---------------------------------------------------------------- else if (GetEnemies()->HasMemory( info.GetAttacker() )) { UpdateEnemyMemory(info.GetAttacker(), vAttackPos); } // ----------------------------------------------------------------- // Otherwise just note the position, but don't add enemy to my list // ----------------------------------------------------------------- else { UpdateEnemyMemory(NULL, vAttackPos); } } // add pain to the conditions if ( IsLightDamage( info ) ) { SetCondition( COND_LIGHT_DAMAGE ); } if ( IsHeavyDamage( info ) ) { SetCondition( COND_HEAVY_DAMAGE ); } ForceGatherConditions(); // Keep track of how much consecutive damage I have recieved if ((gpGlobals->curtime - m_flLastDamageTime) < 1.0) { m_flSumDamage += info.GetDamage(); } else { m_flSumDamage = info.GetDamage(); } m_flLastDamageTime = gpGlobals->curtime; if ( attacker && attacker->IsPlayer() ) m_flLastPlayerDamageTime = gpGlobals->curtime; GetEnemies()->OnTookDamageFrom( info.GetAttacker() ); if (m_flSumDamage > m_iMaxHealth*0.3) { SetCondition(COND_REPEATED_DAMAGE); } NotifyFriendsOfDamage( info.GetAttacker() ); } // --------------------------------------------------------------- // Insert a combat sound so that nearby NPCs know I've been hit // --------------------------------------------------------------- g_helpfunc.CSoundEnt_InsertSound(SOUND_COMBAT, GetAbsOrigin(), 1024, 0.5, BaseEntity(), SOUNDENT_CHANNEL_INJURY ); return 1; }
//----------------------------------------------------------------------------- // Purpose: // Output : void CNPC_RocketTurret::UpdateAimPoint //----------------------------------------------------------------------------- void CNPC_RocketTurret::UpdateAimPoint ( void ) { //If we've become inactive if ( ( m_bEnabled == false ) || ( GetEnemy() == NULL ) ) { SetEnemy( NULL ); SetNextThink( TICK_NEVER_THINK ); m_vecGoalAngles = GetAbsAngles(); return; } //Get our shot positions Vector vecMid = EyePosition(); Vector vecMidEnemy = GetEnemy()->GetAbsOrigin() + (GetEnemy()->WorldAlignMins() + GetEnemy()->WorldAlignMaxs()) * 0.5f; //Calculate dir and dist to enemy m_vecDirToEnemy = vecMidEnemy - vecMid; m_flDistToEnemy = VectorNormalize( m_vecDirToEnemy ); VectorAngles( m_vecDirToEnemy, m_vecAnglesToEnemy ); bool bEnemyVisible = false; if ( !(GetEnemy()->GetFlags() & FL_NOTARGET) ) { bool bEnemyVisibleInWorld = FVisible( GetEnemy() ); // Test portals in our view as possible ways to view the player bool bEnemyVisibleThroughPortal = TestPortalsForLOS( &vecMidEnemy, bEnemyVisibleInWorld ); bEnemyVisible = bEnemyVisibleInWorld || bEnemyVisibleThroughPortal; } //Store off our last seen location UpdateEnemyMemory( GetEnemy(), vecMidEnemy ); if ( bEnemyVisible ) { m_vecDirToEnemy = vecMidEnemy - vecMid; m_flDistToEnemy = VectorNormalize( m_vecDirToEnemy ); VectorAngles( m_vecDirToEnemy, m_vecAnglesToEnemy ); } //Current enemy is not visible if ( ( bEnemyVisible == false ) || ( m_flDistToEnemy > ROCKET_TURRET_RANGE ) ) { // Had LOS, just lost it if ( m_bHasSightOfEnemy ) { m_OnLostTarget.FireOutput( GetEnemy(), this ); } m_bHasSightOfEnemy = false; } //If we can see our enemy if ( bEnemyVisible ) { // Had no LOS, just gained it if ( !m_bHasSightOfEnemy ) { m_OnFoundTarget.FireOutput( GetEnemy(), this ); } m_bHasSightOfEnemy = true; } }