//========================================================= // Revela la posición de los jugadores. //========================================================= void CDirector_Manager::Disclose() { CAI_BaseNPC *pNPC = NULL; do { // Buscamos a todos los hijos en el mapa. pNPC = (CAI_BaseNPC *)gEntList.FindEntityByName(pNPC, CHILD_NAME); // No existe o esta muerto. if ( !pNPC || !pNPC->IsAlive() ) continue; // Ya tiene a un jugador como enemigo. if ( pNPC->GetEnemy() && pNPC->GetEnemy()->IsPlayer() ) continue; // Seleccionamos al jugador más cercano. float flDistance = 0.0f; CIN_Player *pPlayer = UTIL_GetNearestInPlayer(pPlayer->GetAbsOrigin(), flDistance); if ( !pPlayer ) continue; // Le decimos que su nuevo enemigo es el jugador y le damos la ubicación de este. pNPC->SetEnemy(pPlayer); pNPC->UpdateEnemyMemory(pPlayer, pPlayer->GetAbsOrigin()); } while ( pNPC ); }
int DotaObjective::OnTakeDamage( const CTakeDamageInfo &inputInfo ) { if ( m_bMet ) return 0; if ( !(inputInfo.GetDamageType() & DMG_BULLET) ) { CHL2MP_Player * playerAttacker = ToHL2MPPlayer( inputInfo.GetAttacker() ); CreepMaker * maker = (CreepMaker*)gEntList.FindEntityByName( NULL, m_creepMakerName ); if ( !maker ) AssertMsg( false, "Objective can't find its creepmaker!\n" ); CAI_BaseNPC * guardian = (CAI_BaseNPC*)gEntList.FindEntityByName( NULL, m_guardianName ); if( guardian && guardian->IsAlive() ) { if( playerAttacker ) ClientPrint( playerAttacker, HUD_PRINTTALK, UTIL_VarArgs("The guradian is alive in this lane, you can't hurt the gate.\n") ); } else { m_timesHit++; m_timesHit = min(m_timesHit, OBJECTIVE_HEALTHI); // make sure times hit never goes above the maximum times an objective can be hit! CRecipientFilter user; user.AddRecipientsByTeam( this->GetTeam() ); user.MakeReliable(); char szText[200]; Q_snprintf( szText, sizeof(szText), "Your ally gate is under attack from an enemy!" ); UTIL_ClientPrintFilter( user, HUD_PRINTCENTER, szText ); if( playerAttacker ) ClientPrint( playerAttacker, HUD_PRINTTALK, UTIL_VarArgs("Gate has %i health left.\n", OBJECTIVE_HEALTHI - m_timesHit) ); if (m_timesHit >= OBJECTIVE_HEALTHI) { TakeAction(DOBJ_ACTION_CLOSE); } else { IGameEvent *pEvent = gameeventmanager->CreateEvent( "objectivegate_attacked" ); if ( pEvent ) { pEvent->SetString( "lane", GetLane() ); pEvent->SetInt( "team", this->GetTeamNumber() ); pEvent->SetFloat( "health", (OBJECTIVE_HEALTHF - m_timesHit)/OBJECTIVE_HEALTHF ); gameeventmanager->FireEvent( pEvent ); } } } } return 0; }
void CAI_PlaneSolver::GenerateObstacleNpcs( const AILocalMoveGoal_t &goal, float probeDist ) { if ( !ProbeForNpcs() ) { CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); Vector minsSelf, maxsSelf; m_pNpc->CollisionProp()->WorldSpaceSurroundingBounds( &minsSelf, &maxsSelf ); float radiusSelf = (minsSelf.AsVector2D() - maxsSelf.AsVector2D()).Length() * 0.5; for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ ) { CAI_BaseNPC *pAI = ppAIs[i]; if ( pAI != m_pNpc && pAI->IsAlive() && ( !goal.pPath || pAI != goal.pPath->GetTarget() ) ) { Vector mins, maxs; pAI->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs ); if ( mins.z < maxsSelf.z + 12.0 && maxs.z > minsSelf.z - 12.0 ) { float radius = (mins.AsVector2D() - maxs.AsVector2D()).Length() * 0.5; float distance = ( pAI->GetAbsOrigin().AsVector2D() - m_pNpc->GetAbsOrigin().AsVector2D() ).Length(); if ( distance - radius < radiusSelf + probeDist ) { AddObstacle( pAI->WorldSpaceCenter(), radius, pAI, AIMST_AVOID_NPC ); } } } } #ifdef SecobMod__Enable_Fixed_Multiplayer_AI CBaseEntity *pPlayer = UTIL_GetNearestPlayer(m_pNpc->GetAbsOrigin()); #else CBaseEntity *pPlayer = UTIL_PlayerByIndex( 1 ); #endif //SecobMod__Enable_Fixed_Multiplayer_AI if ( pPlayer ) { Vector mins, maxs; pPlayer->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs ); if ( mins.z < maxsSelf.z + 12.0 && maxs.z > minsSelf.z - 12.0 ) { float radius = (mins.AsVector2D() - maxs.AsVector2D()).Length(); float distance = ( pPlayer->GetAbsOrigin().AsVector2D() - m_pNpc->GetAbsOrigin().AsVector2D() ).Length(); if ( distance - radius < radiusSelf + probeDist ) { AddObstacle( pPlayer->WorldSpaceCenter(), radius, pPlayer, AIMST_AVOID_NPC ); } } } } }
void CAI_PlayerAlly::AlertFriends( CBaseEntity *pKiller ) { CBaseEntity *pFriend = NULL; int i; // for each friend in this bsp... for ( i = 0; i < TLK_CFRIENDS; i++ ) { while (pFriend = EnumFriends( pFriend, i, true )) { CAI_BaseNPC *pNPC = pFriend->MyNPCPointer(); if ( pNPC->IsAlive() ) { // If a client killed me, make everyone else mad/afraid of him if ( pKiller->GetFlags() & FL_CLIENT ) { pNPC->SetSchedule( SCHED_TALKER_BETRAYED ); #ifdef ALLIES_CAN_BE_PROVOKED pNPC->Remember( bits_MEMORY_PROVOKED ); if( IsSelected() ) { PlayerSelect( false ); } #endif } else { if( IRelationType(pKiller) == D_HT) { // Killed by an enemy!!! CAI_PlayerAlly *pAlly = (CAI_PlayerAlly *)pNPC; if( pAlly && pAlly->GetExpresser()->CanSpeakConcept( TLK_ALLY_KILLED ) ) { pAlly->Speak( TLK_ALLY_KILLED ); } } } } } } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pKiller - //----------------------------------------------------------------------------- void CNPCSimpleTalker::AlertFriends( CBaseEntity *pKiller ) { CBaseEntity *pFriend = NULL; int i; // for each friend in this bsp... for ( i = 0; i < TLK_CFRIENDS; i++ ) { while ((pFriend = EnumFriends( pFriend, i, true )) != NULL ) { CAI_BaseNPC *pNPC = pFriend->MyNPCPointer(); if ( pNPC->IsAlive() ) { // If a client killed me, make everyone else mad/afraid of him if ( pKiller->GetFlags() & FL_CLIENT ) { CNPCSimpleTalker*pTalkNPC = (CNPCSimpleTalker *)pFriend; if (pTalkNPC && pTalkNPC->IsOkToCombatSpeak()) { // FIXME: need to check CanSpeakConcept? pTalkNPC->Speak( TLK_BETRAYED ); } } else { if( IRelationType(pKiller) == D_HT) { // Killed by an enemy!!! CNPCSimpleTalker *pAlly = (CNPCSimpleTalker *)pNPC; if( pAlly && pAlly->GetExpresser()->CanSpeakConcept( TLK_ALLY_KILLED ) ) { pAlly->Speak( TLK_ALLY_KILLED ); } } } } } } }
//----------------------------------------------------------------------------- // Purpose: // Input : pInflictor - // pAttacker - // flDamage - // bitsDamageType - //----------------------------------------------------------------------------- void CNPC_Stalker::Event_Killed( const CTakeDamageInfo &info ) { if( IsInSquad() && info.GetAttacker()->IsPlayer() ) { AISquadIter_t iter; for ( CAI_BaseNPC *pSquadMember = GetSquad()->GetFirstMember( &iter ); pSquadMember; pSquadMember = GetSquad()->GetNextMember( &iter ) ) { if ( pSquadMember->IsAlive() && pSquadMember != this ) { CNPC_Stalker *pStalker = dynamic_cast <CNPC_Stalker*>(pSquadMember); if( pStalker && pStalker->FVisible(info.GetAttacker()) ) { pStalker->m_iPlayerAggression++; } } } } KillAttackBeam(); BaseClass::Event_Killed( info ); }
//----------------------------------------------------------------------------- // Purpose: Called once per frame after all entities have had a chance to think //----------------------------------------------------------------------------- void CLagCompensationManager::FrameUpdatePostEntityThink() { if ( m_bNeedsAIUpdate ) UpdateAIIndexes(); // only bother if we haven't had one yet else // setting this true here ensures that the update happens at the start of the next frame m_bNeedsAIUpdate = true; if ( (gpGlobals->maxClients <= 1) || !sv_unlag.GetBool() ) { ClearHistory(); return; } m_flTeleportDistanceSqr = sv_lagcompensation_teleport_dist.GetFloat() * sv_lagcompensation_teleport_dist.GetFloat(); VPROF_BUDGET( "FrameUpdatePostEntityThink", "CLagCompensationManager" ); // remove all records before that time: int flDeadtime = gpGlobals->curtime - sv_maxunlag.GetFloat(); // Iterate all active players for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); CUtlFixedLinkedList< LagRecord > *track = &m_PlayerTrack[i-1]; if ( !pPlayer ) { if ( track->Count() > 0 ) { track->RemoveAll(); } continue; } Assert( track->Count() < 1000 ); // insanity check // remove tail records that are too old int tailIndex = track->Tail(); while ( track->IsValidIndex( tailIndex ) ) { LagRecord &tail = track->Element( tailIndex ); // if tail is within limits, stop if ( tail.m_flSimulationTime >= flDeadtime ) break; // remove tail, get new tail track->Remove( tailIndex ); tailIndex = track->Tail(); } // check if head has same simulation time if ( track->Count() > 0 ) { LagRecord &head = track->Element( track->Head() ); // check if player changed simulation time since last time updated if ( head.m_flSimulationTime >= pPlayer->GetSimulationTime() ) continue; // don't add new entry for same or older time } // add new record to player track LagRecord &record = track->Element( track->AddToHead() ); record.m_fFlags = 0; if ( pPlayer->IsAlive() ) { record.m_fFlags |= LC_ALIVE; } record.m_flSimulationTime = pPlayer->GetSimulationTime(); record.m_vecAngles = pPlayer->GetLocalAngles(); record.m_vecOrigin = pPlayer->GetLocalOrigin(); record.m_vecMinsPreScaled = pPlayer->CollisionProp()->OBBMinsPreScaled(); record.m_vecMaxsPreScaled = pPlayer->CollisionProp()->OBBMaxsPreScaled(); int layerCount = pPlayer->GetNumAnimOverlays(); for( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) { CAnimationLayer *currentLayer = pPlayer->GetAnimOverlay(layerIndex); if( currentLayer ) { record.m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle; record.m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder; record.m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence; record.m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight; } } record.m_masterSequence = pPlayer->GetSequence(); record.m_masterCycle = pPlayer->GetCycle(); } // Iterate all active NPCs CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); int nAIs = g_AI_Manager.NumAIs(); for ( int i = 0; i < nAIs; i++ ) { CAI_BaseNPC *pNPC = ppAIs[i]; CUtlFixedLinkedList< LagRecord > *track = &m_EntityTrack[i]; if ( !pNPC ) { track->RemoveAll(); continue; } Assert( track->Count() < 1000 ); // insanity check // remove tail records that are too old int tailIndex = track->Tail(); while ( track->IsValidIndex( tailIndex ) ) { LagRecord &tail = track->Element( tailIndex ); // if tail is within limits, stop if ( tail.m_flSimulationTime >= flDeadtime ) break; // remove tail, get new tail track->Remove( tailIndex ); tailIndex = track->Tail(); } // check if head has same simulation time if ( track->Count() > 0 ) { LagRecord &head = track->Element( track->Head() ); // check if entity changed simulation time since last time updated if ( &head && head.m_flSimulationTime >= pNPC->GetSimulationTime() ) continue; // don't add new entry for same or older time // Simulation Time is set when an entity moves or rotates ... // this error occurs when whatever entity it is that breaks it moves or rotates then, presumably? } // add new record to track LagRecord &record = track->Element( track->AddToHead() ); record.m_fFlags = 0; if ( pNPC->IsAlive() ) { record.m_fFlags |= LC_ALIVE; } record.m_flSimulationTime = pNPC->GetSimulationTime(); record.m_vecAngles = pNPC->GetLocalAngles(); record.m_vecOrigin = pNPC->GetLocalOrigin(); record.m_vecMaxs = pNPC->WorldAlignMaxs(); record.m_vecMins = pNPC->WorldAlignMins(); int layerCount = pNPC->GetNumAnimOverlays(); for( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) { CAnimationLayer *currentLayer = pNPC->GetAnimOverlay(layerIndex); if( currentLayer ) { record.m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle; record.m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder; record.m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence; record.m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight; } } record.m_masterSequence = pNPC->GetSequence(); record.m_masterCycle = pNPC->GetCycle(); } //Clear the current player. m_pCurrentPlayer = NULL; }
//----------------------------------------------------------------------------- // Purpose: Burn targets around us //----------------------------------------------------------------------------- void CEntityFlame::FlameThink( void ) { // Assure that this function will be ticked again even if we early-out in the if below. SetNextThink( gpGlobals->curtime + FLAME_DAMAGE_INTERVAL ); if ( m_hEntAttached ) { if ( m_hEntAttached->GetFlags() & FL_TRANSRAGDOLL ) { SetRenderColorA( 0 ); return; } CAI_BaseNPC *pNPC = m_hEntAttached->MyNPCPointer(); if ( pNPC && !pNPC->IsAlive() ) { UTIL_Remove( this ); // Notify the NPC that it's no longer burning! pNPC->Extinguish(); return; } if( m_hEntAttached->GetWaterLevel() > 0 ) { Vector mins, maxs; mins = m_hEntAttached->WorldSpaceCenter(); maxs = mins; maxs.z = m_hEntAttached->WorldSpaceCenter().z; maxs.x += 32; maxs.y += 32; mins.z -= 32; mins.x -= 32; mins.y -= 32; UTIL_Bubbles( mins, maxs, 12 ); } } else { UTIL_Remove( this ); return; } // See if we're done burning, or our attached ent has vanished if ( m_flLifetime < gpGlobals->curtime || m_hEntAttached == NULL ) { EmitSound( "General.StopBurning" ); m_bPlayingSound = false; SetThink( &CEntityFlame::SUB_Remove ); SetNextThink( gpGlobals->curtime + 0.5f ); // Notify anything we're attached to if ( m_hEntAttached ) { CBaseCombatCharacter *pAttachedCC = m_hEntAttached->MyCombatCharacterPointer(); if( pAttachedCC ) { // Notify the NPC that it's no longer burning! pAttachedCC->Extinguish(); } } return; } if ( m_hEntAttached ) { // Do radius damage ignoring the entity I'm attached to. This will harm things around me. RadiusDamage( CTakeDamageInfo( this, this, 4.0f, DMG_BURN ), GetAbsOrigin(), m_flSize/2, CLASS_NONE, m_hEntAttached ); // Directly harm the entity I'm attached to. This is so we can precisely control how much damage the entity // that is on fire takes without worrying about the flame's position relative to the bodytarget (which is the // distance that the radius damage code uses to determine how much damage to inflict) m_hEntAttached->TakeDamage( CTakeDamageInfo( this, this, FLAME_DIRECT_DAMAGE, DMG_BURN | DMG_DIRECT ) ); if( !m_hEntAttached->IsNPC() && hl2_episodic.GetBool() ) { const int ENTITYFLAME_MOVE_AWAY_DIST = 24; // Make a sound near my origin, and up a little higher (in case I'm on the ground, so NPC's still hear it) CSoundEnt::InsertSound( SOUND_MOVE_AWAY, GetAbsOrigin(), ENTITYFLAME_MOVE_AWAY_DIST, 0.1f, this, SOUNDENT_CHANNEL_REPEATED_DANGER ); CSoundEnt::InsertSound( SOUND_MOVE_AWAY, GetAbsOrigin() + Vector( 0, 0, 48.0f ), ENTITYFLAME_MOVE_AWAY_DIST, 0.1f, this, SOUNDENT_CHANNEL_REPEATING ); } } else { RadiusDamage( CTakeDamageInfo( this, this, FLAME_RADIUS_DAMAGE, DMG_BURN ), GetAbsOrigin(), m_flSize/2, CLASS_NONE, NULL ); } FireSystem_AddHeatInRadius( GetAbsOrigin(), m_flSize/2, 2.0f ); }
//--------------------------------------------------------- // Returns distance to the nearest BaseCombatCharacter. //--------------------------------------------------------- float CBounceBomb::FindNearestNPC() { float flNearest = (BOUNCEBOMB_WARN_RADIUS * BOUNCEBOMB_WARN_RADIUS) + 1.0; // Assume this search won't find anyone. SetNearestNPC( NULL ); CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); int nAIs = g_AI_Manager.NumAIs(); for ( int i = 0; i < nAIs; i++ ) { CAI_BaseNPC *pNPC = ppAIs[ i ]; if( pNPC->IsAlive() ) { // ignore hidden objects if ( pNPC->IsEffectActive( EF_NODRAW ) ) continue; // Don't bother with NPC's that are below me. if( pNPC->EyePosition().z < GetAbsOrigin().z ) continue; // Disregard things that want to be disregarded if( pNPC->Classify() == CLASS_NONE ) continue; // Disregard bullseyes if( pNPC->Classify() == CLASS_BULLSEYE ) continue; // Disregard turrets if( pNPC->m_iClassname == gm_iszFloorTurretClassname || pNPC->m_iClassname == gm_iszGroundTurretClassname ) continue; float flDist = (GetAbsOrigin() - pNPC->GetAbsOrigin()).LengthSqr(); if( flDist < flNearest ) { // Now do a visibility test. if( FVisible( pNPC, MASK_SOLID_BRUSHONLY ) ) { flNearest = flDist; SetNearestNPC( pNPC ); } } } } // finally, check the player. CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); if( pPlayer && !(pPlayer->GetFlags() & FL_NOTARGET) ) { float flDist = (pPlayer->GetAbsOrigin() - GetAbsOrigin() ).LengthSqr(); if( flDist < flNearest && FVisible( pPlayer, MASK_SOLID_BRUSHONLY ) ) { flNearest = flDist; SetNearestNPC( pPlayer ); } } if( m_hNearestNPC.Get() ) { // If sprite is active, update its color to reflect who is nearest. if( IsFriend( m_hNearestNPC ) ) { if( m_bFoeNearest ) { // Changing state to where a friend is nearest. if( IsFriend( m_hNearestNPC ) ) { // Friend UpdateLight( true, 0, 255, 0, 190 ); m_bFoeNearest = false; } } } else // it's a foe { if( !m_bFoeNearest ) { // Changing state to where a foe is nearest. UpdateLight( true, 255, 0, 0, 190 ); m_bFoeNearest = true; } } } return sqrt( flNearest ); }
//----------------------------------------------------------------------------- // Look for a target //----------------------------------------------------------------------------- bool CObjectSentrygun::FindTarget() { // Disable the sentry guns for ifm. if ( tf_sentrygun_notarget.GetBool() ) return false; if ( IsInCommentaryMode() ) return false; // Sapper, etc. if ( IsDisabled() ) return false; // Loop through players within 1100 units (sentry range). Vector vecSentryOrigin = EyePosition(); // Find the opposing team list. CTFPlayer *pPlayer = ToTFPlayer( GetOwner() ); CUtlVector<CTFTeam *> pTeamList; CTFTeam *pTeam = NULL; //CTFTeam *pTeam = pPlayer->GetOpposingTFTeam(); //if ( !pTeam ) // return false; if ( pPlayer ) { // Try builder's team. pTeam = pPlayer->GetTFTeam(); } else { // If we have no builder use our own team number instead. pTeam = GetTFTeam(); } if ( pTeam ) pTeam->GetOpposingTFTeamList( &pTeamList ); else return false; // If we have an enemy get his minimum distance to check against. Vector vecSegment; Vector vecTargetCenter; float flMinDist2 = 1100.0f * 1100.0f; CBaseEntity *pTargetCurrent = NULL; CBaseEntity *pTargetOld = m_hEnemy.Get(); float flOldTargetDist2 = FLT_MAX; // Sentries will try to target players first, then objects. However, if the enemy held was an object it will continue // to try and attack it first. for (int i = 0; i < pTeamList.Size(); i++) { int nTeamCount = pTeamList[i]->GetNumPlayers(); for (int iPlayer = 0; iPlayer < nTeamCount; ++iPlayer) { CTFPlayer *pTargetPlayer = static_cast<CTFPlayer*>(pTeamList[i]->GetPlayer(iPlayer)); if (pTargetPlayer == NULL) continue; // Make sure the player is alive. if (!pTargetPlayer->IsAlive()) continue; if (pTargetPlayer->GetFlags() & FL_NOTARGET) continue; vecTargetCenter = pTargetPlayer->GetAbsOrigin(); vecTargetCenter += pTargetPlayer->GetViewOffset(); VectorSubtract(vecTargetCenter, vecSentryOrigin, vecSegment); float flDist2 = vecSegment.LengthSqr(); // Store the current target distance if we come across it if (pTargetPlayer == pTargetOld) { flOldTargetDist2 = flDist2; } // Check to see if the target is closer than the already validated target. if (flDist2 > flMinDist2) continue; // It is closer, check to see if the target is valid. if (ValidTargetPlayer(pTargetPlayer, vecSentryOrigin, vecTargetCenter)) { flMinDist2 = flDist2; pTargetCurrent = pTargetPlayer; } } // If we already have a target, don't check objects. if (pTargetCurrent == NULL) { int nTeamObjectCount = pTeamList[i]->GetNumObjects(); for (int iObject = 0; iObject < nTeamObjectCount; ++iObject) { CBaseObject *pTargetObject = pTeamList[i]->GetObject(iObject); if (!pTargetObject) continue; vecTargetCenter = pTargetObject->GetAbsOrigin(); vecTargetCenter += pTargetObject->GetViewOffset(); VectorSubtract(vecTargetCenter, vecSentryOrigin, vecSegment); float flDist2 = vecSegment.LengthSqr(); // Store the current target distance if we come across it if (pTargetObject == pTargetOld) { flOldTargetDist2 = flDist2; } // Check to see if the target is closer than the already validated target. if (flDist2 > flMinDist2) continue; // It is closer, check to see if the target is valid. if (ValidTargetObject(pTargetObject, vecSentryOrigin, vecTargetCenter)) { flMinDist2 = flDist2; pTargetCurrent = pTargetObject; } } } // NPCs have lowest priority. if (pTargetCurrent == NULL) { int nTeamNPCCount = pTeamList[i]->GetNumNPCs(); for (int iNPC = 0; iNPC < nTeamNPCCount; ++iNPC) { CAI_BaseNPC *pTargetNPC = pTeamList[i]->GetNPC(iNPC); if (!pTargetNPC) continue; // Make sure NPC is alive. if (!pTargetNPC->IsAlive()) continue; vecTargetCenter = pTargetNPC->GetAbsOrigin(); vecTargetCenter += pTargetNPC->GetViewOffset(); //vecTargetCenter = pTargetNPC->WorldSpaceCenter(); VectorSubtract(vecTargetCenter, vecSentryOrigin, vecSegment); float flDist2 = vecSegment.LengthSqr(); // Store the current target distance if we come across it if (pTargetNPC == pTargetOld) { flOldTargetDist2 = flDist2; } // Check to see if the target is closer than the already validated target. if (flDist2 > flMinDist2) continue; // It is closer, check to see if the target is valid. if (ValidTargetNPC(pTargetNPC, vecSentryOrigin, vecTargetCenter)) { flMinDist2 = flDist2; pTargetCurrent = pTargetNPC; } } } // We have a target. if (pTargetCurrent) { if (pTargetCurrent != pTargetOld) { // flMinDist2 is the new target's distance // flOldTargetDist2 is the old target's distance // Don't switch unless the new target is closer by some percentage if (flMinDist2 < (flOldTargetDist2 * 0.75f)) { FoundTarget(pTargetCurrent, vecSentryOrigin); } } return true; } } return false; }
void CAI_StandoffBehavior::GatherConditions() { CBaseEntity *pLeader = GetPlayerLeader(); if ( pLeader && m_TimeForceCoverHint.Expired() ) { if ( m_PlayerMoveMonitor.IsMarkSet() ) { if (m_PlayerMoveMonitor.TargetMoved( pLeader ) ) { OnChangeTacticalConstraints(); m_PlayerMoveMonitor.ClearMark(); } } else { m_PlayerMoveMonitor.SetMark( pLeader, 60 ); } } if ( m_fForceNewEnemy ) { m_TimePreventForceNewEnemy.Reset(); GetOuter()->SetEnemy( NULL ); DevMsg(2, "Forcing lose enemy from standoff\n"); } BaseClass::GatherConditions(); m_fForceNewEnemy = false; ClearCondition( COND_ABANDON_TIME_EXPIRED ); bool bAbandonStandoff = false; CAI_Squad *pSquad = GetOuter()->GetSquad(); AISquadIter_t iter; if ( GetEnemy() ) { AI_EnemyInfo_t *pEnemyInfo = GetOuter()->GetEnemies()->Find( GetEnemy() ); if ( pEnemyInfo && m_params.flAbandonTimeLimit > 0 && ( ( pEnemyInfo->timeAtFirstHand != AI_INVALID_TIME && gpGlobals->curtime - pEnemyInfo->timeLastSeen > m_params.flAbandonTimeLimit ) || ( pEnemyInfo->timeAtFirstHand == AI_INVALID_TIME && gpGlobals->curtime - pEnemyInfo->timeFirstSeen > m_params.flAbandonTimeLimit * 2 ) ) ) { SetCondition( COND_ABANDON_TIME_EXPIRED ); bAbandonStandoff = true; if ( pSquad ) { for ( CAI_BaseNPC *pSquadMate = pSquad->GetFirstMember( &iter ); pSquadMate; pSquadMate = pSquad->GetNextMember( &iter ) ) { if ( pSquadMate->IsAlive() && pSquadMate != GetOuter() ) { CAI_StandoffBehavior *pSquadmateStandoff; pSquadMate->GetBehavior( &pSquadmateStandoff ); if ( pSquadmateStandoff && pSquadmateStandoff->IsActive() && pSquadmateStandoff->m_hStandoffGoal == m_hStandoffGoal && !pSquadmateStandoff->HasCondition( COND_ABANDON_TIME_EXPIRED ) ) { bAbandonStandoff = false; break; } } } } } } if ( bAbandonStandoff ) { if ( pSquad ) { for ( CAI_BaseNPC *pSquadMate = pSquad->GetFirstMember( &iter ); pSquadMate; pSquadMate = pSquad->GetNextMember( &iter ) ) { CAI_StandoffBehavior *pSquadmateStandoff; pSquadMate->GetBehavior( &pSquadmateStandoff ); if ( pSquadmateStandoff && pSquadmateStandoff->IsActive() && pSquadmateStandoff->m_hStandoffGoal == m_hStandoffGoal ) pSquadmateStandoff->SetActive( false ); } } else SetActive( false ); } else if ( GetOuter()->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT ) { if( DrawBattleLines.GetInt() != 0 ) { if ( IsBehindBattleLines( GetAbsOrigin() ) ) { NDebugOverlay::Box( GetOuter()->GetAbsOrigin(), -Vector(48,48,4), Vector(48,48,4), 255,0,0,8, 0.1 ); } else { NDebugOverlay::Box( GetOuter()->GetAbsOrigin(), -Vector(48,48,4), Vector(48,48,4), 0,255,0,8, 0.1 ); } } } }