Skip to content

Commit 0c8dc37

Browse files
committed
spy detection: cloaked body-block, on-fire silhouette, instant spy-check, area suspicion, death decay
(1) Invisible spy melee check: when bot is stuck (m_fStuckTime>0) with no visible enemy, swing melee every 1s to decloak invisible C&D spies body-blocking doorways. Previously, cloaked spies were completely invisible to stuck detection (isVisible() gate). (2) On-fire disguised spy: remove teammate-attack prerequisite from the flame-silhouette detection branch. A disguised spy on fire is now detected purely by their visible fire effect, matching human players who see the flame silhouette and immediately know it's a spy. (3) Instant spy-check: set m_fLastSeeSpyTime to (now - 5s) in foundSpy() giving a 5s head start to the search radius. The fPossibleDistance calculation starts with a meaningful baseline instead of zero, enabling spy-check tasks to fire immediately when a spy is KNOWN. (4) Area suspicion: m_fSpyAreaSuspicion timer (5-10s) set when a spy is discovered. Adds +800u to the spy-check search radius. Also spreads via TF_VC_SPY voice command (3-6s timer). Nearby bots enter heightened alert state after hearing a spy callout. (5) Death awareness decay: on death, all spy awareness decays one level (KNOWN->SUSPECTED, SUSPECTED->NONE). Combined with m_pPrevSpy already being cleared for spy-killers, this gives spies a genuine advantage from eliminating their spotters — the respawned bot has reduced certainty about who was a spy. New members: m_fInvisSpyCheckTime, m_fSpyAreaSuspicion (CBotFortress). 3 files, 48 insertions, 3 deletions.
1 parent fb5dd76 commit 0c8dc37

2 files changed

Lines changed: 47 additions & 3 deletions

File tree

rcbot2/bot_fortress.cpp

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ void CBotTF2::hearVoiceCommand(edict_t *pPlayer, byte cmd)
142142
{
143143
m_vLastSeeSpy = CBotGlobals::entityOrigin(pPlayer);
144144
m_fSeeSpyTime = engine->Time() + randomFloat(3.0f, 6.0f);
145+
m_fSpyAreaSuspicion = engine->Time() + randomFloat(3.0f, 6.0f);
145146
updateCondition(CONDITION_PARANOID);
146147
// m_pPrevSpy = pPlayer; // HACK
147148
}
@@ -1968,7 +1969,7 @@ void CBotFortress::foundSpy(edict_t *pEdict, TF_Class iDisguise)
19681969
m_pPrevSpy = pEdict;
19691970
m_fSeeSpyTime = engine->Time() + randomFloat(9.0f, 18.0f);
19701971
m_vLastSeeSpy = CBotGlobals::entityOrigin(pEdict);
1971-
m_fLastSeeSpyTime = engine->Time();
1972+
m_fLastSeeSpyTime = engine->Time() - 5.0f; // head start for spy-check search radius
19721973
if (iDisguise && (m_iPrevSpyDisguise != iDisguise))
19731974
m_iPrevSpyDisguise = iDisguise;
19741975

@@ -1980,6 +1981,9 @@ void CBotFortress::foundSpy(edict_t *pEdict, TF_Class iDisguise)
19801981
m_SpyAwareness[iIdx].fWhenBecameKnown = engine->Time();
19811982
m_SpyAwareness[iIdx].iSuspectDisguise = iDisguise;
19821983
}
1984+
1985+
// Area suspicion: heightens paranoia for nearby spy-checking
1986+
m_fSpyAreaSuspicion = engine->Time() + randomFloat(5.0f, 10.0f);
19831987
};
19841988

19851989
// got shot by someone
@@ -2121,6 +2125,8 @@ void CBotTF2::spawnInit()
21212125
m_fLastEurekaTeleport = 0.0f;
21222126
m_iBestObscureTeleExit = -1;
21232127
m_iGuardSlot = ENTINDEX(m_pEdict) % 4;
2128+
m_fInvisSpyCheckTime = 0.0f;
2129+
m_fSpyAreaSuspicion = 0.0f;
21242130

21252131
m_bIsCarryingTeleExit = false;
21262132
m_bIsCarryingSentry = false;
@@ -2775,6 +2781,15 @@ void CBotTF2::died(edict_t *pKiller, const char *pszWeapon)
27752781
{
27762782
CBotFortress::died(pKiller, pszWeapon);
27772783

2784+
// Losing my life means I lose some spy awareness
2785+
for (int i = 0; i < MAX_PLAYERS; i++)
2786+
{
2787+
if (m_SpyAwareness[i].eLevel == SpyAwareness::KNOWN)
2788+
m_SpyAwareness[i].eLevel = SpyAwareness::SUSPECTED;
2789+
else if (m_SpyAwareness[i].eLevel == SpyAwareness::SUSPECTED)
2790+
m_SpyAwareness[i].eLevel = SpyAwareness::NONE;
2791+
}
2792+
27782793
int iWpt = CWaypointLocations::NearestWaypoint(getOrigin(), 256.0f, -1);
27792794
if (iWpt >= 0)
27802795
{
@@ -5234,6 +5249,10 @@ void CBotTF2::modThink()
52345249
if (m_iClass == TF_CLASS_PYRO)
52355250
fPossibleDistance += 200.0f;
52365251

5252+
// Area suspicion: recently spotted a spy or heard a spy callout
5253+
if (m_fSpyAreaSuspicion > engine->Time())
5254+
fPossibleDistance += 800.0f;
5255+
52375256
if ((m_vLastSeeSpy - getOrigin()).Length() < fPossibleDistance)
52385257
{
52395258
updateCondition(CONDITION_PARANOID);
@@ -6719,7 +6738,25 @@ void CBotTF2::checkStuckonSpy(void)
67196738
}
67206739
}
67216740
else
6741+
{
67226742
m_fStuckSpyTime = 0.0f;
6743+
6744+
// No visible spy found but bot is stuck — may be blocked by cloaked spy
6745+
if (m_fStuckTime > 0.0f && (!m_pEnemy || !hasSomeConditions(CONDITION_SEE_CUR_ENEMY)))
6746+
{
6747+
if (m_fInvisSpyCheckTime < engine->Time())
6748+
{
6749+
CBotWeapon *pMelee = getBestWeapon(nullptr, true, true);
6750+
if (pMelee && pMelee->isMelee() && pMelee->hasWeapon())
6751+
{
6752+
if (getCurrentWeapon() != pMelee)
6753+
select_CWeapon(pMelee->getWeaponInfo());
6754+
primaryAttack();
6755+
}
6756+
m_fInvisSpyCheckTime = engine->Time() + 1.0f;
6757+
}
6758+
}
6759+
}
67236760
}
67246761

67256762
bool CBotFortress::isClassOnTeam(int iClass, int iTeam)
@@ -14034,8 +14071,8 @@ bool CBotTF2::isEnemy(edict_t *pEdict, bool bCheckWeapons)
1403414071
// be smart - check if player's health is below 0
1403514072
bValid = true;
1403614073
}
14037-
// if he is on fire and I saw my team mate shoot him within the last 5 seconds, he's a spy!
14038-
else if (CTeamFortress2Mod::TF2_IsPlayerOnFire(pEdict) && (fSpyAttackTime < 5.0f))
14074+
// if he is on fire, I can see his flame silhouette — he's a spy!
14075+
else if (CTeamFortress2Mod::TF2_IsPlayerOnFire(pEdict))
1403914076
{
1404014077
bValid = true;
1404114078
}
@@ -14486,6 +14523,8 @@ CBotTF2::CBotTF2()
1448614523
m_iSpyContext = 0;
1448714524
memset(m_iSpySeenClassCount, 0, sizeof(m_iSpySeenClassCount));
1448814525
m_pSpyLurkTarget = MyEHandle(nullptr);
14526+
m_fInvisSpyCheckTime = 0.0f;
14527+
m_fSpyAreaSuspicion = 0.0f;
1448914528
}
1449014529

1449114530
void CBotTF2::init(bool bVarInit)

rcbot2/bot_fortress.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,11 @@ class CBotFortress : public CBot
912912
// List of spies I saw cloak in front of me
913913
float m_fSpyLastUncloakedList[MAX_PLAYERS];
914914

915+
// Timer for invisible-spy melee check when stuck (1s cooldown)
916+
float m_fInvisSpyCheckTime;
917+
// Area suspicion timer — heightens spy-check paranoia after detection or voice call
918+
float m_fSpyAreaSuspicion;
919+
915920
int m_iTeam;
916921

917922
float m_fWaitTurnSentry; // amount of time to wait before engineer turns their sentry before building

0 commit comments

Comments
 (0)