Skip to content

Commit 5745fd1

Browse files
authored
Merge pull request #465 from Blixibon/mapbase/mp-2025/expanded-npc-and-mapbase-support
[HL2MP] Assorted changes for NPC support, Mapbase features in HL2DM, and new QOL features
2 parents 60bffb8 + 06fa2da commit 5745fd1

77 files changed

Lines changed: 7440 additions & 510 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/game/client/c_ai_basenpc.cpp

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,34 @@
1212
#include "c_basehlplayer.h"
1313
#endif
1414

15+
#ifdef MAPBASE_MP
16+
#include "takedamageinfo.h"
17+
#ifdef HL2MP
18+
#include "c_hl2mp_playerresource.h"
19+
#endif
20+
#endif
21+
1522
#include "death_pose.h"
1623

1724
// memdbgon must be the last include file in a .cpp file!!!
1825
#include "tier0/memdbgon.h"
1926

2027
#define PING_MAX_TIME 2.0
2128

29+
#ifdef MAPBASE_MP
30+
BEGIN_RECV_TABLE_NOBASE( C_AI_BaseNPC, DT_BaseNPCGameData )
31+
RecvPropInt( RECVINFO( m_iHealth ) ),
32+
RecvPropInt( RECVINFO( m_takedamage ) ),
33+
RecvPropInt( RECVINFO( m_bloodColor ) ),
34+
//RecvPropString( RECVINFO( m_szNetname ) ), // Transmitted by player resource now
35+
RecvPropInt( RECVINFO( m_nDefaultPlayerRelationship ) ),
36+
END_RECV_TABLE();
37+
#endif
38+
39+
#ifdef CAI_BaseNPC
40+
#undef CAI_BaseNPC
41+
#endif
42+
2243
IMPLEMENT_CLIENTCLASS_DT( C_AI_BaseNPC, DT_AI_BaseNPC, CAI_BaseNPC )
2344
RecvPropInt( RECVINFO( m_lifeState ) ),
2445
RecvPropBool( RECVINFO( m_bPerformAvoidance ) ),
@@ -31,6 +52,9 @@ IMPLEMENT_CLIENTCLASS_DT( C_AI_BaseNPC, DT_AI_BaseNPC, CAI_BaseNPC )
3152
RecvPropInt( RECVINFO( m_bSpeedModActive ) ),
3253
RecvPropBool( RECVINFO( m_bImportanRagdoll ) ),
3354
RecvPropFloat( RECVINFO( m_flTimePingEffect ) ),
55+
#ifdef MAPBASE_MP
56+
RecvPropDataTable( "npc_gamedata", 0, 0, &REFERENCE_RECV_TABLE( DT_BaseNPCGameData ) ),
57+
#endif
3458
END_RECV_TABLE()
3559

3660
extern ConVar cl_npc_speedmod_intime;
@@ -47,6 +71,9 @@ bool NPC_IsImportantNPC( C_BaseAnimating *pAnimating )
4771

4872
C_AI_BaseNPC::C_AI_BaseNPC()
4973
{
74+
#ifdef MAPBASE_MP
75+
SetBloodColor( DONT_BLEED );
76+
#endif
5077
}
5178

5279
//-----------------------------------------------------------------------------
@@ -183,3 +210,105 @@ bool C_AI_BaseNPC::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x
183210
return bRet;
184211
}
185212

213+
#ifdef MAPBASE_MP
214+
//-----------------------------------------------------------------------------
215+
// Purpose:
216+
// Output : char const
217+
//-----------------------------------------------------------------------------
218+
const char *C_AI_BaseNPC::GetPlayerName( void ) const
219+
{
220+
#ifdef HL2MP
221+
if (g_HL2MP_PR)
222+
{
223+
return g_HL2MP_PR->GetNPCName( entindex() );
224+
}
225+
#endif
226+
227+
return BaseClass::GetPlayerName();
228+
}
229+
230+
//-----------------------------------------------------------------------------
231+
// Purpose:
232+
//-----------------------------------------------------------------------------
233+
void C_AI_BaseNPC::DispatchTraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
234+
{
235+
m_fNoDamageDecal = false;
236+
237+
if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() )
238+
{
239+
if ( IsPlayerAlly( ToBasePlayer( info.GetAttacker() ) ) )
240+
{
241+
m_fNoDamageDecal = true;
242+
return;
243+
}
244+
}
245+
246+
BaseClass::DispatchTraceAttack( info, vecDir, ptr, pAccumulator );
247+
}
248+
249+
//-----------------------------------------------------------------------------
250+
// Purpose:
251+
//-----------------------------------------------------------------------------
252+
void C_AI_BaseNPC::DecalTrace( trace_t *pTrace, char const *decalName )
253+
{
254+
if ( m_fNoDamageDecal )
255+
{
256+
// Don't do impact decals when we shouldn't
257+
// (adapts an existing hack from singleplayer HL2, see serverside counterpart)
258+
m_fNoDamageDecal = false;
259+
return;
260+
}
261+
BaseClass::DecalTrace( pTrace, decalName );
262+
}
263+
264+
//-----------------------------------------------------------------------------
265+
// Purpose:
266+
//-----------------------------------------------------------------------------
267+
void C_AI_BaseNPC::ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName )
268+
{
269+
if ( m_fNoDamageDecal )
270+
{
271+
// Don't do impact decals when we shouldn't
272+
// (adapts an existing hack from singleplayer HL2, see serverside counterpart)
273+
m_fNoDamageDecal = false;
274+
return;
275+
}
276+
BaseClass::ImpactTrace( pTrace, iDamageType, pCustomImpactName );
277+
}
278+
279+
//-----------------------------------------------------------------------------
280+
// Purpose:
281+
//-----------------------------------------------------------------------------
282+
bool C_AI_BaseNPC::IsPlayerAlly( C_BasePlayer *pPlayer )
283+
{
284+
if ( pPlayer == NULL )
285+
{
286+
pPlayer = C_BasePlayer::GetLocalPlayer();
287+
}
288+
289+
if ( pPlayer->GetTeamNumber() == TEAM_UNASSIGNED )
290+
{
291+
// AI relationship code isn't available here, so we currently transmit a var from the server to determine if we're, at least generically, an ally
292+
return (m_nDefaultPlayerRelationship == GR_TEAMMATE);
293+
}
294+
else if (GetTeamNumber() == pPlayer->GetTeamNumber())
295+
{
296+
// Same team probably means allies
297+
return true;
298+
}
299+
300+
return false;
301+
}
302+
303+
//-----------------------------------------------------------------------------
304+
// Purpose:
305+
//-----------------------------------------------------------------------------
306+
bool C_AI_BaseNPC::IsNeutralTo( C_BasePlayer *pPlayer )
307+
{
308+
if ( IsPlayerAlly( pPlayer ) )
309+
return false;
310+
311+
return (m_nDefaultPlayerRelationship == GR_NOTTEAMMATE);
312+
}
313+
#endif
314+

src/game/client/c_ai_basenpc.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414

1515
#include "c_basecombatcharacter.h"
16+
#ifdef MAPBASE_MP
17+
#include "ai_debug_shared.h"
18+
#endif
1619

1720
// NOTE: Moved all controller code into c_basestudiomodel
1821
class C_AI_BaseNPC : public C_BaseCombatCharacter
@@ -41,6 +44,17 @@ class C_AI_BaseNPC : public C_BaseCombatCharacter
4144
void OnDataChanged( DataUpdateType_t type );
4245
bool ImportantRagdoll( void ) { return m_bImportanRagdoll; }
4346

47+
#ifdef MAPBASE_MP
48+
virtual int GetHealth() const { return m_iHealth; }
49+
50+
virtual const char *GetPlayerName( void ) const;
51+
virtual void DispatchTraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator = NULL );
52+
void DecalTrace( trace_t *pTrace, char const *decalName );
53+
void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName );
54+
virtual bool IsPlayerAlly( C_BasePlayer *pPlayer = NULL );
55+
virtual bool IsNeutralTo( C_BasePlayer *pPlayer = NULL );
56+
#endif
57+
4458
private:
4559
C_AI_BaseNPC( const C_AI_BaseNPC & ); // not defined, not accessible
4660
float m_flTimePingEffect;
@@ -55,6 +69,19 @@ class C_AI_BaseNPC : public C_BaseCombatCharacter
5569
bool m_bFadeCorpse;
5670
bool m_bSpeedModActive;
5771
bool m_bImportanRagdoll;
72+
73+
#ifdef MAPBASE_MP
74+
// User-friendly name used for death notices, etc.
75+
// Now transmitted by player resource
76+
//char m_szNetname[32];
77+
78+
// Used to determine whether to draw blood, target ID, etc. on the client
79+
// Uses first 3 gamerules relationship return codes (GR_TEAMMATE, GR_NOTTEAMMATE, and GR_ENEMY)
80+
int m_nDefaultPlayerRelationship;
81+
82+
// Based on the existing decal hack from singleplayer HL2
83+
bool m_fNoDamageDecal;
84+
#endif
5885
};
5986

6087

src/game/client/c_baseanimating.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4365,7 +4365,13 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int
43654365

43664366
case CL_EVENT_FOOTSTEP_LEFT:
43674367
{
4368-
#ifndef HL2MP
4368+
#if !defined(HL2MP) || defined(MAPBASE_MP)
4369+
#ifdef MAPBASE_MP
4370+
// NPCs should still use footstep sounds in MP
4371+
if (!IsNPC())
4372+
break;
4373+
#endif
4374+
43694375
char pSoundName[256];
43704376
if ( !options || !options[0] )
43714377
{
@@ -4391,7 +4397,13 @@ void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int
43914397

43924398
case CL_EVENT_FOOTSTEP_RIGHT:
43934399
{
4394-
#ifndef HL2MP
4400+
#if !defined(HL2MP) || defined(MAPBASE_MP)
4401+
#ifdef MAPBASE_MP
4402+
// NPCs should still use footstep sounds in MP
4403+
if (!IsNPC())
4404+
break;
4405+
#endif
4406+
43954407
char pSoundName[256];
43964408
if ( !options || !options[0] )
43974409
{

src/game/client/c_basecombatcharacter.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,25 @@ void C_BaseCombatCharacter::DoMuzzleFlash()
109109
}
110110
}
111111

112+
#ifdef MAPBASE
113+
// UNDONE: Should these operate on a list of weapon/items
114+
Activity C_BaseCombatCharacter::Weapon_TranslateActivity( Activity baseAct, bool *pRequired )
115+
{
116+
Activity translated = baseAct;
117+
118+
if ( m_hActiveWeapon )
119+
{
120+
translated = m_hActiveWeapon->ActivityOverride( baseAct, pRequired );
121+
}
122+
else if (pRequired)
123+
{
124+
*pRequired = false;
125+
}
126+
127+
return translated;
128+
}
129+
#endif
130+
112131
#ifdef GLOWS_ENABLE
113132
//-----------------------------------------------------------------------------
114133
// Purpose:

src/game/client/c_basecombatcharacter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ class C_BaseCombatCharacter : public C_BaseFlex
116116
HSCRIPT ScriptGetWeapon( int i );
117117
#endif
118118

119+
#ifdef MAPBASE
120+
virtual Activity Weapon_TranslateActivity( Activity baseAct, bool *pRequired );
121+
virtual Activity Weapon_BackupActivity( Activity activity, bool weaponTranslationWasRequired = false, C_BaseCombatWeapon *pSpecificWeapon = NULL );
122+
#endif
123+
119124
public:
120125

121126
float m_flNextAttack;

src/game/client/c_baseentity.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,11 @@ class C_BaseEntity : public IClientEntity
10471047
// are relative to the attachment on this entity.
10481048
void SetParent( C_BaseEntity *pParentEntity, int iParentAttachment=0 );
10491049

1050+
#ifdef MAPBASE_MP
1051+
// Some entities should predict +USE interaction
1052+
virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) {}
1053+
#endif
1054+
10501055
bool PhysicsRunThink( thinkmethods_t thinkMethod = THINK_FIRE_ALL_FUNCTIONS );
10511056
bool PhysicsRunSpecificThink( int nContextIndex, BASEPTR thinkFunc );
10521057

src/game/client/c_baseplayer.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ void C_BasePlayer::FireGameEvent( IGameEvent *event )
816816
//-----------------------------------------------------------------------------
817817
// returns the player name
818818
//-----------------------------------------------------------------------------
819-
const char * C_BasePlayer::GetPlayerName()
819+
const char * C_BasePlayer::GetPlayerName() const
820820
{
821821
return g_PR ? g_PR->GetPlayerName( entindex() ) : "";
822822
}
@@ -2448,6 +2448,13 @@ void C_BasePlayer::PostThink( void )
24482448
{
24492449
SetCollisionBounds( VEC_HULL_MIN, VEC_HULL_MAX );
24502450
}
2451+
2452+
#ifdef MAPBASE_MP
2453+
if ( m_hUseEntity != NULL )
2454+
{
2455+
m_hUseEntity->Use( this, this, USE_SET, 2 );
2456+
}
2457+
#endif
24512458

24522459
if ( !CommentaryModeShouldSwallowInput( this ) )
24532460
{

src/game/client/c_baseplayer.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener
131131
virtual Vector Weapon_ShootPosition();
132132
virtual void Weapon_DropPrimary( void ) {}
133133

134+
#ifdef MAPBASE
135+
virtual Activity Weapon_TranslateActivity( Activity baseAct, bool *pRequired = NULL );
136+
#endif
137+
134138
virtual Vector GetAutoaimVector( float flScale );
135139
void SetSuitUpdate(const char *name, int fgroup, int iNoRepeat);
136140

@@ -310,7 +314,7 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener
310314
virtual void OverrideView( CViewSetup *pSetup );
311315

312316
// returns the player name
313-
const char * GetPlayerName();
317+
const char * GetPlayerName() const;
314318
virtual const Vector GetPlayerMins( void ) const; // uses local player
315319
virtual const Vector GetPlayerMaxs( void ) const; // uses local player
316320

src/game/client/client_hl2mp.vpc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ $Project "Client (HL2MP)"
127127
$File "hl2mp\c_te_hl2mp_shotgun_shot.cpp"
128128
$File "hl2mp\clientmode_hl2mpnormal.cpp"
129129
$File "hl2mp\clientmode_hl2mpnormal.h"
130+
$File "hl2mp\c_hl2mp_playerresource.cpp"
131+
$File "hl2mp\c_hl2mp_playerresource.h"
130132
$File "$SRCDIR\game\shared\hl2mp\hl2mp_gamerules.cpp"
131133
$File "$SRCDIR\game\shared\hl2mp\hl2mp_gamerules.h"
132134
$File "$SRCDIR\game\shared\hl2mp\hl2mp_player_shared.cpp"

src/game/client/hl2/c_basehlplayer.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,30 @@ void C_BaseHLPlayer::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quatern
713713

714714

715715
#ifdef SP_ANIM_STATE
716+
// Set the activity based on an event or current state
717+
void C_BaseHLPlayer::SetAnimation( PLAYER_ANIM playerAnim )
718+
{
719+
#ifdef MAPBASE_MP
720+
if (!m_pPlayerAnimState)
721+
{
722+
BaseClass::SetAnimation( playerAnim );
723+
return;
724+
}
725+
726+
m_pPlayerAnimState->SetPlayerAnimation( playerAnim );
727+
#endif
728+
}
729+
730+
void C_BaseHLPlayer::AddAnimStateLayer( int iSequence, float flBlendIn, float flBlendOut, float flPlaybackRate, bool bHoldAtEnd, bool bOnlyWhenStill )
731+
{
732+
#ifdef MAPBASE_MP
733+
if (!m_pPlayerAnimState)
734+
return;
735+
736+
m_pPlayerAnimState->AddMiscSequence( iSequence, flBlendIn, flBlendOut, flPlaybackRate, bHoldAtEnd, bOnlyWhenStill );
737+
#endif
738+
}
739+
716740
//-----------------------------------------------------------------------------
717741
// Purpose:
718742
//-----------------------------------------------------------------------------
@@ -737,7 +761,7 @@ const Vector &C_BaseHLPlayer::GetRenderOrigin()
737761
const QAngle& C_BaseHLPlayer::GetRenderAngles( void )
738762
{
739763
#ifdef MAPBASE_MP
740-
if ( m_pPlayerAnimState )
764+
if ( m_pPlayerAnimState && !IsRagdoll() )
741765
{
742766
return m_pPlayerAnimState->GetRenderAngles();
743767
}

0 commit comments

Comments
 (0)