1313#endif
1414
1515#ifdef MAPBASE_MP
16+ #include " takedamageinfo.h"
1617#ifdef HL2MP
1718#include " c_hl2mp_playerresource.h"
1819#endif
2526
2627#define PING_MAX_TIME 2.0
2728
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+
2843IMPLEMENT_CLIENTCLASS_DT ( C_AI_BaseNPC, DT_AI_BaseNPC, CAI_BaseNPC )
2944 RecvPropInt( RECVINFO( m_lifeState ) ),
3045 RecvPropBool( RECVINFO( m_bPerformAvoidance ) ),
@@ -37,6 +52,9 @@ IMPLEMENT_CLIENTCLASS_DT( C_AI_BaseNPC, DT_AI_BaseNPC, CAI_BaseNPC )
3752 RecvPropInt( RECVINFO( m_bSpeedModActive ) ),
3853 RecvPropBool( RECVINFO( m_bImportanRagdoll ) ),
3954 RecvPropFloat( RECVINFO( m_flTimePingEffect ) ),
55+ #ifdef MAPBASE_MP
56+ RecvPropDataTable ( " npc_gamedata" , 0 , 0 , &REFERENCE_RECV_TABLE ( DT_BaseNPCGameData ) ),
57+ #endif
4058END_RECV_TABLE ()
4159
4260extern ConVar cl_npc_speedmod_intime;
@@ -53,6 +71,9 @@ bool NPC_IsImportantNPC( C_BaseAnimating *pAnimating )
5371
5472C_AI_BaseNPC::C_AI_BaseNPC ()
5573{
74+ #ifdef MAPBASE_MP
75+ SetBloodColor ( DONT_BLEED );
76+ #endif
5677}
5778
5879// -----------------------------------------------------------------------------
@@ -205,5 +226,89 @@ const char *C_AI_BaseNPC::GetPlayerName( void ) const
205226
206227 return BaseClass::GetPlayerName ();
207228}
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+ }
208313#endif
209314
0 commit comments