Skip to content

Commit d7eef2a

Browse files
committed
Add HL2MP bot possession mechanics and AFK handling
1 parent 24f9063 commit d7eef2a

12 files changed

Lines changed: 698 additions & 0 deletions

src/game/client/clientmode_shared.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,10 @@ void ClientModeShared::Init()
399399
ListenForGameEvent( "game_newmap" );
400400
#endif
401401

402+
#ifdef MAPBASE_MP
403+
ListenForGameEvent( "player_afk" );
404+
#endif
405+
402406
#ifndef _XBOX
403407
HLTVCamera()->Init();
404408
#if defined( REPLAY_ENABLED )
@@ -1632,6 +1636,36 @@ void ClientModeShared::FireGameEvent( IGameEvent *event )
16321636
CReplayMessagePanel::RemoveAll();
16331637
}
16341638
#endif
1639+
#ifdef MAPBASE_MP
1640+
else if ( V_strcmp( "player_afk", eventname ) == 0 )
1641+
{
1642+
if ( !hudChat )
1643+
return;
1644+
1645+
int iPlayerIndex = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
1646+
C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
1647+
if ( pPlayer )
1648+
{
1649+
const char *pszPlayerName = pPlayer->GetPlayerName();
1650+
if (PlayerNameNotSetYet( pszPlayerName ))
1651+
return;
1652+
1653+
CSteamID steamID;
1654+
pPlayer->GetSteamID( &steamID );
1655+
1656+
wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH];
1657+
UTIL_GetFilteredPlayerNameAsWChar( steamID, pszPlayerName, wszPlayerName );
1658+
1659+
wchar_t wszLocalized[100];
1660+
g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#game_idle_spectator" ), 1, wszPlayerName );
1661+
1662+
char szLocalized[100];
1663+
g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof( szLocalized ) );
1664+
1665+
hudChat->Printf( CHAT_FILTER_TEAMCHANGE, "%s", szLocalized );
1666+
}
1667+
}
1668+
#endif
16351669

16361670
else
16371671
{

src/game/client/hl2mp/clientmode_hl2mpnormal.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
#include "hl2mpclientscoreboard.h"
1919
#include "hl2mptextwindow.h"
2020
#include "ienginevgui.h"
21+
#ifdef MAPBASE
22+
#include "hl2mp_gamerules.h"
23+
#include "usermessages.h"
24+
#endif
2125

2226
// memdbgon must be the last include file in a .cpp file!!!
2327
#include "tier0/memdbgon.h"
@@ -109,6 +113,18 @@ ClientModeHL2MPNormal::~ClientModeHL2MPNormal()
109113
}
110114

111115

116+
#ifdef MAPBASE
117+
//-----------------------------------------------------------------------------
118+
// Purpose:
119+
//-----------------------------------------------------------------------------
120+
int g_nNumHideBots = 0;
121+
static void __MsgFunc_HideBotsJoin( bf_read &msg )
122+
{
123+
g_nNumHideBots = msg.ReadChar();
124+
}
125+
#endif
126+
127+
112128
//-----------------------------------------------------------------------------
113129
// Purpose:
114130
//-----------------------------------------------------------------------------
@@ -122,6 +138,46 @@ void ClientModeHL2MPNormal::Init()
122138
{
123139
Warning( "Couldn't load combine panel scheme!\n" );
124140
}
141+
142+
#ifdef MAPBASE
143+
usermessages->HookMessage( "HideBotsJoin", __MsgFunc_HideBotsJoin );
144+
#endif
145+
}
146+
147+
148+
//-----------------------------------------------------------------------------
149+
// Purpose:
150+
//-----------------------------------------------------------------------------
151+
void ClientModeHL2MPNormal::FireGameEvent( IGameEvent *event )
152+
{
153+
const char *eventname = event->GetName();
154+
155+
if (!eventname || !eventname[0])
156+
return;
157+
158+
#ifdef MAPBASE
159+
if ( FStrEq( "player_connect_client", eventname ) || FStrEq( "player_disconnect", eventname ) )
160+
{
161+
if ( event->GetInt( "bot" ) != 0 )
162+
{
163+
if (g_nNumHideBots > 0)
164+
{
165+
g_nNumHideBots--;
166+
return;
167+
}
168+
}
169+
}
170+
else if ( FStrEq( "player_team", eventname ) )
171+
{
172+
// Don't show player team messages during this
173+
if (g_nNumHideBots > 0)
174+
{
175+
return;
176+
}
177+
}
178+
#endif
179+
180+
BaseClass::FireGameEvent( event );
125181
}
126182

127183

src/game/client/hl2mp/clientmode_hl2mpnormal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class ClientModeHL2MPNormal : public ClientModeShared
3232

3333
virtual void Init();
3434
virtual int GetDeathMessageStartHeight( void );
35+
36+
virtual void FireGameEvent( IGameEvent *event );
3537
};
3638

3739
extern IClientMode *GetClientModeNormal();

src/game/server/hl2mp/bot/hl2mp_bot.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,10 @@ void CHL2MPBot::Spawn()
668668
SetBrokenFormation( false );
669669

670670
GetVisionInterface()->ForgetAllKnownEntities();
671+
672+
#ifdef MAPBASE
673+
SetUse( &CHL2MPBot::BotUse );
674+
#endif
671675
}
672676

673677

@@ -847,6 +851,45 @@ void CHL2MPBot::Event_Killed( const CTakeDamageInfo &info )
847851
}
848852

849853

854+
#ifdef MAPBASE
855+
//-----------------------------------------------------------------------------------------------------
856+
int CHL2MPBot::ObjectCaps( void )
857+
{
858+
int nCaps = BaseClass::ObjectCaps();
859+
860+
if ( ( HasAttribute( CHL2MPBot::CAN_POSSESS ) || HasAttribute( CHL2MPBot::IS_NPC ) ) && IsAlive() )
861+
nCaps |= FCAP_IMPULSE_USE;
862+
863+
return nCaps;
864+
}
865+
866+
//-----------------------------------------------------------------------------------------------------
867+
void CHL2MPBot::BotUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
868+
{
869+
if ( HasAttribute( CHL2MPBot::CAN_POSSESS ) )
870+
{
871+
CHL2MP_Player *pPlayer = ToHL2MPPlayer( pActivator );
872+
if ( pPlayer )
873+
{
874+
CRecipientFilter user;
875+
user.AddAllPlayers();
876+
user.MakeReliable();
877+
878+
// Make sure these bots come and go seamlessly
879+
UserMessageBegin( user, "HideBotsJoin" );
880+
WRITE_CHAR( 2 );
881+
MessageEnd();
882+
883+
if (TheHL2MPBots().BotTakeOverPlayer( pPlayer, false ))
884+
{
885+
TheHL2MPBots().PlayerTakeOverBot( pPlayer, this );
886+
}
887+
}
888+
}
889+
}
890+
#endif
891+
892+
850893
//---------------------------------------------------------------------------------------------
851894
class CCollectReachableObjects : public ISearchSurroundingAreasFunctor
852895
{

src/game/server/hl2mp/bot/hl2mp_bot.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ class CHL2MPBot: public NextBotPlayer< CHL2MP_Player >, public CGameEventListene
7575

7676
virtual CNavArea *GetLastKnownArea( void ) const { return static_cast< CNavArea * >( BaseClass::GetLastKnownArea() ); } // return the last nav area the player occupied - NULL if unknown
7777

78+
#ifdef MAPBASE
79+
virtual int ObjectCaps( void );
80+
virtual void BotUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
81+
#endif
82+
7883
// NextBotPlayer
7984
static CBasePlayer *AllocatePlayerEntity( edict_t *pEdict, const char *playerName );
8085

@@ -192,6 +197,9 @@ class CHL2MPBot: public NextBotPlayer< CHL2MP_Player >, public CGameEventListene
192197
ALWAYS_FIRE_WEAPON = 1<<13, // constantly fire our weapon
193198
TELEPORT_TO_HINT = 1<<14, // bot will teleport to hint target instead of walking out from the spawn point
194199
AUTO_JUMP = 1<<18, // auto jump
200+
#ifdef MAPBASE
201+
CAN_POSSESS = 1<<19, // player can switch to this bot
202+
#endif
195203
};
196204
void SetAttribute( int attributeFlag );
197205
void ClearAttribute( int attributeFlag );

0 commit comments

Comments
 (0)