//--------------------------------------------------------- //--------------------------------------------------------- void CNPC_Combine_Cannon::PrescheduleThink( void ) { BaseClass::PrescheduleThink(); // NOTE: We'll deal with this on the client // Think faster if the beam is on, this gives the beam higher resolution. if( m_pBeam ) { SetNextThink( gpGlobals->curtime + 0.03 ); } else { SetNextThink( gpGlobals->curtime + 0.1f ); } // If the enemy has just stepped into view, or we've acquired a new enemy, // Record the last time we've seen the enemy as right now. // // If the enemy has been out of sight for a full second, mark him eluded. if( GetEnemy() != NULL ) { if( gpGlobals->curtime - GetEnemies()->LastTimeSeen( GetEnemy() ) > 30 ) { // Stop pestering enemies after 30 seconds of frustration. GetEnemies()->ClearMemory( GetEnemy() ); SetEnemy(NULL); } } }
//----------------------------------------------------------------------------- // Purpose: Get the number of known enemies within a radius to a point //----------------------------------------------------------------------------- int CAI_BehaviorAlyxInjured::NumKnownEnemiesInRadius( const Vector &vecSource, float flRadius ) { int nNumEnemies = 0; float flRadiusSqr = Square( flRadius ); AIEnemiesIter_t iter; // Iterate through all known enemies for( AI_EnemyInfo_t *pMemory = GetEnemies()->GetFirst(&iter); pMemory != NULL; pMemory = GetEnemies()->GetNext(&iter) ) { if ( pMemory == NULL || pMemory->hEnemy == NULL ) continue; // Must hate or fear them if ( GetOuter()->IRelationType( pMemory->hEnemy ) != D_HT && GetOuter()->IRelationType( pMemory->hEnemy ) != D_FR ) continue; // Count only the enemies I've seen recently if ( gpGlobals->curtime - pMemory->timeLastSeen > 0.5f ) continue; // Must be within the radius we've specified float flEnemyDistSqr = ( vecSource - pMemory->hEnemy->GetAbsOrigin() ).Length2DSqr(); if ( flEnemyDistSqr < flRadiusSqr ) { nNumEnemies++; } } return nNumEnemies; }
//------------------------------------------------------------------------------ void CNPC_EnemyFinder::PrescheduleThink() { BaseClass::PrescheduleThink(); bool bHasEnemies = GetEnemies()->NumEnemies() > 0; if ( GetEnemies()->NumEnemies() > 0 ) { //If I haven't seen my enemy in half a second then we'll assume he's gone. if ( gpGlobals->curtime - GetEnemyLastTimeSeen() >= 0.5f ) { bHasEnemies = false; } } if ( m_bEnemyStatus != bHasEnemies ) { if ( bHasEnemies ) { m_OnAcquireEnemies.FireOutput( this, this ); } else { m_OnLostEnemies.FireOutput( this, this ); } m_bEnemyStatus = bHasEnemies; } if( ai_debug_enemyfinders.GetBool() ) { m_debugOverlays |= OVERLAY_BBOX_BIT; if( IsInSquad() && GetSquad()->NumMembers() > 1 ) { AISquadIter_t iter; CAI_BaseNPC *pSquadmate = m_pSquad ? m_pSquad->GetFirstMember( &iter ) : NULL; while ( pSquadmate ) { NDebugOverlay::Line( WorldSpaceCenter(), pSquadmate->EyePosition(), 255, 255, 0, false, 0.1f ); pSquadmate = m_pSquad->GetNextMember( &iter ); } } } }
//--------------------------------------------------------- //--------------------------------------------------------- void CNPC_GroundTurret::GatherConditions() { if( !IsEnabled() ) { return; } if( !IsOpen() && !UTIL_FindClientInPVS( edict() ) ) { return; } // Throw away old enemies so the turret can retire AIEnemiesIter_t iter; for( AI_EnemyInfo_t *pEMemory = GetEnemies()->GetFirst(&iter); pEMemory != NULL; pEMemory = GetEnemies()->GetNext(&iter) ) { if( pEMemory->timeLastSeen < gpGlobals->curtime - GROUNDTURRET_RETIRE_TIME ) { pEMemory->hEnemy = NULL; } } BaseClass::GatherConditions(); if( GetEnemy() && HasCondition(COND_SEE_ENEMY) ) { m_flTimeLastSawEnemy = gpGlobals->curtime; } else { if( gpGlobals->curtime - m_flTimeLastSawEnemy >= GROUNDTURRET_RETIRE_TIME ) { m_OnAreaClear.FireOutput(this, this); m_flTimeLastSawEnemy = FLT_MAX; return; } } if( HasCondition( COND_SEE_ENEMY ) ) { m_bSeeEnemy = true; } else { m_bSeeEnemy = false; } if( GetEnemy() && m_bSeeEnemy && IsEnabled() ) { if( m_flTimeNextShoot < gpGlobals->curtime ) { Shoot(); } } }
//------------------------------------------------------------------------------ // Purpose: //------------------------------------------------------------------------------ bool CAI_ASW_RangedAttackBehavior::FindFiringLocation( ) { CBaseEntity *pBestEnt = NULL; float flBestDistSq = FLT_MAX; AIEnemiesIter_t iter; CBaseEntity *pEnemy; pEnemy = GetEnemy(); if ( pEnemy && pEnemy->IsAlive() && GetOuter()->FVisible( pEnemy ) ) { m_hTarget = pEnemy; UpdateTargetLocation(); return true; } for( AI_EnemyInfo_t *pEMemory = GetEnemies()->GetFirst( &iter ); pEMemory != NULL; pEMemory = GetEnemies()->GetNext( &iter ) ) { pEnemy = pEMemory->hEnemy; if ( !pEnemy || !pEnemy->IsAlive() || !GetOuter()->FVisible( pEnemy ) ) { continue; } Vector vDelta = GetAbsOrigin() - pEnemy->GetAbsOrigin(); float flLenSq = vDelta.LengthSqr(); if ( flLenSq <= flBestDistSq ) { pBestEnt = pEnemy; flBestDistSq = flLenSq; } } if ( !pBestEnt ) { // just try shooting at our enemy for now if ( pEnemy && pEnemy->IsAlive() ) { UpdateTargetLocation(); return true; } return false; } m_hTarget = pBestEnt; GetOuter()->SetEnemy( pBestEnt ); UpdateTargetLocation(); return true; }
//----------------------------------------------------------------------------- // Purpose: // // //----------------------------------------------------------------------------- void CNPC_EnemyFinder::Spawn( void ) { Precache(); SetModel( "models/roller.mdl" ); // This is a dummy model that is never used! UTIL_SetSize(this, vec3_origin, vec3_origin); SetMoveType( MOVETYPE_NONE ); SetBloodColor( DONT_BLEED ); SetGravity( 0.0 ); m_iHealth = 1; AddFlag( FL_NPC ); SetSolid( SOLID_NONE ); m_bEnemyStatus = false; if (m_flFieldOfView < -1.0) { DevMsg("ERROR: EnemyFinder field of view must be between -1.0 and 1.0\n"); m_flFieldOfView = 0.5; } else if (m_flFieldOfView > 1.0) { DevMsg("ERROR: EnemyFinder field of view must be between -1.0 and 1.0\n"); m_flFieldOfView = 1.0; } CapabilitiesAdd ( bits_CAP_SQUAD ); NPCInit(); // Set this after NPCInit() m_takedamage = DAMAGE_NO; AddEffects( EF_NODRAW ); m_NPCState = NPC_STATE_ALERT; // always alert SetViewOffset( vec3_origin ); if ( m_flMaxSearchDist ) { SetDistLook( m_flMaxSearchDist ); } if ( HasSpawnFlags( SF_ENEMY_FINDER_SHORT_MEMORY ) ) { GetEnemies()->SetEnemyDiscardTime( 0.2 ); } }
//----------------------------------------------------------------------------- // Purpose: The turret doesn't run base AI properly, which is a bad decision. // As a result, it has to manually find enemies. //----------------------------------------------------------------------------- void CNPC_Portal_FloorTurret::HackFindEnemy( void ) { // We have to refresh our memories before finding enemies, so // dead enemies are cleared out before new ones are added. GetEnemies()->RefreshMemories(); GetSenses()->Look( PORTAL_FLOOR_TURRET_RANGE ); SetEnemy( BestEnemy() ); if ( GetEnemy() == NULL ) { // Look through the list of sensed objects for possible targets AISightIter_t iter; CBaseEntity *pObject; CBaseEntity *pNearest = NULL; float flClosestDistSqr = PORTAL_FLOOR_TURRET_RANGE * PORTAL_FLOOR_TURRET_RANGE; for ( pObject = GetSenses()->GetFirstSeenEntity( &iter, SEEN_MISC ); pObject; pObject = GetSenses()->GetNextSeenEntity( &iter ) ) { Vector vVelocity; pObject->GetVelocity( &vVelocity ); // Ignore objects going too slowly if ( vVelocity.LengthSqr() < m_fMovingTargetThreashold ) continue; float flDistSqr = pObject->WorldSpaceCenter().DistToSqr( GetAbsOrigin() ); if ( flDistSqr < flClosestDistSqr ) { flClosestDistSqr = flDistSqr; pNearest = pObject; } } if ( pNearest ) { SetEnemy( pNearest ); m_fMovingTargetThreashold += gpGlobals->curtime * 15.0f; if ( m_fMovingTargetThreashold > 800.0f ) { m_fMovingTargetThreashold = 800.0f; } } } else { m_fMovingTargetThreashold = 20.0f; } }
//------------------------------------------------------------------------------ // Purpose: // Input : // Output : //------------------------------------------------------------------------------ void CAI_ASW_FlickBehavior::Flick( ) { #if 0 for( int i = 0; i < ASWDirector()->GetNPCListCount(); i++ ) { CASW_Alien *pAlien = ASWDirector()->GetNPCFromList( i ); if ( !pAlien || !pAlien->IsAlive() ) { continue; } if ( GetOuter() != pAlien ) { TryFlicking( pAlien ); } } for ( int i = 0; i < ASW_MAX_READY_PLAYERS; i++ ) { // found a connected player? CASW_Player *pOtherPlayer = dynamic_cast< CASW_Player * >( UTIL_PlayerByIndex( i + 1 ) ); // if they're not connected, skip them if ( !pOtherPlayer || !pOtherPlayer->IsConnected() ) { continue; } TryFlicking( pOtherPlayer ); } #else AIEnemiesIter_t iter; for( AI_EnemyInfo_t *pEMemory = GetEnemies()->GetFirst( &iter ); pEMemory != NULL; pEMemory = GetEnemies()->GetNext( &iter ) ) { CBaseEntity *pEntity = pEMemory->hEnemy; if ( pEntity->IsAlive() && GetOuter() != pEntity ) { TryFlicking( pEntity ); } } #endif // turn this into an area of affect // reverse his velocity - if he is coming towards the shield bug, add that back into his outgoing to increase it }
//------------------------------------------------------------------------------ // Updates the enemy //------------------------------------------------------------------------------ void CBaseHelicopter::UpdateEnemy() { if( HasCondition( COND_ENEMY_DEAD ) ) { SetEnemy( NULL ); } // Look for my best enemy. If I change enemies, // be sure and change my prevseen/lastseen timers. if( m_lifeState == LIFE_ALIVE ) { GetSenses()->Look( (int)EnemySearchDistance() ); GetEnemies()->RefreshMemories(); ChooseEnemy(); if( HasEnemy() ) { CBaseEntity *pEnemy = GetEnemy(); GatherEnemyConditions( pEnemy ); if ( FVisible( pEnemy ) ) { if (m_flLastSeen < gpGlobals->curtime - 2) { m_flPrevSeen = gpGlobals->curtime; } m_flLastSeen = gpGlobals->curtime; m_vecTargetPosition = pEnemy->WorldSpaceCenter(); } } else { // look at where we're going instead m_vecTargetPosition = GetDesiredPosition(); } } else { // If we're dead or dying, forget our enemy and don't look for new ones(sjb) SetEnemy( NULL ); } }
void CAI_BaseHumanoid::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ) { bool bSneakAttacked = false; if( ptr->hitgroup == HITGROUP_HEAD ) { if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && info.GetAttacker() != GetEnemy() && !IsInAScript() ) { // Shot in the head by a player I've never seen. In this case the player // has gotten the drop on this enemy and such an attack is always lethal (at close range) bSneakAttacked = true; AIEnemiesIter_t iter; for( AI_EnemyInfo_t *pMemory = GetEnemies()->GetFirst(&iter); pMemory != NULL; pMemory = GetEnemies()->GetNext(&iter) ) { if ( pMemory->hEnemy == info.GetAttacker() ) { bSneakAttacked = false; break; } } float flDist; flDist = (info.GetAttacker()->GetAbsOrigin() - GetAbsOrigin()).Length(); if( flDist > SNEAK_ATTACK_DIST ) { bSneakAttacked = false; } } } if( bSneakAttacked ) { CTakeDamageInfo newInfo = info; newInfo.SetDamage( GetHealth() ); BaseClass::TraceAttack( newInfo, vecDir, ptr ); return; } BaseClass::TraceAttack( info, vecDir, ptr ); }
//========================================================= // Spawn //========================================================= void CNPC_Gargantua::Spawn() { Precache( ); SetModel( "models/garg.mdl" ); SetNavType(NAV_GROUND); SetSolid( SOLID_BBOX ); AddSolidFlags( FSOLID_NOT_STANDABLE ); SetMoveType( MOVETYPE_STEP ); Vector vecSurroundingMins( -80, -80, 0 ); Vector vecSurroundingMaxs( 80, 80, 214 ); CollisionProp()->SetSurroundingBoundsType( USE_SPECIFIED_BOUNDS, &vecSurroundingMins, &vecSurroundingMaxs ); m_bloodColor = BLOOD_COLOR_GREEN; m_iHealth = sk_gargantua_health.GetFloat(); SetViewOffset( Vector ( 0, 0, 96 ) );// taken from mdl file m_flFieldOfView = -0.2;// width of forward view cone ( as a dotproduct result ) m_NPCState = NPC_STATE_NONE; CapabilitiesAdd( bits_CAP_MOVE_GROUND ); CapabilitiesAdd( bits_CAP_INNATE_RANGE_ATTACK1 | bits_CAP_INNATE_MELEE_ATTACK1 | bits_CAP_INNATE_MELEE_ATTACK2 ); SetHullType( HULL_LARGE ); SetHullSizeNormal(); m_pEyeGlow = CSprite::SpriteCreate( GARG_EYE_SPRITE_NAME, GetAbsOrigin(), FALSE ); m_pEyeGlow->SetTransparency( kRenderGlow, 255, 255, 255, 0, kRenderFxNoDissipation ); m_pEyeGlow->SetAttachment( this, 1 ); EyeOff(); m_seeTime = gpGlobals->curtime + 5; m_flameTime = gpGlobals->curtime + 2; NPCInit(); BaseClass::Spawn(); // Give garg a healthy free knowledge. GetEnemies()->SetFreeKnowledgeDuration( 59.0f ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CBaseEntity *CAI_FuncTankBehavior::BestEnemy( void ) { // Only use this BestEnemy call when we are on the manned gun. if ( !m_hFuncTank ||!IsMounted() ) return BaseClass::BestEnemy(); CBaseEntity *pBestEnemy = NULL; int iBestDistSq = MAX_COORD_RANGE * MAX_COORD_RANGE; // so first visible entity will become the closest. int iBestPriority = -1000; bool bBestUnreachable = false; // Forces initial check bool bBestSeen = false; bool bUnreachable = false; int iDistSq; AIEnemiesIter_t iter; // Get the current npc for checking from. CAI_BaseNPC *pNPC = GetOuter(); if ( !pNPC ) return NULL; for( AI_EnemyInfo_t *pEMemory = GetEnemies()->GetFirst( &iter ); pEMemory != NULL; pEMemory = GetEnemies()->GetNext( &iter ) ) { CBaseEntity *pEnemy = pEMemory->hEnemy; if ( !pEnemy || !pEnemy->IsAlive() ) continue; // UNDONE: Move relationship checks into IsValidEnemy? if ( ( pEnemy->GetFlags() & FL_NOTARGET ) || ( pNPC->IRelationType( pEnemy ) != D_HT && pNPC->IRelationType( pEnemy ) != D_FR ) || !IsValidEnemy( pEnemy ) ) continue; if ( pEMemory->timeLastSeen < pNPC->GetAcceptableTimeSeenEnemy() ) continue; if ( pEMemory->timeValidEnemy > gpGlobals->curtime ) continue; // Skip enemies that have eluded me to prevent infinite loops if ( GetEnemies()->HasEludedMe( pEnemy ) ) continue; // Establish the reachability of this enemy bUnreachable = pNPC->IsUnreachable( pEnemy ); // Check view cone of the view tank here. bUnreachable = !m_hFuncTank->IsEntityInViewCone( pEnemy ); if ( !bUnreachable ) { // It's in the viewcone. Now make sure we have LOS to it. bUnreachable = !m_hFuncTank->HasLOSTo( pEnemy ); } // If best is reachable and current is unreachable, skip the unreachable enemy regardless of priority if ( !bBestUnreachable && bUnreachable ) continue; // If best is unreachable and current is reachable, always pick the current regardless of priority if ( bBestUnreachable && !bUnreachable ) { bBestSeen = ( pNPC->GetSenses()->DidSeeEntity( pEnemy ) || pNPC->FVisible( pEnemy ) ); // @TODO (toml 04-02-03): Need to optimize CanSeeEntity() so multiple calls in frame do not recalculate, rather cache iBestPriority = pNPC->IRelationPriority( pEnemy ); iBestDistSq = static_cast<int>((pEnemy->GetAbsOrigin() - GetAbsOrigin() ).LengthSqr()); pBestEnemy = pEnemy; bBestUnreachable = bUnreachable; } // If both are unreachable or both are reachable, chose enemy based on priority and distance else if ( pNPC->IRelationPriority( pEnemy ) > iBestPriority ) { // this entity is disliked MORE than the entity that we // currently think is the best visible enemy. No need to do // a distance check, just get mad at this one for now. iBestPriority = pNPC->IRelationPriority ( pEnemy ); iBestDistSq = static_cast<int>(( pEnemy->GetAbsOrigin() - GetAbsOrigin() ).LengthSqr()); pBestEnemy = pEnemy; bBestUnreachable = bUnreachable; } else if ( pNPC->IRelationPriority( pEnemy ) == iBestPriority ) { // this entity is disliked just as much as the entity that // we currently think is the best visible enemy, so we only // get mad at it if it is closer. iDistSq = static_cast<int>(( pEnemy->GetAbsOrigin() - GetAbsOrigin() ).LengthSqr()); bool bCloser = ( iDistSq < iBestDistSq ) ; if ( bCloser || !bBestSeen ) { // @TODO (toml 04-02-03): Need to optimize FVisible() so multiple calls in frame do not recalculate, rather cache bool fSeen = ( pNPC->GetSenses()->DidSeeEntity( pEnemy ) || pNPC->FVisible( pEnemy ) ); if ( ( bCloser && ( fSeen || !bBestSeen ) ) || ( !bCloser && !bBestSeen && fSeen ) ) { bBestSeen = fSeen; iBestDistSq = iDistSq; iBestPriority = pNPC->IRelationPriority( pEnemy ); pBestEnemy = pEnemy; bBestUnreachable = bUnreachable; } } } } return pBestEnemy; }
int CASW_Harvester::SelectHarvesterCombatSchedule() { int nSched = SelectFlinchSchedule_ASW(); if ( nSched != SCHED_NONE ) { // if we flinch, push forward the next attack float spawn_interval = 2.0f; m_flNextAttack = gpGlobals->curtime + spawn_interval; return nSched; } if ( HasCondition(COND_NEW_ENEMY) && gpGlobals->curtime - GetEnemies()->FirstTimeSeen(GetEnemy()) < 2.0 ) { return SCHED_WAKE_ANGRY; } if ( HasCondition( COND_ENEMY_DEAD ) ) { // clear the current (dead) enemy and try to find another. SetEnemy( NULL ); if ( ChooseEnemy() ) { ClearCondition( COND_ENEMY_DEAD ); return SelectSchedule(); } SetState( NPC_STATE_ALERT ); return SelectSchedule(); } #ifdef ASW_FEARFUL_HARVESTERS // If I'm scared of this enemy run away if ( IRelationType( GetEnemy() ) == D_FR ) { if (HasCondition( COND_SEE_ENEMY ) || HasCondition( COND_LIGHT_DAMAGE )|| HasCondition( COND_HEAVY_DAMAGE )) { FearSound(); //ClearCommandGoal(); return SCHED_RUN_FROM_ENEMY; } // If I've seen the enemy recently, cower. Ignore the time for unforgettable enemies. AI_EnemyInfo_t *pMemory = GetEnemies()->Find( GetEnemy() ); if ( (pMemory && pMemory->bUnforgettable) || (GetEnemyLastTimeSeen() > (gpGlobals->curtime - 5.0)) ) { // If we're facing him, just look ready. Otherwise, face him. if ( FInAimCone( GetEnemy()->EyePosition() ) ) return SCHED_COMBAT_STAND; return SCHED_FEAR_FACE; } } #endif // Check if need to reload if ( HasCondition( COND_LOW_PRIMARY_AMMO ) || HasCondition( COND_NO_PRIMARY_AMMO ) ) { return SCHED_HIDE_AND_RELOAD; } #ifdef ASW_FEARFUL_HARVESTERS if ( HasCondition(COND_TOO_CLOSE_TO_ATTACK) ) return SCHED_RUN_FROM_ENEMY; //SCHED_BACK_AWAY_FROM_ENEMY; #endif if ( GetShotRegulator()->IsInRestInterval() ) { if ( HasCondition(COND_CAN_RANGE_ATTACK1) ) return SCHED_COMBAT_FACE; } // we can see the enemy if ( HasCondition(COND_CAN_RANGE_ATTACK1) ) { return SCHED_RANGE_ATTACK1; } if ( HasCondition(COND_CAN_RANGE_ATTACK2) ) return SCHED_RANGE_ATTACK2; if ( HasCondition(COND_CAN_MELEE_ATTACK1) ) return SCHED_MELEE_ATTACK1; if ( HasCondition(COND_CAN_MELEE_ATTACK2) ) return SCHED_MELEE_ATTACK2; if ( HasCondition(COND_NOT_FACING_ATTACK) ) return SCHED_COMBAT_FACE; // if we're not attacking, then back away return SCHED_RUN_FROM_ENEMY; }
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: //----------------------------------------------------------------------------- void CNPC_Combine_Cannon::Spawn( void ) { Precache(); /// HACK: SetModel( "models/combine_soldier.mdl" ); // Setup our ancillary beams but keep them hidden for now CreateLaser(); CreateAncillaryBeams(); m_iAmmoType = GetAmmoDef()->Index( "CombineHeavyCannon" ); SetHullType( HULL_HUMAN ); SetHullSizeNormal(); UTIL_SetSize( this, Vector( -16, -16 , 0 ), Vector( 16, 16, 64 ) ); SetSolid( SOLID_BBOX ); AddSolidFlags( FSOLID_NOT_STANDABLE ); SetMoveType( MOVETYPE_FLY ); m_bloodColor = DONT_BLEED; m_iHealth = 10; m_flFieldOfView = DOT_45DEGREE; m_NPCState = NPC_STATE_NONE; if( HasSpawnFlags( SF_STARTDISABLED ) ) { m_fEnabled = false; } else { m_fEnabled = true; } CapabilitiesClear(); CapabilitiesAdd( bits_CAP_INNATE_RANGE_ATTACK1 | bits_CAP_SIMPLE_RADIUS_DAMAGE ); m_HackedGunPos = Vector ( 0, 0, 0 ); AddSpawnFlags( SF_NPC_LONG_RANGE | SF_NPC_ALWAYSTHINK ); NPCInit(); // Limit our look distance SetDistLook( m_flSightDist ); AddEffects( EF_NODRAW ); AddSolidFlags( FSOLID_NOT_SOLID ); // Point the cursor straight ahead so that the sniper's // first sweep of the laser doesn't look weird. Vector vecForward; AngleVectors( GetLocalAngles(), &vecForward ); m_vecPaintCursor = GetBulletOrigin() + vecForward * 1024; // none! GetEnemies()->SetFreeKnowledgeDuration( 0.0f ); GetEnemies()->SetEnemyDiscardTime( 2.0f ); m_flTimeLastAttackedPlayer = 0.0f; }
TFlickInfo *CAI_ASW_FlickBehavior::GetFlickActivity( ) { Vector vRightNPC, vForwardNPC, vForwardEnemy; int nCount = 0; int nFlickTotal[ MAX_FLICKS ]; for( int i = 0; i < MAX_FLICKS; i++ ) { nFlickTotal[ i ] = 0; } AngleVectors( GetAbsAngles(), &vForwardNPC, &vRightNPC, NULL ); #ifdef DRAW_DEBUG UTIL_AddDebugLine( GetAbsOrigin(), GetAbsOrigin() + vForwardNPC * 300.0f, true, false ); #endif // #ifdef DRAW_DEBUG AIEnemiesIter_t iter; for( AI_EnemyInfo_t *pEMemory = GetEnemies()->GetFirst( &iter ); pEMemory != NULL; pEMemory = GetEnemies()->GetNext( &iter ) ) { CBaseEntity *pEntity = pEMemory->hEnemy; Vector vDelta = GetAbsOrigin() - pEntity->GetAbsOrigin(); float flLenSq = vDelta.LengthSqr(); if ( flLenSq > m_flDistanceSq ) { continue; } #ifdef DRAW_DEBUG UTIL_AddDebugLine( GetAbsOrigin(), pEntity->GetAbsOrigin(), true, false ); #endif // #ifdef DRAW_DEBUG vForwardEnemy = vDelta; vForwardEnemy.NormalizeInPlace(); float flResult = vForwardNPC.Dot( vForwardEnemy ); if ( flResult > 0.0f ) { // we are behind continue; } flResult = vRightNPC.Dot( vForwardEnemy ); for( int j = 0; j < MAX_FLICKS; j++ ) { if ( flResult >= FlickInfo[ j ].m_flMinDot && flResult <= FlickInfo[ j ].m_flMaxDot ) { // we are within the flick angle of this arm nFlickTotal[ j ]++; nCount++; break; } } } if ( nCount > 0 ) { int nTotal = 0; nCount = RandomInt( 0, nCount - 1 ); for( int j = 0; j < MAX_FLICKS; j++ ) { nTotal += nFlickTotal[ j ]; if ( nCount < nTotal ) { return &FlickInfo[ j ]; } } } return NULL; }
bool CNPC_Bullsquid::SeenEnemyWithinTime(float flTime) { float flLastSeenTime = GetEnemies()->LastTimeSeen(GetEnemy()); return (flLastSeenTime != 0.0f && (gpGlobals->curtime - flLastSeenTime) < flTime); }
//------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ void CBaseHelicopter::Hunt( void ) { UpdateTrackNavigation( ); if( HasCondition( COND_ENEMY_DEAD ) ) { SetEnemy( NULL ); } // Look for my best enemy. If I change enemies, // be sure and change my prevseen/lastseen timers. if( m_lifeState == LIFE_ALIVE ) { GetSenses()->Look( 4092 ); GetEnemies()->RefreshMemories(); ChooseEnemy(); if( HasEnemy() ) { GatherEnemyConditions( GetEnemy() ); if (FVisible( GetEnemy() )) { if (m_flLastSeen < gpGlobals->curtime - 2) { m_flPrevSeen = gpGlobals->curtime; } m_flLastSeen = gpGlobals->curtime; m_vecTargetPosition = GetEnemy()->WorldSpaceCenter(); } } else { // look at where we're going instead m_vecTargetPosition = GetDesiredPosition(); } } else { // If we're dead or dying, forget our enemy and don't look for new ones(sjb) SetEnemy( NULL ); } if ( 1 ) { Vector targetDir = m_vecTargetPosition - GetAbsOrigin(); Vector desiredDir = GetDesiredPosition() - GetAbsOrigin(); VectorNormalize( targetDir ); VectorNormalize( desiredDir ); if ( !IsCrashing() && m_flLastSeen + 5 > gpGlobals->curtime ) //&& DotProduct( targetDir, desiredDir) > 0.25) { // If we've seen the target recently, face the target. //Msg( "Facing Target \n" ); m_vecDesiredFaceDir = targetDir; } else { // Face our desired position. // Msg( "Facing Position\n" ); m_vecDesiredFaceDir = desiredDir; } } else { // Face the way the path corner tells us to. //Msg( "Facing my path corner\n" ); m_vecDesiredFaceDir = GetGoalOrientation(); } Flight(); UpdatePlayerDopplerShift( ); // ALERT( at_console, "%.0f %.0f %.0f\n", gpGlobals->curtime, m_flLastSeen, m_flPrevSeen ); if (m_fHelicopterFlags & BITS_HELICOPTER_GUN_ON) { //if ( (m_flLastSeen + 1 > gpGlobals->curtime) && (m_flPrevSeen + 2 < gpGlobals->curtime) ) { if (FireGun( )) { // slow down if we're firing if (m_flGoalSpeed > m_flMaxSpeedFiring ) { m_flGoalSpeed = m_flMaxSpeedFiring; } } } } if (m_fHelicopterFlags & BITS_HELICOPTER_MISSILE_ON) { AimRocketGun(); } // Finally, forget dead enemies. if( GetEnemy() != NULL && (!GetEnemy()->IsAlive() || GetEnemy()->GetFlags() & FL_NOTARGET) ) { SetEnemy( NULL ); } }