diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index fc641d5f29..2d3b7ac73e 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -1730,7 +1730,11 @@ int CBasePlayer::OnTakeDamage_Alive( const CTakeDamageInfo &info ) { event->SetInt("userid", GetUserID() ); event->SetInt("health", MAX(0, m_iHealth) ); +#ifdef NEO + event->SetFloat("damageamount", info.GetDamage()); +#else event->SetInt("priority", 5 ); // HLTV event priority, not transmitted +#endif if ( attacker->IsPlayer() ) { diff --git a/src/game/shared/neo/neo_gamerules.cpp b/src/game/shared/neo/neo_gamerules.cpp index 59c405c589..c05244fec7 100644 --- a/src/game/shared/neo/neo_gamerules.cpp +++ b/src/game/shared/neo/neo_gamerules.cpp @@ -35,9 +35,15 @@ #include "nav_mesh.h" #include "neo_npc_dummy.h" #include "materialsystem/imaterialsystem.h" +#include #include +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" +#ifdef GAME_DLL extern ConVar weaponstay; #endif @@ -681,10 +687,12 @@ CNEORules::CNEORules() m_bCyberspaceLevel = false; ResetMapSessionCommon(); - ListenForGameEvent("round_start"); - ListenForGameEvent("game_end"); + ListenForGameEvent("game_end"); + ListenForGameEvent("round_start"); #ifdef GAME_DLL + ListenForGameEvent("player_hurt"); + weaponstay.InstallChangeCallback(CvarChanged_WeaponStay); #endif } @@ -1920,7 +1928,7 @@ void CNEORules::FireGameEvent(IGameEvent* event) #endif } - if (Q_strcmp(type, "game_end") == 0) + else if (Q_strcmp(type, "game_end") == 0) { #ifdef CLIENT_DLL if (sv_neo_client_autorecord.GetBool() && cl_neo_client_autorecord_allow.GetBool()) @@ -1933,6 +1941,33 @@ void CNEORules::FireGameEvent(IGameEvent* event) m_bServerIsCurrentlyAutoRecording = false; #endif // GAME_DLL } + +#ifdef GAME_DLL + else if (V_strcmp(type, "player_hurt") == 0) + { + const int victimUserid = event->GetInt("userid", INVALID_USER_ID); + const auto victim = static_cast(UTIL_PlayerByUserId(victimUserid)); + if (!victim) + return; + + const int attackerUserid = event->GetInt("attacker", INVALID_USER_ID); + const auto attacker = attackerUserid + ? static_cast(UTIL_PlayerByUserId(attackerUserid)) + : GetWorldEntity(); + if (!attacker) + return; + + const auto dmg = event->GetFloat("damageamount"); + if (!dmg) + return; + + AssertFitsArray(attacker->entindex(), victim->entindex(), m_flDamageDealt); + m_flDamageDealt[attacker->entindex()][victim->entindex()] += dmg; + + AssertFitsArray(attacker->entindex(), victim->entindex(), m_iNumHits); + m_iNumHits[attacker->entindex()][victim->entindex()] += 1; + } +#endif } #ifdef GAME_DLL diff --git a/src/game/shared/neo/neo_gamerules.h b/src/game/shared/neo/neo_gamerules.h index 8feb445ea8..2994ca4c31 100644 --- a/src/game/shared/neo/neo_gamerules.h +++ b/src/game/shared/neo/neo_gamerules.h @@ -495,6 +495,13 @@ class CNEORules : public CHL2MPRules, public CGameEventListener Vector m_vecPreviousJuggernautSpawn = vec3_origin; bool m_bGotMatchWinner = false; int m_iMatchWinner = TEAM_UNASSIGNED; + + // Attackers and their respective damage dealt to everyone else. + // Index 0 is the damage attributed to the world, like damage by gravity. + float m_flDamageDealt[MAX_PLAYERS_ARRAY_SAFE][MAX_PLAYERS_ARRAY_SAFE] = {}; + // Attackers and their respective number of hits that landed on enemies. + // Index 0 is the damage attributed to the world, like damage by gravity. + int m_iNumHits[MAX_PLAYERS_ARRAY_SAFE][MAX_PLAYERS_ARRAY_SAFE] = {}; #endif CNetworkVar(int, m_nRoundStatus); CNetworkVar(int, m_iHiddenHudElements); diff --git a/src/public/tier0/dbg.h b/src/public/tier0/dbg.h index 8bc1ed878b..8fb7520ebb 100644 --- a/src/public/tier0/dbg.h +++ b/src/public/tier0/dbg.h @@ -390,6 +390,23 @@ DBG_INTERFACE struct SDL_Window * GetAssertDialogParent(); #endif // DBGFLAG_ASSERT +#ifdef NEO +template +constexpr void AssertFitsArray(const auto i, const T (&arr)[N]) +{ + Assert(i >= 0); + Assert(i < _ARRAYSIZE(arr)); +} + +template +constexpr void AssertFitsArray(const auto i, const auto j, const T (&arr)[N][M]) +{ + Assert(i >= 0); + Assert(i < _ARRAYSIZE(arr[0])); + AssertFitsArray(j, arr[i]); +} +#endif + // The Always version of the assert macros are defined even when DBGFLAG_ASSERT is not, // so they will be available even in release. #define AssertAlways( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false )