From e507d00b980a3e60844f3596e3697c677605bc23 Mon Sep 17 00:00:00 2001 From: Hosomi-PC Date: Thu, 21 May 2026 21:27:38 +0100 Subject: [PATCH 01/16] Implement ATK --- .../client/neo/ui/neo_hud_round_state.cpp | 4 +- src/game/shared/neo/neo_gamerules.cpp | 312 ++++++++++++------ src/game/shared/neo/neo_gamerules.h | 13 +- src/game/shared/neo/neo_player_spawnpoint.cpp | 37 ++- src/game/shared/neo/neo_player_spawnpoint.h | 10 +- 5 files changed, 257 insertions(+), 119 deletions(-) diff --git a/src/game/client/neo/ui/neo_hud_round_state.cpp b/src/game/client/neo/ui/neo_hud_round_state.cpp index aec87e7174..5b5a39f215 100644 --- a/src/game/client/neo/ui/neo_hud_round_state.cpp +++ b/src/game/client/neo/ui/neo_hud_round_state.cpp @@ -378,9 +378,9 @@ void CNEOHud_RoundState::UpdateStateForNeoHudElementDraw() roundTimeLeft = NEORules()->GetRemainingPreRoundFreezeTime(true); int secsTotal = 0.0f; - if (roundStatus == NeoRoundStatus::Overtime && NEORules()->GetGameType() == NEO_GAME_TYPE_CTG) + if (roundStatus == NeoRoundStatus::Overtime && (NEORules()->GetGameType() == NEO_GAME_TYPE_CTG || NEORules()->GetGameType() == NEO_GAME_TYPE_ATK)) { - secsTotal = RoundFloatToInt(NEORules()->GetCTGOverTime()); + secsTotal = RoundFloatToInt(NEORules()->GetOverTime((NeoGameType)NEORules()->GetGameType())); } else { diff --git a/src/game/shared/neo/neo_gamerules.cpp b/src/game/shared/neo/neo_gamerules.cpp index 0ddbbb19ab..0230ace686 100644 --- a/src/game/shared/neo/neo_gamerules.cpp +++ b/src/game/shared/neo/neo_gamerules.cpp @@ -372,6 +372,7 @@ const NeoGameTypeSettings NEO_GAME_TYPE_SETTINGS[NEO_GAME_TYPE__TOTAL] = { /*NEO_GAME_TYPE_EMT*/ {"EMT", true, false, true, false, false}, /*NEO_GAME_TYPE_TUT*/ {"TUT", true, false, false, false, false}, /*NEO_GAME_TYPE_JGR*/ {"JGR", true, true, false, true, false}, +/*NEO_GAME_TYPE_ATK*/ {"ATK", false, true, false, true, false}, }; #ifdef CLIENT_DLL @@ -459,6 +460,8 @@ ConVar sv_neo_dm_score_limit("sv_neo_dm_score_limit", "7", FCVAR_REPLICATED, "DM ConVar sv_neo_jgr_score_limit("sv_neo_jgr_score_limit", "0", FCVAR_REPLICATED, "JGR score limit", true, 0.0f, true, 99.0f); +ConVar sv_neo_atk_score_limit("sv_neo_atk_score_limit", "7", FCVAR_REPLICATED, "ATK score limit", true, 0.0f, true, 99.0f); + // Round Limit ConVar sv_neo_tdm_round_limit("sv_neo_tdm_round_limit", "0", FCVAR_REPLICATED, "TDM max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); @@ -470,6 +473,8 @@ ConVar sv_neo_dm_round_limit("sv_neo_dm_round_limit", "0", FCVAR_REPLICATED, "DM ConVar sv_neo_jgr_round_limit("sv_neo_jgr_round_limit", "5", FCVAR_REPLICATED, "JGR max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +ConVar sv_neo_atk_round_limit("sv_neo_atk_round_limit", "0", FCVAR_REPLICATED, "ATK max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); + // Round Time Limit (make these sv_neo at some point) ConVar neo_tdm_round_timelimit("neo_tdm_round_timelimit", "10.25", FCVAR_REPLICATED, "TDM round timelimit, in minutes.", true, 0.0f, false, 600.0f); @@ -486,6 +491,9 @@ ConVar neo_dm_round_timelimit("neo_dm_round_timelimit", "10.25", FCVAR_REPLICATE ConVar neo_jgr_round_timelimit("neo_jgr_round_timelimit", "4.25", FCVAR_REPLICATED, "JGR round timelimit, in minutes.", true, 0.0f, false, 600.0f); +ConVar neo_atk_round_timelimit("neo_atk_round_timelimit", "3.25", FCVAR_REPLICATED, "ATK round timelimit, in minutes.", + true, 0.0f, false, 600.0f); + ConVar sv_neo_ignore_wep_xp_limit("sv_neo_ignore_wep_xp_limit", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "If true, allow equipping any loadout regardless of player XP.", true, 0.0f, true, 1.0f); @@ -496,6 +504,10 @@ ConVar sv_neo_ctg_ghost_overtime_enabled("sv_neo_ctg_ghost_overtime_enabled", "0 ConVar sv_neo_ctg_ghost_overtime("sv_neo_ctg_ghost_overtime", "45", FCVAR_REPLICATED, "Adds up to this many seconds to the round while the ghost is held.", true, 0, true, 120); ConVar sv_neo_ctg_ghost_overtime_grace("sv_neo_ctg_ghost_overtime_grace", "10", FCVAR_REPLICATED, "Number of seconds left in the round when the ghost is dropped in overtime.", true, 0, true, 30); ConVar sv_neo_ctg_ghost_overtime_grace_decay("sv_neo_ctg_ghost_overtime_grace_decay", "0", FCVAR_REPLICATED, "Slowly reduce the grace time as overtime goes on.", true, 0, true, 1); +ConVar sv_neo_atk_ghost_overtime_enabled("sv_neo_atk_ghost_overtime_enabled", "0", FCVAR_REPLICATED, "Enable ghost overtime in the ATK mode.", true, 0, true, 1); +ConVar sv_neo_atk_ghost_overtime("sv_neo_atk_ghost_overtime", "45", FCVAR_REPLICATED, "Adds up to this many seconds to the round while the ghost is held.", true, 0, true, 120); +ConVar sv_neo_atk_ghost_overtime_grace("sv_neo_atk_ghost_overtime_grace", "10", FCVAR_REPLICATED, "Number of seconds left in the round when the ghost is dropped in overtime.", true, 0, true, 30); +ConVar sv_neo_atk_ghost_overtime_grace_decay("sv_neo_atk_ghost_overtime_grace_decay", "0", FCVAR_REPLICATED, "Slowly reduce the grace time as overtime goes on.", true, 0, true, 1); #ifdef CLIENT_DLL extern ConVar neo_fov; @@ -1250,19 +1262,7 @@ void CNEORules::Think(void) return; } - if (m_nGameTypeSelected == NEO_GAME_TYPE_CTG) - { - if (sv_neo_ctg_ghost_overtime_enabled.GetBool() && m_nRoundStatus == NeoRoundStatus::RoundLive && m_iGhosterPlayer && - (m_flNeoRoundStartTime + (neo_ctg_round_timelimit.GetFloat() * 60) - sv_neo_ctg_ghost_overtime_grace.GetFloat()) < gpGlobals->curtime) - { - m_nRoundStatus = NeoRoundStatus::Overtime; - } - - if (m_nRoundStatus == NeoRoundStatus::Overtime && m_iGhosterPlayer) - { - m_flGhostLastHeld = gpGlobals->curtime; - } - } + CheckOvertime(); if (g_fGameOver) // someone else quit the game already { @@ -1376,77 +1376,7 @@ void CNEORules::Think(void) // Note that exactly zero here means infinite round time. else if (GetRoundRemainingTime() < 0) { - if (GetGameType() == NEO_GAME_TYPE_TDM) - { - if (GetGlobalTeam(TEAM_JINRAI)->GetScore() > GetGlobalTeam(TEAM_NSF)->GetScore()) - { - SetWinningTeam(TEAM_JINRAI, NEO_VICTORY_POINTS, false, true, false, false); - return; - } - - if (GetGlobalTeam(TEAM_NSF)->GetScore() > GetGlobalTeam(TEAM_JINRAI)->GetScore()) - { - SetWinningTeam(TEAM_NSF, NEO_VICTORY_POINTS, false, true, false, false); - return; - } - } - else if (GetGameType() == NEO_GAME_TYPE_DM) - { - // Winning player - CNEO_Player *pWinners[MAX_PLAYERS + 1] = {}; - int iWinnersTotal = 0; - int iWinnerXP = 0; - GetDMHighestScorers(&pWinners, &iWinnersTotal, &iWinnerXP); - if (iWinnersTotal == 1) - { - SetWinningDMPlayer(pWinners[0]); - return; - } - // Otherwise go into overtime - } - else if (GetGameType() == NEO_GAME_TYPE_JGR) - { - if ((!m_pJuggernautPlayer && m_pJuggernautItem && !m_pJuggernautItem->IsBeingActivatedByLosingTeam()) || - (!m_pJuggernautPlayer && !m_pJuggernautItem)) // Juggernaut is absent entirely - { - if (GetGlobalTeam(TEAM_JINRAI)->GetScore() > GetGlobalTeam(TEAM_NSF)->GetScore()) - { - SetWinningTeam(TEAM_JINRAI, NEO_VICTORY_POINTS, false, true, false, false); - return; - } - - if (GetGlobalTeam(TEAM_NSF)->GetScore() > GetGlobalTeam(TEAM_JINRAI)->GetScore()) - { - SetWinningTeam(TEAM_NSF, NEO_VICTORY_POINTS, false, true, false, false); - return; - } - } - else - { - if (m_nRoundStatus == NeoRoundStatus::RoundLive) - { - m_nRoundStatus = NeoRoundStatus::Overtime; - } - - if (m_pJuggernautPlayer) - { - const int jgrTeam = m_pJuggernautPlayer->GetTeamNumber(); - const int oppositeTeam = (m_pJuggernautPlayer->GetTeamNumber() == TEAM_JINRAI ? TEAM_NSF : TEAM_JINRAI); - if (GetGlobalTeam(jgrTeam)->GetScore() > GetGlobalTeam(oppositeTeam)->GetScore()) - { - SetWinningTeam(jgrTeam, NEO_VICTORY_POINTS, false, true, false, false); - return; - } - } - - return; - } - } - - if (IsTeamplay()) - { - SetWinningTeam(TEAM_SPECTATOR, NEO_VICTORY_STALEMATE, false, false, true, false); - } + RoundTimeout(); } if (m_pGhost) @@ -1792,6 +1722,41 @@ void CNEORules::AwardRankUp(CNEO_Player *pClient) pClient->AddPoints(1, false, true); } +void CNEORules::CheckOvertime() +{ + bool overtimeEnabled; + float overtimeGrace; + float roundTimeLimit; + + switch (m_nGameTypeSelected) + { + case NEO_GAME_TYPE_CTG: + overtimeEnabled = sv_neo_ctg_ghost_overtime_enabled.GetBool(); + roundTimeLimit = neo_ctg_round_timelimit.GetFloat() * 60; + overtimeGrace = sv_neo_ctg_ghost_overtime_grace.GetFloat(); + break; + case NEO_GAME_TYPE_ATK: + overtimeEnabled = sv_neo_atk_ghost_overtime_enabled.GetBool(); + roundTimeLimit = neo_atk_round_timelimit.GetFloat() * 60; + overtimeGrace = sv_neo_atk_ghost_overtime_grace.GetFloat(); + break; + default: + return; + } + + if (overtimeEnabled && m_nRoundStatus == NeoRoundStatus::RoundLive && m_iGhosterPlayer && + (m_nGameTypeSelected != NEO_GAME_TYPE_ATK || m_iGhosterTeam == GetAttackingTeam()) && // only the attacking team gets overtime in ATK + (m_flNeoRoundStartTime + roundTimeLimit - overtimeGrace) < gpGlobals->curtime) + { + m_nRoundStatus = NeoRoundStatus::Overtime; + } + + if (m_nRoundStatus == NeoRoundStatus::Overtime && m_iGhosterPlayer) + { + m_flGhostLastHeld = gpGlobals->curtime; + } +} + // Return remaining time in seconds. Zero means there is no time limit. float CNEORules::GetRoundRemainingTime() const { @@ -1824,7 +1789,7 @@ float CNEORules::GetRoundRemainingTime() const roundTimeLimit = neo_ctg_round_timelimit.GetFloat() * 60.f; if (m_nRoundStatus == NeoRoundStatus::Overtime) { - return GetCTGOverTime(); + return GetOverTime(NEO_GAME_TYPE_CTG); } break; case NEO_GAME_TYPE_VIP: @@ -1836,6 +1801,13 @@ float CNEORules::GetRoundRemainingTime() const case NEO_GAME_TYPE_JGR: roundTimeLimit = neo_jgr_round_timelimit.GetFloat() * 60.f; break; + case NEO_GAME_TYPE_ATK: + roundTimeLimit = neo_atk_round_timelimit.GetFloat() * 60.f; + if (m_nRoundStatus == NeoRoundStatus::Overtime) + { + return GetOverTime(NEO_GAME_TYPE_ATK); + } + break; default: break; } @@ -1844,12 +1816,34 @@ float CNEORules::GetRoundRemainingTime() const return (m_flNeoRoundStartTime + roundTimeLimit) - gpGlobals->curtime; } -float CNEORules::GetCTGOverTime() const +float CNEORules::GetOverTime(NeoGameType eGameType) const { - float roundTimeLimit = neo_ctg_round_timelimit.GetFloat() * 60.f; - float overtime = (m_flNeoRoundStartTime + roundTimeLimit + sv_neo_ctg_ghost_overtime.GetFloat()) - gpGlobals->curtime; + float roundTimeLimit; + float overtimeBaseAmount; + float overtimeGrace; + bool graceDecay; + + if (eGameType == NeoGameType::NEO_GAME_TYPE_CTG) + { + roundTimeLimit = neo_ctg_round_timelimit.GetFloat() * 60.f; + overtimeBaseAmount = sv_neo_ctg_ghost_overtime.GetFloat(); + overtimeGrace = sv_neo_ctg_ghost_overtime_grace.GetFloat(); + graceDecay = sv_neo_ctg_ghost_overtime_grace_decay.GetBool(); + } + else if (eGameType == NeoGameType::NEO_GAME_TYPE_ATK) + { + roundTimeLimit = neo_atk_round_timelimit.GetFloat() * 60.f; + overtimeBaseAmount = sv_neo_atk_ghost_overtime.GetFloat(); + overtimeGrace = sv_neo_atk_ghost_overtime_grace.GetFloat(); + graceDecay = sv_neo_atk_ghost_overtime_grace_decay.GetBool(); + } + else + { + throw std::exception("Tried to calculate overtime for a gamemode with no overtime implementation"); + } + float overtime = (m_flNeoRoundStartTime + roundTimeLimit + overtimeBaseAmount) - gpGlobals->curtime; - if (sv_neo_ctg_ghost_overtime_grace_decay.GetBool()) + if (graceDecay) { if (m_iGhosterPlayer) { @@ -1857,13 +1851,13 @@ float CNEORules::GetCTGOverTime() const } else { - float overtimeAtGhostDrop = (m_flNeoRoundStartTime + roundTimeLimit + sv_neo_ctg_ghost_overtime.GetFloat()) - m_flGhostLastHeld; - return (overtimeAtGhostDrop * sv_neo_ctg_ghost_overtime_grace.GetFloat() / (sv_neo_ctg_ghost_overtime.GetFloat() + sv_neo_ctg_ghost_overtime_grace.GetFloat())) - (gpGlobals->curtime - m_flGhostLastHeld); + float overtimeAtGhostDrop = (m_flNeoRoundStartTime + roundTimeLimit + overtimeBaseAmount) - m_flGhostLastHeld; + return (overtimeAtGhostDrop * overtimeGrace / (overtimeBaseAmount + overtimeGrace)) - (gpGlobals->curtime - m_flGhostLastHeld); } } else { - float grace = sv_neo_ctg_ghost_overtime_grace.GetFloat() - (gpGlobals->curtime - m_flGhostLastHeld); + float grace = overtimeGrace - (gpGlobals->curtime - m_flGhostLastHeld); if (m_iGhosterPlayer || overtime < grace) { return overtime; @@ -1938,8 +1932,8 @@ void CNEORules::FireGameEvent(IGameEvent* event) // Purpose: Spawns one ghost at a randomly chosen Neo ghost spawn point. void CNEORules::SpawnTheGhost(const Vector *origin) { - // No ghost spawns and this map isn't named "_ctg". Probably not a CTG map. - if (m_ghostSpawns.IsEmpty() && (V_stristr(GameRules()->MapName(), "_ctg") == 0)) + // No ghost spawns + if (m_ghostSpawns.IsEmpty()) { m_pGhost = nullptr; return; @@ -2642,6 +2636,9 @@ const int CNEORules::GetScoreLimit() const case NEO_GAME_TYPE_JGR: return sv_neo_jgr_score_limit.GetInt(); break; + case NEO_GAME_TYPE_ATK: + return sv_neo_atk_score_limit.GetInt(); + break; default: return sv_neo_ctg_score_limit.GetInt(); break; @@ -2667,6 +2664,9 @@ const int CNEORules::GetRoundLimit() const case NEO_GAME_TYPE_JGR: return sv_neo_jgr_round_limit.GetInt(); break; + case NEO_GAME_TYPE_ATK: + return sv_neo_atk_round_limit.GetInt(); + break; default: return sv_neo_ctg_round_limit.GetInt(); break; @@ -2926,6 +2926,105 @@ void CNEORules::StartNextRound() DevMsg("New round start here!\n"); } + +void CNEORules::RoundTimeout() +{ + bool winnerDetermined = false; + switch (GetGameType()) + { + case NEO_GAME_TYPE_TDM: winnerDetermined = RoundTimeoutTDM(); + break; + case NEO_GAME_TYPE_DM: winnerDetermined = RoundTimeoutDM(); + break; + case NEO_GAME_TYPE_JGR: winnerDetermined = RoundTimeoutJGR(); + break; + case NEO_GAME_TYPE_ATK: winnerDetermined = RoundTimeoutATK(); + break; + default: + break; + } + if (!winnerDetermined && IsTeamplay()) + { + SetWinningTeam(TEAM_SPECTATOR, NEO_VICTORY_STALEMATE, false, false, true, false); + } +} + +bool CNEORules::RoundTimeoutTDM() +{ + if (GetGlobalTeam(TEAM_JINRAI)->GetScore() > GetGlobalTeam(TEAM_NSF)->GetScore()) + { + SetWinningTeam(TEAM_JINRAI, NEO_VICTORY_POINTS, false, true, false, false); + return true; + } + if (GetGlobalTeam(TEAM_NSF)->GetScore() > GetGlobalTeam(TEAM_JINRAI)->GetScore()) + { + SetWinningTeam(TEAM_NSF, NEO_VICTORY_POINTS, false, true, false, false); + return true; + } + return false; +} + +bool CNEORules::RoundTimeoutDM() +{ + // Winning player + CNEO_Player* pWinners[MAX_PLAYERS + 1] = {}; + int iWinnersTotal = 0; + int iWinnerXP = 0; + GetDMHighestScorers(&pWinners, &iWinnersTotal, &iWinnerXP); + if (iWinnersTotal == 1) + { + SetWinningDMPlayer(pWinners[0]); + return true; + } + // Otherwise go into overtime + return false; +} + +bool CNEORules::RoundTimeoutJGR() +{ + if ((!m_pJuggernautPlayer && m_pJuggernautItem && !m_pJuggernautItem->IsBeingActivatedByLosingTeam()) || + (!m_pJuggernautPlayer && !m_pJuggernautItem)) // Juggernaut is absent entirely + { + if (GetGlobalTeam(TEAM_JINRAI)->GetScore() > GetGlobalTeam(TEAM_NSF)->GetScore()) + { + SetWinningTeam(TEAM_JINRAI, NEO_VICTORY_POINTS, false, true, false, false); + return true; + } + + if (GetGlobalTeam(TEAM_NSF)->GetScore() > GetGlobalTeam(TEAM_JINRAI)->GetScore()) + { + SetWinningTeam(TEAM_NSF, NEO_VICTORY_POINTS, false, true, false, false); + return true; + } + } + else + { + if (m_nRoundStatus == NeoRoundStatus::RoundLive) + { + m_nRoundStatus = NeoRoundStatus::Overtime; + } + + if (m_pJuggernautPlayer) + { + const int jgrTeam = m_pJuggernautPlayer->GetTeamNumber(); + const int oppositeTeam = (m_pJuggernautPlayer->GetTeamNumber() == TEAM_JINRAI ? TEAM_NSF : TEAM_JINRAI); + if (GetGlobalTeam(jgrTeam)->GetScore() > GetGlobalTeam(oppositeTeam)->GetScore()) + { + SetWinningTeam(jgrTeam, NEO_VICTORY_POINTS, false, true, false, false); + return true; + } + } + + return true; + } + return false; +} + +bool CNEORules::RoundTimeoutATK() +{ + SetWinningTeam(GetDefendingTeam(), NEO_VICTORY_ATK_TIMEOUT, false, true, false, false); + return true; +} #endif bool CNEORules::IsRoundPreRoundFreeze() const @@ -2987,6 +3086,8 @@ const SZWSZTexts NEO_GAME_TYPE_DESC_STRS[NEO_GAME_TYPE__TOTAL] = { SZWSZ_INIT("Deathmatch"), SZWSZ_INIT("Free Roam"), SZWSZ_INIT("Training"), + SZWSZ_INIT("Juggernaut"), + SZWSZ_INIT("Attack/Defend"), }; const char *CNEORules::GetGameDescription(void) @@ -3207,13 +3308,14 @@ void CNEORules::SetGameRelatedVars() ResetTDM(); ResetGhost(); - if (GetGameType() == NEO_GAME_TYPE_CTG) + NeoGameType eGameType = (NeoGameType)GetGameType(); + if (eGameType == NEO_GAME_TYPE_CTG || eGameType == NEO_GAME_TYPE_ATK) { SpawnTheGhost(); } ResetVIP(); - if (GetGameType() == NEO_GAME_TYPE_VIP) + if (eGameType == NEO_GAME_TYPE_VIP) { if (!m_iEscortingTeam) { @@ -3231,7 +3333,7 @@ void CNEORules::SetGameRelatedVars() m_iEscortingTeam.Set(0); } - if (GetGameType() == NEO_GAME_TYPE_TDM) + if (eGameType == NEO_GAME_TYPE_TDM) { for (int i = 0; i < GetNumberOfTeams(); i++) { @@ -3239,7 +3341,7 @@ void CNEORules::SetGameRelatedVars() } } - if (GetGameType() == NEO_GAME_TYPE_DM) + if (eGameType == NEO_GAME_TYPE_DM) { for (int i = 1; i <= gpGlobals->maxClients; ++i) { @@ -3251,7 +3353,7 @@ void CNEORules::SetGameRelatedVars() } } - if (GetGameType() == NEO_GAME_TYPE_JGR) + if (eGameType == NEO_GAME_TYPE_JGR) { ResetJGR(); SpawnTheJuggernaut(); @@ -3893,7 +3995,7 @@ void CNEORules::SetWinningTeam(int team, int iWinReason, bool bForceMapReset, bo } } } - else if (GetGameType() == NEO_GAME_TYPE_CTG || GetGameType() == NEO_GAME_TYPE_VIP) + else if (GetGameType() == NEO_GAME_TYPE_CTG || GetGameType() == NEO_GAME_TYPE_VIP || GetGameType() == NEO_GAME_TYPE_ATK) { if (sv_neo_survivor_bonus.GetBool() && player->IsAlive()) { @@ -4705,6 +4807,16 @@ bool CNEORules::IsJuggernautLocked() const return false; } +int CNEORules::GetAttackingTeam() const +{ + return roundNumberIsEven() ? TEAM_JINRAI : TEAM_NSF; +} + +int CNEORules::GetDefendingTeam() const +{ + return roundNumberIsEven() ? TEAM_NSF : TEAM_JINRAI; +} + const char *CNEORules::GetTeamClantag(const int iTeamNum) const { switch (iTeamNum) diff --git a/src/game/shared/neo/neo_gamerules.h b/src/game/shared/neo/neo_gamerules.h index 5602e0b267..79dcf4b2b7 100644 --- a/src/game/shared/neo/neo_gamerules.h +++ b/src/game/shared/neo/neo_gamerules.h @@ -104,6 +104,7 @@ enum NeoGameType { NEO_GAME_TYPE_EMT, NEO_GAME_TYPE_TUT, NEO_GAME_TYPE_JGR, + NEO_GAME_TYPE_ATK, NEO_GAME_TYPE__TOTAL // Number of game types }; @@ -131,6 +132,7 @@ enum NeoWinReason { NEO_VICTORY_VIP_ELIMINATION, NEO_VICTORY_TEAM_ELIMINATION, NEO_VICTORY_TIMEOUT_WIN_BY_NUMBERS, + NEO_VICTORY_ATK_TIMEOUT, NEO_VICTORY_POINTS, NEO_VICTORY_FORFEIT, NEO_VICTORY_STALEMATE, // Not actually a victory @@ -287,8 +289,10 @@ class CNEORules : public CHL2MPRules, public CGameEventListener virtual bool CheckGameOver(void) OVERRIDE; + void CheckOvertime(); + float GetRoundRemainingTime() const; - float GetCTGOverTime() const; + float GetOverTime(NeoGameType eGameType) const; float GetRoundAccumulatedTime() const; #ifdef GAME_DLL float MirrorDamageMultiplier() const; @@ -331,6 +335,11 @@ class CNEORules : public CHL2MPRules, public CGameEventListener void CheckGameType(); void CheckGameConfig(); void StartNextRound(); + void RoundTimeout(); + bool RoundTimeoutTDM(); + bool RoundTimeoutDM(); + bool RoundTimeoutJGR(); + bool RoundTimeoutATK(); virtual const char* GetChatFormat(bool bTeamOnly, CBasePlayer* pPlayer) OVERRIDE; virtual const char* GetChatPrefix(bool bTeamOnly, CBasePlayer* pPlayer) OVERRIDE { return ""; } // handled by GetChatFormat @@ -379,6 +388,8 @@ class CNEORules : public CHL2MPRules, public CGameEventListener inline int roundNumber() const { return m_iRoundNumber; } inline bool roundNumberIsEven() const { return (roundNumber() % 2 == 0); } + int GetAttackingTeam() const; + int GetDefendingTeam() const; #ifdef GLOWS_ENABLE void GetTeamGlowColor(int teamNumber, float &r, float &g, float &b) diff --git a/src/game/shared/neo/neo_player_spawnpoint.cpp b/src/game/shared/neo/neo_player_spawnpoint.cpp index f3acb0f902..3085af1dca 100644 --- a/src/game/shared/neo/neo_player_spawnpoint.cpp +++ b/src/game/shared/neo/neo_player_spawnpoint.cpp @@ -10,25 +10,25 @@ // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" -class CNEOSpawnPoint_Jinrai : public CNEOSpawnPoint +class CNEOSpawnPoint_Attacker : public CNEOSpawnPoint { public: - CNEOSpawnPoint_Jinrai() : CNEOSpawnPoint() + CNEOSpawnPoint_Attacker() : CNEOSpawnPoint() { - m_iOwningTeam = TEAM_JINRAI; + m_eSide = E_TeamSide::Attacker; } }; -LINK_ENTITY_TO_CLASS(info_player_attacker, CNEOSpawnPoint_Jinrai); +LINK_ENTITY_TO_CLASS(info_player_attacker, CNEOSpawnPoint_Attacker); -class CNEOSpawnPoint_NSF : public CNEOSpawnPoint +class CNEOSpawnPoint_Defender : public CNEOSpawnPoint { public: - CNEOSpawnPoint_NSF() : CNEOSpawnPoint() + CNEOSpawnPoint_Defender() : CNEOSpawnPoint() { - m_iOwningTeam = TEAM_NSF; + m_eSide = E_TeamSide::Defender; } }; -LINK_ENTITY_TO_CLASS(info_player_defender, CNEOSpawnPoint_NSF); +LINK_ENTITY_TO_CLASS(info_player_defender, CNEOSpawnPoint_Defender); #ifdef GAME_DLL IMPLEMENT_SERVERCLASS_ST(CNEOSpawnPoint, DT_NEOSpawnPoint) @@ -55,7 +55,7 @@ END_DATADESC() CNEOSpawnPoint::CNEOSpawnPoint() { - m_iOwningTeam = TEAM_UNASSIGNED; + m_eSide = E_TeamSide::Unspecified; } CNEOSpawnPoint::~CNEOSpawnPoint() @@ -69,7 +69,7 @@ void CNEOSpawnPoint::Spawn() { BaseClass::Spawn(); - AssertMsg(m_iOwningTeam == TEAM_JINRAI || m_iOwningTeam == TEAM_NSF || m_iOwningTeam == TEAM_ANY, + AssertMsg(m_eSide == E_TeamSide::Unspecified || m_eSide == E_TeamSide::Attacker || m_eSide == E_TeamSide::Defender, "CNEOSpawnPoint shouldn't be instantiated directly; use info_player_attacker/defender instead!\n"); #if(0) @@ -85,13 +85,20 @@ void CNEOSpawnPoint::Spawn() int CNEOSpawnPoint::GetOwningTeam() const { - const bool alternate = NEORules()->roundNumberIsEven(); - int owningTeam = m_iOwningTeam; - if (!alternate && owningTeam != TEAM_ANY) + switch (m_eSide) { - owningTeam = (owningTeam == TEAM_JINRAI) ? TEAM_NSF : (owningTeam == TEAM_NSF) ? TEAM_JINRAI : owningTeam; + case E_TeamSide::Attacker: + return NEORules()->GetAttackingTeam(); + case E_TeamSide::Defender: + return NEORules()->GetDefendingTeam(); + default: + return TEAM_ANY; } - return owningTeam; +} + +E_TeamSide CNEOSpawnPoint::GetSide() const +{ + return m_eSide; } #ifdef GAME_DLL diff --git a/src/game/shared/neo/neo_player_spawnpoint.h b/src/game/shared/neo/neo_player_spawnpoint.h index 9095a603b3..90598453e8 100644 --- a/src/game/shared/neo/neo_player_spawnpoint.h +++ b/src/game/shared/neo/neo_player_spawnpoint.h @@ -12,6 +12,13 @@ #define CNEOSpawnPoint C_NEOSpawnPoint #endif +enum class E_TeamSide +{ + Unspecified, + Attacker, + Defender +}; + class CNEOSpawnPoint : public CBaseEntity { DECLARE_CLASS(CNEOSpawnPoint, CBaseEntity); @@ -29,6 +36,7 @@ class CNEOSpawnPoint : public CBaseEntity virtual void Spawn() override; int GetOwningTeam() const; + E_TeamSide GetSide() const; #ifdef GAME_DLL bool m_bDisabled; @@ -40,7 +48,7 @@ class CNEOSpawnPoint : public CBaseEntity #endif protected: - int m_iOwningTeam; + E_TeamSide m_eSide; private: CNEOSpawnPoint(const CNEOSpawnPoint &other); From 1135162c2d9c5ab801a9928e2a05cce82963f9d2 Mon Sep 17 00:00:00 2001 From: Hosomi-PC Date: Thu, 21 May 2026 22:02:00 +0100 Subject: [PATCH 02/16] fix build error --- src/game/server/subs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/server/subs.cpp b/src/game/server/subs.cpp index 92e27d7e09..f49201c969 100644 --- a/src/game/server/subs.cpp +++ b/src/game/server/subs.cpp @@ -55,7 +55,7 @@ class CBaseDMStart : public CPointEntity CBaseDMStart() : CNEOSpawnPoint() { - m_iOwningTeam = TEAM_ANY; + m_eSide = E_TeamSide::Unspecified; } #else DECLARE_CLASS( CBaseDMStart, CPointEntity ); From c4227c8517d43ea4bf4fc2c081928b5a2fd430bd Mon Sep 17 00:00:00 2001 From: Hosomi-PC Date: Thu, 21 May 2026 22:02:07 +0100 Subject: [PATCH 03/16] Add victory message --- src/game/shared/neo/neo_gamerules.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/game/shared/neo/neo_gamerules.cpp b/src/game/shared/neo/neo_gamerules.cpp index 0230ace686..2bfc06d89d 100644 --- a/src/game/shared/neo/neo_gamerules.cpp +++ b/src/game/shared/neo/neo_gamerules.cpp @@ -3903,6 +3903,9 @@ void CNEORules::SetWinningTeam(int team, int iWinReason, bool bForceMapReset, bo case NEO_VICTORY_TIMEOUT_WIN_BY_NUMBERS: V_sprintf_safe(victoryMsg, "Team %s wins by numbers!\n", (team == TEAM_JINRAI ? "Jinrai" : "NSF")); break; + case NEO_VICTORY_ATK_TIMEOUT: + V_sprintf_safe(victoryMsg, "Team %s wins by defending the ghost!\n", (team == TEAM_JINRAI ? "Jinrai" : "NSF")); + break; case NEO_VICTORY_POINTS: V_sprintf_safe(victoryMsg, "Team %s wins by highest score!\n", (team == TEAM_JINRAI ? "Jinrai" : "NSF")); break; From 6a43998268575820a96f9fe6f29a7d6ba6452cb6 Mon Sep 17 00:00:00 2001 From: Hosomi-PC Date: Thu, 21 May 2026 22:33:28 +0100 Subject: [PATCH 04/16] Update fgd --- game/bin/rebuild.fgd | 1 + 1 file changed, 1 insertion(+) diff --git a/game/bin/rebuild.fgd b/game/bin/rebuild.fgd index 19d69818fa..4f5aa29b1e 100644 --- a/game/bin/rebuild.fgd +++ b/game/bin/rebuild.fgd @@ -40,6 +40,7 @@ 2 : "VIP" 3 : "DM" 6 : "JGR" + 7 : "ATK 4 : "Empty" 5 : "Tutorial" ] From 1744ebad7c19f8fffc9e4cd7a72e77ce4305cf76 Mon Sep 17 00:00:00 2001 From: Hosomi-PC Date: Thu, 21 May 2026 22:55:15 +0100 Subject: [PATCH 05/16] fix linux build --- src/game/shared/neo/neo_gamerules.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/shared/neo/neo_gamerules.cpp b/src/game/shared/neo/neo_gamerules.cpp index 2bfc06d89d..26824377db 100644 --- a/src/game/shared/neo/neo_gamerules.cpp +++ b/src/game/shared/neo/neo_gamerules.cpp @@ -1839,7 +1839,7 @@ float CNEORules::GetOverTime(NeoGameType eGameType) const } else { - throw std::exception("Tried to calculate overtime for a gamemode with no overtime implementation"); + Assert(false && "Tried to calculate overtime for a gamemode with no overtime implementation"); } float overtime = (m_flNeoRoundStartTime + roundTimeLimit + overtimeBaseAmount) - gpGlobals->curtime; From ce73170fbb0cff19c83d3ed9e7802bd5f22c7815 Mon Sep 17 00:00:00 2001 From: Hosomi-PC Date: Thu, 21 May 2026 23:08:06 +0100 Subject: [PATCH 06/16] Fix CI error --- src/game/shared/neo/neo_gamerules.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/game/shared/neo/neo_gamerules.cpp b/src/game/shared/neo/neo_gamerules.cpp index 26824377db..a9c69f5f22 100644 --- a/src/game/shared/neo/neo_gamerules.cpp +++ b/src/game/shared/neo/neo_gamerules.cpp @@ -1823,24 +1823,25 @@ float CNEORules::GetOverTime(NeoGameType eGameType) const float overtimeGrace; bool graceDecay; - if (eGameType == NeoGameType::NEO_GAME_TYPE_CTG) + switch (eGameType) { + case NeoGameType::NEO_GAME_TYPE_CTG: roundTimeLimit = neo_ctg_round_timelimit.GetFloat() * 60.f; overtimeBaseAmount = sv_neo_ctg_ghost_overtime.GetFloat(); overtimeGrace = sv_neo_ctg_ghost_overtime_grace.GetFloat(); graceDecay = sv_neo_ctg_ghost_overtime_grace_decay.GetBool(); - } - else if (eGameType == NeoGameType::NEO_GAME_TYPE_ATK) - { + break; + case NeoGameType::NEO_GAME_TYPE_ATK: roundTimeLimit = neo_atk_round_timelimit.GetFloat() * 60.f; overtimeBaseAmount = sv_neo_atk_ghost_overtime.GetFloat(); overtimeGrace = sv_neo_atk_ghost_overtime_grace.GetFloat(); graceDecay = sv_neo_atk_ghost_overtime_grace_decay.GetBool(); - } - else - { + break; + default: Assert(false && "Tried to calculate overtime for a gamemode with no overtime implementation"); + return; } + float overtime = (m_flNeoRoundStartTime + roundTimeLimit + overtimeBaseAmount) - gpGlobals->curtime; if (graceDecay) From 5f944c1a1f0cec760e172b7a45398814ff15c9da Mon Sep 17 00:00:00 2001 From: Hosomi-PC Date: Thu, 21 May 2026 23:13:38 +0100 Subject: [PATCH 07/16] My shame is growing --- src/game/shared/neo/neo_gamerules.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/shared/neo/neo_gamerules.cpp b/src/game/shared/neo/neo_gamerules.cpp index a9c69f5f22..2cc3aa8e3d 100644 --- a/src/game/shared/neo/neo_gamerules.cpp +++ b/src/game/shared/neo/neo_gamerules.cpp @@ -1839,7 +1839,7 @@ float CNEORules::GetOverTime(NeoGameType eGameType) const break; default: Assert(false && "Tried to calculate overtime for a gamemode with no overtime implementation"); - return; + return (m_flNeoRoundStartTime + roundTimeLimit) - gpGlobals->curtime; } float overtime = (m_flNeoRoundStartTime + roundTimeLimit + overtimeBaseAmount) - gpGlobals->curtime; From 1a2af01443459f92184cae1588efbe94f1ecc841 Mon Sep 17 00:00:00 2001 From: Hosomi-PC Date: Thu, 21 May 2026 23:32:35 +0100 Subject: [PATCH 08/16] Fix uninitialized return after assert(false) --- src/game/shared/neo/neo_gamerules.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/shared/neo/neo_gamerules.cpp b/src/game/shared/neo/neo_gamerules.cpp index 2cc3aa8e3d..95a7927669 100644 --- a/src/game/shared/neo/neo_gamerules.cpp +++ b/src/game/shared/neo/neo_gamerules.cpp @@ -1839,7 +1839,7 @@ float CNEORules::GetOverTime(NeoGameType eGameType) const break; default: Assert(false && "Tried to calculate overtime for a gamemode with no overtime implementation"); - return (m_flNeoRoundStartTime + roundTimeLimit) - gpGlobals->curtime; + return 0; } float overtime = (m_flNeoRoundStartTime + roundTimeLimit + overtimeBaseAmount) - gpGlobals->curtime; From 93330ed235425e4122db75aae7f939871e55e543 Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Tue, 2 Jun 2026 20:10:09 +0100 Subject: [PATCH 09/16] wip --- src/game/client/CMakeLists.txt | 25 +- src/game/server/CMakeLists.txt | 25 +- src/game/server/neo/neo_client.cpp | 23 + src/game/server/neo/neo_game_config.cpp | 16 +- src/game/server/neo/neo_game_config.h | 11 +- src/game/shared/hl2mp/hl2mp_gamerules.h | 4 +- .../neo/{ => gamerules}/neo_gamerules.cpp | 886 ++++-------------- .../neo/{ => gamerules}/neo_gamerules.h | 348 ++++--- .../neo/gamerules/neo_gamerules_atk.cpp | 115 +++ .../shared/neo/gamerules/neo_gamerules_atk.h | 42 + .../neo/gamerules/neo_gamerules_ctg.cpp | 193 ++++ .../shared/neo/gamerules/neo_gamerules_ctg.h | 42 + .../shared/neo/gamerules/neo_gamerules_dm.cpp | 260 +++++ .../shared/neo/gamerules/neo_gamerules_dm.h | 54 ++ .../neo/gamerules/neo_gamerules_emt.cpp | 65 ++ .../shared/neo/gamerules/neo_gamerules_emt.h | 41 + .../neo/gamerules/neo_gamerules_jgr.cpp | 157 ++++ .../shared/neo/gamerules/neo_gamerules_jgr.h | 44 + .../neo/gamerules/neo_gamerules_tdm.cpp | 113 +++ .../shared/neo/gamerules/neo_gamerules_tdm.h | 44 + .../neo/gamerules/neo_gamerules_tut.cpp | 84 ++ .../shared/neo/gamerules/neo_gamerules_tut.h | 41 + .../neo/gamerules/neo_gamerules_vip.cpp | 177 ++++ .../shared/neo/gamerules/neo_gamerules_vip.h | 41 + 24 files changed, 1943 insertions(+), 908 deletions(-) rename src/game/shared/neo/{ => gamerules}/neo_gamerules.cpp (85%) rename src/game/shared/neo/{ => gamerules}/neo_gamerules.h (78%) create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_atk.cpp create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_atk.h create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_ctg.h create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_dm.cpp create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_dm.h create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_emt.cpp create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_emt.h create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_jgr.h create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_tdm.h create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_tut.cpp create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_tut.h create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_vip.cpp create mode 100644 src/game/shared/neo/gamerules/neo_gamerules_vip.h diff --git a/src/game/client/CMakeLists.txt b/src/game/client/CMakeLists.txt index 19c2458a4c..194f5b45dd 100644 --- a/src/game/client/CMakeLists.txt +++ b/src/game/client/CMakeLists.txt @@ -21,6 +21,7 @@ target_include_directories(client ${CMAKE_SOURCE_DIR}/game/shared/hl2mp ${CMAKE_SOURCE_DIR}/game/shared/Multiplayer ${CMAKE_SOURCE_DIR}/game/shared/neo + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules ${CMAKE_SOURCE_DIR}/game/shared/neo/weapons ${CMAKE_SOURCE_DIR}/public ${CMAKE_SOURCE_DIR}/thirdparty/sixensesdk/include @@ -1629,8 +1630,6 @@ target_sources_grouped( FILES ${CMAKE_SOURCE_DIR}/game/shared/neo/achievements_neo.cpp ${CMAKE_SOURCE_DIR}/game/shared/neo/achievements_neo.h - ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_gamerules.cpp - ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_gamerules.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_ghost_cap_point.cpp ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_ghost_cap_point.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_juggernaut.cpp @@ -1663,6 +1662,28 @@ target_sources_grouped( ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_serial.h ) +target_sources_grouped( + TARGET client + NAME "Source Files\\Shared\\Gamerules" + FILES + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_atk.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_atk.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_ctg.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_ctg.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_dm.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_dm.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_jgr.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_jgr.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_tdm.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_tdm.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_tut.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_tut.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_vip.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_vip.h +) + target_sources_grouped( TARGET client NAME "Source Files\\Shared\\Weapons" diff --git a/src/game/server/CMakeLists.txt b/src/game/server/CMakeLists.txt index fe219a20cc..29ef9c8955 100644 --- a/src/game/server/CMakeLists.txt +++ b/src/game/server/CMakeLists.txt @@ -42,6 +42,7 @@ target_include_directories(server ${CMAKE_SOURCE_DIR}/game/shared/hl2mp ${CMAKE_SOURCE_DIR}/game/shared/Multiplayer ${CMAKE_SOURCE_DIR}/game/shared/neo + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules ${CMAKE_SOURCE_DIR}/game/shared/neo/weapons ${CMAKE_SOURCE_DIR}/utils/common ${CMAKE_SOURCE_DIR}/public @@ -1346,8 +1347,6 @@ target_sources_grouped( FILES ${CMAKE_SOURCE_DIR}/game/shared/neo/achievements_neo.cpp ${CMAKE_SOURCE_DIR}/game/shared/neo/achievements_neo.h - ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_gamerules.cpp - ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_gamerules.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_ghost_cap_point.cpp ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_ghost_cap_point.h ${CMAKE_SOURCE_DIR}/game/shared/neo/neo_juggernaut.cpp @@ -1517,6 +1516,28 @@ target_sources_grouped( neo/bot/map_entities/neo_bot_proxy.h ) +target_sources_grouped( + TARGET server + NAME "NEO\\Gamerules" + FILES + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_atk.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_atk.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_ctg.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_ctg.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_dm.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_dm.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_jgr.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_jgr.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_tdm.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_tdm.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_tut.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_tut.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_vip.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_vip.h +) + target_sources_grouped( TARGET server NAME "NEO\\Weapons" diff --git a/src/game/server/neo/neo_client.cpp b/src/game/server/neo/neo_client.cpp index d1e6b3b167..212e0dc282 100644 --- a/src/game/server/neo/neo_client.cpp +++ b/src/game/server/neo/neo_client.cpp @@ -1,5 +1,6 @@ #include "cbase.h" #include "neo_player.h" +#include "neo_game_config.h" #include "neo_gamerules.h" #include "gamerules.h" #include "teamplay_gamerules.h" @@ -393,5 +394,27 @@ void GameStartFrame( void ) //========================================================= void InstallGameRules() { + if (const CNEOGameConfig* pEntGameCfg = NEOGameConfig()) + { + switch (pEntGameCfg->m_GameType) + { + case NEO_GAME_TYPE_TDM: + CreateGameRulesObject( "CNEORulesTDM" ); + return; + case NEO_GAME_TYPE_CTG: + case NEO_GAME_TYPE_VIP: + case NEO_GAME_TYPE_DM: + break; + case NEO_GAME_TYPE_EMT: + CreateGameRulesObject( "CNEORules" ); + return; + case NEO_GAME_TYPE_TUT: + case NEO_GAME_TYPE_JGR: + case NEO_GAME_TYPE_ATK: + default: + break; + } + } + CreateGameRulesObject( "CNEORules" ); } diff --git a/src/game/server/neo/neo_game_config.cpp b/src/game/server/neo/neo_game_config.cpp index dab9ada034..804f43e846 100644 --- a/src/game/server/neo/neo_game_config.cpp +++ b/src/game/server/neo/neo_game_config.cpp @@ -1,4 +1,5 @@ #include "neo_game_config.h" +#include "neo_gamerules.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -26,6 +27,19 @@ END_DATADESC() extern ConVar sv_neo_comp; +CNEOGameConfig *g_pNEOGameConfig = nullptr; + +CNEOGameConfig::CNEOGameConfig() +{ + Assert( !g_pNEOGameConfig ); + g_pNEOGameConfig = this; +} + +CNEOGameConfig::~CNEOGameConfig() +{ + g_pNEOGameConfig = nullptr; +} + void CNEOGameConfig::Spawn() { if (sv_neo_comp.GetBool()) @@ -44,7 +58,7 @@ void CNEOGameConfig::InputFireTeamWin(inputdata_t& inputData) void CNEOGameConfig::InputFireDMPlayerWin(inputdata_t& inputData) { - CBasePlayer* pPlayer = NULL; + CBasePlayer* pPlayer = nullptr; if (inputData.pActivator && inputData.pActivator->IsPlayer()) { diff --git a/src/game/server/neo/neo_game_config.h b/src/game/server/neo/neo_game_config.h index c9a8729c88..fb08ecc44f 100644 --- a/src/game/server/neo/neo_game_config.h +++ b/src/game/server/neo/neo_game_config.h @@ -1,15 +1,16 @@ #pragma once #include "cbase.h" -#include "baseentity.h" #include "neo_gamerules.h" class CNEOGameConfig : public CLogicalEntity { - DECLARE_CLASS(CNEOGameConfig, CBaseEntity); + DECLARE_CLASS(CNEOGameConfig, CLogicalEntity); DECLARE_DATADESC(); public: + CNEOGameConfig(); + ~CNEOGameConfig(); virtual void Spawn() override; int m_GameType = NEO_GAME_TYPE_TDM; @@ -30,3 +31,9 @@ class CNEOGameConfig : public CLogicalEntity COutputEvent m_OnRoundStart; COutputEvent m_OnCompetitive; }; + +extern CNEOGameConfig *g_pNEOGameConfig; +inline CNEOGameConfig *NEOGameConfig() +{ + return g_pNEOGameConfig; +} \ No newline at end of file diff --git a/src/game/shared/hl2mp/hl2mp_gamerules.h b/src/game/shared/hl2mp/hl2mp_gamerules.h index 38b2dbfa51..83fc13f3b0 100644 --- a/src/game/shared/hl2mp/hl2mp_gamerules.h +++ b/src/game/shared/hl2mp/hl2mp_gamerules.h @@ -173,7 +173,7 @@ class CHL2MPRules : public CTeamplayRules bool IsTeamplay( void ) { #ifdef NEO - return GetTeamPlayEnabled(); + return GetTeamPlayEnabled(); // NEO TODO (Adam) Just make this virtual instead #else return m_bTeamPlayEnabled; #endif @@ -185,7 +185,7 @@ class CHL2MPRules : public CTeamplayRules #ifdef NEO protected: - CNetworkVar(float, m_flGameStartTime); + CNetworkVar(float, m_flGameStartTime); // NEO TODO (Adam) Make a protected getter instead? #else private: CNetworkVar(float, m_flGameStartTime); diff --git a/src/game/shared/neo/neo_gamerules.cpp b/src/game/shared/neo/gamerules/neo_gamerules.cpp similarity index 85% rename from src/game/shared/neo/neo_gamerules.cpp rename to src/game/shared/neo/gamerules/neo_gamerules.cpp index 95a7927669..70c80d8128 100644 --- a/src/game/shared/neo/neo_gamerules.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules.cpp @@ -63,37 +63,9 @@ ConVar sv_neo_clantag_allow("sv_neo_clantag_allow", "1", FCVAR_REPLICATED, "", t ConVar sv_neo_dev_test_clantag("sv_neo_dev_test_clantag", "", FCVAR_REPLICATED | FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Debug-mode only - Override all clantags with this value."); #endif -#define STR_GAMEOPTS "TDM=0, CTG=1, VIP=2, DM=3" -#define STR_GAMEBWOPTS "TDM=1, CTG=2, VIP=4, DM=8" #ifdef CLIENT_DLL -ConVar neo_vote_game_mode("neo_vote_game_mode", "1", FCVAR_USERINFO, "Vote on game mode to play. " STR_GAMEOPTS, true, 0, true, NEO_GAME_TYPE__TOTAL - 1); ConVar neo_vip_eligible("cl_neo_vip_eligible", "1", FCVAR_ARCHIVE, "Eligible for VIP", true, 0, true, 1); #endif // CLIENT_DLL -#ifdef GAME_DLL -ConVar sv_neo_vip_ctg_on_death("sv_neo_vip_ctg_on_death", "0", FCVAR_ARCHIVE, "Spawn Ghost when VIP dies, continue the game", true, 0, true, 1); -ConVar sv_neo_jgr_max_points("sv_neo_jgr_max_points", "20", FCVAR_GAMEDLL, "Maximum points required for a team to win in JGR", true, 1, false, 0); -#endif - -#ifdef GAME_DLL -// NEO TODO (nullsystem): Change how voting done from convar to menu selection -enum eGamemodeEnforcement -{ - GAMEMODE_ENFORCEMENT_MAP = 0, // Only use the gamemode enforced by the map - GAMEMODE_ENFORCEMENT_SINGLE, // Only use the single gamemode enforced by the server - GAMEMODE_ENFORCEMENT_RAND, // Randomly choose a gamemode on each map initialization based on a list - GAMEMODE_ENFORCEMENT_VOTE, // Allow vote by players on pre-match - - GAMEMODE_ENFORCEMENT__TOTAL, -}; -ConVar sv_neo_gamemode_enforcement("sv_neo_gamemode_enforcement", "0", FCVAR_REPLICATED, - "How the gamemode are determined. 0 = By map, 1 = By sv_neo_gamemode_single, 2 = Random, 3 = Pre-match voting", - true, 0.0f, true, GAMEMODE_ENFORCEMENT__TOTAL - 1); -ConVar sv_neo_gamemode_single("sv_neo_gamemode_single", "3", FCVAR_REPLICATED, "The gamemode that is enforced by the server. " STR_GAMEOPTS, - true, 0.0f, true, NEO_GAME_TYPE__TOTAL - 1); -ConVar sv_neo_gamemode_random_allow("sv_neo_gamemode_random_allow", "11", FCVAR_REPLICATED, - "In bitwise, the gamemodes that are allowed for random selection. Default = TDM+CTG+DM. " STR_GAMEBWOPTS, - true, 1.0f, true, (1 << NEO_GAME_TYPE__TOTAL)); // Can't be zero, minimum has to set to a bitwise value -#endif #ifdef GAME_DLL #ifdef DEBUG @@ -450,8 +422,6 @@ ConVar neo_round_sudden_death("neo_round_sudden_death", "1", FCVAR_REPLICATED, " "neo_round_limit, go into sudden death where match won't end until a team won.", true, 0.0f, true, 1.0f); // Score Limit -ConVar sv_neo_tdm_score_limit("sv_neo_tdm_score_limit", "1", FCVAR_REPLICATED, "TDM score limit", true, 0.0f, true, 99.0f); - ConVar sv_neo_ctg_score_limit("sv_neo_ctg_score_limit", "7", FCVAR_REPLICATED, "CTG score limit", true, 0.0f, true, 99.0f); ConVar sv_neo_vip_score_limit("sv_neo_vip_score_limit", "7", FCVAR_REPLICATED, "VIP score limit", true, 0.0f, true, 99.0f); @@ -463,8 +433,6 @@ ConVar sv_neo_jgr_score_limit("sv_neo_jgr_score_limit", "0", FCVAR_REPLICATED, " ConVar sv_neo_atk_score_limit("sv_neo_atk_score_limit", "7", FCVAR_REPLICATED, "ATK score limit", true, 0.0f, true, 99.0f); // Round Limit -ConVar sv_neo_tdm_round_limit("sv_neo_tdm_round_limit", "0", FCVAR_REPLICATED, "TDM max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); - ConVar sv_neo_ctg_round_limit("sv_neo_ctg_round_limit", "0", FCVAR_REPLICATED, "CTG max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); ConVar sv_neo_vip_round_limit("sv_neo_vip_round_limit", "0", FCVAR_REPLICATED, "VIP max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); @@ -476,11 +444,6 @@ ConVar sv_neo_jgr_round_limit("sv_neo_jgr_round_limit", "5", FCVAR_REPLICATED, " ConVar sv_neo_atk_round_limit("sv_neo_atk_round_limit", "0", FCVAR_REPLICATED, "ATK max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); // Round Time Limit (make these sv_neo at some point) -ConVar neo_tdm_round_timelimit("neo_tdm_round_timelimit", "10.25", FCVAR_REPLICATED, "TDM round timelimit, in minutes.", - true, 0.0f, false, 600.0f); - -ConVar neo_ctg_round_timelimit("neo_ctg_round_timelimit", "3.25", FCVAR_REPLICATED, "CTG round timelimit, in minutes.", - true, 0.0f, false, 600.0f); ConVar neo_vip_round_timelimit("neo_vip_round_timelimit", "3.25", FCVAR_REPLICATED, "VIP round timelimit, in minutes.", true, 0.0f, false, 600.0f); @@ -491,24 +454,9 @@ ConVar neo_dm_round_timelimit("neo_dm_round_timelimit", "10.25", FCVAR_REPLICATE ConVar neo_jgr_round_timelimit("neo_jgr_round_timelimit", "4.25", FCVAR_REPLICATED, "JGR round timelimit, in minutes.", true, 0.0f, false, 600.0f); -ConVar neo_atk_round_timelimit("neo_atk_round_timelimit", "3.25", FCVAR_REPLICATED, "ATK round timelimit, in minutes.", - true, 0.0f, false, 600.0f); - ConVar sv_neo_ignore_wep_xp_limit("sv_neo_ignore_wep_xp_limit", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "If true, allow equipping any loadout regardless of player XP.", true, 0.0f, true, 1.0f); -ConVar sv_neo_dm_win_xp("sv_neo_dm_win_xp", "50", FCVAR_REPLICATED, "The XP limit to win the match.", - true, 0.0f, true, 1000.0f); - -ConVar sv_neo_ctg_ghost_overtime_enabled("sv_neo_ctg_ghost_overtime_enabled", "0", FCVAR_REPLICATED, "Enable ghost overtime.", true, 0, true, 1); -ConVar sv_neo_ctg_ghost_overtime("sv_neo_ctg_ghost_overtime", "45", FCVAR_REPLICATED, "Adds up to this many seconds to the round while the ghost is held.", true, 0, true, 120); -ConVar sv_neo_ctg_ghost_overtime_grace("sv_neo_ctg_ghost_overtime_grace", "10", FCVAR_REPLICATED, "Number of seconds left in the round when the ghost is dropped in overtime.", true, 0, true, 30); -ConVar sv_neo_ctg_ghost_overtime_grace_decay("sv_neo_ctg_ghost_overtime_grace_decay", "0", FCVAR_REPLICATED, "Slowly reduce the grace time as overtime goes on.", true, 0, true, 1); -ConVar sv_neo_atk_ghost_overtime_enabled("sv_neo_atk_ghost_overtime_enabled", "0", FCVAR_REPLICATED, "Enable ghost overtime in the ATK mode.", true, 0, true, 1); -ConVar sv_neo_atk_ghost_overtime("sv_neo_atk_ghost_overtime", "45", FCVAR_REPLICATED, "Adds up to this many seconds to the round while the ghost is held.", true, 0, true, 120); -ConVar sv_neo_atk_ghost_overtime_grace("sv_neo_atk_ghost_overtime_grace", "10", FCVAR_REPLICATED, "Number of seconds left in the round when the ghost is dropped in overtime.", true, 0, true, 30); -ConVar sv_neo_atk_ghost_overtime_grace_decay("sv_neo_atk_ghost_overtime_grace_decay", "0", FCVAR_REPLICATED, "Slowly reduce the grace time as overtime goes on.", true, 0, true, 1); - #ifdef CLIENT_DLL extern ConVar neo_fov; #endif @@ -652,11 +600,6 @@ static void CvarChanged_WeaponStay(IConVar* convar, const char* pOldVal, float f wep = gEntList.NextEntByClass(wep); } } - -static CNEOGameConfig *GetActiveGameConfig() -{ - return static_cast(gEntList.FindEntityByClassname(nullptr, "neo_game_config")); -} #endif CNEORules::CNEORules() @@ -850,7 +793,6 @@ extern ConVar mp_chattime; void CNEORules::ResetMapSessionCommon() { - SetRoundStatus(NeoRoundStatus::Idle); m_iRoundNumber = 0; m_bIsMatchPoint = false; m_bIsDoOrDie = false; @@ -867,6 +809,7 @@ void CNEORules::ResetMapSessionCommon() m_flNeoNextRoundStartTime = 0.0f; m_flGhostLastHeld = 0.0f; #ifdef GAME_DLL + SetRoundStatus(NeoRoundStatus::Idle); m_pRestoredInfos.Purge(); m_readyAccIDs.Purge(); m_bIgnoreOverThreshold = false; @@ -909,7 +852,7 @@ void CNEORules::ChangeLevel(void) ResetMapSessionCommon(); if (!m_bRotatingMapRightNow && sv_neo_readyup_lobby.GetBool() && !sv_neo_readyup_autointermission.GetBool()) { - m_bChangelevelDone = false; + m_bChangelevelDone = false; // NEO TODO (Adam) Is this really necessary? Why is the gamerules object thinking when the map begins to change } else { @@ -932,170 +875,23 @@ bool CNEORules::CheckGameOver(void) return gameOver; } -void CNEORules::GetDMHighestScorers( #ifdef GAME_DLL - CNEO_Player *(*pHighestPlayers)[MAX_PLAYERS + 1], -#endif - int *iHighestPlayersTotal, - int *iHighestXP) const +void CNEORules::UpdateFromGameConfig() { - *iHighestPlayersTotal = 0; - *iHighestXP = 0; -#ifdef GAME_DLL - for (int i = 1; i <= gpGlobals->maxClients; ++i) -#else - if (!g_PR) + if (const auto pEntGameCfg = NEOGameConfig()) { - return; - } - - for (int i = 0; i < (MAX_PLAYERS + 1); ++i) -#endif - { - int iXP = 0; - -#ifdef GAME_DLL - auto pCmpPlayer = static_cast(UTIL_PlayerByIndex(i)); - if (!pCmpPlayer) - { - continue; - } - iXP = pCmpPlayer->m_iXP; -#else - if (!g_PR->IsConnected(i)) - { - continue; - } - iXP = g_PR->GetXP(i); -#endif - - if (iXP == *iHighestXP) - { -#ifdef GAME_DLL - (*pHighestPlayers)[(*iHighestPlayersTotal)++] = pCmpPlayer; -#else - (*iHighestPlayersTotal)++; -#endif - } - else if (iXP > *iHighestXP) - { - *iHighestPlayersTotal = 0; - *iHighestXP = iXP; -#ifdef GAME_DLL - (*pHighestPlayers)[(*iHighestPlayersTotal)++] = pCmpPlayer; -#else - (*iHighestPlayersTotal)++; -#endif - } + m_iHiddenHudElements = pEntGameCfg->m_HiddenHudElements; + m_iForcedTeam = pEntGameCfg->m_ForcedTeam; + m_iForcedClass = pEntGameCfg->m_ForcedClass; + m_iForcedSkin = pEntGameCfg->m_ForcedSkin; + m_iForcedWeapon = pEntGameCfg->m_ForcedWeapon; + m_bCyberspaceLevel = pEntGameCfg->m_Cyberspace; } } - -#ifdef GAME_DLL -void CNEORules::CheckGameType() -{ - // Static as CNEORules doesn't persists through map changes - static int iStaticInitOnCmd = -1; - static int iStaticInitOnRandAllow = -1; - static bool staticGamemodesCanPick[NEO_GAME_TYPE__TOTAL] = {}; - static int iStaticLastPick = -1; // Mostly so it doesn't repeat on array refresh - - const int iGamemodeEnforce = sv_neo_gamemode_enforcement.GetInt(); - const int iGamemodeRandAllow = sv_neo_gamemode_random_allow.GetInt(); - // Update on what to select on first map load or server operator changes sv_neo_gamemode_enforcement - const bool bCheckOnGameType = (!m_bGamemodeTypeBeenInitialized || iGamemodeEnforce != iStaticInitOnCmd || - iGamemodeRandAllow != iStaticInitOnRandAllow); - if (!bCheckOnGameType) - { - return; - } - - // NEO NOTE (nullsystem): CNEORules always recreated on map change, yet entities properly found - // happens later. So checking and init on game type will execute here once. - switch (iGamemodeEnforce) - { - case GAMEMODE_ENFORCEMENT_SINGLE: - { - m_nGameTypeSelected = sv_neo_gamemode_single.GetInt(); - } break; - case GAMEMODE_ENFORCEMENT_RAND: - { - const int iBWAllow = sv_neo_gamemode_random_allow.GetInt(); // Min of 1, cannot be zero - Assert(iBWAllow > 0); - - // Check if all are used up - { - int iAllowsPicks = 0; - for (int i = 0; i < NEO_GAME_TYPE__TOTAL; ++i) - { - iAllowsPicks += staticGamemodesCanPick[i]; - } - if (iAllowsPicks == 0 || iGamemodeRandAllow != iStaticInitOnRandAllow) - { -#ifdef DEBUG - DevMsg("Array reset!\n"); -#endif - // Preset true to those not-allowed, preset false to those allowed - int iTotalPicks = 0; - for (int i = 0; i < NEO_GAME_TYPE__TOTAL; ++i) - { - const bool bCanPick = (iBWAllow & (1 << i)); - iTotalPicks += bCanPick; - staticGamemodesCanPick[i] = bCanPick; - } - if (iTotalPicks <= 1) - { - iStaticLastPick = -1; - } - } - } - - m_nGameTypeSelected = RandomInt(0, NEO_GAME_TYPE__TOTAL - 1); - for (int iWalk = 0; - (!staticGamemodesCanPick[m_nGameTypeSelected] || m_nGameTypeSelected == iStaticLastPick) && - iWalk < NEO_GAME_TYPE__TOTAL; - ++iWalk) - { - m_nGameTypeSelected = LoopAroundInArray(m_nGameTypeSelected + 1, NEO_GAME_TYPE__TOTAL); - } - -#ifdef DEBUG - for (int i = 0; i < NEO_GAME_TYPE__TOTAL; ++i) - { - DevMsg("%d | %s: %s\n", i, NEO_GAME_TYPE_DESC_STRS[i].szStr, staticGamemodesCanPick[i] ? "Allowed" : "Not allowed"); - } - DevMsg("Pick: %d | Prev: %d\n", m_nGameTypeSelected.Get(), iStaticLastPick); #endif - staticGamemodesCanPick[m_nGameTypeSelected] = false; - iStaticLastPick = m_nGameTypeSelected; - } break; - default: - { - const auto pEntGameCfg = GetActiveGameConfig(); - m_nGameTypeSelected = (pEntGameCfg) ? pEntGameCfg->m_GameType : NEO_GAME_TYPE_EMT; - } break; - } - m_bGamemodeTypeBeenInitialized = true; - iStaticInitOnCmd = iGamemodeEnforce; - iStaticInitOnRandAllow = iGamemodeRandAllow; -} - -void CNEORules::CheckGameConfig() -{ - CheckGameType(); - - const auto pEntGameCfg = GetActiveGameConfig(); - m_iHiddenHudElements = (pEntGameCfg) ? pEntGameCfg->m_HiddenHudElements : 0; - - m_iForcedTeam = (pEntGameCfg) ? pEntGameCfg->m_ForcedTeam : -1; - m_iForcedClass = (pEntGameCfg) ? pEntGameCfg->m_ForcedClass : -1; - m_iForcedSkin = (pEntGameCfg) ? pEntGameCfg->m_ForcedSkin : -1; - m_iForcedWeapon = (pEntGameCfg) ? pEntGameCfg->m_ForcedWeapon : -1; - - m_bCyberspaceLevel = (pEntGameCfg) ? pEntGameCfg->m_Cyberspace : false; -} -#endif +// Add a gamemode for background maps bool CNEORules::CheckShouldNotThink() { #ifdef GAME_DLL @@ -1109,53 +905,29 @@ bool CNEORules::CheckShouldNotThink() return false; } -void CNEORules::Think(void) -{ #ifdef GAME_DLL - CheckGameConfig(); - if (CheckShouldNotThink()) - { - // This is kind of wonky, but we only need it for the tutorial, in order to play the dummy beacon sounds... - if (!m_pGhost && GetGameType() == NEO_GAME_TYPE_TUT) - { - auto pEnt = gEntList.FirstEnt(); - while (pEnt) - { - if (dynamic_cast(pEnt)) - { - m_pGhost = static_cast(pEnt); - m_hGhost = m_pGhost; - return; - } - pEnt = gEntList.NextEnt(pEnt); - } - } - if (m_pGhost) m_pGhost->UpdateNearestGhostBeaconDist(); - return; - } +bool CNEORules::RoundIdlePausedStartThink() +{ + UpdateFromGameConfig(); - const bool bIsIdleState = m_nRoundStatus == NeoRoundStatus::Idle - || m_nRoundStatus == NeoRoundStatus::Warmup - || m_nRoundStatus == NeoRoundStatus::Countdown; - bool bIsPause = m_nRoundStatus == NeoRoundStatus::Pause; - if (bIsIdleState && gpGlobals->curtime > m_flNeoNextRoundStartTime) + if (IsRoundIdle() && gpGlobals->curtime > m_flNeoNextRoundStartTime) { StartNextRound(); - return; + return true; } // Make the pause instant if we're still in freeze time - if (m_nRoundStatus == NeoRoundStatus::PreRoundFreeze && m_flPauseDur > 0.0f && - m_iRoundNumber == (m_iPausingRound - 1)) + if (NeoRoundStatus::PreRoundFreeze == m_nRoundStatus && + m_flPauseDur > 0.0f && + m_iPausingRound - 1 == m_iRoundNumber) { SetRoundStatus(NeoRoundStatus::Pause); - bIsPause = true; m_bPausedByPreRoundFreeze = true; m_flNeoNextRoundStartTime = 0.0f; m_flPauseEnd = gpGlobals->curtime + m_flPauseDur; } - if (bIsPause) + if (IsRoundPaused()) { if (gpGlobals->curtime >= m_flPauseEnd) { @@ -1172,7 +944,7 @@ void CNEORules::Think(void) m_flPauseDur = 0.0f; m_flPauseEnd = 0.0f; StartNextRound(); - return; + return true; } else if (gpGlobals->curtime > m_flNeoNextRoundStartTime) { @@ -1180,109 +952,104 @@ void CNEORules::Think(void) UTIL_CenterPrintAll("- MATCH IS CURRENTLY PAUSED -\n"); } } +} - // Allow respawn if it's an idle, warmup round, pausing, or deathmatch-type gamemode - const bool bIsDMType = (m_nGameTypeSelected == NEO_GAME_TYPE_DM || m_nGameTypeSelected == NEO_GAME_TYPE_TDM || m_nGameTypeSelected == NEO_GAME_TYPE_JGR); - if (bIsDMType || bIsIdleState || bIsPause) - { - CRecipientFilter filter; - filter.MakeReliable(); - - for (int i = 1; i <= gpGlobals->maxClients; i++) - { - auto player = static_cast(UTIL_PlayerByIndex(i)); - if (player && player->IsDead() && (bIsPause || player->DeathCount() > 0)) - { - const int playerTeam = player->GetTeamNumber(); - if ((playerTeam == TEAM_JINRAI || playerTeam == TEAM_NSF) && RespawnWithRet(player, false)) - { - player->m_bInAim = false; - player->m_bCarryingGhost = false; - player->m_bInThermOpticCamo = false; - player->m_bInVision = false; - player->m_bIneligibleForLoadoutPick = false; - player->SetTestMessageVisible(false); - - if (!bIsIdleState && !bIsPause && bIsDMType) - { - engine->ClientCommand(player->edict(), "loadoutmenu"); - } - else - { - filter.AddRecipient(player); - } - } - } - } - - if (filter.GetRecipientCount() > 0 && bIsIdleState) - { - UserMessageBegin(filter, "IdleRespawnShowMenu"); - MessageEnd(); - } - } +void CNEORules::PlayerRespawnThink() +{ + if (!(IsRoundIdle() || IsRoundPaused())) + return; - if (m_bThinkCheckClantags) + CRecipientFilter filter; + for (int i = 1; i <= gpGlobals->maxClients; i++) { - m_bThinkCheckClantags = false; - int iHasClantags[TEAM__TOTAL] = {}; - bool bClantagSet[TEAM__TOTAL] = {}; - char szTeamClantags[TEAM__TOTAL][NEO_MAX_CLANTAG_LENGTH] = {}; - for (int i = 1; i <= gpGlobals->maxClients; ++i) + auto player = static_cast(UTIL_PlayerByIndex(i)); + if (player && player->IsDead() && (IsRoundPaused() || player->DeathCount() > 0)) { - auto pNeoPlayer = static_cast(UTIL_PlayerByIndex(i)); - if (pNeoPlayer) + const int playerTeam = player->GetTeamNumber(); + if ((playerTeam == TEAM_JINRAI || playerTeam == TEAM_NSF) && RespawnWithRet(player, false)) { - const int iTeam = pNeoPlayer->GetTeamNumber(); - if (!bClantagSet[iTeam]) + player->m_bInAim = false; + player->m_bCarryingGhost = false; + player->m_bInThermOpticCamo = false; + player->m_bInVision = false; + player->m_bIneligibleForLoadoutPick = false; + player->SetTestMessageVisible(false); + + if (!IsRoundIdle() && !IsRoundPaused()) { - bClantagSet[iTeam] = true; - V_strcpy_safe(szTeamClantags[iTeam], pNeoPlayer->GetNeoClantag()), - ++iHasClantags[iTeam]; + engine->ClientCommand(player->edict(), "loadoutmenu"); } else { - iHasClantags[iTeam] += (V_strcmp(szTeamClantags[iTeam], pNeoPlayer->GetNeoClantag()) == 0); + filter.AddRecipient(player); } } } - - char *pszClantagMod[TEAM__TOTAL] = {}; - pszClantagMod[TEAM_JINRAI] = m_szNeoJinraiClantag.GetForModify(); - pszClantagMod[TEAM_NSF] = m_szNeoNSFClantag.GetForModify(); - for (const int i : {TEAM_JINRAI, TEAM_NSF}) - { - V_strncpy(pszClantagMod[i], (iHasClantags[i] == GetGlobalTeam(i)->GetNumPlayers()) ? - szTeamClantags[i] : "", NEO_MAX_CLANTAG_LENGTH); - } } - if (bIsPause) + if (filter.GetRecipientCount() > 0 && IsRoundIdle()) { - return; + filter.MakeReliable(); + UserMessageBegin(filter, "IdleRespawnShowMenu"); + MessageEnd(); } +} - CheckOvertime(); - - if (g_fGameOver) // someone else quit the game already +void CNEORules::CheckClantagsThink() +{ + if (!m_bThinkCheckClantags) + return; + + m_bThinkCheckClantags = false; + int iHasClantags[TEAM__TOTAL] = {}; + bool bClantagSet[TEAM__TOTAL] = {}; + char szTeamClantags[TEAM__TOTAL][NEO_MAX_CLANTAG_LENGTH] = {}; + for (int i = 1; i <= gpGlobals->maxClients; ++i) { - // check to see if we should change levels now - if (m_flIntermissionEndTime < gpGlobals->curtime) + auto pNeoPlayer = static_cast(UTIL_PlayerByIndex(i)); + if (pNeoPlayer) { - if (!m_bChangelevelDone) + const int iTeam = pNeoPlayer->GetTeamNumber(); + if (!bClantagSet[iTeam]) { - m_bChangelevelDone = true; - ChangeLevel(); // intermission is over + bClantagSet[iTeam] = true; + V_strcpy_safe(szTeamClantags[iTeam], pNeoPlayer->GetNeoClantag()), + ++iHasClantags[iTeam]; + } + else + { + iHasClantags[iTeam] += (V_strcmp(szTeamClantags[iTeam], pNeoPlayer->GetNeoClantag()) == 0); } } + } - return; + char *pszClantagMod[TEAM__TOTAL] = {}; + pszClantagMod[TEAM_JINRAI] = m_szNeoJinraiClantag.GetForModify(); + pszClantagMod[TEAM_NSF] = m_szNeoNSFClantag.GetForModify(); + for (const int i : {TEAM_JINRAI, TEAM_NSF}) + { + V_strncpy(pszClantagMod[i], (iHasClantags[i] == GetGlobalTeam(i)->GetNumPlayers()) ? + szTeamClantags[i] : "", NEO_MAX_CLANTAG_LENGTH); } -#endif +} - BaseClass::Think(); +bool CNEORules::GameOverThink() +{ + if (!g_fGameOver) + return false; -#ifdef GAME_DLL + // check to see if we should change levels now + if (m_flIntermissionEndTime < gpGlobals->curtime && !m_bChangelevelDone) + { + m_bChangelevelDone = true; + ChangeLevel(); // intermission is over + } + + return true; +} + +void CNEORules::TeamDamageThink() +{ if (MirrorDamageMultiplier() > 0.0f && gpGlobals->curtime > (m_flPrevThinkMirrorDmg + 0.25f)) { @@ -1327,7 +1094,10 @@ void CNEORules::Think(void) m_flPrevThinkKick = gpGlobals->curtime; } +} +bool CNEORules::RoundOverThink() +{ if (IsRoundOver()) { // If the next round was not scheduled yet @@ -1349,8 +1119,7 @@ void CNEORules::Think(void) { if (m_bGotMatchWinner) { - IGameEvent *event = gameeventmanager->CreateEvent("game_end"); - if (event) + if (IGameEvent *event = gameeventmanager->CreateEvent("game_end")) { event->SetInt("winner", m_iMatchWinner); gameeventmanager->FireEvent(event); @@ -1371,204 +1140,18 @@ void CNEORules::Think(void) } } - return; + return true; } // Note that exactly zero here means infinite round time. else if (GetRoundRemainingTime() < 0) { RoundTimeout(); } + return false; +} - if (m_pGhost) - { - // Update ghosting team info - int nextGhosterTeam = TEAM_UNASSIGNED; - int nextGhosterPlayerIdx = 0; - CNEO_Player *pGhosterPlayer = static_cast(m_pGhost->GetOwner()); - if (pGhosterPlayer) - { - nextGhosterTeam = pGhosterPlayer->GetTeamNumber(); - nextGhosterPlayerIdx = pGhosterPlayer->entindex(); - Assert(nextGhosterTeam == TEAM_JINRAI || nextGhosterTeam == TEAM_NSF); - m_pGhost->UpdateNearestGhostBeaconDist(); - } - m_iGhosterTeam = nextGhosterTeam; - m_iGhosterPlayer = nextGhosterPlayerIdx; - - Assert(UTIL_IsValidEntity(m_pGhost)); - - if (m_pGhost->GetAbsOrigin().IsValid()) - { - // Someone's carrying it - m_vecGhostMarkerPos = (nextGhosterTeam == TEAM_JINRAI || nextGhosterTeam == TEAM_NSF) ? - // NEO NOTE (Adam) GetGhostMarkerPos() can return m_vecGhostMarkerPos if m_pGhost is invalid, but we've checked for m_pGhost above so should be fine? - GetGhostMarkerPos() : m_pGhost->GetAbsOrigin(); - } - else - { - Assert(false); - } - - // Check if the ghost was capped during this Think - int captorTeam, captorClient; - for (int i = 0; i < m_pGhostCaps.Count(); i++) - { - auto pGhostCap = dynamic_cast(UTIL_EntityByIndex(m_pGhostCaps[i])); - if (!pGhostCap) - { - Assert(false); - continue; - } - - // If a ghost was captured - if (pGhostCap->IsGhostCaptured(captorTeam, captorClient)) - { - // Turn off all capzones - for (int i = 0; i < m_pGhostCaps.Count(); i++) - { - auto pGhostCap = dynamic_cast(UTIL_EntityByIndex(m_pGhostCaps[i])); - if (!pGhostCap) - { - Assert(false); - continue; - } - pGhostCap->SetActive(false); - } - - IGameEvent* event = gameeventmanager->CreateEvent("ghost_capture"); - if (event) - { - CBasePlayer* pCaptorClient = UTIL_PlayerByIndex(captorClient); - event->SetInt("userid", pCaptorClient ? pCaptorClient->GetUserID() : INVALID_USER_ID); - gameeventmanager->FireEvent(event); - } - - // And then announce team victory - SetWinningTeam(captorTeam, NEO_VICTORY_GHOST_CAPTURE, false, true, false, false); - - break; - } - } - } - else if (m_pJuggernautItem) - { - if (IsRoundLive() && (gpGlobals->curtime > (m_flNeoRoundStartTime + sv_neo_preround_freeze_time.GetFloat()) + 20.0f) && IsJuggernautLocked()) - { - UTIL_CenterPrintAll("- JUGGERNAUT ENABLED -\n"); - - EmitSound_t soundParams; - soundParams.m_pSoundName = "HUD.GhostPickUp"; - soundParams.m_nChannel = CHAN_USER_BASE; - soundParams.m_bWarnOnDirectWaveReference = false; - soundParams.m_bEmitCloseCaption = false; - soundParams.m_SoundLevel = ATTN_TO_SNDLVL(ATTN_NONE); - - CRecipientFilter soundFilter; - soundFilter.AddAllPlayers(); - soundFilter.MakeReliable(); - m_pJuggernautItem->EmitSound(soundFilter, m_pJuggernautItem->entindex(), soundParams); - - m_pJuggernautItem->m_bLocked = false; - } - } - - if (GetGameType() == NEO_GAME_TYPE_JGR && IsRoundLive()) - { - if (GetGlobalTeam(TEAM_JINRAI)->GetScore() >= sv_neo_jgr_max_points.GetInt()) - { - SetWinningTeam(TEAM_JINRAI, NEO_VICTORY_POINTS, false, true, false, false); - return; - } - - if (GetGlobalTeam(TEAM_NSF)->GetScore() >= sv_neo_jgr_max_points.GetInt()) - { - SetWinningTeam(TEAM_NSF, NEO_VICTORY_POINTS, false, true, false, false); - return; - } - } - - if (GetGameType() == NEO_GAME_TYPE_VIP && IsRoundLive() && !m_pGhost) - { - if (!m_pVIP) - { - if (sv_neo_vip_ctg_on_death.GetBool()) - { - UTIL_CenterPrintAll("- HVT DOWN - RECOVER THE GHOST -\n"); - SpawnTheGhost(); - } - else - { - // Assume vip player disconnected, forfeit round - SetWinningTeam(GetOpposingTeam(m_iEscortingTeam), NEO_VICTORY_FORFEIT, false, true, false, false); - } - IGameEvent* event = gameeventmanager->CreateEvent("vip_death"); - if (event) - { - gameeventmanager->FireEvent(event); - } - } - else if (!m_pVIP->IsAlive()) - { - if (sv_neo_vip_ctg_on_death.GetBool()) - { - UTIL_CenterPrintAll("- HVT DOWN - RECOVER THE GHOST -\n"); - SpawnTheGhost(&m_pVIP->GetAbsOrigin()); - } - else - { - // VIP was killed, end round - SetWinningTeam(GetOpposingTeam(m_iEscortingTeam), NEO_VICTORY_VIP_ELIMINATION, false, true, false, false); - } - IGameEvent* event = gameeventmanager->CreateEvent("vip_death"); - if (event) - { - event->SetInt("userid", m_pVIP->GetUserID()); - gameeventmanager->FireEvent(event); - } - } - - // Check if the vip was escorted during this Think - int captorTeam, captorClient; - for (int i = 0; i < m_pGhostCaps.Count(); i++) - { - auto pGhostCap = dynamic_cast(UTIL_EntityByIndex(m_pGhostCaps[i])); - if (!pGhostCap) - { - Assert(false); - continue; - } - - // If vip was escorted - if (pGhostCap->IsGhostCaptured(captorTeam, captorClient)) - { - // Turn off all capzones - for (int i = 0; i < m_pGhostCaps.Count(); i++) - { - auto pGhostCap = dynamic_cast(UTIL_EntityByIndex(m_pGhostCaps[i])); - if (!pGhostCap) - { - Assert(false); - continue; - } - pGhostCap->SetActive(false); - } - - // And then announce team victory - SetWinningTeam(captorTeam, NEO_VICTORY_VIP_ESCORT, false, true, false, false); - - IGameEvent* event = gameeventmanager->CreateEvent("vip_extract"); - if (event) - { - CBasePlayer* pCaptorClient = UTIL_PlayerByIndex(captorClient); - event->SetInt("userid", pCaptorClient ? pCaptorClient->GetUserID() : INVALID_USER_ID); - gameeventmanager->FireEvent(event); - } - - break; - } - } - } - +void CNEORules::RoundStatusThink() +{ if (m_nRoundStatus == NeoRoundStatus::PreRoundFreeze) { if (IsRoundOver()) @@ -1583,119 +1166,57 @@ void CNEORules::Think(void) } } } - else if (IsRoundLive()) - { - COMPILE_TIME_ASSERT(TEAM_JINRAI == 2 && TEAM_NSF == 3); - if (GetGameType() != NEO_GAME_TYPE_TDM && GetGameType() != NEO_GAME_TYPE_DM && GetGameType() != NEO_GAME_TYPE_JGR) - { - auto jinraiAlive = GetGlobalTeam(TEAM_JINRAI)->GetAliveMembers(); - auto nsfAlive = GetGlobalTeam(TEAM_NSF)->GetAliveMembers(); +} - if (jinraiAlive == 0 && nsfAlive == 0) { - SetWinningTeam(TEAM_SPECTATOR, NEO_VICTORY_STALEMATE, false, false, true, false); - } - else if(jinraiAlive == 0 || nsfAlive == 0) { - auto winningTeam = jinraiAlive > nsfAlive ? TEAM_JINRAI : TEAM_NSF; - SetWinningTeam(winningTeam, NEO_VICTORY_TEAM_ELIMINATION, false, true, false, false); - } - } - if (GetGameType() == NEO_GAME_TYPE_DM && sv_neo_dm_win_xp.GetInt() > 0) - { - // End game early if there's already a player past the winning XP - CNEO_Player *pHighestPlayers[MAX_PLAYERS + 1] = {}; - int iWinningTotal = 0; - int iWinningXP = 0; - GetDMHighestScorers(&pHighestPlayers, &iWinningTotal, &iWinningXP); - if (iWinningXP >= sv_neo_dm_win_xp.GetInt() && iWinningTotal == 1) - { - SetWinningDMPlayer(pHighestPlayers[0]); - } - } +void CNEORules::CheckWinByElimination() +{ + if (!IsRoundLive()) + return; + + const int jinraiAlive = GetGlobalTeam(TEAM_JINRAI)->GetAliveMembers(); + const int nsfAlive = GetGlobalTeam(TEAM_NSF)->GetAliveMembers(); + + if (jinraiAlive == 0 && nsfAlive == 0) { + SetWinningTeam(TEAM_SPECTATOR, NEO_VICTORY_STALEMATE, false, false, true, false); + } + else if(jinraiAlive == 0 || nsfAlive == 0) { + auto winningTeam = jinraiAlive > nsfAlive ? TEAM_JINRAI : TEAM_NSF; + SetWinningTeam(winningTeam, NEO_VICTORY_TEAM_ELIMINATION, false, true, false, false); } -#endif } +#endif // GAME_DLL -#ifdef GAME_DLL -void CNEORules::SetWinningDMPlayer(CNEO_Player *pWinner) +COMPILE_TIME_ASSERT(TEAM_JINRAI == 2 && TEAM_NSF == 3); +void CNEORules::Think(void) { - if (IsRoundOver()) - { +#ifdef GAME_DLL + if (RoundIdlePausedStartThink()) return; - } - if (auto pEntGameCfg = GetActiveGameConfig()) - { - pEntGameCfg->m_OnDMRoundEnd.FireOutput(pWinner, pEntGameCfg); - } + PlayerRespawnThink(); - SetRoundStatus(NeoRoundStatus::PostRound); - char victoryMsg[128]; - // TODO: Per client since client has neo_name settings - V_sprintf_safe(victoryMsg, "%s is the winner of the deathmatch!\n", pWinner->GetNeoPlayerName()); + CheckClantagsThink(); - CRecipientFilter filter; - filter.AddAllPlayers(); - UserMessageBegin(filter, "RoundResult"); - WRITE_STRING("tie"); - WRITE_FLOAT(gpGlobals->curtime); - WRITE_STRING(victoryMsg); - MessageEnd(); + if (IsRoundPaused()) + return; - EmitSound_t soundParams; - soundParams.m_nChannel = CHAN_AUTO; - soundParams.m_SoundLevel = SNDLVL_NONE; - soundParams.m_flVolume = 0.33f; - // Differing between Jinrai/NSF only as a sound cosmetic (no affect on DM) - const int team = pWinner->GetTeamNumber(); - soundParams.m_pSoundName = (team == TEAM_JINRAI) ? "gameplay/jinrai.mp3" : (team == TEAM_NSF) ? "gameplay/nsf.mp3" : "gameplay/draw.mp3"; - soundParams.m_bWarnOnDirectWaveReference = false; - soundParams.m_bEmitCloseCaption = false; + GameOverThink(); + + CheckOvertime(); - for (int i = 1; i <= gpGlobals->maxClients; ++i) - { - CBasePlayer* basePlayer = UTIL_PlayerByIndex(i); - auto player = static_cast(basePlayer); - if (player) - { - if (!player->IsBot() || player->IsHLTV()) - { - const char* volStr = engine->GetClientConVarValue(i, "snd_victory_volume"); - const float jingleVolume = volStr ? atof(volStr) : 0.33f; - soundParams.m_flVolume = jingleVolume; + BaseClass::Think(); - CRecipientFilter soundFilter; - soundFilter.AddRecipient(basePlayer); - soundFilter.MakeReliable(); - player->EmitSound(soundFilter, i, soundParams); - } - } - } + TeamDamageThink(); - GoToIntermission(); + if (RoundOverThink()) + return; - IGameEvent *event = gameeventmanager->CreateEvent("game_end"); - if (event) - { - event->SetInt("winner", pWinner->GetUserID()); - gameeventmanager->FireEvent(event); - } -} + RoundStatusThink(); #endif - -void CNEORules::AwardRankUp(int client) -{ - auto player = UTIL_PlayerByIndex(client); - if (player) - { - AwardRankUp(static_cast(player)); - } } -#ifdef CLIENT_DLL -void CNEORules::AwardRankUp(C_NEO_Player *pClient) -#else +#ifdef GAME_DLL void CNEORules::AwardRankUp(CNEO_Player *pClient) -#endif { Assert(m_nRoundStatus != NeoRoundStatus::Pause); if (m_nRoundStatus == NeoRoundStatus::Pause) @@ -1721,41 +1242,12 @@ void CNEORules::AwardRankUp(CNEO_Player *pClient) // If we're beyond max rank, just award +1 point. pClient->AddPoints(1, false, true); } +#endif -void CNEORules::CheckOvertime() -{ - bool overtimeEnabled; - float overtimeGrace; - float roundTimeLimit; - - switch (m_nGameTypeSelected) - { - case NEO_GAME_TYPE_CTG: - overtimeEnabled = sv_neo_ctg_ghost_overtime_enabled.GetBool(); - roundTimeLimit = neo_ctg_round_timelimit.GetFloat() * 60; - overtimeGrace = sv_neo_ctg_ghost_overtime_grace.GetFloat(); - break; - case NEO_GAME_TYPE_ATK: - overtimeEnabled = sv_neo_atk_ghost_overtime_enabled.GetBool(); - roundTimeLimit = neo_atk_round_timelimit.GetFloat() * 60; - overtimeGrace = sv_neo_atk_ghost_overtime_grace.GetFloat(); - break; - default: - return; - } +ConVar sv_neo_tdm_score_limit("sv_neo_tdm_score_limit", "1", FCVAR_REPLICATED, "TDM score limit", true, 0.0f, true, 99.0f); +ConVar sv_neo_tdm_round_limit("sv_neo_tdm_round_limit", "0", FCVAR_REPLICATED, "TDM max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +ConVar neo_tdm_round_timelimit("neo_tdm_round_timelimit", "10.25", FCVAR_REPLICATED, "TDM round timelimit, in minutes.", true, 0.0f, false, 600.0f); - if (overtimeEnabled && m_nRoundStatus == NeoRoundStatus::RoundLive && m_iGhosterPlayer && - (m_nGameTypeSelected != NEO_GAME_TYPE_ATK || m_iGhosterTeam == GetAttackingTeam()) && // only the attacking team gets overtime in ATK - (m_flNeoRoundStartTime + roundTimeLimit - overtimeGrace) < gpGlobals->curtime) - { - m_nRoundStatus = NeoRoundStatus::Overtime; - } - - if (m_nRoundStatus == NeoRoundStatus::Overtime && m_iGhosterPlayer) - { - m_flGhostLastHeld = gpGlobals->curtime; - } -} // Return remaining time in seconds. Zero means there is no time limit. float CNEORules::GetRoundRemainingTime() const @@ -2257,40 +1749,6 @@ void CNEORules::JuggernautTotalRemoval(CNEO_Juggernaut *pJuggernaut) } } -void CNEORules::GatherGameTypeVotes() -{ - int gameTypes[NEO_GAME_TYPE__TOTAL] = {}; - - for (int i = 1; i <= gpGlobals->maxClients; i++) - { - if (CBasePlayer* pPlayer = static_cast(UTIL_PlayerByIndex(i))) - { - if (pPlayer->IsBot()) - continue; - const char *clientGameTypeVote = engine->GetClientConVarValue(i, "neo_vote_game_mode"); - if (!clientGameTypeVote) - continue; - if (!clientGameTypeVote[0]) - continue; - int gameType = atoi(clientGameTypeVote); - gameTypes[gameType]++; - } - } - - int mostVotes = gameTypes[0]; - int mostPopularGameType = 0; - for (int i = 1; i < NEO_GAME_TYPE__TOTAL; i++) - { - if (gameTypes[i] > mostVotes) // NEOTODO (Adam) Handle draws - { - mostVotes = gameTypes[i]; - mostPopularGameType = i; - } - } - - m_nGameTypeSelected = mostPopularGameType; -} - bool CNEORules::ReadyUpPlayerIsReady(CNEO_Player *pNeoPlayer) const { if (!pNeoPlayer) return false; @@ -2820,11 +2278,6 @@ void CNEORules::StartNextRound() const bool bFromStarting = (m_nRoundStatus == NeoRoundStatus::Warmup || m_nRoundStatus == NeoRoundStatus::Countdown); - if (sv_neo_gamemode_enforcement.GetInt() == GAMEMODE_ENFORCEMENT_VOTE && bFromStarting) - { - GatherGameTypeVotes(); - } - // NEO TODO (nullsystem): There should be a more sophisticated logic to be able to restore XP // for when moving from idle to preroundfreeze, or in the future, competitive with whatever // extra stuff in there. But to keep it simple: just clear if it was a warmup. @@ -3064,6 +2517,23 @@ bool CNEORules::IsRoundOn() const return (m_nRoundStatus == NeoRoundStatus::PreRoundFreeze) || IsRoundLive() || (m_nRoundStatus == NeoRoundStatus::PostRound); } +bool CNEORules::IsRoundIdle() const +{ + switch (m_nRoundStatus) + { + case NeoRoundStatus::Idle: + case NeoRoundStatus::Warmup: + case NeoRoundStatus::Countdown: + return false; + } + return true; +} + +bool CNEORules::IsRoundPaused() const +{ + return m_nRoundStatus == NeoRoundStatus::Pause; +} + void CNEORules::CreateStandardEntities(void) { BaseClass::CreateStandardEntities(); @@ -3155,7 +2625,7 @@ void CNEORules::CleanUpMap() CNEOBaseCombatWeapon *pWeapon = dynamic_cast(pCur); if (pWeapon) { - UTIL_Remove(pCur); + UTIL_Remove(pCur); // NEO TODO (Adam) are there any weapons in s_NeoPreserveEnts that wouldn't be removed if we didnt check for cneobasecombatweapon here? } // remove entities that has to be restored on roundrestart (breakables etc) else if (!FindInList(s_NeoPreserveEnts, pCur->GetClassname())) @@ -3243,18 +2713,13 @@ void CNEORules::CleanUpMap() ResetGhostCapPoints(); // OnCompetitive needs to fire every time the map resets, along with all the entities, props, etc. - auto pEntGameCfg = GetActiveGameConfig(); - if (pEntGameCfg && sv_neo_comp.GetBool()) + if (auto pEntGameCfg = NEOGameConfig(); + pEntGameCfg && sv_neo_comp.GetBool()) { pEntGameCfg->m_OnCompetitive.FireOutput(nullptr, pEntGameCfg); } } -void CNEORules::CheckRestartGame() -{ - BaseClass::CheckRestartGame(); -} - void CNEORules::PurgeGhostCapPoints() { m_pGhostCaps.Purge(); @@ -3412,7 +2877,7 @@ void CNEORules::ResetJGR() void CNEORules::RestartGame() { // bounds check - if (mp_timelimit.GetInt() < 0) + if (mp_timelimit.GetInt() < 0) // NEO NOTE (Adam) Just give mp_timelimit cvar a lower bound of 0? { mp_timelimit.SetValue(0); } @@ -3464,19 +2929,6 @@ void CNEORules::RestartGame() m_bCompleteReset = false; ResetMapSessionCommon(); - - // NEO FIXME (Rain): this GatherGameTypeVotes business seems a bit wonky, - // since it'll just gather the clients' "neo_vote_game_mode" cvar values - // without prompting for some kind of a vote. So the most likely result - // is the map just switching to the "neo_vote_game_mode" default value (CTG), - // which may not be appropriate for the map. - const bool bFromStarting = (m_nRoundStatus == NeoRoundStatus::Warmup - || m_nRoundStatus == NeoRoundStatus::Countdown); - if (sv_neo_gamemode_enforcement.GetInt() == GAMEMODE_ENFORCEMENT_VOTE && bFromStarting) - { - GatherGameTypeVotes(); - } - SetGameRelatedVars(); IGameEvent * event = gameeventmanager->CreateEvent("round_start"); @@ -3798,7 +3250,7 @@ void CNEORules::SetWinningTeam(int team, int iWinReason, bool bForceMapReset, bo return; } - if (auto pEntGameCfg = GetActiveGameConfig()) + if (auto pEntGameCfg = NEOGameConfig()) { pEntGameCfg->m_OnRoundEnd.Set(team, nullptr, pEntGameCfg); } @@ -4320,9 +3772,9 @@ const char* CNEORules::GetChatFormat(bool bTeamOnly, CBasePlayer* pPlayer) } #endif -#ifdef GAME_DLL void CNEORules::DeathNotice(CBasePlayer* pVictim, const CTakeDamageInfo& info) { +#ifdef GAME_DLL // Work out what killed the player, and send a message to all clients about it const char* killer_weapon_name = "world"; // by default, the player is killed by the world int killer_ID = 0; @@ -4444,8 +3896,8 @@ void CNEORules::DeathNotice(CBasePlayer* pVictim, const CTakeDamageInfo& info) gameeventmanager->FireEvent(event); } +#endif // GAME_DLL } -#endif #ifdef GAME_DLL void CNEORules::ClientDisconnected(edict_t* pClient) @@ -4622,6 +4074,7 @@ CBaseEntity *CNEORules::GetPlayerSpawnSpot(CBasePlayer *pPlayer) #endif +#ifdef GAME_DLL void CNEORules::SetRoundStatus(NeoRoundStatus status) { if (status != NeoRoundStatus::PreRoundFreeze && status != NeoRoundStatus::PostRound) @@ -4635,20 +4088,17 @@ void CNEORules::SetRoundStatus(NeoRoundStatus status) player->RemoveNeoFlag(NEO_FL_FREEZETIME); } } -#ifdef GAME_DLL if (status == NeoRoundStatus::RoundLive) { UTIL_CenterPrintAll("- GO! GO! GO! -\n"); - if (auto pEntGameCfg = GetActiveGameConfig()) + if (auto pEntGameCfg = NEOGameConfig()) { pEntGameCfg->m_OnRoundStart.FireOutput(nullptr, pEntGameCfg); } } -#endif } -#ifdef GAME_DLL if (status == NeoRoundStatus::PreRoundFreeze) { // we clear these so people who rejoin on a different round to the round when they left aren't prevented from spawning. This is done before all players are // spawned on the new round so these values will be overwritten for those players who are still in the game @@ -4664,10 +4114,10 @@ void CNEORules::SetRoundStatus(NeoRoundStatus status) m_bIsMatchPoint = RoundIsMatchPoint(); m_bIsInSuddenDeath = RoundIsInSuddenDeath(); } -#endif // GAME_DLL m_nRoundStatus = status; } +#endif NeoRoundStatus CNEORules::GetRoundStatus() const { @@ -4835,8 +4285,8 @@ const char *CNEORules::GetTeamClantag(const int iTeamNum) const void CNEORules::OnNavMeshLoad(void) { // We need to access the game config directly because the game type might not be set at this stage - auto cfg = GetActiveGameConfig(); - if (!cfg || cfg->m_GameType != NEO_GAME_TYPE_DM) + if (auto pEntGameCfg = NEOGameConfig(); + !pEntGameCfg || pEntGameCfg->m_GameType != NEO_GAME_TYPE_DM) { TheNavMesh->SetPlayerSpawnName("info_player_defender"); } diff --git a/src/game/shared/neo/neo_gamerules.h b/src/game/shared/neo/gamerules/neo_gamerules.h similarity index 78% rename from src/game/shared/neo/neo_gamerules.h rename to src/game/shared/neo/gamerules/neo_gamerules.h index 79dcf4b2b7..4e03eebcdd 100644 --- a/src/game/shared/neo/neo_gamerules.h +++ b/src/game/shared/neo/gamerules/neo_gamerules.h @@ -24,8 +24,6 @@ #include "utlhashtable.h" #endif -#include "neo_player_shared.h" - #ifdef CLIENT_DLL #define CNEORules C_NEORules #define CNEOGameRulesProxy C_NEOGameRulesProxy @@ -173,201 +171,165 @@ enum NeoSpectateEvent { class CNEORules : public CHL2MPRules, public CGameEventListener { -public: - DECLARE_CLASS( CNEORules, CHL2MPRules ); -// This makes datatables able to access our private vars. -#ifdef CLIENT_DLL - DECLARE_CLIENTCLASS_NOBASE(); +#ifdef GAME_DLL +friend class CNEORulesATK; +friend class CNEORulesCTG; +friend class CNEORulesDM; +friend class CNEORulesEMT; +friend class CNEORulesJGR; +friend class CNEORulesTDM; +friend class CNEORulesTUT; +friend class CNEORulesVIP; #else - DECLARE_SERVERCLASS_NOBASE(); -#endif +friend class C_NEORulesATK; +friend class C_NEORulesCTG; +friend class C_NEORulesDM; +friend class C_NEORulesEMT; +friend class C_NEORulesJGR; +friend class C_NEORulesTDM; +friend class C_NEORulesTUT; +friend class C_NEORulesVIP; +#endif // GAME_DLL + +public: + DECLARE_CLASS( CNEORules, CHL2MPRules ); + // This makes datatables able to access our private vars. + DECLARE_NETWORKCLASS_NOBASE(); + CNEORules(); virtual ~CNEORules(); + + // IGameEventListener interface: + virtual void FireGameEvent(IGameEvent *event) OVERRIDE; + + virtual void Think() OVERRIDE; + + // This is the supposed encrypt key on NT, although it has its issues. + // See https://steamcommunity.com/groups/ANPA/discussions/0/1482109512299590948/ + // (and NT Discord) for discussions. + virtual const unsigned char* GetEncryptionKey(void) OVERRIDE { return (unsigned char*)"tBA%-ygc"; } #ifdef GAME_DLL - virtual void Precache() OVERRIDE; + bool RoundIdlePausedStartThink(); + virtual void PlayerRespawnThink(); + void CheckClantagsThink(); + bool GameOverThink(); + void TeamDamageThink(); + bool RoundOverThink(); + void RoundStatusThink(); + void CheckWinByElimination(); + + virtual void Precache() override; + virtual void InitDefaultAIRelationships(void); // NEO NOTE (Adam) override? + + + virtual bool ClientConnected(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) override; + virtual bool ClientCommand(CBaseEntity* pEdict, const CCommand& args) override; + virtual void ClientDisconnected(edict_t* pClient) override; + virtual const char* GetChatFormat(bool bTeamOnly, CBasePlayer* pPlayer) OVERRIDE; + virtual const char* GetChatPrefix(bool bTeamOnly, CBasePlayer* pPlayer) OVERRIDE { return ""; } // handled by GetChatFormat + virtual const char* GetChatLocation(bool bTeamOnly, CBasePlayer* pPlayer) OVERRIDE { return NULL; } // unimplemented - virtual bool ClientConnected(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) OVERRIDE; + CBaseEntity *GetPlayerSpawnSpot(CBasePlayer *pPlayer) override; + virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) OVERRIDE; + virtual float FlPlayerFallDamage(CBasePlayer* pPlayer) OVERRIDE; - virtual bool ClientCommand(CBaseEntity* pEdict, const CCommand& args) OVERRIDE; virtual void SetWinningTeam(int team, int iWinReason, bool bForceMapReset = true, bool bSwitchTeams = false, bool bDontAddScore = false, bool bFinal = false) OVERRIDE; - void SetWinningDMPlayer(CNEO_Player *pWinner); - - virtual void ChangeLevel(void) OVERRIDE; - - virtual void ClientDisconnected(edict_t* pClient) OVERRIDE; + void AwardRankUp(CNEO_Player *pClient); + void SetRoundStatus(NeoRoundStatus status); - CBaseEntity *GetPlayerSpawnSpot(CBasePlayer *pPlayer) override; - virtual bool IsOfficialMap(void) override; + // NEOGameConfig is a logic entity, which is a server only entity. To access config values client side, we need to copy values to a networked entity + void UpdateFromGameConfig(); + void StartNextRound(); + void RoundTimeout(); + bool RoundTimeoutTDM(); // NEO TODO (Adam) move to related gamerules + bool RoundTimeoutDM(); // NEO TODO (Adam) move to related gamerules + bool RoundTimeoutJGR(); // NEO TODO (Adam) move to related gamerules + bool RoundTimeoutATK(); // NEO TODO (Adam) move to related gamerules - virtual void MarkAchievement ( IRecipientFilter& filter, char const *pchAchievementName ) override; - virtual void InitDefaultAIRelationships(void); -#endif - virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 ) OVERRIDE; + struct ReadyPlayers + { + int array[TEAM__TOTAL]; + }; + void CheckChatCommand(CNEO_Player *pNeoPlayer, const char *pSzChat); + ReadyPlayers FetchReadyPlayers() const; // NEO TODO (Adam) This needs to be shown in the ui somewhere instead, ready up button + CUtlHashtable m_readyAccIDs; // NEO NOTE (Adam) What's wrong with player ent index + bool m_bIgnoreOverThreshold = false; + bool ReadyUpPlayerIsReady(CNEO_Player *pNeoPlayer) const; - virtual const char* GetGameName() { return NEO_GAME_NAME; } -#ifdef NEO - bool GetTeamPlayEnabled() const override; -#endif + virtual void CleanUpMap() OVERRIDE; + virtual void RestartGame() OVERRIDE; + virtual void ChangeLevel(void) OVERRIDE; -#ifdef GAME_DLL - virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) OVERRIDE; + virtual bool IsOfficialMap(void) override; + virtual void MarkAchievement ( IRecipientFilter& filter, char const *pchAchievementName ) override; #endif - virtual int GetGameType(void) OVERRIDE; - int GetHiddenHudElements(); - int GetForcedTeam(); - int GetForcedClass(); - int GetForcedSkin(); - int GetForcedWeapon(); - bool IsCyberspace(); - virtual const char* GetGameTypeName(void) OVERRIDE; - bool CanChangeTeamClassLoadoutWhenAlive(); - bool CanRespawnAnyTime(); - - void GetDMHighestScorers( -#ifdef GAME_DLL - CNEO_Player *(*pHighestPlayers)[MAX_PLAYERS + 1], -#endif - int *iHighestPlayersTotal, - int *iHighestXP) const; +#ifdef CLIENT_DLL +#endif // CLIENT_DLL - virtual void Think( void ) OVERRIDE; virtual void CreateStandardEntities( void ) OVERRIDE; - - virtual const char *GetGameDescription( void ) OVERRIDE; virtual const CViewVectors* GetViewVectors() const OVERRIDE; - const NEOViewVectors* GetNEOViewVectors() const; - virtual void ClientSettingsChanged(CBasePlayer *pPlayer) OVERRIDE; + virtual void ClientSettingsChanged(CBasePlayer *pPlayer) OVERRIDE; virtual void ClientSpawned(edict_t* pPlayer) OVERRIDE; + + virtual void PlayerKilled(CBasePlayer *pVictim, const CTakeDamageInfo &info) OVERRIDE; + virtual void DeathNotice(CBasePlayer* pVictim, const CTakeDamageInfo& info) OVERRIDE; - virtual void DeathNotice(CBasePlayer* pVictim, const CTakeDamageInfo& info) OVERRIDE -#ifdef CLIENT_DLL - { } -#else - ; -#endif - - bool RoundIsInSuddenDeath() const; - bool RoundIsMatchPoint() const; - bool RoundIsDoOrDie() const; + virtual const char* GetGameName() { return NEO_GAME_NAME; } + virtual const char* GetGameTypeName(void) override; + virtual int GetGameType(void) override; + virtual const char *GetGameDescription( void ) override; + bool GetTeamPlayEnabled() const override; + int GetHiddenHudElements(); + int GetForcedTeam(); + int GetForcedClass(); + int GetForcedSkin(); + int GetForcedWeapon(); + bool IsCyberspace(); + bool CanChangeTeamClassLoadoutWhenAlive(); // NEO TODO (Adam) Replace with gamemode specific check wherever used + bool CanRespawnAnyTime(); // NEO TODO (Adam) Replace with gamemode specific check wherever used virtual int DefaultFOV(void) override; - + + bool CheckShouldNotThink(); // NEO TODO (Adam) Remove + + const char *GetTeamClantag(const int iTeamNum) const; + inline int roundNumber() const { return m_iRoundNumber; } + inline bool roundNumberIsEven() const { return (roundNumber() % 2 == 0); } + NeoRoundStatus GetRoundStatus() const; + int GetAttackingTeam() const; + int GetDefendingTeam() const; float GetRemainingPreRoundFreezeTime(const bool clampToZero) const; - float GetMapRemainingTime(); - - void PurgeGhostCapPoints(); - - void ResetGhostCapPoints(); - - void SetGameRelatedVars(); - void ResetTDM(); - void ResetGhost(); - void ResetVIP(); - void ResetJGR(); - - void CheckRestartGame(); - - void AwardRankUp(int client); -#ifdef CLIENT_DLL - void AwardRankUp(C_NEO_Player *pClient); -#else - void AwardRankUp(CNEO_Player *pClient); -#endif - - virtual bool CheckGameOver(void) OVERRIDE; - - void CheckOvertime(); - float GetRoundRemainingTime() const; float GetOverTime(NeoGameType eGameType) const; + virtual void CheckOvertime(); + virtual bool CheckGameOver(void) OVERRIDE; // NEO TODO (Adam) this changes map as a side effect, better name? Also is this called client side anywhere? float GetRoundAccumulatedTime() const; #ifdef GAME_DLL float MirrorDamageMultiplier() const; #endif - -#ifdef GAME_DLL - void CheckIfCapPrevent(CNEO_Player *capPreventerPlayer); -#endif - virtual void PlayerKilled(CBasePlayer *pVictim, const CTakeDamageInfo &info) OVERRIDE; - - // IGameEventListener interface: - virtual void FireGameEvent(IGameEvent *event) OVERRIDE; - -#ifdef CLIENT_DLL - void CleanUpMap(); - void RestartGame(); -#else - virtual void CleanUpMap() OVERRIDE; - virtual void RestartGame() OVERRIDE; - - virtual float FlPlayerFallDamage(CBasePlayer* pPlayer) OVERRIDE; -#endif + bool RoundIsInSuddenDeath() const; + bool RoundIsMatchPoint() const; + bool RoundIsDoOrDie() const; bool IsRoundPreRoundFreeze() const; bool IsRoundLive() const; bool IsRoundOn() const; bool IsRoundOver() const; -#ifdef GAME_DLL - void GatherGameTypeVotes(); - - struct ReadyPlayers - { - int array[TEAM__TOTAL]; - }; - void CheckChatCommand(CNEO_Player *pNeoPlayer, const char *pSzChat); - ReadyPlayers FetchReadyPlayers() const; - CUtlHashtable m_readyAccIDs; - bool m_bIgnoreOverThreshold = false; - bool ReadyUpPlayerIsReady(CNEO_Player *pNeoPlayer) const; - - void CheckGameType(); - void CheckGameConfig(); - void StartNextRound(); - void RoundTimeout(); - bool RoundTimeoutTDM(); - bool RoundTimeoutDM(); - bool RoundTimeoutJGR(); - bool RoundTimeoutATK(); - - virtual const char* GetChatFormat(bool bTeamOnly, CBasePlayer* pPlayer) OVERRIDE; - virtual const char* GetChatPrefix(bool bTeamOnly, CBasePlayer* pPlayer) OVERRIDE { return ""; } // handled by GetChatFormat - virtual const char* GetChatLocation(bool bTeamOnly, CBasePlayer* pPlayer) OVERRIDE { return NULL; } // unimplemented -#endif - bool CheckShouldNotThink(); - - void SetRoundStatus(NeoRoundStatus status); - NeoRoundStatus GetRoundStatus() const; - - // This is the supposed encrypt key on NT, although it has its issues. - // See https://steamcommunity.com/groups/ANPA/discussions/0/1482109512299590948/ - // (and NT Discord) for discussions. - virtual const unsigned char* GetEncryptionKey(void) OVERRIDE { return (unsigned char*)"tBA%-ygc"; } - - int GetGhosterTeam() const { return m_iGhosterTeam; } - int GetGhosterPlayer() const { return m_iGhosterPlayer; } - bool GhostExists() const { return m_bGhostExists; } - const Vector& GetGhostPos() const; - Vector GetGhostMarkerPos() const; - - int GetJuggernautPlayer() const { return m_iJuggernautPlayerIndex; } - bool JuggernautItemExists() const; - const Vector& GetJuggernautMarkerPos() const; - bool IsJuggernautLocked() const; - - - int GetOpposingTeam(const int team) const + bool IsRoundIdle() const; + inline bool IsRoundPaused() const; + int GetOpposingTeam(const int team) const // NEO TODO (Adam) move to .cpp and / or gamemode specific gamerules { if (team == TEAM_JINRAI) { return TEAM_NSF; } if (team == TEAM_NSF) { return TEAM_JINRAI; } @@ -375,7 +337,7 @@ class CNEORules : public CHL2MPRules, public CGameEventListener return TEAM_SPECTATOR; } - int GetOpposingTeam(const CBaseCombatCharacter* player) const + int GetOpposingTeam(const CBaseCombatCharacter* player) const // NEO TODO (Adam) move to .cpp and / or gamemode specific gamerules { if (!player) { @@ -385,37 +347,61 @@ class CNEORules : public CHL2MPRules, public CGameEventListener return GetOpposingTeam(player->GetTeamNumber()); } - - inline int roundNumber() const { return m_iRoundNumber; } - inline bool roundNumberIsEven() const { return (roundNumber() % 2 == 0); } - int GetAttackingTeam() const; - int GetDefendingTeam() const; - #ifdef GLOWS_ENABLE void GetTeamGlowColor(int teamNumber, float &r, float &g, float &b) +{ + if (teamNumber == TEAM_JINRAI) { - if (teamNumber == TEAM_JINRAI) - { - r = static_cast(COLOR_JINRAI.r()/255.f); - g = static_cast(COLOR_JINRAI.g()/255.f); - b = static_cast(COLOR_JINRAI.b()/255.f); - } - else if (teamNumber == TEAM_NSF) - { - r = static_cast(COLOR_NSF.r()/255.f); - g = static_cast(COLOR_NSF.g()/255.f); - b = static_cast(COLOR_NSF.b()/255.f); - } - else - { - r = 0.76f; - g = 0.76f; - b = 0.76f; - } + r = static_cast(COLOR_JINRAI.r()/255.f); + g = static_cast(COLOR_JINRAI.g()/255.f); + b = static_cast(COLOR_JINRAI.b()/255.f); + } + else if (teamNumber == TEAM_NSF) + { + r = static_cast(COLOR_NSF.r()/255.f); + g = static_cast(COLOR_NSF.g()/255.f); + b = static_cast(COLOR_NSF.b()/255.f); } + else + { + r = 0.76f; + g = 0.76f; + b = 0.76f; + } +} #endif - const char *GetTeamClantag(const int iTeamNum) const; + + virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 ) OVERRIDE; + + void PurgeGhostCapPoints(); // NEO TODO (Adam) move to ctg / vip gamerules + void ResetGhostCapPoints(); // NEO TODO (Adam) move to ctg / vip gamerules + + void SetGameRelatedVars(); // NEO TODO (Adam) move to related gamerules + void ResetTDM(); // NEO TODO (Adam) move to related gamerules + void ResetGhost(); // NEO TODO (Adam) move to related gamerules + void ResetVIP(); // NEO TODO (Adam) move to related gamerules + void ResetJGR(); // NEO TODO (Adam) move to related gamerules + + +#ifdef GAME_DLL + void CheckIfCapPrevent(CNEO_Player *capPreventerPlayer); // NEO TODO (Adam) move to related gamerules +#endif + + // NEO TODO (Adam) Move to gamemode specific gamerules + int GetGhosterTeam() const { return m_iGhosterTeam; } + int GetGhosterPlayer() const { return m_iGhosterPlayer; } + bool GhostExists() const { return m_bGhostExists; } + const Vector& GetGhostPos() const; + Vector GetGhostMarkerPos() const; + + // NEO TODO (Adam) Move to gamemode specific gamerules + int GetJuggernautPlayer() const { return m_iJuggernautPlayerIndex; } + bool JuggernautItemExists() const; + const Vector& GetJuggernautMarkerPos() const; + bool IsJuggernautLocked() const; + + #ifdef GAME_DLL void OnNavMeshLoad() override; #endif // GAME_DL: @@ -445,7 +431,7 @@ class CNEORules : public CHL2MPRules, public CGameEventListener CNetworkVar(float, m_flPauseEnd); private: - void ResetMapSessionCommon(); + void ResetMapSessionCommon(); // NEO TODO (Adam) Is this needed client side #ifdef GAME_DLL const int GetScoreLimit() const; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp new file mode 100644 index 0000000000..cf84f73d79 --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp @@ -0,0 +1,115 @@ +#include "cbase.h" +#include "neo_gamerules_atk.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +REGISTER_GAMERULES_CLASS( CNEORulesATK ); + +BEGIN_NETWORK_TABLE_NOBASE( CNEORulesATK, DT_NEORulesATK ) +END_NETWORK_TABLE() + +LINK_ENTITY_TO_CLASS( neo_gamerules_atk, CNEOGameRulesATKProxy ); +IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesATKProxy, DT_NEOGameRulesATKProxy ); + +#ifdef CLIENT_DLL + void RecvProxy_NEORulesATK( const RecvProp *pProp, void **pOut, + void *pData, int objectID ) + { + CNEORulesATK *pRules = NEORulesATK(); + Assert( pRules ); + *pOut = pRules; + } + + BEGIN_RECV_TABLE( CNEOGameRulesATKProxy, DT_NEOGameRulesATKProxy ) + RecvPropDataTable( "neo_gamerules_atk_data", 0, 0, + &REFERENCE_RECV_TABLE( DT_NEORulesATK ), + RecvProxy_NEORulesATK ) + END_RECV_TABLE() +#else + void *SendProxy_NEORulesATK( const SendProp *pProp, + const void *pStructBase, const void *pData, + CSendProxyRecipients *pRecipients, int objectID ) + { + CNEORulesATK *pRules = NEORulesATK(); + Assert( pRules ); + return pRules; + } + + BEGIN_SEND_TABLE(CNEOGameRulesATKProxy, DT_NEOGameRulesATKProxy) + SendPropDataTable("neo_gamerules_atk_data", 0, + &REFERENCE_SEND_TABLE(DT_NEORulesATK), + SendProxy_NEORulesATK) + END_SEND_TABLE() +#endif + +ConVar sv_neo_atk_round_timelimit("neo_atk_round_timelimit", "3.25", FCVAR_REPLICATED, "ATK round timelimit, in minutes.", true, 0.0f, false, 600.0f); + +ConVar sv_neo_atk_ghost_overtime_enabled("sv_neo_atk_ghost_overtime_enabled", "0", FCVAR_REPLICATED, "Enable ghost overtime in the ATK mode.", true, 0, true, 1); +ConVar sv_neo_atk_ghost_overtime("sv_neo_atk_ghost_overtime", "45", FCVAR_REPLICATED, "Adds up to this many seconds to the round while the ghost is held.", true, 0, true, 120); +ConVar sv_neo_atk_ghost_overtime_grace("sv_neo_atk_ghost_overtime_grace", "10", FCVAR_REPLICATED, "Number of seconds left in the round when the ghost is dropped in overtime.", true, 0, true, 30); +ConVar sv_neo_atk_ghost_overtime_grace_decay("sv_neo_atk_ghost_overtime_grace_decay", "0", FCVAR_REPLICATED, "Slowly reduce the grace time as overtime goes on.", true, 0, true, 1); + +// +//CNEORulesATK::CNEORulesATK() +//{ +//} +// +//CNEORulesATK::~CNEORulesATK() +//{ +//} + +void CNEORulesATK::FireGameEvent(IGameEvent* event) +{ + BaseClass::FireGameEvent(event); +} + +void CNEORulesATK::CheckOvertime() +{ + if (!sv_neo_atk_ghost_overtime_enabled.GetBool()) + return; + + float overtimeGrace = sv_neo_atk_round_timelimit.GetFloat() * 60; + float roundTimeLimit = sv_neo_atk_ghost_overtime_grace.GetFloat(); + + if (NeoRoundStatus::RoundLive == m_nRoundStatus && m_iGhosterPlayer && GetAttackingTeam() == m_iGhosterTeam && + (m_flNeoRoundStartTime + roundTimeLimit - overtimeGrace) < gpGlobals->curtime) + { + m_nRoundStatus = NeoRoundStatus::Overtime; + } + + if (m_nRoundStatus == NeoRoundStatus::Overtime && m_iGhosterPlayer) + { + m_flGhostLastHeld = gpGlobals->curtime; + } +} + +void CNEORulesATK::Think() +{ +#ifdef GAME_DLL + if (RoundIdlePausedStartThink()) + return; + + PlayerRespawnThink(); + + CheckClantagsThink(); + + if (IsRoundPaused()) + return; + + GameOverThink(); + + CheckOvertime(); + + CHL2MPRules::Think(); + + TeamDamageThink(); + + if (RoundOverThink()) + return; + + RoundStatusThink(); + + CheckWinByElimination(); +#endif // GAME_DLL +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_atk.h b/src/game/shared/neo/gamerules/neo_gamerules_atk.h new file mode 100644 index 0000000000..115466f54b --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_atk.h @@ -0,0 +1,42 @@ +#pragma once + +#include "neo_gamerules.h" +#include "GameEventListener.h" + +#ifdef CLIENT_DLL + #define CNEORulesATK C_NEORulesATK + #define CNEOGameRulesATKProxy C_NEOGameRulesATKProxy +#endif +// +//ConVar sv_neo_atk_score_limit("sv_neo_atk_score_limit", "1", FCVAR_REPLICATED, "ATK score limit", true, 0.0f, true, 99.0f); +//ConVar sv_neo_atk_round_limit("sv_neo_atk_round_limit", "0", FCVAR_REPLICATED, "ATK max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +//ConVar sv_neo_atk_round_timelimit("neo_atk_round_timelimit", "10.25", FCVAR_REPLICATED, "ATK round timelimit, in minutes.", true, 0.0f, false, 600.0f); + +class CNEOGameRulesATKProxy : public CNEOGameRulesProxy +{ +public: + DECLARE_CLASS( CNEOGameRulesATKProxy, CNEOGameRulesProxy ); + DECLARE_NETWORKCLASS(); +}; + +class CNEORulesATK : public CNEORules, public CGameEventListener +{ +public: + DECLARE_CLASS(CNEORulesATK, CNEORules); + DECLARE_NETWORKCLASS_NOBASE(); + + + //CNEORulesATK(); + //virtual ~CNEORulesATK(); + + // IGameEventListener interface: + virtual void FireGameEvent(IGameEvent *event) override; + + virtual void CheckOvertime(); + virtual void Think() override final; +}; + +inline CNEORulesATK *CNEORulesATK() +{ + return static_cast(g_pGameRules); +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp new file mode 100644 index 0000000000..e51891a55f --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp @@ -0,0 +1,193 @@ +#include "cbase.h" +#include "neo_gamerules_ctg.h" + +#ifdef GAME_DLL + #include "neo_ghost_spawn_point.h" + #include "neo_ghost_cap_point.h" +#else +#endif // GAME_DLL + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +REGISTER_GAMERULES_CLASS( CNEORulesCTG ); + +BEGIN_NETWORK_TABLE_NOBASE( CNEORulesCTG, DT_NEORulesCTG ) +END_NETWORK_TABLE() + +LINK_ENTITY_TO_CLASS( neo_gamerules_ctg, CNEOGameRulesCTGProxy ); +IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesCTGProxy, DT_NEOGameRulesCTGProxy ); + +#ifdef CLIENT_DLL + void RecvProxy_NEORulesCTG( const RecvProp *pProp, void **pOut, + void *pData, int objectID ) + { + CNEORulesCTG *pRules = NEORulesCTG(); + Assert( pRules ); + *pOut = pRules; + } + + BEGIN_RECV_TABLE( CNEOGameRulesCTGProxy, DT_NEOGameRulesCTGProxy ) + RecvPropDataTable( "neo_gamerules_ctg_data", 0, 0, + &REFERENCE_RECV_TABLE( DT_NEORulesCTG ), + RecvProxy_NEORulesCTG ) + END_RECV_TABLE() +#else + void *SendProxy_NEORulesCTG( const SendProp *pProp, + const void *pStructBase, const void *pData, + CSendProxyRecipients *pRecipients, int objectID ) + { + CNEORulesCTG *pRules = NEORulesCTG(); + Assert( pRules ); + return pRules; + } + + BEGIN_SEND_TABLE(CNEOGameRulesCTGProxy, DT_NEOGameRulesCTGProxy) + SendPropDataTable("neo_gamerules_ctg_data", 0, + &REFERENCE_SEND_TABLE(DT_NEORulesCTG), + SendProxy_NEORulesCTG) + END_SEND_TABLE() +#endif + +ConVar sv_neo_ctg_round_timelimit("neo_ctg_round_timelimit", "3.25", FCVAR_REPLICATED, "CTG round timelimit, in minutes.", true, 0.0f, false, 600.0f); + +ConVar sv_neo_ctg_ghost_overtime_enabled("sv_neo_ctg_ghost_overtime_enabled", "0", FCVAR_REPLICATED, "Enable ghost overtime.", true, 0, true, 1); +ConVar sv_neo_ctg_ghost_overtime("sv_neo_ctg_ghost_overtime", "45", FCVAR_REPLICATED, "Adds up to this many seconds to the round while the ghost is held.", true, 0, true, 120); +ConVar sv_neo_ctg_ghost_overtime_grace("sv_neo_ctg_ghost_overtime_grace", "10", FCVAR_REPLICATED, "Number of seconds left in the round when the ghost is dropped in overtime.", true, 0, true, 30); +ConVar sv_neo_ctg_ghost_overtime_grace_decay("sv_neo_ctg_ghost_overtime_grace_decay", "0", FCVAR_REPLICATED, "Slowly reduce the grace time as overtime goes on.", true, 0, true, 1); + +CNEORulesCTG::CNEORulesCTG() +{ + +} + +CNEORulesCTG::~CNEORulesCTG() +{ +} + +void CNEORulesCTG::FireGameEvent(IGameEvent* event) +{ + BaseClass::FireGameEvent(event); +} + +void CNEORulesCTG::CheckOvertime() +{ + if (!sv_neo_ctg_ghost_overtime_enabled.GetBool()) + return; + + float overtimeGrace = sv_neo_ctg_round_timelimit.GetFloat() * 60; + float roundTimeLimit = sv_neo_ctg_ghost_overtime_grace.GetFloat(); + + if (NeoRoundStatus::RoundLive == m_nRoundStatus && m_iGhosterPlayer && + (m_flNeoRoundStartTime + roundTimeLimit - overtimeGrace) < gpGlobals->curtime) + { + m_nRoundStatus = NeoRoundStatus::Overtime; + } + + if (m_nRoundStatus == NeoRoundStatus::Overtime && m_iGhosterPlayer) + { + m_flGhostLastHeld = gpGlobals->curtime; + } +} + +void CNEORulesCTG::Think() +{ +#ifdef GAME_DLL + if (RoundIdlePausedStartThink()) + return; + + PlayerRespawnThink(); + + CheckClantagsThink(); + + if (IsRoundPaused()) + return; + + GameOverThink(); + + CheckOvertime(); + + CHL2MPRules::Think(); + + TeamDamageThink(); + + if (RoundOverThink()) + return; + + RoundStatusThink(); + + if (m_pGhost) + { + // Update ghosting team info + int nextGhosterTeam = TEAM_UNASSIGNED; + int nextGhosterPlayerIdx = 0; + CNEO_Player *pGhosterPlayer = static_cast(m_pGhost->GetOwner()); + if (pGhosterPlayer) + { + nextGhosterTeam = pGhosterPlayer->GetTeamNumber(); + nextGhosterPlayerIdx = pGhosterPlayer->entindex(); + Assert(nextGhosterTeam == TEAM_JINRAI || nextGhosterTeam == TEAM_NSF); + m_pGhost->UpdateNearestGhostBeaconDist(); + } + m_iGhosterTeam = nextGhosterTeam; + m_iGhosterPlayer = nextGhosterPlayerIdx; + + Assert(UTIL_IsValidEntity(m_pGhost)); + + if (m_pGhost->GetAbsOrigin().IsValid()) + { + // Someone's carrying it + // NEO NOTE (Adam) GetGhostMarkerPos() can return m_vecGhostMarkerPos if m_pGhost is invalid, but we've checked for m_pGhost above so should be fine? + m_vecGhostMarkerPos = (nextGhosterTeam == TEAM_JINRAI || nextGhosterTeam == TEAM_NSF) ? GetGhostMarkerPos() + : m_pGhost->GetAbsOrigin(); + } + else + { + Assert(false); + } + + // Check if the ghost was capped during this Think + int captorTeam, captorClient; + for (int i = 0; i < m_pGhostCaps.Count(); i++) + { + auto pGhostCap = dynamic_cast(UTIL_EntityByIndex(m_pGhostCaps[i])); + if (!pGhostCap) + { + Assert(false); + continue; + } + + // If a ghost was captured + if (pGhostCap->IsGhostCaptured(captorTeam, captorClient)) + { + // Turn off all capzones + for (int i = 0; i < m_pGhostCaps.Count(); i++) + { + auto pGhostCap = dynamic_cast(UTIL_EntityByIndex(m_pGhostCaps[i])); + if (!pGhostCap) + { + Assert(false); + continue; + } + pGhostCap->SetActive(false); + } + + IGameEvent* event = gameeventmanager->CreateEvent("ghost_capture"); + if (event) + { + CBasePlayer* pCaptorClient = UTIL_PlayerByIndex(captorClient); + event->SetInt("userid", pCaptorClient ? pCaptorClient->GetUserID() : INVALID_USER_ID); + gameeventmanager->FireEvent(event); + } + + // And then announce team victory + SetWinningTeam(captorTeam, NEO_VICTORY_GHOST_CAPTURE, false, true, false, false); + + break; + } + } + } + + CheckWinByElimination(); +#endif // GAME_DLL +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_ctg.h b/src/game/shared/neo/gamerules/neo_gamerules_ctg.h new file mode 100644 index 0000000000..7a44c23e2c --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_ctg.h @@ -0,0 +1,42 @@ +#pragma once + +#include "neo_gamerules.h" +#include "GameEventListener.h" + +#ifdef CLIENT_DLL + #define CNEORulesCTG C_NEORulesCTG + #define CNEOGameRulesCTGProxy C_NEOGameRulesCTGProxy +#endif +// +//ConVar sv_neo_ctg_score_limit("sv_neo_ctg_score_limit", "1", FCVAR_REPLICATED, "CTG score limit", true, 0.0f, true, 99.0f); +//ConVar sv_neo_ctg_round_limit("sv_neo_ctg_round_limit", "0", FCVAR_REPLICATED, "CTG max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +//ConVar sv_neo_ctg_round_timelimit("neo_ctg_round_timelimit", "10.25", FCVAR_REPLICATED, "CTG round timelimit, in minutes.", true, 0.0f, false, 600.0f); + +class CNEOGameRulesCTGProxy : public CNEOGameRulesProxy +{ +public: + DECLARE_CLASS( CNEOGameRulesCTGProxy, CNEOGameRulesProxy ); + DECLARE_NETWORKCLASS(); +}; + +class CNEORulesCTG : public CNEORules, public CGameEventListener +{ +public: + DECLARE_CLASS(CNEORulesCTG, CNEORules); + DECLARE_NETWORKCLASS_NOBASE(); + + + CNEORulesCTG(); + virtual ~CNEORulesCTG(); + + // IGameEventListener interface: + virtual void FireGameEvent(IGameEvent *event) override; + + virtual void CheckOvertime(); + virtual void Think() override final; +}; + +inline CNEORulesCTG *NEORulesCTG() +{ + return static_cast(g_pGameRules); +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp b/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp new file mode 100644 index 0000000000..41bf2bcbea --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp @@ -0,0 +1,260 @@ +#include "cbase.h" +#include "neo_gamerules_dm.h" +#ifdef GAME_DLL +#include "neo_game_config.h" +#else +#include "c_playerresource.h" +#endif // GAME_DLL + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +REGISTER_GAMERULES_CLASS( CNEORulesDM ); + +BEGIN_NETWORK_TABLE_NOBASE( CNEORulesDM, DT_NEORulesDM ) +END_NETWORK_TABLE() + +LINK_ENTITY_TO_CLASS( neo_gamerules_dm, CNEOGameRulesDMProxy ); +IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesDMProxy, DT_NEOGameRulesDMProxy ); + +#ifdef CLIENT_DLL + void RecvProxy_NEORulesDM( const RecvProp *pProp, void **pOut, + void *pData, int objectID ) + { + CNEORulesDM *pRules = NEORulesDM(); + Assert( pRules ); + *pOut = pRules; + } + + BEGIN_RECV_TABLE( CNEOGameRulesDMProxy, DT_NEOGameRulesDMProxy ) + RecvPropDataTable( "neo_gamerules_dm_data", 0, 0, + &REFERENCE_RECV_TABLE( DT_NEORulesDM ), + RecvProxy_NEORulesDM ) + END_RECV_TABLE() +#else + void *SendProxy_NEORulesDM( const SendProp *pProp, + const void *pStructBase, const void *pData, + CSendProxyRecipients *pRecipients, int objectID ) + { + CNEORulesDM *pRules = NEORulesDM(); + Assert( pRules ); + return pRules; + } + + BEGIN_SEND_TABLE(CNEOGameRulesDMProxy, DT_NEOGameRulesDMProxy) + SendPropDataTable("neo_gamerules_dm_data", 0, + &REFERENCE_SEND_TABLE(DT_NEORulesDM), + SendProxy_NEORulesDM) + END_SEND_TABLE() +#endif + +ConVar sv_neo_dm_win_xp("sv_neo_dm_win_xp", "50", FCVAR_REPLICATED, "The XP limit to win the match.", true, 0.0f, true, 1000.0f); + +extern bool RespawnWithRet(CBaseEntity *pEdict, bool fCopyCorpse); + +CNEORulesDM::CNEORulesDM() +{ + +} + +CNEORulesDM::~CNEORulesDM() +{ +} + +void CNEORulesDM::FireGameEvent(IGameEvent* event) +{ + BaseClass::FireGameEvent(event); +} + +#ifdef GAME_DLL +void CNEORulesDM::PlayerRespawnThink() +{ + for (int i = 1; i <= gpGlobals->maxClients; i++) + { + auto player = static_cast(UTIL_PlayerByIndex(i)); + if (player && player->IsDead() && (IsRoundPaused() || player->DeathCount() > 0)) + { + const int playerTeam = player->GetTeamNumber(); + if ((playerTeam == TEAM_JINRAI || playerTeam == TEAM_NSF) && RespawnWithRet(player, false)) + { + player->m_bInAim = false; + player->m_bCarryingGhost = false; + player->m_bInThermOpticCamo = false; + player->m_bInVision = false; + player->m_bIneligibleForLoadoutPick = false; + player->SetTestMessageVisible(false); + + engine->ClientCommand(player->edict(), "loadoutmenu"); + } + } + } +} +#endif // GAME_DLL + +void CNEORulesDM::Think() +{ +#ifdef GAME_DLL + if (RoundIdlePausedStartThink()) + return; + + PlayerRespawnThink(); + + CheckClantagsThink(); + + if (IsRoundPaused()) + return; + + GameOverThink(); + + CheckOvertime(); + + CHL2MPRules::Think(); + + TeamDamageThink(); + + if (RoundOverThink()) + return; + + RoundStatusThink(); + + // Win by XP + if (IsRoundLive() && sv_neo_dm_win_xp.GetInt() > 0) + { + // End game early if there's already a player past the winning XP + CNEO_Player *pHighestPlayers[MAX_PLAYERS + 1] = {}; + int iWinningTotal = 0; + int iWinningXP = 0; + GetDMHighestScorers(&pHighestPlayers, &iWinningTotal, &iWinningXP); + if (iWinningXP >= sv_neo_dm_win_xp.GetInt() && iWinningTotal == 1) + { + SetWinningDMPlayer(pHighestPlayers[0]); + } + } +#endif // GAME_DLL +} + + +void CNEORulesDM::GetDMHighestScorers( +#ifdef GAME_DLL + CNEO_Player *(*pHighestPlayers)[MAX_PLAYERS + 1], +#endif + int *iHighestPlayersTotal, + int *iHighestXP) const +{ + *iHighestPlayersTotal = 0; + *iHighestXP = 0; +#ifdef GAME_DLL + for (int i = 1; i <= gpGlobals->maxClients; ++i) +#else + if (!g_PR) + { + return; + } + + for (int i = 0; i < (MAX_PLAYERS + 1); ++i) +#endif + { + int iXP = 0; + +#ifdef GAME_DLL + auto pCmpPlayer = static_cast(UTIL_PlayerByIndex(i)); + if (!pCmpPlayer) + { + continue; + } + iXP = pCmpPlayer->m_iXP; +#else + if (!g_PR->IsConnected(i)) + { + continue; + } + iXP = g_PR->GetXP(i); +#endif + + if (iXP == *iHighestXP) + { +#ifdef GAME_DLL + (*pHighestPlayers)[(*iHighestPlayersTotal)++] = pCmpPlayer; +#else + (*iHighestPlayersTotal)++; +#endif + } + else if (iXP > *iHighestXP) + { + *iHighestPlayersTotal = 0; + *iHighestXP = iXP; +#ifdef GAME_DLL + (*pHighestPlayers)[(*iHighestPlayersTotal)++] = pCmpPlayer; +#else + (*iHighestPlayersTotal)++; +#endif + } + } +} + +#ifdef GAME_DLL +void CNEORulesDM::SetWinningDMPlayer(CNEO_Player *pWinner) +{ + if (IsRoundOver()) + { + return; + } + + if (auto pEntGameCfg = NEOGameConfig()) + { + pEntGameCfg->m_OnDMRoundEnd.FireOutput(pWinner, pEntGameCfg); + } + + SetRoundStatus(NeoRoundStatus::PostRound); + char victoryMsg[128]; + // TODO: Per client since client has neo_name settings + V_sprintf_safe(victoryMsg, "%s is the winner of the deathmatch!\n", pWinner->GetNeoPlayerName()); + + CRecipientFilter filter; + filter.AddAllPlayers(); + UserMessageBegin(filter, "RoundResult"); + WRITE_STRING("tie"); + WRITE_FLOAT(gpGlobals->curtime); + WRITE_STRING(victoryMsg); + MessageEnd(); + + EmitSound_t soundParams; + soundParams.m_nChannel = CHAN_AUTO; + soundParams.m_SoundLevel = SNDLVL_NONE; + soundParams.m_flVolume = 0.33f; + // Differing between Jinrai/NSF only as a sound cosmetic (no affect on DM) + const int team = pWinner->GetTeamNumber(); + soundParams.m_pSoundName = (team == TEAM_JINRAI) ? "gameplay/jinrai.mp3" : (team == TEAM_NSF) ? "gameplay/nsf.mp3" : "gameplay/draw.mp3"; + soundParams.m_bWarnOnDirectWaveReference = false; + soundParams.m_bEmitCloseCaption = false; + + for (int i = 1; i <= gpGlobals->maxClients; ++i) + { + CBasePlayer* basePlayer = UTIL_PlayerByIndex(i); + auto player = static_cast(basePlayer); + if (player) + { + if (!player->IsBot() || player->IsHLTV()) + { + const char* volStr = engine->GetClientConVarValue(i, "snd_victory_volume"); + const float jingleVolume = volStr ? atof(volStr) : 0.33f; + soundParams.m_flVolume = jingleVolume; + + CRecipientFilter soundFilter; + soundFilter.AddRecipient(basePlayer); + soundFilter.MakeReliable(); + player->EmitSound(soundFilter, i, soundParams); + } + } + } + + GoToIntermission(); + + IGameEvent *event = gameeventmanager->CreateEvent("game_end"); + if (event) + { + event->SetInt("winner", pWinner->GetUserID()); + gameeventmanager->FireEvent(event); + } +} +#endif // GAME_DLL \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_dm.h b/src/game/shared/neo/gamerules/neo_gamerules_dm.h new file mode 100644 index 0000000000..54b0f879d4 --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_dm.h @@ -0,0 +1,54 @@ +#pragma once + +#include "neo_gamerules.h" +#include "GameEventListener.h" + +#ifdef CLIENT_DLL + #define CNEORulesDM C_NEORulesDM + #define CNEOGameRulesDMProxy C_NEOGameRulesDMProxy +#endif +// +//ConVar sv_neo_dm_score_limit("sv_neo_dm_score_limit", "1", FCVAR_REPLICATED, "DM score limit", true, 0.0f, true, 99.0f); +//ConVar sv_neo_dm_round_limit("sv_neo_dm_round_limit", "0", FCVAR_REPLICATED, "DM max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +//ConVar sv_neo_dm_round_timelimit("neo_dm_round_timelimit", "10.25", FCVAR_REPLICATED, "DM round timelimit, in minutes.", true, 0.0f, false, 600.0f); + +class CNEOGameRulesDMProxy : public CNEOGameRulesProxy +{ +public: + DECLARE_CLASS( CNEOGameRulesDMProxy, CNEOGameRulesProxy ); + DECLARE_NETWORKCLASS(); +}; + +class CNEORulesDM : public CNEORules, public CGameEventListener +{ +public: + DECLARE_CLASS(CNEORulesDM, CNEORules); + DECLARE_NETWORKCLASS_NOBASE(); + + + CNEORulesDM(); + virtual ~CNEORulesDM(); + + // IGameEventListener interface: + virtual void FireGameEvent(IGameEvent *event) override; + + virtual void Think() override final; +#ifdef GAME_DLL + virtual void PlayerRespawnThink() override final; +#endif // GAME_DLL + + void GetDMHighestScorers( +#ifdef GAME_DLL + CNEO_Player *(*pHighestPlayers)[MAX_PLAYERS + 1], +#endif + int *iHighestPlayersTotal, + int *iHighestXP) const; +#ifdef GAME_DLL + void SetWinningDMPlayer(CNEO_Player *pWinner); +#endif // GAME_DLL +}; + +inline CNEORulesDM *NEORulesDM() +{ + return static_cast(g_pGameRules); +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp b/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp new file mode 100644 index 0000000000..882cbefe6c --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp @@ -0,0 +1,65 @@ +#include "cbase.h" +#include "neo_gamerules_emt.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +REGISTER_GAMERULES_CLASS( CNEORulesEMT ); + +BEGIN_NETWORK_TABLE_NOBASE( CNEORulesEMT, DT_NEORulesEMT ) +END_NETWORK_TABLE() + +LINK_ENTITY_TO_CLASS( neo_gamerules_emt, CNEOGameRulesEMTProxy ); +IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesEMTProxy, DT_NEOGameRulesEMTProxy ); + +#ifdef CLIENT_DLL + void RecvProxy_NEORulesEMT( const RecvProp *pProp, void **pOut, + void *pData, int objectID ) + { + CNEORulesEMT *pRules = NEORulesEMT(); + Assert( pRules ); + *pOut = pRules; + } + + BEGIN_RECV_TABLE( CNEOGameRulesEMTProxy, DT_NEOGameRulesEMTProxy ) + RecvPropDataTable( "neo_gamerules_emt_data", 0, 0, + &REFERENCE_RECV_TABLE( DT_NEORulesEMT ), + RecvProxy_NEORulesEMT ) + END_RECV_TABLE() +#else + void *SendProxy_NEORulesEMT( const SendProp *pProp, + const void *pStructBase, const void *pData, + CSendProxyRecipients *pRecipients, int objectID ) + { + CNEORulesEMT *pRules = NEORulesEMT(); + Assert( pRules ); + return pRules; + } + + BEGIN_SEND_TABLE(CNEOGameRulesEMTProxy, DT_NEOGameRulesEMTProxy) + SendPropDataTable("neo_gamerules_emt_data", 0, + &REFERENCE_SEND_TABLE(DT_NEORulesEMT), + SendProxy_NEORulesEMT) + END_SEND_TABLE() +#endif + +CNEORulesEMT::CNEORulesEMT() +{ + +} + +CNEORulesEMT::~CNEORulesEMT() +{ +} + +void CNEORulesEMT::FireGameEvent(IGameEvent* event) +{ + BaseClass::FireGameEvent(event); +} + +void CNEORulesEMT::Think() +{ +#ifdef GAME_DLL + UpdateFromGameConfig(); +#endif // GAME_DLL +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_emt.h b/src/game/shared/neo/gamerules/neo_gamerules_emt.h new file mode 100644 index 0000000000..a5185a0ed3 --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_emt.h @@ -0,0 +1,41 @@ +#pragma once + +#include "neo_gamerules.h" +#include "GameEventListener.h" + +#ifdef CLIENT_DLL + #define CNEORulesEMT C_NEORulesEMT + #define CNEOGameRulesEMTProxy C_NEOGameRulesEMTProxy +#endif +// +//ConVar sv_neo_emt_score_limit("sv_neo_emt_score_limit", "1", FCVAR_REPLICATED, "EMT score limit", true, 0.0f, true, 99.0f); +//ConVar sv_neo_emt_round_limit("sv_neo_emt_round_limit", "0", FCVAR_REPLICATED, "EMT max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +//ConVar sv_neo_emt_round_timelimit("neo_emt_round_timelimit", "10.25", FCVAR_REPLICATED, "EMT round timelimit, in minutes.", true, 0.0f, false, 600.0f); + +class CNEOGameRulesEMTProxy : public CNEOGameRulesProxy +{ +public: + DECLARE_CLASS( CNEOGameRulesEMTProxy, CNEOGameRulesProxy ); + DECLARE_NETWORKCLASS(); +}; + +class CNEORulesEMT : public CNEORules, public CGameEventListener +{ +public: + DECLARE_CLASS(CNEORulesEMT, CNEORules); + DECLARE_NETWORKCLASS_NOBASE(); + + + CNEORulesEMT(); + virtual ~CNEORulesEMT(); + + // IGameEventListener interface: + virtual void FireGameEvent(IGameEvent *event) override; + + virtual void Think() override final; +}; + +inline CNEORulesEMT *NEORulesEMT() +{ + return static_cast(g_pGameRules); +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp b/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp new file mode 100644 index 0000000000..5386231931 --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp @@ -0,0 +1,157 @@ +#include "cbase.h" +#include "neo_gamerules_jgr.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +REGISTER_GAMERULES_CLASS( CNEORulesJGR ); + +BEGIN_NETWORK_TABLE_NOBASE( CNEORulesJGR, DT_NEORulesJGR ) +END_NETWORK_TABLE() + +LINK_ENTITY_TO_CLASS( neo_gamerules_jgr, CNEOGameRulesJGRProxy ); +IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesJGRProxy, DT_NEOGameRulesJGRProxy ); + +#ifdef CLIENT_DLL + void RecvProxy_NEORulesJGR( const RecvProp *pProp, void **pOut, + void *pData, int objectID ) + { + CNEORulesJGR *pRules = NEORulesJGR(); + Assert( pRules ); + *pOut = pRules; + } + + BEGIN_RECV_TABLE( CNEOGameRulesJGRProxy, DT_NEOGameRulesJGRProxy ) + RecvPropDataTable( "neo_gamerules_jgr_data", 0, 0, + &REFERENCE_RECV_TABLE( DT_NEORulesJGR ), + RecvProxy_NEORulesJGR ) + END_RECV_TABLE() +#else + void *SendProxy_NEORulesJGR( const SendProp *pProp, + const void *pStructBase, const void *pData, + CSendProxyRecipients *pRecipients, int objectID ) + { + CNEORulesJGR *pRules = NEORulesJGR(); + Assert( pRules ); + return pRules; + } + + BEGIN_SEND_TABLE(CNEOGameRulesJGRProxy, DT_NEOGameRulesJGRProxy) + SendPropDataTable("neo_gamerules_jgr_data", 0, + &REFERENCE_SEND_TABLE(DT_NEORulesJGR), + SendProxy_NEORulesJGR) + END_SEND_TABLE() +#endif + +ConVar sv_neo_jgr_max_points("sv_neo_jgr_max_points", "20", FCVAR_GAMEDLL, "Maximum points required for a team to win in JGR", true, 1, false, 0); + +extern bool RespawnWithRet(CBaseEntity *pEdict, bool fCopyCorpse); + +//CNEORulesJGR::CNEORulesJGR() +//{ +// +//} +// +//CNEORulesJGR::~CNEORulesJGR() +//{ +//} + +void CNEORulesJGR::FireGameEvent(IGameEvent* event) +{ + BaseClass::FireGameEvent(event); +} + +#ifdef GAME_DLL +void CNEORulesJGR::PlayerRespawnThink() +{ + for (int i = 1; i <= gpGlobals->maxClients; i++) + { + auto player = static_cast(UTIL_PlayerByIndex(i)); + if (player && player->IsDead() && (IsRoundPaused() || player->DeathCount() > 0)) + { + const int playerTeam = player->GetTeamNumber(); + if ((playerTeam == TEAM_JINRAI || playerTeam == TEAM_NSF) && RespawnWithRet(player, false)) + { + player->m_bInAim = false; + player->m_bCarryingGhost = false; + player->m_bInThermOpticCamo = false; + player->m_bInVision = false; + player->m_bIneligibleForLoadoutPick = false; + player->SetTestMessageVisible(false); + + engine->ClientCommand(player->edict(), "loadoutmenu"); + } + } + } +} +#endif // GAME_DLL + +extern ConVar sv_neo_preround_freeze_time; + +void CNEORulesJGR::Think() +{ +#ifdef GAME_DLL + if (RoundIdlePausedStartThink()) + return; + + PlayerRespawnThink(); + + CheckClantagsThink(); + + if (IsRoundPaused()) + return; + + GameOverThink(); + + CheckOvertime(); + + CHL2MPRules::Think(); + + TeamDamageThink(); + + if (RoundOverThink()) + return; + + RoundStatusThink(); + + if (IsRoundLive()) + { + // Unlock the Juggernaut + if (m_pJuggernautItem && (gpGlobals->curtime > (m_flNeoRoundStartTime + sv_neo_preround_freeze_time.GetFloat()) + 20.0f) && IsJuggernautLocked()) + { + UTIL_CenterPrintAll("- JUGGERNAUT ENABLED -\n"); + + EmitSound_t soundParams; + soundParams.m_pSoundName = "HUD.GhostPickUp"; + soundParams.m_nChannel = CHAN_USER_BASE; + soundParams.m_bWarnOnDirectWaveReference = false; + soundParams.m_bEmitCloseCaption = false; + soundParams.m_SoundLevel = ATTN_TO_SNDLVL(ATTN_NONE); + + CRecipientFilter soundFilter; + soundFilter.AddAllPlayers(); + soundFilter.MakeReliable(); + m_pJuggernautItem->EmitSound(soundFilter, m_pJuggernautItem->entindex(), soundParams); + + m_pJuggernautItem->m_bLocked = false; + } + + // Check win condition + { + const int maxPoints = sv_neo_jgr_max_points.GetInt(); + if (GetGlobalTeam(TEAM_JINRAI)->GetScore() >= maxPoints) + { + SetWinningTeam(TEAM_JINRAI, NEO_VICTORY_POINTS, false, true, false, false); + return; + } + + if (GetGlobalTeam(TEAM_NSF)->GetScore() >= maxPoints) + { + SetWinningTeam(TEAM_NSF, NEO_VICTORY_POINTS, false, true, false, false); + return; + } + } + } + +#endif // GAME_DLL +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_jgr.h b/src/game/shared/neo/gamerules/neo_gamerules_jgr.h new file mode 100644 index 0000000000..ebd3738544 --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_jgr.h @@ -0,0 +1,44 @@ +#pragma once + +#include "neo_gamerules.h" +#include "GameEventListener.h" + +#ifdef CLIENT_DLL + #define CNEORulesJGR C_NEORulesJGR + #define CNEOGameRulesJGRProxy C_NEOGameRulesJGRProxy +#endif +// +//ConVar sv_neo_jgr_score_limit("sv_neo_jgr_score_limit", "1", FCVAR_REPLICATED, "JGR score limit", true, 0.0f, true, 99.0f); +//ConVar sv_neo_jgr_round_limit("sv_neo_jgr_round_limit", "0", FCVAR_REPLICATED, "JGR max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +//ConVar sv_neo_jgr_round_timelimit("neo_jgr_round_timelimit", "10.25", FCVAR_REPLICATED, "JGR round timelimit, in minutes.", true, 0.0f, false, 600.0f); + +class CNEOGameRulesJGRProxy : public CNEOGameRulesProxy +{ +public: + DECLARE_CLASS( CNEOGameRulesJGRProxy, CNEOGameRulesProxy ); + DECLARE_NETWORKCLASS(); +}; + +class CNEORulesJGR : public CNEORules, public CGameEventListener +{ +public: + DECLARE_CLASS(CNEORulesJGR, CNEORules); + DECLARE_NETWORKCLASS_NOBASE(); + /* + + CNEORulesJGR(); + virtual ~CNEORulesJGR(); + */ + // IGameEventListener interface: + virtual void FireGameEvent(IGameEvent *event) override; + + virtual void Think() override final; +#ifdef GAME_DLL + virtual void PlayerRespawnThink() override final; +#endif // GAME_DLL +}; + +inline CNEORulesJGR *NEORulesJGR() +{ + return static_cast(g_pGameRules); +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp b/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp new file mode 100644 index 0000000000..f90854c678 --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp @@ -0,0 +1,113 @@ +#include "cbase.h" +#include "neo_gamerules_tdm.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +REGISTER_GAMERULES_CLASS( CNEORulesTDM ); + +BEGIN_NETWORK_TABLE_NOBASE( CNEORulesTDM, DT_NEORulesTDM ) +END_NETWORK_TABLE() + +LINK_ENTITY_TO_CLASS( neo_gamerules_tdm, CNEOGameRulesTDMProxy ); +IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesTDMProxy, DT_NEOGameRulesTDMProxy ); + +#ifdef CLIENT_DLL + void RecvProxy_NEORulesTDM( const RecvProp *pProp, void **pOut, + void *pData, int objectID ) + { + CNEORulesTDM *pRules = NEORulesTDM(); + Assert( pRules ); + *pOut = pRules; + } + + BEGIN_RECV_TABLE( CNEOGameRulesTDMProxy, DT_NEOGameRulesTDMProxy ) + RecvPropDataTable( "neo_gamerules_tdm_data", 0, 0, + &REFERENCE_RECV_TABLE( DT_NEORulesTDM ), + RecvProxy_NEORulesTDM ) + END_RECV_TABLE() +#else + void *SendProxy_NEORulesTDM( const SendProp *pProp, + const void *pStructBase, const void *pData, + CSendProxyRecipients *pRecipients, int objectID ) + { + CNEORulesTDM *pRules = NEORulesTDM(); + Assert( pRules ); + return pRules; + } + + BEGIN_SEND_TABLE(CNEOGameRulesTDMProxy, DT_NEOGameRulesTDMProxy) + SendPropDataTable("neo_gamerules_tdm_data", 0, + &REFERENCE_SEND_TABLE(DT_NEORulesTDM), + SendProxy_NEORulesTDM) + END_SEND_TABLE() +#endif + +extern bool RespawnWithRet(CBaseEntity *pEdict, bool fCopyCorpse); + +CNEORulesTDM::CNEORulesTDM() +{ + +} + +CNEORulesTDM::~CNEORulesTDM() +{ +} + +void CNEORulesTDM::FireGameEvent(IGameEvent* event) +{ + BaseClass::FireGameEvent(event); +} + +#ifdef GAME_DLL +void CNEORulesTDM::PlayerRespawnThink() +{ + for (int i = 1; i <= gpGlobals->maxClients; i++) + { + auto player = static_cast(UTIL_PlayerByIndex(i)); + if (player && player->IsDead() && (IsRoundPaused() || player->DeathCount() > 0)) + { + const int playerTeam = player->GetTeamNumber(); + if ((playerTeam == TEAM_JINRAI || playerTeam == TEAM_NSF) && RespawnWithRet(player, false)) + { + player->m_bInAim = false; + player->m_bCarryingGhost = false; + player->m_bInThermOpticCamo = false; + player->m_bInVision = false; + player->m_bIneligibleForLoadoutPick = false; + player->SetTestMessageVisible(false); + + engine->ClientCommand(player->edict(), "loadoutmenu"); + } + } + } +} +#endif // GAME_DLL + +void CNEORulesTDM::Think() +{ +#ifdef GAME_DLL + if (RoundIdlePausedStartThink()) + return; + + PlayerRespawnThink(); + + CheckClantagsThink(); + + if (IsRoundPaused()) + return; + + GameOverThink(); + + CheckOvertime(); + + CHL2MPRules::Think(); + + TeamDamageThink(); + + if (RoundOverThink()) + return; + + RoundStatusThink(); +#endif // GAME_DLL +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tdm.h b/src/game/shared/neo/gamerules/neo_gamerules_tdm.h new file mode 100644 index 0000000000..618d112388 --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_tdm.h @@ -0,0 +1,44 @@ +#pragma once + +#include "neo_gamerules.h" +#include "GameEventListener.h" + +#ifdef CLIENT_DLL + #define CNEORulesTDM C_NEORulesTDM + #define CNEOGameRulesTDMProxy C_NEOGameRulesTDMProxy +#endif +// +//ConVar sv_neo_tdm_score_limit("sv_neo_tdm_score_limit", "1", FCVAR_REPLICATED, "TDM score limit", true, 0.0f, true, 99.0f); +//ConVar sv_neo_tdm_round_limit("sv_neo_tdm_round_limit", "0", FCVAR_REPLICATED, "TDM max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +//ConVar sv_neo_tdm_round_timelimit("neo_tdm_round_timelimit", "10.25", FCVAR_REPLICATED, "TDM round timelimit, in minutes.", true, 0.0f, false, 600.0f); + +class CNEOGameRulesTDMProxy : public CNEOGameRulesProxy +{ +public: + DECLARE_CLASS( CNEOGameRulesTDMProxy, CNEOGameRulesProxy ); + DECLARE_NETWORKCLASS(); +}; + +class CNEORulesTDM : public CNEORules, public CGameEventListener +{ +public: + DECLARE_CLASS(CNEORulesTDM, CNEORules); + DECLARE_NETWORKCLASS_NOBASE(); + + + CNEORulesTDM(); + virtual ~CNEORulesTDM(); + + // IGameEventListener interface: + virtual void FireGameEvent(IGameEvent *event) override; + + virtual void Think() override final; +#ifdef GAME_DLL + virtual void PlayerRespawnThink() override final; +#endif // GAME_DLL +}; + +inline CNEORulesTDM *NEORulesTDM() +{ + return static_cast(g_pGameRules); +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp b/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp new file mode 100644 index 0000000000..e5218419b4 --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp @@ -0,0 +1,84 @@ +#include "cbase.h" +#include "neo_gamerules_tut.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +REGISTER_GAMERULES_CLASS( CNEORulesTUT ); + +BEGIN_NETWORK_TABLE_NOBASE( CNEORulesTUT, DT_NEORulesTUT ) +END_NETWORK_TABLE() + +LINK_ENTITY_TO_CLASS( neo_gamerules_tut, CNEOGameRulesTUTProxy ); +IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesTUTProxy, DT_NEOGameRulesTUTProxy ); + +#ifdef CLIENT_DLL + void RecvProxy_NEORulesTUT( const RecvProp *pProp, void **pOut, + void *pData, int objectID ) + { + CNEORulesTUT *pRules = NEORulesTUT(); + Assert( pRules ); + *pOut = pRules; + } + + BEGIN_RECV_TABLE( CNEOGameRulesTUTProxy, DT_NEOGameRulesTUTProxy ) + RecvPropDataTable( "neo_gamerules_tut_data", 0, 0, + &REFERENCE_RECV_TABLE( DT_NEORulesTUT ), + RecvProxy_NEORulesTUT ) + END_RECV_TABLE() +#else + void *SendProxy_NEORulesTUT( const SendProp *pProp, + const void *pStructBase, const void *pData, + CSendProxyRecipients *pRecipients, int objectID ) + { + CNEORulesTUT *pRules = NEORulesTUT(); + Assert( pRules ); + return pRules; + } + + BEGIN_SEND_TABLE(CNEOGameRulesTUTProxy, DT_NEOGameRulesTUTProxy) + SendPropDataTable("neo_gamerules_tut_data", 0, + &REFERENCE_SEND_TABLE(DT_NEORulesTUT), + SendProxy_NEORulesTUT) + END_SEND_TABLE() +#endif + +CNEORulesTUT::CNEORulesTUT() +{ + +} + +CNEORulesTUT::~CNEORulesTUT() +{ +} + +void CNEORulesTUT::FireGameEvent(IGameEvent* event) +{ + BaseClass::FireGameEvent(event); +} + +void CNEORulesTUT::Think() +{ +#ifdef GAME_DLL + UpdateFromGameConfig(); + + { + // This is kind of wonky, but we only need it for the tutorial, in order to play the dummy beacon sounds... + if (!m_pGhost) + { + auto pEnt = gEntList.FirstEnt(); + while (pEnt) + { + if (dynamic_cast(pEnt)) + { + m_pGhost = static_cast(pEnt); + m_hGhost = m_pGhost; + return; + } + pEnt = gEntList.NextEnt(pEnt); + } + } + if (m_pGhost) m_pGhost->UpdateNearestGhostBeaconDist(); + } +#endif // GAME_DLL +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tut.h b/src/game/shared/neo/gamerules/neo_gamerules_tut.h new file mode 100644 index 0000000000..c723b76a85 --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_tut.h @@ -0,0 +1,41 @@ +#pragma once + +#include "neo_gamerules.h" +#include "GameEventListener.h" + +#ifdef CLIENT_DLL + #define CNEORulesTUT C_NEORulesTUT + #define CNEOGameRulesTUTProxy C_NEOGameRulesTUTProxy +#endif +// +//ConVar sv_neo_tut_score_limit("sv_neo_tut_score_limit", "1", FCVAR_REPLICATED, "TUT score limit", true, 0.0f, true, 99.0f); +//ConVar sv_neo_tut_round_limit("sv_neo_tut_round_limit", "0", FCVAR_REPLICATED, "TUT max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +//ConVar sv_neo_tut_round_timelimit("neo_tut_round_timelimit", "10.25", FCVAR_REPLICATED, "TUT round timelimit, in minutes.", true, 0.0f, false, 600.0f); + +class CNEOGameRulesTUTProxy : public CNEOGameRulesProxy +{ +public: + DECLARE_CLASS( CNEOGameRulesTUTProxy, CNEOGameRulesProxy ); + DECLARE_NETWORKCLASS(); +}; + +class CNEORulesTUT : public CNEORules, public CGameEventListener +{ +public: + DECLARE_CLASS(CNEORulesTUT, CNEORules); + DECLARE_NETWORKCLASS_NOBASE(); + + + CNEORulesTUT(); + virtual ~CNEORulesTUT(); + + // IGameEventListener interface: + virtual void FireGameEvent(IGameEvent *event) override; + + virtual void Think() override final; +}; + +inline CNEORulesTUT *NEORulesTUT() +{ + return static_cast(g_pGameRules); +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp b/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp new file mode 100644 index 0000000000..afb3dcf820 --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp @@ -0,0 +1,177 @@ +#include "cbase.h" +#include "neo_gamerules_vip.h" + +#ifdef GAME_DLL + #include "neo_ghost_cap_point.h" +#else +#endif // GAME_DLL + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +REGISTER_GAMERULES_CLASS( CNEORulesVIP ); + +BEGIN_NETWORK_TABLE_NOBASE( CNEORulesVIP, DT_NEORulesVIP ) +END_NETWORK_TABLE() + +LINK_ENTITY_TO_CLASS( neo_gamerules_vip, CNEOGameRulesVIPProxy ); +IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesVIPProxy, DT_NEOGameRulesVIPProxy ); + +#ifdef CLIENT_DLL + void RecvProxy_NEORulesVIP( const RecvProp *pProp, void **pOut, + void *pData, int objectID ) + { + CNEORulesVIP *pRules = NEORulesVIP(); + Assert( pRules ); + *pOut = pRules; + } + + BEGIN_RECV_TABLE( CNEOGameRulesVIPProxy, DT_NEOGameRulesVIPProxy ) + RecvPropDataTable( "neo_gamerules_vip_data", 0, 0, + &REFERENCE_RECV_TABLE( DT_NEORulesVIP ), + RecvProxy_NEORulesVIP ) + END_RECV_TABLE() +#else + void *SendProxy_NEORulesVIP( const SendProp *pProp, + const void *pStructBase, const void *pData, + CSendProxyRecipients *pRecipients, int objectID ) + { + CNEORulesVIP *pRules = NEORulesVIP(); + Assert( pRules ); + return pRules; + } + + BEGIN_SEND_TABLE(CNEOGameRulesVIPProxy, DT_NEOGameRulesVIPProxy) + SendPropDataTable("neo_gamerules_vip_data", 0, + &REFERENCE_SEND_TABLE(DT_NEORulesVIP), + SendProxy_NEORulesVIP) + END_SEND_TABLE() +#endif + +ConVar sv_neo_vip_ctg_on_death("sv_neo_vip_ctg_on_death", "0", FCVAR_ARCHIVE, "Spawn Ghost when VIP dies, continue the game", true, 0, true, 1); + +CNEORulesVIP::CNEORulesVIP() +{ + +} + +CNEORulesVIP::~CNEORulesVIP() +{ +} + +void CNEORulesVIP::FireGameEvent(IGameEvent* event) +{ + BaseClass::FireGameEvent(event); +} + +void CNEORulesVIP::Think() +{ +#ifdef GAME_DLL + if (RoundIdlePausedStartThink()) + return; + + PlayerRespawnThink(); + + CheckClantagsThink(); + + if (IsRoundPaused()) + return; + + GameOverThink(); + + CheckOvertime(); + + CHL2MPRules::Think(); + + TeamDamageThink(); + + if (RoundOverThink()) + return; + + RoundStatusThink(); + + // Check win condition + if (!m_pGhost) + { + if (!m_pVIP) + { + if (sv_neo_vip_ctg_on_death.GetBool()) + { + UTIL_CenterPrintAll("- HVT DOWN - RECOVER THE GHOST -\n"); + SpawnTheGhost(); + } + else + { + // Assume vip player disconnected, forfeit round + SetWinningTeam(GetOpposingTeam(m_iEscortingTeam), NEO_VICTORY_FORFEIT, false, true, false, false); + } + + if (IGameEvent* event = gameeventmanager->CreateEvent("vip_death");) + { + gameeventmanager->FireEvent(event); + } + } + else if (!m_pVIP->IsAlive()) + { + if (sv_neo_vip_ctg_on_death.GetBool()) + { + UTIL_CenterPrintAll("- HVT DOWN - RECOVER THE GHOST -\n"); + SpawnTheGhost(&m_pVIP->GetAbsOrigin()); + } + else + { + // VIP was killed, end round + SetWinningTeam(GetOpposingTeam(m_iEscortingTeam), NEO_VICTORY_VIP_ELIMINATION, false, true, false, false); + } + + if (IGameEvent* event = gameeventmanager->CreateEvent("vip_death");) + { + event->SetInt("userid", m_pVIP->GetUserID()); + gameeventmanager->FireEvent(event); + } + } + + // Check if the vip was escorted during this Think + int captorTeam, captorClient; + for (int i = 0; i < m_pGhostCaps.Count(); i++) + { + auto pGhostCap = dynamic_cast(UTIL_EntityByIndex(m_pGhostCaps[i])); + if (!pGhostCap) + { + Assert(false); + continue; + } + + // If vip was escorted + if (pGhostCap->IsGhostCaptured(captorTeam, captorClient)) + { + // Turn off all capzones + for (int i = 0; i < m_pGhostCaps.Count(); i++) + { + auto pGhostCap = dynamic_cast(UTIL_EntityByIndex(m_pGhostCaps[i])); + if (!pGhostCap) + { + Assert(false); + continue; + } + pGhostCap->SetActive(false); + } + + // And then announce team victory + SetWinningTeam(captorTeam, NEO_VICTORY_VIP_ESCORT, false, true, false, false); + + if (IGameEvent* event = gameeventmanager->CreateEvent("vip_extract");) + { + CBasePlayer* pCaptorClient = UTIL_PlayerByIndex(captorClient); + event->SetInt("userid", pCaptorClient ? pCaptorClient->GetUserID() : INVALID_USER_ID); + gameeventmanager->FireEvent(event); + } + + break; + } + } + } + + CheckWinByElimination(); +#endif // GAME_DLL +} \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_vip.h b/src/game/shared/neo/gamerules/neo_gamerules_vip.h new file mode 100644 index 0000000000..c27895eb4f --- /dev/null +++ b/src/game/shared/neo/gamerules/neo_gamerules_vip.h @@ -0,0 +1,41 @@ +#pragma once + +#include "neo_gamerules.h" +#include "GameEventListener.h" + +#ifdef CLIENT_DLL + #define CNEORulesVIP C_NEORulesVIP + #define CNEOGameRulesVIPProxy C_NEOGameRulesVIPProxy +#endif +// +//ConVar sv_neo_vip_score_limit("sv_neo_vip_score_limit", "1", FCVAR_REPLICATED, "VIP score limit", true, 0.0f, true, 99.0f); +//ConVar sv_neo_vip_round_limit("sv_neo_vip_round_limit", "0", FCVAR_REPLICATED, "VIP max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +//ConVar sv_neo_vip_round_timelimit("neo_vip_round_timelimit", "10.25", FCVAR_REPLICATED, "VIP round timelimit, in minutes.", true, 0.0f, false, 600.0f); + +class CNEOGameRulesVIPProxy : public CNEOGameRulesProxy +{ +public: + DECLARE_CLASS( CNEOGameRulesVIPProxy, CNEOGameRulesProxy ); + DECLARE_NETWORKCLASS(); +}; + +class CNEORulesVIP : public CNEORules, public CGameEventListener +{ +public: + DECLARE_CLASS(CNEORulesVIP, CNEORules); + DECLARE_NETWORKCLASS_NOBASE(); + + + CNEORulesVIP(); + virtual ~CNEORulesVIP(); + + // IGameEventListener interface: + virtual void FireGameEvent(IGameEvent *event) override; + + virtual void Think() override final; +}; + +inline CNEORulesVIP *NEORulesVIP() +{ + return static_cast(g_pGameRules); +} \ No newline at end of file From d61bfb57fcdd7a7b317abd2ee733b862115a7923 Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Wed, 3 Jun 2026 21:16:02 +0100 Subject: [PATCH 10/16] wip --- src/game/client/CMakeLists.txt | 2 + .../client/neo/ui/neo_hud_round_state.cpp | 5 +- src/game/server/CMakeLists.txt | 4 +- src/game/server/neo/neo_dm_spawn.cpp | 255 -------- src/game/server/neo/neo_dm_spawn.h | 20 - src/game/server/neo/neo_game_config.cpp | 3 +- .../shared/neo/gamerules/neo_gamerules.cpp | 557 +++--------------- src/game/shared/neo/gamerules/neo_gamerules.h | 33 +- .../neo/gamerules/neo_gamerules_atk.cpp | 44 +- .../shared/neo/gamerules/neo_gamerules_atk.h | 13 +- .../neo/gamerules/neo_gamerules_ctg.cpp | 58 +- .../shared/neo/gamerules/neo_gamerules_ctg.h | 15 +- .../shared/neo/gamerules/neo_gamerules_dm.cpp | 72 ++- .../shared/neo/gamerules/neo_gamerules_dm.h | 17 +- .../neo/gamerules/neo_gamerules_emt.cpp | 39 +- .../shared/neo/gamerules/neo_gamerules_emt.h | 18 +- .../neo/gamerules/neo_gamerules_jgr.cpp | 119 +++- .../shared/neo/gamerules/neo_gamerules_jgr.h | 23 +- .../neo/gamerules/neo_gamerules_tdm.cpp | 68 ++- .../shared/neo/gamerules/neo_gamerules_tdm.h | 21 +- .../neo/gamerules/neo_gamerules_tut.cpp | 42 +- .../shared/neo/gamerules/neo_gamerules_tut.h | 17 +- .../neo/gamerules/neo_gamerules_vip.cpp | 52 +- .../shared/neo/gamerules/neo_gamerules_vip.h | 14 +- 24 files changed, 663 insertions(+), 848 deletions(-) delete mode 100644 src/game/server/neo/neo_dm_spawn.cpp delete mode 100644 src/game/server/neo/neo_dm_spawn.h diff --git a/src/game/client/CMakeLists.txt b/src/game/client/CMakeLists.txt index 194f5b45dd..8ef7ef7ae7 100644 --- a/src/game/client/CMakeLists.txt +++ b/src/game/client/CMakeLists.txt @@ -1674,6 +1674,8 @@ target_sources_grouped( ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_ctg.h ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_dm.cpp ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_dm.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_emt.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_emt.h ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_jgr.cpp ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_jgr.h ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_tdm.cpp diff --git a/src/game/client/neo/ui/neo_hud_round_state.cpp b/src/game/client/neo/ui/neo_hud_round_state.cpp index 5b5a39f215..3f553d92f6 100644 --- a/src/game/client/neo/ui/neo_hud_round_state.cpp +++ b/src/game/client/neo/ui/neo_hud_round_state.cpp @@ -20,6 +20,7 @@ #include "c_playerresource.h" #include "vgui_avatarimage.h" #include "neo_scoreboard.h" +#include "neo_gamerules_dm.h" #include "hltvcamera.h" @@ -380,7 +381,7 @@ void CNEOHud_RoundState::UpdateStateForNeoHudElementDraw() int secsTotal = 0.0f; if (roundStatus == NeoRoundStatus::Overtime && (NEORules()->GetGameType() == NEO_GAME_TYPE_CTG || NEORules()->GetGameType() == NEO_GAME_TYPE_ATK)) { - secsTotal = RoundFloatToInt(NEORules()->GetOverTime((NeoGameType)NEORules()->GetGameType())); + secsTotal = RoundFloatToInt(NEORules()->GetRoundRemainingTime()); } else { @@ -408,7 +409,7 @@ void CNEOHud_RoundState::UpdateStateForNeoHudElementDraw() else { [[maybe_unused]] int iDMHighestTotal; - NEORules()->GetDMHighestScorers(&iDMHighestTotal, &iDMHighestXP); + NEORulesDM()->GetDMHighestScorers(&iDMHighestTotal, &iDMHighestXP); } char szPlayersAliveANSI[ARRAYSIZE(m_wszPlayersAliveUnicode)] = {}; diff --git a/src/game/server/CMakeLists.txt b/src/game/server/CMakeLists.txt index 29ef9c8955..e264a8b0e5 100644 --- a/src/game/server/CMakeLists.txt +++ b/src/game/server/CMakeLists.txt @@ -1409,8 +1409,6 @@ target_sources_grouped( neo/neo_te_tocflash.h neo/neo_tracefilter_collisiongroupdelta.h neo/neo_typeconverter.cpp - neo/neo_dm_spawn.cpp - neo/neo_dm_spawn.h ) target_sources_grouped( @@ -1528,6 +1526,8 @@ target_sources_grouped( ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_ctg.h ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_dm.cpp ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_dm.h + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_emt.cpp + ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_emt.h ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_jgr.cpp ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_jgr.h ${CMAKE_SOURCE_DIR}/game/shared/neo/gamerules/neo_gamerules_tdm.cpp diff --git a/src/game/server/neo/neo_dm_spawn.cpp b/src/game/server/neo/neo_dm_spawn.cpp deleted file mode 100644 index e1fe2a4d2a..0000000000 --- a/src/game/server/neo/neo_dm_spawn.cpp +++ /dev/null @@ -1,255 +0,0 @@ -#include "neo_dm_spawn.h" - -#include -#include "cbase.h" -#include "inetchannelinfo.h" -#include "neo_player.h" -#include "neo_misc.h" -#include "util_shared.h" -#include "filesystem.h" -#include "utlbuffer.h" - -#include "tier0/memdbgon.h" - -static inline CUtlVector gDMSpawnLocs; -static inline int gDMSpawnCur = 0; -static inline CUtlVector gDMSpawnUsed; -static inline int gDMSpawnUsedTally = 0; - -namespace DMSpawn -{ -bool HasDMSpawn() -{ - return !gDMSpawnLocs.IsEmpty(); -} - -Info GiveNextSpawn() -{ - if (gDMSpawnLocs.IsEmpty()) return Info{}; - - // Try to give the next available spawn rather than just giving only a random number - const int iSpawnTotal = gDMSpawnLocs.Size(); - if (gDMSpawnUsedTally >= iSpawnTotal) - { - gDMSpawnUsed.SetCount(iSpawnTotal); - gDMSpawnUsedTally = 0; - } - - // iChecked for sanity check so it never inf. loop - static bool bCheckLeft = false; // Alternate check directions per spawning - int iPickSpawn = RandomInt(0, iSpawnTotal - 1); - for (int iChecked = 0; gDMSpawnUsed[iPickSpawn] && iChecked < iSpawnTotal; ++iChecked) - { - iPickSpawn = LoopAroundInArray(iPickSpawn + (bCheckLeft ? -1 : +1), iSpawnTotal); - } - bCheckLeft = !bCheckLeft; - - gDMSpawnUsed[iPickSpawn] = true; - ++gDMSpawnUsedTally; - return gDMSpawnLocs[iPickSpawn]; -} -} - -static CNEO_Player *LoopbackPlayer() -{ - for (int i = 1; i <= gpGlobals->maxClients; ++i) - { - auto *pPlayer = static_cast(UTIL_PlayerByIndex(i)); - if (!pPlayer || pPlayer->IsBot()) - { - continue; - } - INetChannelInfo *nci = engine->GetPlayerNetInfo(i); - Assert(nci); - if (nci) - { - if (nci->IsLoopback()) - { - return pPlayer; - } - } - } - return nullptr; -} - -static void DMSpawnComCallbackCreate() -{ - if (auto *player = LoopbackPlayer()) - { - const Vector newLoc = player->GetAbsOrigin(); - const QAngle lookAngle = player->GetAbsAngles(); - bool bAlreadyApplied = false; - for (const auto &spawn : gDMSpawnLocs) - { - if (spawn.pos == newLoc) - { - bAlreadyApplied = true; - break; - } - } - if (bAlreadyApplied) - { - Msg("DM Spawn already applied\n"); - } - else - { - gDMSpawnLocs.AddToTail(DMSpawn::Info{newLoc, lookAngle.y}); - gDMSpawnUsed.AddToTail(false); - Msg("DM Spawn: %.2f %.2f %.2f (%.2f) created\n", newLoc.x, newLoc.y, newLoc.z, lookAngle.y); - } - } -} - -static void DMSpawnComCallbackRemoveAll() -{ - gDMSpawnLocs.RemoveAll(); - gDMSpawnUsed.RemoveAll(); -} - -static void DMSpawnComCallbackRemoveOne(const CCommand &command) -{ - static constexpr char USAGE_MSG[] = "Usage: sv_neo_dmspawn_removeone [spawn index]\n"; - if (command.ArgC() != 2) - { - Msg(USAGE_MSG); - return; - } - const auto optIdx = StrToInt(command.Arg(1)); - if (!optIdx) - { - Msg(USAGE_MSG); - return; - } - - const int idx = *optIdx; - if (!IN_BETWEEN_AR(0, idx, gDMSpawnLocs.Size())) - { - Msg("Error: Index %d is not within 0 to %d.\n", idx, gDMSpawnLocs.Size() - 1); - return; - } - - gDMSpawnLocs.Remove(idx); - gDMSpawnUsed.Remove(idx); - Msg("Removed spawn %d\n", idx); -} - -static void DMSpawnComCallbackPrintLocs() -{ - for (int i = 0; i < gDMSpawnLocs.Size(); ++i) - { - const auto &spawn = gDMSpawnLocs[i]; - Msg("DM Spawn [%d]: %.2f %.2f %.2f (%.2f)\n", i, spawn.pos.x, spawn.pos.y, spawn.pos.z, spawn.lookY); - } -} - -static constexpr unsigned int MAGIC_NUMBER = 0x15AF73DA; -static constexpr int DMSPAWN_SERIAL_CURRENT = 1; - -void DMSpawnComCallbackSave([[maybe_unused]] const CCommand &command) -{ - if (gDMSpawnLocs.IsEmpty()) - { - return; - } - - CUtlBuffer buf; - buf.PutUnsignedInt(MAGIC_NUMBER); - buf.PutInt(DMSPAWN_SERIAL_CURRENT); - buf.PutInt(gDMSpawnLocs.Size()); - for (const auto &spawn : gDMSpawnLocs) - { - buf.PutFloat(spawn.pos.x); - buf.PutFloat(spawn.pos.y); - buf.PutFloat(spawn.pos.z); - buf.PutFloat(spawn.lookY); - } - - char szCurrentMapName[MAX_MAP_NAME + 1]; - V_strcpy_safe(szCurrentMapName, STRING(gpGlobals->mapname)); - filesystem->CreateDirHierarchy("maps/dm_locs"); - - char szFName[512]; - V_sprintf_safe(szFName, "maps/dm_locs/%s.loc", szCurrentMapName); - if (!filesystem->WriteFile(szFName, nullptr, buf)) - { - Msg("Failed to write file: %s\n", szFName); - return; - } - Msg("DMSpawn file saved: %s\n", szFName); -} - -void DMSpawnComCallbackLoad([[maybe_unused]] const CCommand &command) -{ - gDMSpawnLocs.RemoveAll(); - - char szCurrentMapName[MAX_MAP_NAME + 1]; - V_strcpy_safe(szCurrentMapName, STRING(gpGlobals->mapname)); - - CUtlBuffer buf(0, 0, CUtlBuffer::READ_ONLY); - char szFName[512]; - V_sprintf_safe(szFName, "maps/dm_locs/%s.loc", szCurrentMapName); - if (!filesystem->ReadFile(szFName, nullptr, buf)) - { - Msg("DMSpawn file not found: %s\n", szFName); - return; - } - - if (buf.GetUnsignedInt() != MAGIC_NUMBER) - { - return; - } - - /*const int version =*/ (void)buf.GetInt(); - const int locsSize = buf.GetInt(); - for (int i = 0; i < locsSize && buf.IsValid(); ++i) - { - DMSpawn::Info spawn = {}; - spawn.pos.x = buf.GetFloat(); - spawn.pos.y = buf.GetFloat(); - spawn.pos.z = buf.GetFloat(); - spawn.lookY = buf.GetFloat(); - gDMSpawnLocs.AddToTail(spawn); - } - gDMSpawnUsed.SetCount(gDMSpawnLocs.Size()); - Msg("DMSpawn file loaded: %s\n", szFName); -} - -static void DMSpawnComCallbackTeleportNext() -{ - if (gDMSpawnLocs.IsEmpty()) return; - gDMSpawnCur = LoopAroundInArray(gDMSpawnCur + 1, gDMSpawnLocs.Size()); - if (auto *pPlayer = LoopbackPlayer()) - { - const auto &spawn = gDMSpawnLocs[gDMSpawnCur]; - const QAngle spawnAngle{0, spawn.lookY, 0}; - pPlayer->SetAbsOrigin(spawn.pos); - pPlayer->SetAbsAngles(spawnAngle); - pPlayer->SnapEyeAngles(spawnAngle); - Msg("Teleported to spawn %d: %.2f %.2f %.2f (%.2f)\n", gDMSpawnCur, spawn.pos.x, spawn.pos.y, spawn.pos.z, spawn.lookY); - } -} - -static void DMSpawnComCallbackMapinfo() -{ - char szCurrentMapName[MAX_MAP_NAME + 1]; - V_strcpy_safe(szCurrentMapName, STRING(gpGlobals->mapname)); - - int iEntCount = 0; - CBaseEntity *entDMSpawn = nullptr; - while ((entDMSpawn = gEntList.FindEntityByClassname(entDMSpawn, "info_player_deathmatch"))) - { - ++iEntCount; - } - - Msg("Deathmatch spawns for: %s\ndmspawn spawns count: %d\ninfo_player_deathmatch count: %d\nAllow deathmatch: %s", - szCurrentMapName, gDMSpawnLocs.Size(), iEntCount, (iEntCount > 0 || !gDMSpawnLocs.IsEmpty()) ? "YES" : "NO"); -} - -ConCommand sv_neo_dmspawn_create("sv_neo_dmspawn_create", &DMSpawnComCallbackCreate, "DMSpawn - Create a new spawn", FCVAR_USERINFO | FCVAR_CHEAT); -ConCommand sv_neo_dmspawn_removeallspawns("sv_neo_dmspawn_removeallspawns", &DMSpawnComCallbackRemoveAll, "DMSpawn - Remove all spawns", FCVAR_USERINFO | FCVAR_CHEAT); -ConCommand sv_neo_dmspawn_removeone("sv_neo_dmspawn_removeone", &DMSpawnComCallbackRemoveOne, "DMSpawn - Remove one spawn by a given index", FCVAR_USERINFO | FCVAR_CHEAT); -ConCommand sv_neo_dmspawn_printlocs("sv_neo_dmspawn_printlocs", &DMSpawnComCallbackPrintLocs, "DMSpawn - Print locations and Y-angle of all spawns", FCVAR_USERINFO | FCVAR_CHEAT); -ConCommand sv_neo_dmspawn_save("sv_neo_dmspawn_save", &DMSpawnComCallbackSave, "DMSpawn - Save spawn file to filesystem", FCVAR_USERINFO | FCVAR_CHEAT); -ConCommand sv_neo_dmspawn_load("sv_neo_dmspawn_load", &DMSpawnComCallbackLoad, "DMSpawn - Load spawn file from filesystem", FCVAR_USERINFO | FCVAR_CHEAT); -ConCommand sv_neo_dmspawn_teleportnext("sv_neo_dmspawn_teleportnext", &DMSpawnComCallbackTeleportNext, "DMSpawn - Teleport to the next spawn", FCVAR_USERINFO | FCVAR_CHEAT); -ConCommand sv_neo_dmspawn_mapinfo("sv_neo_dmspawn_mapinfo", &DMSpawnComCallbackMapinfo, "DMSpawn - Map deathmatch spawns check and information", FCVAR_USERINFO); diff --git a/src/game/server/neo/neo_dm_spawn.h b/src/game/server/neo/neo_dm_spawn.h deleted file mode 100644 index 6c483bf726..0000000000 --- a/src/game/server/neo/neo_dm_spawn.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "mathlib/vector.h" -#include "convar.h" - -namespace DMSpawn -{ - -struct Info -{ - Vector pos; - float lookY; -}; - -bool HasDMSpawn(); -Info GiveNextSpawn(); - -} - -void DMSpawnComCallbackLoad([[maybe_unused]] const CCommand &command = CCommand{}); diff --git a/src/game/server/neo/neo_game_config.cpp b/src/game/server/neo/neo_game_config.cpp index 804f43e846..beadfb9643 100644 --- a/src/game/server/neo/neo_game_config.cpp +++ b/src/game/server/neo/neo_game_config.cpp @@ -1,5 +1,6 @@ #include "neo_game_config.h" #include "neo_gamerules.h" +#include "neo_gamerules_dm.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -67,7 +68,7 @@ void CNEOGameConfig::InputFireDMPlayerWin(inputdata_t& inputData) if (pPlayer) { - NEORules()->SetWinningDMPlayer(static_cast(pPlayer)); + NEORulesDM()->SetWinningDMPlayer(static_cast(pPlayer)); } } diff --git a/src/game/shared/neo/gamerules/neo_gamerules.cpp b/src/game/shared/neo/gamerules/neo_gamerules.cpp index 70c80d8128..a0859b0300 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules.cpp @@ -30,7 +30,6 @@ #include "hl2mp_gameinterface.h" #include "player_resource.h" #include "inetchannelinfo.h" -#include "neo_dm_spawn.h" #include "neo_game_config.h" #include "nav_mesh.h" #include "neo_npc_dummy.h" @@ -421,38 +420,6 @@ ConVar neo_round_limit("neo_round_limit", "0", FCVAR_REPLICATED | FCVAR_HIDDEN, ConVar neo_round_sudden_death("neo_round_sudden_death", "1", FCVAR_REPLICATED, "If neo_round_limit is not 0 and round is past " "neo_round_limit, go into sudden death where match won't end until a team won.", true, 0.0f, true, 1.0f); -// Score Limit -ConVar sv_neo_ctg_score_limit("sv_neo_ctg_score_limit", "7", FCVAR_REPLICATED, "CTG score limit", true, 0.0f, true, 99.0f); - -ConVar sv_neo_vip_score_limit("sv_neo_vip_score_limit", "7", FCVAR_REPLICATED, "VIP score limit", true, 0.0f, true, 99.0f); - -ConVar sv_neo_dm_score_limit("sv_neo_dm_score_limit", "7", FCVAR_REPLICATED, "DM score limit", true, 0.0f, true, 99.0f); - -ConVar sv_neo_jgr_score_limit("sv_neo_jgr_score_limit", "0", FCVAR_REPLICATED, "JGR score limit", true, 0.0f, true, 99.0f); - -ConVar sv_neo_atk_score_limit("sv_neo_atk_score_limit", "7", FCVAR_REPLICATED, "ATK score limit", true, 0.0f, true, 99.0f); - -// Round Limit -ConVar sv_neo_ctg_round_limit("sv_neo_ctg_round_limit", "0", FCVAR_REPLICATED, "CTG max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); - -ConVar sv_neo_vip_round_limit("sv_neo_vip_round_limit", "0", FCVAR_REPLICATED, "VIP max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); - -ConVar sv_neo_dm_round_limit("sv_neo_dm_round_limit", "0", FCVAR_REPLICATED, "DM max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); - -ConVar sv_neo_jgr_round_limit("sv_neo_jgr_round_limit", "5", FCVAR_REPLICATED, "JGR max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); - -ConVar sv_neo_atk_round_limit("sv_neo_atk_round_limit", "0", FCVAR_REPLICATED, "ATK max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); - -// Round Time Limit (make these sv_neo at some point) - -ConVar neo_vip_round_timelimit("neo_vip_round_timelimit", "3.25", FCVAR_REPLICATED, "VIP round timelimit, in minutes.", - true, 0.0f, false, 600.0f); - -ConVar neo_dm_round_timelimit("neo_dm_round_timelimit", "10.25", FCVAR_REPLICATED, "DM round timelimit, in minutes.", - true, 0.0f, false, 600.0f); - -ConVar neo_jgr_round_timelimit("neo_jgr_round_timelimit", "4.25", FCVAR_REPLICATED, "JGR round timelimit, in minutes.", - true, 0.0f, false, 600.0f); ConVar sv_neo_ignore_wep_xp_limit("sv_neo_ignore_wep_xp_limit", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "If true, allow equipping any loadout regardless of player XP.", true, 0.0f, true, 1.0f); @@ -831,7 +798,6 @@ void CNEORules::ResetMapSessionCommon() m_bTeamBeenAwardedDueToCapPrevent = false; V_memset(m_arrayiEntPrevCap, 0, sizeof(m_arrayiEntPrevCap)); m_iEntPrevCapSize = 0; - DMSpawnComCallbackLoad(); m_vecPreviousGhostSpawn = vec3_origin; m_vecPreviousJuggernautSpawn = vec3_origin; m_pJuggernautItem = nullptr; @@ -906,7 +872,7 @@ bool CNEORules::CheckShouldNotThink() } #ifdef GAME_DLL -bool CNEORules::RoundIdlePausedStartThink() +bool CNEORules::RoundStartFromIdleOrPausedThink() { UpdateFromGameConfig(); @@ -952,6 +918,8 @@ bool CNEORules::RoundIdlePausedStartThink() UTIL_CenterPrintAll("- MATCH IS CURRENTLY PAUSED -\n"); } } + + return false; } void CNEORules::PlayerRespawnThink() @@ -1190,7 +1158,7 @@ COMPILE_TIME_ASSERT(TEAM_JINRAI == 2 && TEAM_NSF == 3); void CNEORules::Think(void) { #ifdef GAME_DLL - if (RoundIdlePausedStartThink()) + if (RoundStartFromIdleOrPausedThink()) return; PlayerRespawnThink(); @@ -1244,113 +1212,62 @@ void CNEORules::AwardRankUp(CNEO_Player *pClient) } #endif -ConVar sv_neo_tdm_score_limit("sv_neo_tdm_score_limit", "1", FCVAR_REPLICATED, "TDM score limit", true, 0.0f, true, 99.0f); -ConVar sv_neo_tdm_round_limit("sv_neo_tdm_round_limit", "0", FCVAR_REPLICATED, "TDM max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); -ConVar neo_tdm_round_timelimit("neo_tdm_round_timelimit", "10.25", FCVAR_REPLICATED, "TDM round timelimit, in minutes.", true, 0.0f, false, 600.0f); - +float CNEORules::GetRoundRemainingTime() const +{ + Assert(false); // Implement in the derived gamemode class + constexpr float DEFAULT_ROUND_TIMELIMIT = 3.25f; + return GetRoundRemainingTime(DEFAULT_ROUND_TIMELIMIT); +} // Return remaining time in seconds. Zero means there is no time limit. -float CNEORules::GetRoundRemainingTime() const +float CNEORules::GetRoundRemainingTime(float flGameTypeRoundTimeLimit) const { - if (m_nRoundStatus == NeoRoundStatus::Idle) + if (NeoRoundStatus::Idle == m_nRoundStatus) { - return 0; + return 0.f; } - if (m_nRoundStatus == NeoRoundStatus::PostRound) + if (NeoRoundStatus::PostRound == m_nRoundStatus) { return m_flNeoNextRoundStartTime - gpGlobals->curtime; } float roundTimeLimit = 0.f; - if (m_nRoundStatus == NeoRoundStatus::Warmup) + if (NeoRoundStatus::Warmup == m_nRoundStatus) { roundTimeLimit = sv_neo_warmup_round_time.GetFloat(); } - else if (m_nRoundStatus == NeoRoundStatus::Countdown) + else if (NeoRoundStatus::Countdown == m_nRoundStatus) { roundTimeLimit = sv_neo_readyup_countdown.GetFloat(); } else { - switch (m_nGameTypeSelected) { - case NEO_GAME_TYPE_TDM: - roundTimeLimit = neo_tdm_round_timelimit.GetFloat() * 60.f; - break; - case NEO_GAME_TYPE_CTG: - roundTimeLimit = neo_ctg_round_timelimit.GetFloat() * 60.f; - if (m_nRoundStatus == NeoRoundStatus::Overtime) - { - return GetOverTime(NEO_GAME_TYPE_CTG); - } - break; - case NEO_GAME_TYPE_VIP: - roundTimeLimit = neo_vip_round_timelimit.GetFloat() * 60.f; - break; - case NEO_GAME_TYPE_DM: - roundTimeLimit = neo_dm_round_timelimit.GetFloat() * 60.f; - break; - case NEO_GAME_TYPE_JGR: - roundTimeLimit = neo_jgr_round_timelimit.GetFloat() * 60.f; - break; - case NEO_GAME_TYPE_ATK: - roundTimeLimit = neo_atk_round_timelimit.GetFloat() * 60.f; - if (m_nRoundStatus == NeoRoundStatus::Overtime) - { - return GetOverTime(NEO_GAME_TYPE_ATK); - } - break; - default: - break; - } + roundTimeLimit = flGameTypeRoundTimeLimit * 60.f; } return (m_flNeoRoundStartTime + roundTimeLimit) - gpGlobals->curtime; } -float CNEORules::GetOverTime(NeoGameType eGameType) const +float CNEORules::GetOverTime(float flRoundTimeLimit, float flOvertimeBaseAmount, float flOvertimeGrace, float flGraceDecay) const { - float roundTimeLimit; - float overtimeBaseAmount; - float overtimeGrace; - bool graceDecay; - - switch (eGameType) - { - case NeoGameType::NEO_GAME_TYPE_CTG: - roundTimeLimit = neo_ctg_round_timelimit.GetFloat() * 60.f; - overtimeBaseAmount = sv_neo_ctg_ghost_overtime.GetFloat(); - overtimeGrace = sv_neo_ctg_ghost_overtime_grace.GetFloat(); - graceDecay = sv_neo_ctg_ghost_overtime_grace_decay.GetBool(); - break; - case NeoGameType::NEO_GAME_TYPE_ATK: - roundTimeLimit = neo_atk_round_timelimit.GetFloat() * 60.f; - overtimeBaseAmount = sv_neo_atk_ghost_overtime.GetFloat(); - overtimeGrace = sv_neo_atk_ghost_overtime_grace.GetFloat(); - graceDecay = sv_neo_atk_ghost_overtime_grace_decay.GetBool(); - break; - default: - Assert(false && "Tried to calculate overtime for a gamemode with no overtime implementation"); - return 0; - } + float overtime = (m_flNeoRoundStartTime + flRoundTimeLimit + flOvertimeBaseAmount) - gpGlobals->curtime; - float overtime = (m_flNeoRoundStartTime + roundTimeLimit + overtimeBaseAmount) - gpGlobals->curtime; - - if (graceDecay) + if (flGraceDecay) { - if (m_iGhosterPlayer) + if (m_iGhosterPlayer) // NEO TODO (Adam) gamemode specific check? { return overtime; } else { - float overtimeAtGhostDrop = (m_flNeoRoundStartTime + roundTimeLimit + overtimeBaseAmount) - m_flGhostLastHeld; - return (overtimeAtGhostDrop * overtimeGrace / (overtimeBaseAmount + overtimeGrace)) - (gpGlobals->curtime - m_flGhostLastHeld); + float overtimeAtGhostDrop = (m_flNeoRoundStartTime + flRoundTimeLimit + flOvertimeBaseAmount) - m_flGhostLastHeld; + return (overtimeAtGhostDrop * flOvertimeGrace / (flOvertimeBaseAmount + flOvertimeGrace)) - (gpGlobals->curtime - m_flGhostLastHeld); } } else { - float grace = overtimeGrace - (gpGlobals->curtime - m_flGhostLastHeld); + float grace = flOvertimeGrace - (gpGlobals->curtime - m_flGhostLastHeld); if (m_iGhosterPlayer || overtime < grace) { return overtime; @@ -2076,62 +1993,6 @@ CNEORules::ReadyPlayers CNEORules::FetchReadyPlayers() const return readyPlayers; } -const int CNEORules::GetScoreLimit() const -{ - switch (m_nGameTypeSelected) - { - case NEO_GAME_TYPE_TDM: - return sv_neo_tdm_score_limit.GetInt(); - break; - case NEO_GAME_TYPE_CTG: - return sv_neo_ctg_score_limit.GetInt(); - break; - case NEO_GAME_TYPE_VIP: - return sv_neo_vip_score_limit.GetInt(); - break; - case NEO_GAME_TYPE_DM: - return sv_neo_dm_score_limit.GetInt(); - break; - case NEO_GAME_TYPE_JGR: - return sv_neo_jgr_score_limit.GetInt(); - break; - case NEO_GAME_TYPE_ATK: - return sv_neo_atk_score_limit.GetInt(); - break; - default: - return sv_neo_ctg_score_limit.GetInt(); - break; - } -} - -const int CNEORules::GetRoundLimit() const -{ - switch (m_nGameTypeSelected) - { - case NEO_GAME_TYPE_TDM: - return sv_neo_tdm_round_limit.GetInt(); - break; - case NEO_GAME_TYPE_CTG: - return sv_neo_ctg_round_limit.GetInt(); - break; - case NEO_GAME_TYPE_VIP: - return sv_neo_vip_round_limit.GetInt(); - break; - case NEO_GAME_TYPE_DM: - return sv_neo_dm_round_limit.GetInt(); - break; - case NEO_GAME_TYPE_JGR: - return sv_neo_jgr_round_limit.GetInt(); - break; - case NEO_GAME_TYPE_ATK: - return sv_neo_atk_round_limit.GetInt(); - break; - default: - return sv_neo_ctg_round_limit.GetInt(); - break; - } -} - void CNEORules::StartNextRound() { // Only check ready-up on idle state @@ -2380,105 +2241,6 @@ void CNEORules::StartNextRound() DevMsg("New round start here!\n"); } - -void CNEORules::RoundTimeout() -{ - bool winnerDetermined = false; - switch (GetGameType()) - { - case NEO_GAME_TYPE_TDM: winnerDetermined = RoundTimeoutTDM(); - break; - case NEO_GAME_TYPE_DM: winnerDetermined = RoundTimeoutDM(); - break; - case NEO_GAME_TYPE_JGR: winnerDetermined = RoundTimeoutJGR(); - break; - case NEO_GAME_TYPE_ATK: winnerDetermined = RoundTimeoutATK(); - break; - default: - break; - } - if (!winnerDetermined && IsTeamplay()) - { - SetWinningTeam(TEAM_SPECTATOR, NEO_VICTORY_STALEMATE, false, false, true, false); - } -} - -bool CNEORules::RoundTimeoutTDM() -{ - if (GetGlobalTeam(TEAM_JINRAI)->GetScore() > GetGlobalTeam(TEAM_NSF)->GetScore()) - { - SetWinningTeam(TEAM_JINRAI, NEO_VICTORY_POINTS, false, true, false, false); - return true; - } - if (GetGlobalTeam(TEAM_NSF)->GetScore() > GetGlobalTeam(TEAM_JINRAI)->GetScore()) - { - SetWinningTeam(TEAM_NSF, NEO_VICTORY_POINTS, false, true, false, false); - return true; - } - return false; -} - -bool CNEORules::RoundTimeoutDM() -{ - // Winning player - CNEO_Player* pWinners[MAX_PLAYERS + 1] = {}; - int iWinnersTotal = 0; - int iWinnerXP = 0; - GetDMHighestScorers(&pWinners, &iWinnersTotal, &iWinnerXP); - if (iWinnersTotal == 1) - { - SetWinningDMPlayer(pWinners[0]); - return true; - } - // Otherwise go into overtime - return false; -} - -bool CNEORules::RoundTimeoutJGR() -{ - if ((!m_pJuggernautPlayer && m_pJuggernautItem && !m_pJuggernautItem->IsBeingActivatedByLosingTeam()) || - (!m_pJuggernautPlayer && !m_pJuggernautItem)) // Juggernaut is absent entirely - { - if (GetGlobalTeam(TEAM_JINRAI)->GetScore() > GetGlobalTeam(TEAM_NSF)->GetScore()) - { - SetWinningTeam(TEAM_JINRAI, NEO_VICTORY_POINTS, false, true, false, false); - return true; - } - - if (GetGlobalTeam(TEAM_NSF)->GetScore() > GetGlobalTeam(TEAM_JINRAI)->GetScore()) - { - SetWinningTeam(TEAM_NSF, NEO_VICTORY_POINTS, false, true, false, false); - return true; - } - } - else - { - if (m_nRoundStatus == NeoRoundStatus::RoundLive) - { - m_nRoundStatus = NeoRoundStatus::Overtime; - } - - if (m_pJuggernautPlayer) - { - const int jgrTeam = m_pJuggernautPlayer->GetTeamNumber(); - const int oppositeTeam = (m_pJuggernautPlayer->GetTeamNumber() == TEAM_JINRAI ? TEAM_NSF : TEAM_JINRAI); - if (GetGlobalTeam(jgrTeam)->GetScore() > GetGlobalTeam(oppositeTeam)->GetScore()) - { - SetWinningTeam(jgrTeam, NEO_VICTORY_POINTS, false, true, false, false); - return true; - } - } - - return true; - } - return false; -} - -bool CNEORules::RoundTimeoutATK() -{ - SetWinningTeam(GetDefendingTeam(), NEO_VICTORY_ATK_TIMEOUT, false, true, false, false); - return true; -} #endif bool CNEORules::IsRoundPreRoundFreeze() const @@ -2509,29 +2271,45 @@ bool CNEORules::IsRoundOver() const bool CNEORules::IsRoundLive() const { - return (m_nRoundStatus == NeoRoundStatus::RoundLive || m_nRoundStatus == NeoRoundStatus::Overtime); + switch (m_nRoundStatus) + { + case NeoRoundStatus::RoundLive: + case NeoRoundStatus::Overtime: + return true; + } + return false; } bool CNEORules::IsRoundOn() const { - return (m_nRoundStatus == NeoRoundStatus::PreRoundFreeze) || IsRoundLive() || (m_nRoundStatus == NeoRoundStatus::PostRound); + switch (m_nRoundStatus) + { + case NeoRoundStatus::Idle: + case NeoRoundStatus::Warmup: + case NeoRoundStatus::PreRoundFreeze: + case NeoRoundStatus::Overtime: + case NeoRoundStatus::PostRound: + case NeoRoundStatus::Countdown: + return true; + } + return false; } bool CNEORules::IsRoundIdle() const { switch (m_nRoundStatus) { - case NeoRoundStatus::Idle: - case NeoRoundStatus::Warmup: - case NeoRoundStatus::Countdown: - return false; + case NeoRoundStatus::Idle: + case NeoRoundStatus::Warmup: + case NeoRoundStatus::Countdown: + return true; } - return true; + return false; } bool CNEORules::IsRoundPaused() const { - return m_nRoundStatus == NeoRoundStatus::Pause; + return NeoRoundStatus::Pause == m_nRoundStatus; } void CNEORules::CreateStandardEntities(void) @@ -2550,22 +2328,6 @@ void CNEORules::CreateStandardEntities(void) #endif } -const SZWSZTexts NEO_GAME_TYPE_DESC_STRS[NEO_GAME_TYPE__TOTAL] = { - SZWSZ_INIT("Team Deathmatch"), - SZWSZ_INIT("Capture the Ghost"), - SZWSZ_INIT("Extract or Kill the VIP"), - SZWSZ_INIT("Deathmatch"), - SZWSZ_INIT("Free Roam"), - SZWSZ_INIT("Training"), - SZWSZ_INIT("Juggernaut"), - SZWSZ_INIT("Attack/Defend"), -}; - -const char *CNEORules::GetGameDescription(void) -{ - return NEO_GAME_TYPE_DESC_STRS[GetGameType()].szStr; -} - const CViewVectors *CNEORules::GetViewVectors() const { return &g_NEOViewVectors; @@ -2769,64 +2531,7 @@ void CNEORules::ResetGhostCapPoints() } } -void CNEORules::SetGameRelatedVars() -{ - ResetTDM(); - - ResetGhost(); - NeoGameType eGameType = (NeoGameType)GetGameType(); - if (eGameType == NEO_GAME_TYPE_CTG || eGameType == NEO_GAME_TYPE_ATK) - { - SpawnTheGhost(); - } - - ResetVIP(); - if (eGameType == NEO_GAME_TYPE_VIP) - { - if (!m_iEscortingTeam) - { - m_iEscortingTeam.Set(RandomInt(TEAM_JINRAI, TEAM_NSF)); - } - else - { - m_iEscortingTeam.Set(m_iEscortingTeam.Get() == TEAM_JINRAI ? TEAM_NSF : TEAM_JINRAI); - } - - SelectTheVIP(); - } - else - { - m_iEscortingTeam.Set(0); - } - - if (eGameType == NEO_GAME_TYPE_TDM) - { - for (int i = 0; i < GetNumberOfTeams(); i++) - { - GetGlobalTeam(i)->SetScore(0); - } - } - - if (eGameType == NEO_GAME_TYPE_DM) - { - for (int i = 1; i <= gpGlobals->maxClients; ++i) - { - auto pPlayer = static_cast(UTIL_PlayerByIndex(i)); - if (pPlayer) - { - pPlayer->m_iXP.GetForModify() = 0; - } - } - } - - if (eGameType == NEO_GAME_TYPE_JGR) - { - ResetJGR(); - SpawnTheJuggernaut(); - } -} - -void CNEORules::ResetTDM() +void CNEORules::ResetTeamScores() { for (int i = 0; i < GetNumberOfTeams(); i++) { @@ -3385,7 +3090,7 @@ void CNEORules::SetWinningTeam(int team, int iWinReason, bool bForceMapReset, bo WRITE_FLOAT(gpGlobals->curtime); // when did they win if(iWinReason != NEO_VICTORY_MAPIO) { - WRITE_STRING(victoryMsg); // extra message (who capped or last kill or who got the most points or whatever) + WRITE_STRING(victoryMsg); // extra message (who capped or last kill or who got the most points or whatever) } MessageEnd(); @@ -3581,99 +3286,74 @@ void CNEORules::CheckIfCapPrevent(CNEO_Player *capPreventerPlayer) void CNEORules::PlayerKilled(CBasePlayer *pVictim, const CTakeDamageInfo &info) { +#ifdef GAME_DLL BaseClass::PlayerKilled(pVictim, info); - auto attacker = dynamic_cast(info.GetAttacker()); - auto victim = dynamic_cast(pVictim); - auto grenade = dynamic_cast(info.GetInflictor()); + auto pNEOAttacker = dynamic_cast(info.GetAttacker()); + auto pNEOVictim = dynamic_cast(pVictim); + auto pGrenade = dynamic_cast(info.GetInflictor()); - if (!victim) + if (!pNEOVictim) { + Assert(false); return; } - if (m_nRoundStatus == NeoRoundStatus::Pause) + if (NeoRoundStatus::Pause == m_nRoundStatus) { -#ifdef GAME_DLL - // Counter-act the death count for pausing state - victim->IncrementDeathCount(-1); -#endif + // restore the death count during pause + pNEOVictim->IncrementDeathCount(-1); return; } // Suicide or suicide by environment (non-grenade as grenade is likely from a player) - if (attacker == victim || (!attacker && !grenade)) + if (pNEOAttacker == pNEOVictim || (!pNEOAttacker && !pGrenade)) { - victim->AddPoints(-1, true); -#ifdef GAME_DLL - CheckIfCapPrevent(victim); -#endif + pNEOVictim->AddPoints(-1, true); + CheckIfCapPrevent(pNEOVictim); } -#ifdef GAME_DLL - else if (!attacker && grenade && grenade->GetTeamNumber() == victim->GetTeamNumber()) + else if (!pNEOAttacker && pGrenade && pGrenade->GetTeamNumber() == pNEOVictim->GetTeamNumber()) { // Death by own team's grenade, but the player is already disconnected. Check for cap prevent. - CheckIfCapPrevent(victim); + CheckIfCapPrevent(pNEOVictim); } -#endif - else if (attacker) + else if (pNEOAttacker) { // Team kill - if (IsTeamplay() && attacker->GetTeamNumber() == victim->GetTeamNumber()) + if (IsTeamplay() && pNEOAttacker->GetTeamNumber() == pNEOVictim->GetTeamNumber()) { - attacker->AddPoints(-1, true); -#ifdef GAME_DLL + pNEOAttacker->AddPoints(-1, true); if (sv_neo_teamdamage_kick.GetBool() && IsRoundLive()) { - ++attacker->m_iTeamKillsInflicted; + ++pNEOAttacker->m_iTeamKillsInflicted; } for (int i = 0; i < m_iEntPrevCapSize; ++i) { - if (m_arrayiEntPrevCap[i] == attacker->entindex()) + if (m_arrayiEntPrevCap[i] == pNEOAttacker->entindex()) { // Posthumous teamkill to prevent ghost cap scenario: // Player-A throws nade at Player-B, Player-A suicides right after, // Player-B gets killed from the nade - This dodges the general case // as Player-A is not the final player, but it was Player-A's intention // to prevent the ghost cap. - CheckIfCapPrevent(victim); + CheckIfCapPrevent(pNEOVictim); break; } } -#endif } // Enemy kill else { - attacker->AddPoints(1, false); -#ifdef GAME_DLL - if (GetGameType() == NEO_GAME_TYPE_JGR && IsRoundLive()) - { - if (attacker->GetClass() == NEO_CLASS_JUGGERNAUT) - { - auto jgrTeam = attacker->GetTeam(); - jgrTeam->SetScore(Min(jgrTeam->GetScore() + 2, sv_neo_jgr_max_points.GetInt())); - } - else if (m_pJuggernautPlayer) - { - const int attackerTeam = attacker->GetTeamNumber(); - const int jgrTeam = m_pJuggernautPlayer->GetTeamNumber(); - - if (attackerTeam == jgrTeam) - { - attacker->GetTeam()->AddScore(1); - } - } - } -#endif + pNEOAttacker->AddPoints(1, false); + EnemyPlayerKilled(pNEOVictim, pNEOAttacker, info); } } - if (auto *assister = FetchAssists(attacker, victim)) + if (auto *assister = FetchAssists(pNEOAttacker, pNEOVictim)) { // Team kill assist - if (assister->GetTeamNumber() == victim->GetTeamNumber()) + if (assister->GetTeamNumber() == pNEOVictim->GetTeamNumber()) { if (sv_neo_teamdamage_assists.GetBool()) { @@ -3686,6 +3366,7 @@ void CNEORules::PlayerKilled(CBasePlayer *pVictim, const CTakeDamageInfo &info) assister->AddPoints(1, false); } } +#endif // GAME_DLL } #ifdef GAME_DLL @@ -3980,98 +3661,34 @@ bool CNEORules::GetTeamPlayEnabled() const #ifdef GAME_DLL bool CNEORules::FPlayerCanRespawn(CBasePlayer* pPlayer) { - // Special case for spectator player takeover CNEO_Player* pNeoPlayer = ToNEOPlayer(pPlayer); - Assert(pNeoPlayer); - if (pNeoPlayer->GetSpectatorTakeoverPlayerPending()) - { - return true; - } - - auto gameType = GetGameType(); - - if (gameType == NEO_GAME_TYPE_JGR && (pPlayer->GetTeamNumber() == m_iLastJuggernautTeam)) + if (!pNeoPlayer) { - if (m_pJuggernautPlayer || (gpGlobals->curtime - m_flJuggernautDeathTime) <= 8.0f) - { - return false; - } + Assert(false); + return false; } - - if (CanRespawnAnyTime()) - { - if (GetRoundStatus() == PostRound) - { - return false; - } - + + // Special case for spectator player takeover + if (pNeoPlayer->GetSpectatorTakeoverPlayerPending()) return true; - } - else if (gameType == NEO_GAME_TYPE_TUT) - { - if (pPlayer->IsAlive()) - { - return false; - } + if (!IsRoundOn()) return true; - } - - auto jinrai = GetGlobalTeam(TEAM_JINRAI); - auto nsf = GetGlobalTeam(TEAM_NSF); - - if (jinrai && nsf) - { - if (!IsRoundOn()) - { - return true; - } - - if (pNeoPlayer->m_bSpawnedThisRound && !IsRoundPreRoundFreeze()) - { - return false; - } - } - else - { - Assert(false); - } + if (pNeoPlayer->m_bSpawnedThisRound && !IsRoundPreRoundFreeze()) + return false; + // Do not let anyone who tried to team-kill during mirror damage + live round to respawn - if (static_cast(pPlayer)->m_bKilledInflicted) - { + if (pNeoPlayer->m_bKilledInflicted) return false; - } - + // Did we make it in time to spawn for this round? if (GetRemainingPreRoundFreezeTime(false) + sv_neo_latespawn_max_time.GetFloat() > 0) - { return true; - } return false; } -CBaseEntity *CNEORules::GetPlayerSpawnSpot(CBasePlayer *pPlayer) -{ - // NEO NOTE (nullsystem): If available + DM, instead of by entity, player spawn - // by set position. It doesn't seem anything utilizes what returned anyway. - if (m_nGameTypeSelected == NEO_GAME_TYPE_DM && DMSpawn::HasDMSpawn()) - { - const auto spawn = DMSpawn::GiveNextSpawn(); - const QAngle spawnAngle{0, spawn.lookY, 0}; - pPlayer->SetLocalOrigin(spawn.pos + Vector(0,0,1)); - pPlayer->SetAbsVelocity(vec3_origin); - pPlayer->SetLocalAngles(spawnAngle); - pPlayer->m_Local.m_vecPunchAngle = vec3_angle; - pPlayer->m_Local.m_vecPunchAngleVel = vec3_angle; - pPlayer->SnapEyeAngles(spawnAngle); - return nullptr; - } - - return BaseClass::GetPlayerSpawnSpot(pPlayer); -} - #endif #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules.h b/src/game/shared/neo/gamerules/neo_gamerules.h index 4e03eebcdd..abb2041d34 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules.h +++ b/src/game/shared/neo/gamerules/neo_gamerules.h @@ -212,7 +212,7 @@ friend class C_NEORulesVIP; virtual const unsigned char* GetEncryptionKey(void) OVERRIDE { return (unsigned char*)"tBA%-ygc"; } #ifdef GAME_DLL - bool RoundIdlePausedStartThink(); + bool RoundStartFromIdleOrPausedThink(); virtual void PlayerRespawnThink(); void CheckClantagsThink(); bool GameOverThink(); @@ -232,8 +232,7 @@ friend class C_NEORulesVIP; virtual const char* GetChatPrefix(bool bTeamOnly, CBasePlayer* pPlayer) OVERRIDE { return ""; } // handled by GetChatFormat virtual const char* GetChatLocation(bool bTeamOnly, CBasePlayer* pPlayer) OVERRIDE { return NULL; } // unimplemented - CBaseEntity *GetPlayerSpawnSpot(CBasePlayer *pPlayer) override; - virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) OVERRIDE; + virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) override; virtual float FlPlayerFallDamage(CBasePlayer* pPlayer) OVERRIDE; @@ -245,11 +244,7 @@ friend class C_NEORulesVIP; // NEOGameConfig is a logic entity, which is a server only entity. To access config values client side, we need to copy values to a networked entity void UpdateFromGameConfig(); void StartNextRound(); - void RoundTimeout(); - bool RoundTimeoutTDM(); // NEO TODO (Adam) move to related gamerules - bool RoundTimeoutDM(); // NEO TODO (Adam) move to related gamerules - bool RoundTimeoutJGR(); // NEO TODO (Adam) move to related gamerules - bool RoundTimeoutATK(); // NEO TODO (Adam) move to related gamerules + virtual void RoundTimeout() {}; struct ReadyPlayers @@ -283,15 +278,16 @@ friend class C_NEORulesVIP; virtual void ClientSettingsChanged(CBasePlayer *pPlayer) OVERRIDE; virtual void ClientSpawned(edict_t* pPlayer) OVERRIDE; - virtual void PlayerKilled(CBasePlayer *pVictim, const CTakeDamageInfo &info) OVERRIDE; + virtual void PlayerKilled(CBasePlayer *pVictim, const CTakeDamageInfo &info) override; + virtual void EnemyPlayerKilled(CNEO_Player* pVictim, CNEO_Player* pAttacker, const CTakeDamageInfo& info) {}; virtual void DeathNotice(CBasePlayer* pVictim, const CTakeDamageInfo& info) OVERRIDE; virtual const char* GetGameName() { return NEO_GAME_NAME; } virtual const char* GetGameTypeName(void) override; virtual int GetGameType(void) override; - virtual const char *GetGameDescription( void ) override; - bool GetTeamPlayEnabled() const override; + virtual const char* GetGameDescription(void) override { return NEO_GAME_NAME; }; + virtual bool GetTeamPlayEnabled() const override; int GetHiddenHudElements(); int GetForcedTeam(); int GetForcedClass(); @@ -312,8 +308,9 @@ friend class C_NEORulesVIP; int GetDefendingTeam() const; float GetRemainingPreRoundFreezeTime(const bool clampToZero) const; float GetMapRemainingTime(); - float GetRoundRemainingTime() const; - float GetOverTime(NeoGameType eGameType) const; + virtual float GetRoundRemainingTime() const; + float GetRoundRemainingTime(float flGameTypeRoundTimeLimit) const; + float GetOverTime(float flRoundTimeLimit, float flOvertimeBaseAmount, float flOvertimeGrace, float flGraceDecay) const; virtual void CheckOvertime(); virtual bool CheckGameOver(void) OVERRIDE; // NEO TODO (Adam) this changes map as a side effect, better name? Also is this called client side anywhere? float GetRoundAccumulatedTime() const; @@ -377,8 +374,10 @@ friend class C_NEORulesVIP; void PurgeGhostCapPoints(); // NEO TODO (Adam) move to ctg / vip gamerules void ResetGhostCapPoints(); // NEO TODO (Adam) move to ctg / vip gamerules - void SetGameRelatedVars(); // NEO TODO (Adam) move to related gamerules - void ResetTDM(); // NEO TODO (Adam) move to related gamerules +#ifdef GAME_DLL + virtual void SetGameRelatedVars() {}; + void ResetTeamScores(); +#endif // GAME_DLL void ResetGhost(); // NEO TODO (Adam) move to related gamerules void ResetVIP(); // NEO TODO (Adam) move to related gamerules void ResetJGR(); // NEO TODO (Adam) move to related gamerules @@ -434,8 +433,8 @@ friend class C_NEORulesVIP; void ResetMapSessionCommon(); // NEO TODO (Adam) Is this needed client side #ifdef GAME_DLL - const int GetScoreLimit() const; - const int GetRoundLimit() const; + virtual const int GetScoreLimit() const { Assert(false); return 0; }; + virtual const int GetRoundLimit() const { Assert(false); return 0; }; void SpawnTheGhost(const Vector *origin = nullptr); void SpawnTheJuggernaut(const Vector *origin = nullptr); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp index cf84f73d79..3312ca4f9e 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp @@ -43,14 +43,15 @@ IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesATKProxy, DT_NEOGameRulesATKProxy ); END_SEND_TABLE() #endif -ConVar sv_neo_atk_round_timelimit("neo_atk_round_timelimit", "3.25", FCVAR_REPLICATED, "ATK round timelimit, in minutes.", true, 0.0f, false, 600.0f); +ConVar sv_neo_atk_round_limit("sv_neo_atk_round_limit", "0", FCVAR_REPLICATED, "ATK max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +ConVar sv_neo_atk_round_timelimit("sv_neo_atk_round_timelimit", "3.25", FCVAR_REPLICATED, "ATK round timelimit, in minutes.", true, 0.0f, false, 600.0f); +ConVar sv_neo_atk_score_limit("sv_neo_atk_score_limit", "7", FCVAR_REPLICATED, "ATK score limit", true, 0.0f, true, 99.0f); ConVar sv_neo_atk_ghost_overtime_enabled("sv_neo_atk_ghost_overtime_enabled", "0", FCVAR_REPLICATED, "Enable ghost overtime in the ATK mode.", true, 0, true, 1); ConVar sv_neo_atk_ghost_overtime("sv_neo_atk_ghost_overtime", "45", FCVAR_REPLICATED, "Adds up to this many seconds to the round while the ghost is held.", true, 0, true, 120); ConVar sv_neo_atk_ghost_overtime_grace("sv_neo_atk_ghost_overtime_grace", "10", FCVAR_REPLICATED, "Number of seconds left in the round when the ghost is dropped in overtime.", true, 0, true, 30); ConVar sv_neo_atk_ghost_overtime_grace_decay("sv_neo_atk_ghost_overtime_grace_decay", "0", FCVAR_REPLICATED, "Slowly reduce the grace time as overtime goes on.", true, 0, true, 1); -// //CNEORulesATK::CNEORulesATK() //{ //} @@ -78,16 +79,51 @@ void CNEORulesATK::CheckOvertime() m_nRoundStatus = NeoRoundStatus::Overtime; } - if (m_nRoundStatus == NeoRoundStatus::Overtime && m_iGhosterPlayer) + if (NeoRoundStatus::Overtime == m_nRoundStatus && m_iGhosterPlayer) { m_flGhostLastHeld = gpGlobals->curtime; } } +float CNEORulesATK::GetRoundRemainingTime() const +{ + if (NeoRoundStatus::Overtime == m_nRoundStatus) + { + return GetOverTime(sv_neo_atk_round_timelimit.GetFloat() * 60.f, + sv_neo_atk_ghost_overtime.GetFloat(), + sv_neo_atk_ghost_overtime_grace.GetFloat(), + sv_neo_atk_ghost_overtime_grace_decay.GetBool()); + } + return BaseClass::GetRoundRemainingTime(sv_neo_atk_round_timelimit.GetFloat()); +} + +#ifdef GAME_DLL +void CNEORulesATK::SetGameRelatedVars() +{ + ResetGhost(); + SpawnTheGhost(); +} + +const int CNEORulesATK::GetScoreLimit() const +{ + return sv_neo_atk_score_limit.GetInt(); +} + +const int CNEORulesATK::GetRoundLimit() const +{ + return sv_neo_atk_round_limit.GetInt(); +} + +void CNEORulesATK::RoundTimeout() +{ + SetWinningTeam(GetDefendingTeam(), NEO_VICTORY_ATK_TIMEOUT, false, true, false, false); +} +#endif // GAME_DLL + void CNEORulesATK::Think() { #ifdef GAME_DLL - if (RoundIdlePausedStartThink()) + if (RoundStartFromIdleOrPausedThink()) return; PlayerRespawnThink(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_atk.h b/src/game/shared/neo/gamerules/neo_gamerules_atk.h index 115466f54b..6aed1abb5c 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_atk.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_atk.h @@ -25,18 +25,27 @@ class CNEORulesATK : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesATK, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - //CNEORulesATK(); //virtual ~CNEORulesATK(); // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; + + const char* GetGameDescription() override { return "Attack/Defend"; } + virtual bool GetTeamPlayEnabled() const override { return true; }; virtual void CheckOvertime(); + virtual float GetRoundRemainingTime() const override final; +#ifdef GAME_DLL + virtual void SetGameRelatedVars() override final; + virtual const int GetScoreLimit() const override final; + virtual const int GetRoundLimit() const override final; + virtual void RoundTimeout() override final; +#endif // GAME_DLL virtual void Think() override final; }; -inline CNEORulesATK *CNEORulesATK() +inline CNEORulesATK *NEORulesATK() { return static_cast(g_pGameRules); } \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp index e51891a55f..e23612e48e 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp @@ -48,22 +48,23 @@ IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesCTGProxy, DT_NEOGameRulesCTGProxy ); SendProxy_NEORulesCTG) END_SEND_TABLE() #endif - -ConVar sv_neo_ctg_round_timelimit("neo_ctg_round_timelimit", "3.25", FCVAR_REPLICATED, "CTG round timelimit, in minutes.", true, 0.0f, false, 600.0f); + +ConVar sv_neo_ctg_round_limit("sv_neo_ctg_round_limit", "0", FCVAR_REPLICATED, "CTG max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +ConVar sv_neo_ctg_round_timelimit("sv_neo_ctg_round_timelimit", "3.25", FCVAR_REPLICATED, "CTG round timelimit, in minutes.", true, 0.0f, false, 0.0f); +ConVar sv_neo_ctg_score_limit("sv_neo_ctg_score_limit", "7", FCVAR_REPLICATED, "CTG score limit", true, 0.0f, true, 99.0f); ConVar sv_neo_ctg_ghost_overtime_enabled("sv_neo_ctg_ghost_overtime_enabled", "0", FCVAR_REPLICATED, "Enable ghost overtime.", true, 0, true, 1); ConVar sv_neo_ctg_ghost_overtime("sv_neo_ctg_ghost_overtime", "45", FCVAR_REPLICATED, "Adds up to this many seconds to the round while the ghost is held.", true, 0, true, 120); ConVar sv_neo_ctg_ghost_overtime_grace("sv_neo_ctg_ghost_overtime_grace", "10", FCVAR_REPLICATED, "Number of seconds left in the round when the ghost is dropped in overtime.", true, 0, true, 30); ConVar sv_neo_ctg_ghost_overtime_grace_decay("sv_neo_ctg_ghost_overtime_grace_decay", "0", FCVAR_REPLICATED, "Slowly reduce the grace time as overtime goes on.", true, 0, true, 1); -CNEORulesCTG::CNEORulesCTG() -{ - -} - -CNEORulesCTG::~CNEORulesCTG() -{ -} +//CNEORulesCTG::CNEORulesCTG() +//{ +//} +// +//CNEORulesCTG::~CNEORulesCTG() +//{ +//} void CNEORulesCTG::FireGameEvent(IGameEvent* event) { @@ -90,10 +91,45 @@ void CNEORulesCTG::CheckOvertime() } } +float CNEORulesCTG::GetRoundRemainingTime() const +{ + if (NeoRoundStatus::Overtime == m_nRoundStatus) + { + return GetOverTime(sv_neo_ctg_round_timelimit.GetFloat() * 60.f, + sv_neo_ctg_ghost_overtime.GetFloat(), + sv_neo_ctg_ghost_overtime_grace.GetFloat(), + sv_neo_ctg_ghost_overtime_grace_decay.GetBool()); + } + return BaseClass::GetRoundRemainingTime(sv_neo_ctg_round_timelimit.GetFloat()); +} + +#ifdef GAME_DLL +void CNEORulesCTG::SetGameRelatedVars() +{ + ResetGhost(); + SpawnTheGhost(); +} + +const int CNEORulesCTG::GetScoreLimit() const +{ + return sv_neo_ctg_score_limit.GetInt(); +} + +const int CNEORulesCTG::GetRoundLimit() const +{ + return sv_neo_ctg_round_limit.GetInt(); +} + +void CNEORulesCTG::RoundTimeout() +{ + SetWinningTeam(TEAM_SPECTATOR, NEO_VICTORY_STALEMATE, false, false, true, false); +} +#endif // GAME_DLL + void CNEORulesCTG::Think() { #ifdef GAME_DLL - if (RoundIdlePausedStartThink()) + if (RoundStartFromIdleOrPausedThink()) return; PlayerRespawnThink(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_ctg.h b/src/game/shared/neo/gamerules/neo_gamerules_ctg.h index 7a44c23e2c..030b21b2e4 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_ctg.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_ctg.h @@ -25,14 +25,23 @@ class CNEORulesCTG : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesCTG, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - - CNEORulesCTG(); - virtual ~CNEORulesCTG(); + //CNEORulesCTG(); + //virtual ~CNEORulesCTG(); // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; + + const char* GetGameDescription() override { return "Capture the Ghost"; } + virtual bool GetTeamPlayEnabled() const override { return true; }; virtual void CheckOvertime(); + virtual float GetRoundRemainingTime() const override final; +#ifdef GAME_DLL + virtual void SetGameRelatedVars() override final; + virtual const int GetScoreLimit() const override final; + virtual const int GetRoundLimit() const override final; + virtual void RoundTimeout() override final; +#endif // GAME_DLL virtual void Think() override final; }; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp b/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp index 41bf2bcbea..43be90dca1 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp @@ -47,19 +47,22 @@ IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesDMProxy, DT_NEOGameRulesDMProxy ); SendProxy_NEORulesDM) END_SEND_TABLE() #endif + +ConVar sv_neo_dm_round_limit("sv_neo_dm_round_limit", "0", FCVAR_REPLICATED, "DM max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +ConVar sv_neo_dm_round_timelimit("sv_neo_dm_round_timelimit", "10.25", FCVAR_REPLICATED, "DM round timelimit, in minutes.", true, 0.0f, false, 0.0f); +ConVar sv_neo_dm_score_limit("sv_neo_dm_score_limit", "7", FCVAR_REPLICATED, "DM score limit", true, 0.0f, true, 99.0f); ConVar sv_neo_dm_win_xp("sv_neo_dm_win_xp", "50", FCVAR_REPLICATED, "The XP limit to win the match.", true, 0.0f, true, 1000.0f); extern bool RespawnWithRet(CBaseEntity *pEdict, bool fCopyCorpse); -CNEORulesDM::CNEORulesDM() -{ - -} - -CNEORulesDM::~CNEORulesDM() -{ -} +//CNEORulesDM::CNEORulesDM() +//{ +//} +// +//CNEORulesDM::~CNEORulesDM() +//{ +//} void CNEORulesDM::FireGameEvent(IGameEvent* event) { @@ -91,10 +94,61 @@ void CNEORulesDM::PlayerRespawnThink() } #endif // GAME_DLL +float CNEORulesDM::GetRoundRemainingTime() const +{ + return BaseClass::GetRoundRemainingTime(sv_neo_dm_round_timelimit.GetFloat()); +} + +#ifdef GAME_DLL +bool CNEORulesDM::FPlayerCanRespawn(CBasePlayer* pPlayer) +{ + if (NeoRoundStatus::PostRound == m_nRoundStatus) + return false; + + return true; +} + +void CNEORulesDM::SetGameRelatedVars() +{ + for (int i = 1; i <= gpGlobals->maxClients; ++i) + { + if (auto pPlayer = static_cast(UTIL_PlayerByIndex(i))) + { + pPlayer->m_iXP.GetForModify() = 0; + } + } +} + +const int CNEORulesDM::GetScoreLimit() const +{ + return sv_neo_dm_score_limit.GetInt(); +} + +const int CNEORulesDM::GetRoundLimit() const +{ + return sv_neo_dm_round_limit.GetInt(); +} + +void CNEORulesDM::RoundTimeout() +{ + // Winning player + CNEO_Player* pWinners[MAX_PLAYERS + 1] = {}; + int iWinnersTotal = 0; + int iWinnerXP = 0; + GetDMHighestScorers(&pWinners, &iWinnersTotal, &iWinnerXP); + if (iWinnersTotal == 1) + { + SetWinningDMPlayer(pWinners[0]); + } + + // Otherwise go into overtime +} +#endif // GAME_DLL + void CNEORulesDM::Think() { #ifdef GAME_DLL - if (RoundIdlePausedStartThink()) + if (RoundStartFromIdleOrPausedThink()) return; PlayerRespawnThink(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_dm.h b/src/game/shared/neo/gamerules/neo_gamerules_dm.h index 54b0f879d4..79f3fc06b8 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_dm.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_dm.h @@ -25,13 +25,24 @@ class CNEORulesDM : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesDM, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - - CNEORulesDM(); - virtual ~CNEORulesDM(); + //CNEORulesDM(); + //virtual ~CNEORulesDM(); // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; + + const char* GetGameDescription() override { return "Deathmatch"; } + virtual bool GetTeamPlayEnabled() const override { return false; }; + virtual float GetRoundRemainingTime() const override final; +#ifdef GAME_DLL + virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) override final; + + virtual void SetGameRelatedVars() override final; + virtual const int GetScoreLimit() const override final; + virtual const int GetRoundLimit() const override final; + virtual void RoundTimeout() override final; +#endif // GAME_DLL virtual void Think() override final; #ifdef GAME_DLL virtual void PlayerRespawnThink() override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp b/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp index 882cbefe6c..b8e8c586e2 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp @@ -43,20 +43,51 @@ IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesEMTProxy, DT_NEOGameRulesEMTProxy ); END_SEND_TABLE() #endif -CNEORulesEMT::CNEORulesEMT() +//CNEORulesEMT::CNEORulesEMT() +//{ +//} +// +//CNEORulesEMT::~CNEORulesEMT() +//{ +//} + +void CNEORulesEMT::FireGameEvent(IGameEvent* event) { + BaseClass::FireGameEvent(event); +} +float CNEORulesEMT::GetRoundRemainingTime() const +{ +#ifdef GAME_DLL + Assert(false); // Shouldn't be calling this server side +#endif // GAME_DLL + return 0.f; } -CNEORulesEMT::~CNEORulesEMT() +#ifdef GAME_DLL +bool CNEORulesEMT::FPlayerCanRespawn(CBasePlayer* pPlayer) { + return true; } -void CNEORulesEMT::FireGameEvent(IGameEvent* event) +const int CNEORulesEMT::GetScoreLimit() const { - BaseClass::FireGameEvent(event); + Assert(false); + return 1; +} + +const int CNEORulesEMT::GetRoundLimit() const +{ + Assert(false); + return 1; } +void CNEORulesEMT::RoundTimeout() +{ + Assert(false); +} +#endif // GAME_DLL + void CNEORulesEMT::Think() { #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_emt.h b/src/game/shared/neo/gamerules/neo_gamerules_emt.h index a5185a0ed3..a7f33d0328 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_emt.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_emt.h @@ -25,13 +25,25 @@ class CNEORulesEMT : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesEMT, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - - CNEORulesEMT(); - virtual ~CNEORulesEMT(); + //CNEORulesEMT(); + //virtual ~CNEORulesEMT(); // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; + + + virtual float GetRoundRemainingTime() const override final; + virtual bool GetTeamPlayEnabled() const override { return true; }; + +#ifdef GAME_DLL + virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) override final; + + virtual void SetGameRelatedVars() override final {}; + virtual const int GetScoreLimit() const override final; + virtual const int GetRoundLimit() const override final; + virtual void RoundTimeout() override final; +#endif // GAME_DLL virtual void Think() override final; }; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp b/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp index 5386231931..83dc4d18e1 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp @@ -42,7 +42,10 @@ IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesJGRProxy, DT_NEOGameRulesJGRProxy ); SendProxy_NEORulesJGR) END_SEND_TABLE() #endif - + +ConVar sv_neo_jgr_round_limit("sv_neo_jgr_round_limit", "5", FCVAR_REPLICATED, "JGR max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +ConVar sv_neo_jgr_round_timelimit("sv_neo_jgr_round_timelimit", "4.25", FCVAR_REPLICATED, "JGR round timelimit, in minutes.", true, 0.0f, false, 0.0f); +ConVar sv_neo_jgr_score_limit("sv_neo_jgr_score_limit", "0", FCVAR_REPLICATED, "JGR score limit", true, 0.0f, true, 99.0f); ConVar sv_neo_jgr_max_points("sv_neo_jgr_max_points", "20", FCVAR_GAMEDLL, "Maximum points required for a team to win in JGR", true, 1, false, 0); extern bool RespawnWithRet(CBaseEntity *pEdict, bool fCopyCorpse); @@ -86,12 +89,122 @@ void CNEORulesJGR::PlayerRespawnThink() } #endif // GAME_DLL -extern ConVar sv_neo_preround_freeze_time; +float CNEORulesJGR::GetRoundRemainingTime() const +{ + return BaseClass::GetRoundRemainingTime(sv_neo_jgr_round_timelimit.GetFloat()); +} + +#ifdef GAME_DLL +bool CNEORulesJGR::FPlayerCanRespawn(CBasePlayer* pPlayer) +{ + CNEO_Player* pNeoPlayer = ToNEOPlayer(pPlayer); + if (!pNeoPlayer) + { + Assert(false); + return false; + } + + // Special case for spectator player takeover + if (pNeoPlayer->GetSpectatorTakeoverPlayerPending()) + return true; + + if (pPlayer->GetTeamNumber() == m_iLastJuggernautTeam && + (m_pJuggernautPlayer || (gpGlobals->curtime - m_flJuggernautDeathTime) <= 8.0f)) + { + return false; + } + + if (NeoRoundStatus::PostRound == m_nRoundStatus) + return false; + + return true; +} + +void CNEORulesJGR::EnemyPlayerKilled(CNEO_Player* pVictim, CNEO_Player* pAttacker, const CTakeDamageInfo& info) +{ + if (!IsRoundLive()) + return; + + if (pAttacker->GetClass() == NEO_CLASS_JUGGERNAUT) + { + auto jgrTeam = pAttacker->GetTeam(); + jgrTeam->SetScore(jgrTeam->GetScore()); + } + else if (m_pJuggernautPlayer) + { + const int attackerTeam = pAttacker->GetTeamNumber(); + const int jgrTeam = m_pJuggernautPlayer->GetTeamNumber(); + + if (attackerTeam == jgrTeam) + { + pAttacker->GetTeam()->AddScore(1); + } + } +} + +void CNEORulesJGR::SetGameRelatedVars() +{ + ResetJGR(); + SpawnTheJuggernaut(); +} +const int CNEORulesJGR::GetScoreLimit() const +{ + return sv_neo_jgr_score_limit.GetInt(); +} + +const int CNEORulesJGR::GetRoundLimit() const +{ + return sv_neo_jgr_round_limit.GetInt(); +} + +void CNEORulesJGR::RoundTimeout() +{ + if ((!m_pJuggernautPlayer && m_pJuggernautItem && !m_pJuggernautItem->IsBeingActivatedByLosingTeam()) || + (!m_pJuggernautPlayer && !m_pJuggernautItem)) // Juggernaut is absent entirely + { + if (GetGlobalTeam(TEAM_JINRAI)->GetScore() > GetGlobalTeam(TEAM_NSF)->GetScore()) + { + SetWinningTeam(TEAM_JINRAI, NEO_VICTORY_POINTS, false, true, false, false); + return; + } + + if (GetGlobalTeam(TEAM_NSF)->GetScore() > GetGlobalTeam(TEAM_JINRAI)->GetScore()) + { + SetWinningTeam(TEAM_NSF, NEO_VICTORY_POINTS, false, true, false, false); + return; + } + } + else + { + if (m_nRoundStatus == NeoRoundStatus::RoundLive) + { + m_nRoundStatus = NeoRoundStatus::Overtime; + } + + if (m_pJuggernautPlayer) + { + const int jgrTeam = m_pJuggernautPlayer->GetTeamNumber(); + const int oppositeTeam = (m_pJuggernautPlayer->GetTeamNumber() == TEAM_JINRAI ? TEAM_NSF : TEAM_JINRAI); + if (GetGlobalTeam(jgrTeam)->GetScore() > GetGlobalTeam(oppositeTeam)->GetScore()) + { + SetWinningTeam(jgrTeam, NEO_VICTORY_POINTS, false, true, false, false); + return; + } + } + + return; + } + + SetWinningTeam(TEAM_SPECTATOR, NEO_VICTORY_STALEMATE, false, false, true, false); +} +#endif // GAME_DLL + +extern ConVar sv_neo_preround_freeze_time; void CNEORulesJGR::Think() { #ifdef GAME_DLL - if (RoundIdlePausedStartThink()) + if (RoundStartFromIdleOrPausedThink()) return; PlayerRespawnThink(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_jgr.h b/src/game/shared/neo/gamerules/neo_gamerules_jgr.h index ebd3738544..53d05fb40a 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_jgr.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_jgr.h @@ -24,14 +24,27 @@ class CNEORulesJGR : public CNEORules, public CGameEventListener public: DECLARE_CLASS(CNEORulesJGR, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - /* - - CNEORulesJGR(); - virtual ~CNEORulesJGR(); - */ + + //CNEORulesJGR(); + //virtual ~CNEORulesJGR(); + // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; + + const char* GetGameDescription() override { return "Juggernaut"; } + virtual bool GetTeamPlayEnabled() const override { return true; }; + + virtual float GetRoundRemainingTime() const override final; +#ifdef GAME_DLL + virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) override final; + + virtual void EnemyPlayerKilled(CNEO_Player* pVictim, CNEO_Player* pAttacker, const CTakeDamageInfo& info) override final; + virtual void SetGameRelatedVars() override final; + virtual const int GetScoreLimit() const override final; + virtual const int GetRoundLimit() const override final; + virtual void RoundTimeout() override final; +#endif // GAME_DLL virtual void Think() override final; #ifdef GAME_DLL virtual void PlayerRespawnThink() override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp b/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp index f90854c678..31d386e197 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp @@ -43,16 +43,20 @@ IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesTDMProxy, DT_NEOGameRulesTDMProxy ); END_SEND_TABLE() #endif -extern bool RespawnWithRet(CBaseEntity *pEdict, bool fCopyCorpse); - -CNEORulesTDM::CNEORulesTDM() -{ -} +ConVar sv_neo_tdm_score_limit("sv_neo_tdm_score_limit", "1", FCVAR_REPLICATED, "TDM score limit", true, 0.0f, true, 99.0f); +ConVar sv_neo_tdm_round_limit("sv_neo_tdm_round_limit", "0", FCVAR_REPLICATED, "TDM max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +ConVar sv_neo_tdm_round_timelimit("sv_neo_tdm_round_timelimit", "10.25", FCVAR_REPLICATED, "TDM round timelimit, in minutes.", true, 0.0f, false, 0.0f); + +extern bool RespawnWithRet(CBaseEntity *pEdict, bool fCopyCorpse); -CNEORulesTDM::~CNEORulesTDM() -{ -} +//CNEORulesTDM::CNEORulesTDM() +//{ +//} +// +//CNEORulesTDM::~CNEORulesTDM() +//{ +//} void CNEORulesTDM::FireGameEvent(IGameEvent* event) { @@ -84,10 +88,56 @@ void CNEORulesTDM::PlayerRespawnThink() } #endif // GAME_DLL +float CNEORulesTDM::GetRoundRemainingTime() const +{ + return BaseClass::GetRoundRemainingTime(sv_neo_tdm_round_timelimit.GetFloat()); +} + +#ifdef GAME_DLL +bool CNEORulesTDM::FPlayerCanRespawn(CBasePlayer* pPlayer) +{ + if (NeoRoundStatus::PostRound == m_nRoundStatus) + return false; + + return true; +} + +void CNEORulesTDM::SetGameRelatedVars() +{ + ResetTeamScores(); +} + +const int CNEORulesTDM::GetScoreLimit() const +{ + return sv_neo_tdm_score_limit.GetInt(); +} + +const int CNEORulesTDM::GetRoundLimit() const +{ + return sv_neo_tdm_round_limit.GetInt(); +} + +void CNEORulesTDM::RoundTimeout() +{ + if (GetGlobalTeam(TEAM_JINRAI)->GetScore() > GetGlobalTeam(TEAM_NSF)->GetScore()) + { + SetWinningTeam(TEAM_JINRAI, NEO_VICTORY_POINTS, false, true, false, false); + return; + } + if (GetGlobalTeam(TEAM_NSF)->GetScore() > GetGlobalTeam(TEAM_JINRAI)->GetScore()) + { + SetWinningTeam(TEAM_NSF, NEO_VICTORY_POINTS, false, true, false, false); + return; + } + + SetWinningTeam(TEAM_SPECTATOR, NEO_VICTORY_STALEMATE, false, false, true, false); +} +#endif // GAME_DLL + void CNEORulesTDM::Think() { #ifdef GAME_DLL - if (RoundIdlePausedStartThink()) + if (RoundStartFromIdleOrPausedThink()) return; PlayerRespawnThink(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tdm.h b/src/game/shared/neo/gamerules/neo_gamerules_tdm.h index 618d112388..9e4212a1cb 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tdm.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_tdm.h @@ -7,10 +7,6 @@ #define CNEORulesTDM C_NEORulesTDM #define CNEOGameRulesTDMProxy C_NEOGameRulesTDMProxy #endif -// -//ConVar sv_neo_tdm_score_limit("sv_neo_tdm_score_limit", "1", FCVAR_REPLICATED, "TDM score limit", true, 0.0f, true, 99.0f); -//ConVar sv_neo_tdm_round_limit("sv_neo_tdm_round_limit", "0", FCVAR_REPLICATED, "TDM max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); -//ConVar sv_neo_tdm_round_timelimit("neo_tdm_round_timelimit", "10.25", FCVAR_REPLICATED, "TDM round timelimit, in minutes.", true, 0.0f, false, 600.0f); class CNEOGameRulesTDMProxy : public CNEOGameRulesProxy { @@ -25,13 +21,24 @@ class CNEORulesTDM : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesTDM, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - - CNEORulesTDM(); - virtual ~CNEORulesTDM(); + //CNEORulesTDM(); + //virtual ~CNEORulesTDM(); // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; + + const char* GetGameDescription() override { return "Team Deathmatch"; } + virtual bool GetTeamPlayEnabled() const override { return true; }; + virtual float GetRoundRemainingTime() const override final; +#ifdef GAME_DLL + virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) override final; + + virtual void SetGameRelatedVars() override final; + virtual const int GetScoreLimit() const override final; + virtual const int GetRoundLimit() const override final; + virtual void RoundTimeout() override final; +#endif // GAME_DLL virtual void Think() override final; #ifdef GAME_DLL virtual void PlayerRespawnThink() override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp b/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp index e5218419b4..948875f458 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp @@ -43,20 +43,54 @@ IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesTUTProxy, DT_NEOGameRulesTUTProxy ); END_SEND_TABLE() #endif -CNEORulesTUT::CNEORulesTUT() +//CNEORulesTUT::CNEORulesTUT() +//{ +//} +// +//CNEORulesTUT::~CNEORulesTUT() +//{ +//} + +void CNEORulesTUT::FireGameEvent(IGameEvent* event) +{ + BaseClass::FireGameEvent(event); +} + +float CNEORulesTUT::GetRoundRemainingTime() const +{ +#ifdef GAME_DLL + Assert(false); // Shouldn't be calling this server side +#endif // GAME_DLL + return 0.f; +} + +#ifdef GAME_DLL +bool CNEORulesTUT::FPlayerCanRespawn(CBasePlayer* pPlayer) { + if (pPlayer->IsAlive()) + return false; + return true; } -CNEORulesTUT::~CNEORulesTUT() +const int CNEORulesTUT::GetScoreLimit() const { + Assert(false); + return 1; } -void CNEORulesTUT::FireGameEvent(IGameEvent* event) +const int CNEORulesTUT::GetRoundLimit() const { - BaseClass::FireGameEvent(event); + Assert(false); + return 1; } +void CNEORulesTUT::RoundTimeout() +{ + Assert(false); +} +#endif // GAME_DLL + void CNEORulesTUT::Think() { #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tut.h b/src/game/shared/neo/gamerules/neo_gamerules_tut.h index c723b76a85..4aa297cb9c 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tut.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_tut.h @@ -24,14 +24,25 @@ class CNEORulesTUT : public CNEORules, public CGameEventListener public: DECLARE_CLASS(CNEORulesTUT, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - - CNEORulesTUT(); - virtual ~CNEORulesTUT(); + //CNEORulesTUT(); + //virtual ~CNEORulesTUT(); // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; + + const char* GetGameDescription() override { return "Training"; }; + virtual bool GetTeamPlayEnabled() const override { return true; }; + + virtual float GetRoundRemainingTime() const override final; +#ifdef GAME_DLL + virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) override final; + virtual void SetGameRelatedVars() override final {}; + virtual const int GetScoreLimit() const override final; + virtual const int GetRoundLimit() const override final; + virtual void RoundTimeout() override final; +#endif // GAME_DLL virtual void Think() override final; }; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp b/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp index afb3dcf820..c99ed7416e 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp @@ -47,27 +47,63 @@ IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesVIPProxy, DT_NEOGameRulesVIPProxy ); SendProxy_NEORulesVIP) END_SEND_TABLE() #endif + +ConVar sv_neo_vip_round_limit("sv_neo_vip_round_limit", "0", FCVAR_REPLICATED, "VIP max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); +ConVar sv_neo_vip_round_timelimit("sv_neo_vip_round_timelimit", "3.25", FCVAR_REPLICATED, "VIP round timelimit, in minutes.", true, 0.0f, false, 0.0f); +ConVar sv_neo_vip_score_limit("sv_neo_vip_score_limit", "7", FCVAR_REPLICATED, "VIP score limit", true, 0.0f, true, 99.0f); ConVar sv_neo_vip_ctg_on_death("sv_neo_vip_ctg_on_death", "0", FCVAR_ARCHIVE, "Spawn Ghost when VIP dies, continue the game", true, 0, true, 1); -CNEORulesVIP::CNEORulesVIP() +//CNEORulesVIP::CNEORulesVIP() +//{ +//} +// +//CNEORulesVIP::~CNEORulesVIP() +//{ +//} + +void CNEORulesVIP::FireGameEvent(IGameEvent* event) +{ + BaseClass::FireGameEvent(event); +} + +float CNEORulesVIP::GetRoundRemainingTime() const +{ + return BaseClass::GetRoundRemainingTime(sv_neo_vip_round_timelimit.GetFloat()); +} + +#ifdef GAME_DLL +void CNEORulesVIP::SetGameRelatedVars() { + ResetVIP(); + + if (!m_iEscortingTeam) + { + m_iEscortingTeam.Set(RandomInt(TEAM_JINRAI, TEAM_NSF)); + } + else + { + m_iEscortingTeam.Set(m_iEscortingTeam.Get() == TEAM_JINRAI ? TEAM_NSF : TEAM_JINRAI); + } + SelectTheVIP(); } -CNEORulesVIP::~CNEORulesVIP() +const int CNEORulesVIP::GetScoreLimit() const { + return sv_neo_vip_score_limit.GetInt(); } -void CNEORulesVIP::FireGameEvent(IGameEvent* event) +const int CNEORulesVIP::GetRoundLimit() const { - BaseClass::FireGameEvent(event); + return sv_neo_vip_round_limit.GetInt(); } +#endif // GAME_DLL void CNEORulesVIP::Think() { #ifdef GAME_DLL - if (RoundIdlePausedStartThink()) + if (RoundStartFromIdleOrPausedThink()) return; PlayerRespawnThink(); @@ -106,7 +142,7 @@ void CNEORulesVIP::Think() SetWinningTeam(GetOpposingTeam(m_iEscortingTeam), NEO_VICTORY_FORFEIT, false, true, false, false); } - if (IGameEvent* event = gameeventmanager->CreateEvent("vip_death");) + if (IGameEvent* event = gameeventmanager->CreateEvent("vip_death")) { gameeventmanager->FireEvent(event); } @@ -124,7 +160,7 @@ void CNEORulesVIP::Think() SetWinningTeam(GetOpposingTeam(m_iEscortingTeam), NEO_VICTORY_VIP_ELIMINATION, false, true, false, false); } - if (IGameEvent* event = gameeventmanager->CreateEvent("vip_death");) + if (IGameEvent* event = gameeventmanager->CreateEvent("vip_death")) { event->SetInt("userid", m_pVIP->GetUserID()); gameeventmanager->FireEvent(event); @@ -160,7 +196,7 @@ void CNEORulesVIP::Think() // And then announce team victory SetWinningTeam(captorTeam, NEO_VICTORY_VIP_ESCORT, false, true, false, false); - if (IGameEvent* event = gameeventmanager->CreateEvent("vip_extract");) + if (IGameEvent* event = gameeventmanager->CreateEvent("vip_extract")) { CBasePlayer* pCaptorClient = UTIL_PlayerByIndex(captorClient); event->SetInt("userid", pCaptorClient ? pCaptorClient->GetUserID() : INVALID_USER_ID); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_vip.h b/src/game/shared/neo/gamerules/neo_gamerules_vip.h index c27895eb4f..758deaf274 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_vip.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_vip.h @@ -25,13 +25,21 @@ class CNEORulesVIP : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesVIP, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - - CNEORulesVIP(); - virtual ~CNEORulesVIP(); + //CNEORulesVIP(); + //virtual ~CNEORulesVIP(); // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; + + virtual float GetRoundRemainingTime() const override final; + virtual bool GetTeamPlayEnabled() const override { return true; }; +#ifdef GAME_DLL + virtual void SetGameRelatedVars() override final; + virtual const int GetScoreLimit() const override final; + virtual const int GetRoundLimit() const override final; + virtual void RoundTimeout() override final; +#endif // GAME_DLL virtual void Think() override final; }; From ef32c6f8302fea01a4e8eeee850682ea1f6e4a39 Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Fri, 5 Jun 2026 10:04:53 +0100 Subject: [PATCH 11/16] working ctg (and maybe others) --- src/game/client/neo/ui/neo_hud_childelement.h | 2 +- .../client/neo/ui/neo_hud_friendly_marker.h | 2 +- src/game/server/neo/neo_client.cpp | 24 +------- src/game/server/neo/neo_game_config.cpp | 10 ++++ src/game/shared/hl2mp/hl2mp_gamerules.h | 8 +++ .../shared/neo/gamerules/neo_gamerules.cpp | 60 +++++++++++++++++-- src/game/shared/neo/gamerules/neo_gamerules.h | 5 +- .../neo/gamerules/neo_gamerules_atk.cpp | 7 ++- .../neo/gamerules/neo_gamerules_ctg.cpp | 7 ++- .../shared/neo/gamerules/neo_gamerules_dm.cpp | 7 ++- .../neo/gamerules/neo_gamerules_emt.cpp | 2 + .../neo/gamerules/neo_gamerules_jgr.cpp | 7 ++- .../neo/gamerules/neo_gamerules_tdm.cpp | 7 ++- .../neo/gamerules/neo_gamerules_tut.cpp | 2 + .../neo/gamerules/neo_gamerules_vip.cpp | 7 ++- .../shared/neo/gamerules/neo_gamerules_vip.h | 2 +- 16 files changed, 114 insertions(+), 45 deletions(-) diff --git a/src/game/client/neo/ui/neo_hud_childelement.h b/src/game/client/neo/ui/neo_hud_childelement.h index 896c3f41c2..10f4bdae40 100644 --- a/src/game/client/neo/ui/neo_hud_childelement.h +++ b/src/game/client/neo/ui/neo_hud_childelement.h @@ -4,7 +4,7 @@ #pragma once #endif -#include "neo_gamerules.h" +#include "gamerules/neo_gamerules.h" class C_NEO_Player; diff --git a/src/game/client/neo/ui/neo_hud_friendly_marker.h b/src/game/client/neo/ui/neo_hud_friendly_marker.h index 9f83af606a..8efb4d21d8 100644 --- a/src/game/client/neo/ui/neo_hud_friendly_marker.h +++ b/src/game/client/neo/ui/neo_hud_friendly_marker.h @@ -3,7 +3,7 @@ #include "hudelement.h" #include -#include "neo_gamerules.h" +#include "gamerules/neo_gamerules.h" #include "neo_hud_worldpos_marker.h" enum NeoIFFMarkerSegment diff --git a/src/game/server/neo/neo_client.cpp b/src/game/server/neo/neo_client.cpp index 212e0dc282..b3ed95b99e 100644 --- a/src/game/server/neo/neo_client.cpp +++ b/src/game/server/neo/neo_client.cpp @@ -394,27 +394,5 @@ void GameStartFrame( void ) //========================================================= void InstallGameRules() { - if (const CNEOGameConfig* pEntGameCfg = NEOGameConfig()) - { - switch (pEntGameCfg->m_GameType) - { - case NEO_GAME_TYPE_TDM: - CreateGameRulesObject( "CNEORulesTDM" ); - return; - case NEO_GAME_TYPE_CTG: - case NEO_GAME_TYPE_VIP: - case NEO_GAME_TYPE_DM: - break; - case NEO_GAME_TYPE_EMT: - CreateGameRulesObject( "CNEORules" ); - return; - case NEO_GAME_TYPE_TUT: - case NEO_GAME_TYPE_JGR: - case NEO_GAME_TYPE_ATK: - default: - break; - } - } - - CreateGameRulesObject( "CNEORules" ); + CreateGameRulesObject( "CNEORulesEMT" ); } diff --git a/src/game/server/neo/neo_game_config.cpp b/src/game/server/neo/neo_game_config.cpp index beadfb9643..b35dd1eebc 100644 --- a/src/game/server/neo/neo_game_config.cpp +++ b/src/game/server/neo/neo_game_config.cpp @@ -47,6 +47,16 @@ void CNEOGameConfig::Spawn() { m_OnCompetitive.FireOutput(nullptr, this); } + + // Create new gamerules object + { + for (int i = g_Teams.Count() - 1; i >= 0; i--) + { + UTIL_RemoveImmediate(g_Teams[i]); + } + + CreateGameRulesObject(NEO_GAME_TYPE_CLASS_NAMES[m_GameType]); + } } // Inputs diff --git a/src/game/shared/hl2mp/hl2mp_gamerules.h b/src/game/shared/hl2mp/hl2mp_gamerules.h index 83fc13f3b0..308213c38b 100644 --- a/src/game/shared/hl2mp/hl2mp_gamerules.h +++ b/src/game/shared/hl2mp/hl2mp_gamerules.h @@ -86,6 +86,14 @@ class CHL2MPRules : public CTeamplayRules #ifdef NEO friend class CNEORules; + friend class CNEORulesATK; + friend class CNEORulesCTG; + friend class CNEORulesDM; + friend class CNEORulesEMT; + friend class CNEORulesJGR; + friend class CNEORulesTDM; + friend class CNEORulesTUT; + friend class CNEORulesVIP; #endif #ifdef CLIENT_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules.cpp b/src/game/shared/neo/gamerules/neo_gamerules.cpp index a0859b0300..fda30f13f9 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules.cpp @@ -346,6 +346,18 @@ const NeoGameTypeSettings NEO_GAME_TYPE_SETTINGS[NEO_GAME_TYPE__TOTAL] = { /*NEO_GAME_TYPE_ATK*/ {"ATK", false, true, false, true, false}, }; +const char* NEO_GAME_TYPE_CLASS_NAMES[NEO_GAME_TYPE__TOTAL] = +{ + "CNEORulesTDM", + "CNEORulesCTG", + "CNEORulesVIP", + "CNEORulesDM", + "CNEORulesEMT", + "CNEORulesTUT", + "CNEORulesJGR", + "CNEORulesATK" +}; + #ifdef CLIENT_DLL void RecvProxy_NEORules( const RecvProp *pProp, void **pOut, void *pData, int objectID ) @@ -1155,9 +1167,48 @@ void CNEORules::CheckWinByElimination() #endif // GAME_DLL COMPILE_TIME_ASSERT(TEAM_JINRAI == 2 && TEAM_NSF == 3); +bool CNEORules::CHL2MPRulesThink() +{ +#ifdef GAME_DLL + if ( g_fGameOver ) // someone else quit the game already + { + // check to see if we should change levels now + if ( m_flIntermissionEndTime < gpGlobals->curtime ) + { + if ( !m_bChangelevelDone ) + { + ChangeLevel(); // intermission is over + m_bChangelevelDone = true; + } + } + + return true; + } + + if ( GetMapRemainingTime() < 0 ) + { + GoToIntermission(); + return true; + } + + if ( gpGlobals->curtime > m_tmNextPeriodicThink ) + { + CheckAllPlayersReady(); + CheckRestartGame(); + m_tmNextPeriodicThink = gpGlobals->curtime + 1.0; + } + + ManageObjectRelocation(); +#endif // GAME_DLL + + return false; +} + void CNEORules::Think(void) { #ifdef GAME_DLL + CGameRules::Think(); + if (RoundStartFromIdleOrPausedThink()) return; @@ -1172,7 +1223,8 @@ void CNEORules::Think(void) CheckOvertime(); - BaseClass::Think(); + if (CHL2MPRulesThink()) + return; TeamDamageThink(); @@ -2284,12 +2336,10 @@ bool CNEORules::IsRoundOn() const { switch (m_nRoundStatus) { - case NeoRoundStatus::Idle: - case NeoRoundStatus::Warmup: case NeoRoundStatus::PreRoundFreeze: + case NeoRoundStatus::RoundLive: case NeoRoundStatus::Overtime: case NeoRoundStatus::PostRound: - case NeoRoundStatus::Countdown: return true; } return false; @@ -3655,7 +3705,7 @@ void CNEORules::ClientDisconnected(edict_t* pClient) bool CNEORules::GetTeamPlayEnabled() const { - return m_nGameTypeSelected != NEO_GAME_TYPE_DM; + return true; } #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules.h b/src/game/shared/neo/gamerules/neo_gamerules.h index abb2041d34..b92c82b454 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules.h +++ b/src/game/shared/neo/gamerules/neo_gamerules.h @@ -107,6 +107,8 @@ enum NeoGameType { NEO_GAME_TYPE__TOTAL // Number of game types }; +extern const char* NEO_GAME_TYPE_CLASS_NAMES[NEO_GAME_TYPE__TOTAL]; + struct NeoGameTypeSettings; extern const SZWSZTexts NEO_GAME_TYPE_DESC_STRS[NEO_GAME_TYPE__TOTAL]; @@ -205,6 +207,7 @@ friend class C_NEORulesVIP; virtual void FireGameEvent(IGameEvent *event) OVERRIDE; virtual void Think() OVERRIDE; + bool CHL2MPRulesThink(); // This is the supposed encrypt key on NT, although it has its issues. // See https://steamcommunity.com/groups/ANPA/discussions/0/1482109512299590948/ @@ -311,7 +314,7 @@ friend class C_NEORulesVIP; virtual float GetRoundRemainingTime() const; float GetRoundRemainingTime(float flGameTypeRoundTimeLimit) const; float GetOverTime(float flRoundTimeLimit, float flOvertimeBaseAmount, float flOvertimeGrace, float flGraceDecay) const; - virtual void CheckOvertime(); + virtual void CheckOvertime() {}; virtual bool CheckGameOver(void) OVERRIDE; // NEO TODO (Adam) this changes map as a side effect, better name? Also is this called client side anywhere? float GetRoundAccumulatedTime() const; #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp index 3312ca4f9e..054e48cedd 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp @@ -123,6 +123,8 @@ void CNEORulesATK::RoundTimeout() void CNEORulesATK::Think() { #ifdef GAME_DLL + CGameRules::Think(); + if (RoundStartFromIdleOrPausedThink()) return; @@ -136,8 +138,9 @@ void CNEORulesATK::Think() GameOverThink(); CheckOvertime(); - - CHL2MPRules::Think(); + + if (CHL2MPRulesThink()) + return; TeamDamageThink(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp index e23612e48e..66d89153d8 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp @@ -129,6 +129,8 @@ void CNEORulesCTG::RoundTimeout() void CNEORulesCTG::Think() { #ifdef GAME_DLL + CGameRules::Think(); + if (RoundStartFromIdleOrPausedThink()) return; @@ -142,8 +144,9 @@ void CNEORulesCTG::Think() GameOverThink(); CheckOvertime(); - - CHL2MPRules::Think(); + + if (CHL2MPRulesThink()) + return; TeamDamageThink(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp b/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp index 43be90dca1..8672c4f219 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp @@ -148,6 +148,8 @@ void CNEORulesDM::RoundTimeout() void CNEORulesDM::Think() { #ifdef GAME_DLL + CGameRules::Think(); + if (RoundStartFromIdleOrPausedThink()) return; @@ -161,8 +163,9 @@ void CNEORulesDM::Think() GameOverThink(); CheckOvertime(); - - CHL2MPRules::Think(); + + if (CHL2MPRulesThink()) + return; TeamDamageThink(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp b/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp index b8e8c586e2..b28775fcf6 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp @@ -91,6 +91,8 @@ void CNEORulesEMT::RoundTimeout() void CNEORulesEMT::Think() { #ifdef GAME_DLL + CGameRules::Think(); + UpdateFromGameConfig(); #endif // GAME_DLL } \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp b/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp index 83dc4d18e1..877ea7ac02 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp @@ -204,6 +204,8 @@ extern ConVar sv_neo_preround_freeze_time; void CNEORulesJGR::Think() { #ifdef GAME_DLL + CGameRules::Think(); + if (RoundStartFromIdleOrPausedThink()) return; @@ -217,8 +219,9 @@ void CNEORulesJGR::Think() GameOverThink(); CheckOvertime(); - - CHL2MPRules::Think(); + + if (CHL2MPRulesThink()) + return; TeamDamageThink(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp b/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp index 31d386e197..61cd1b5324 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp @@ -137,6 +137,8 @@ void CNEORulesTDM::RoundTimeout() void CNEORulesTDM::Think() { #ifdef GAME_DLL + CGameRules::Think(); + if (RoundStartFromIdleOrPausedThink()) return; @@ -149,9 +151,8 @@ void CNEORulesTDM::Think() GameOverThink(); - CheckOvertime(); - - CHL2MPRules::Think(); + if (CHL2MPRulesThink()) + return; TeamDamageThink(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp b/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp index 948875f458..97787cb107 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp @@ -94,6 +94,8 @@ void CNEORulesTUT::RoundTimeout() void CNEORulesTUT::Think() { #ifdef GAME_DLL + CGameRules::Think(); + UpdateFromGameConfig(); { diff --git a/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp b/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp index c99ed7416e..f64d49b2b1 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp @@ -103,6 +103,8 @@ const int CNEORulesVIP::GetRoundLimit() const void CNEORulesVIP::Think() { #ifdef GAME_DLL + CGameRules::Think(); + if (RoundStartFromIdleOrPausedThink()) return; @@ -116,8 +118,9 @@ void CNEORulesVIP::Think() GameOverThink(); CheckOvertime(); - - CHL2MPRules::Think(); + + if (CHL2MPRulesThink()) + return; TeamDamageThink(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_vip.h b/src/game/shared/neo/gamerules/neo_gamerules_vip.h index 758deaf274..e4c15afebb 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_vip.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_vip.h @@ -38,7 +38,7 @@ class CNEORulesVIP : public CNEORules, public CGameEventListener virtual void SetGameRelatedVars() override final; virtual const int GetScoreLimit() const override final; virtual const int GetRoundLimit() const override final; - virtual void RoundTimeout() override final; + //virtual void RoundTimeout() override final; #endif // GAME_DLL virtual void Think() override final; }; From 85e299f6b13440b29f97bc062c0fc9336708a564 Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Fri, 5 Jun 2026 15:16:36 +0100 Subject: [PATCH 12/16] make neo_gamerules abstract --- .../shared/neo/gamerules/neo_gamerules.cpp | 111 ++---------------- src/game/shared/neo/gamerules/neo_gamerules.h | 19 ++- .../neo/gamerules/neo_gamerules_atk.cpp | 2 + .../shared/neo/gamerules/neo_gamerules_atk.h | 10 +- .../neo/gamerules/neo_gamerules_ctg.cpp | 2 + .../shared/neo/gamerules/neo_gamerules_ctg.h | 8 +- .../shared/neo/gamerules/neo_gamerules_dm.cpp | 2 + .../shared/neo/gamerules/neo_gamerules_dm.h | 8 +- .../shared/neo/gamerules/neo_gamerules_emt.h | 10 +- .../neo/gamerules/neo_gamerules_jgr.cpp | 2 + .../shared/neo/gamerules/neo_gamerules_jgr.h | 8 +- .../neo/gamerules/neo_gamerules_tdm.cpp | 2 + .../shared/neo/gamerules/neo_gamerules_tdm.h | 8 +- .../shared/neo/gamerules/neo_gamerules_tut.h | 10 +- .../neo/gamerules/neo_gamerules_vip.cpp | 2 + .../shared/neo/gamerules/neo_gamerules_vip.h | 8 +- 16 files changed, 88 insertions(+), 124 deletions(-) diff --git a/src/game/shared/neo/gamerules/neo_gamerules.cpp b/src/game/shared/neo/gamerules/neo_gamerules.cpp index fda30f13f9..c42405e5f6 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules.cpp @@ -224,8 +224,6 @@ void CNEOGameRulesProxy::OnDataChanged(DataUpdateType_t updateType) } #endif // CLIENT_DLL -REGISTER_GAMERULES_CLASS( CNEORules ); - BEGIN_NETWORK_TABLE_NOBASE( CNEORules, DT_NEORules ) // NEO TODO (Rain): NEO specific game modes var (CTG/TDM/...) #ifdef CLIENT_DLL @@ -233,7 +231,6 @@ BEGIN_NETWORK_TABLE_NOBASE( CNEORules, DT_NEORules ) RecvPropTime(RECVINFO(m_flNeoRoundStartTime)), RecvPropTime(RECVINFO(m_flPauseEnd)), RecvPropInt(RECVINFO(m_nRoundStatus)), - RecvPropInt(RECVINFO(m_nGameTypeSelected)), RecvPropInt(RECVINFO(m_iRoundNumber)), RecvPropBool(RECVINFO(m_bIsMatchPoint)), RecvPropBool(RECVINFO(m_bIsDoOrDie)), @@ -267,7 +264,6 @@ BEGIN_NETWORK_TABLE_NOBASE( CNEORules, DT_NEORules ) SendPropTime(SENDINFO(m_flNeoRoundStartTime)), SendPropTime(SENDINFO(m_flPauseEnd)), SendPropInt(SENDINFO(m_nRoundStatus), NumBitsForCount(RoundStatusTotal), SPROP_UNSIGNED), - SendPropInt(SENDINFO(m_nGameTypeSelected), NumBitsForCount(NEO_GAME_TYPE__TOTAL), SPROP_UNSIGNED), SendPropInt(SENDINFO(m_iRoundNumber)), SendPropBool(SENDINFO(m_bIsMatchPoint)), SendPropBool(SENDINFO(m_bIsDoOrDie)), @@ -325,27 +321,6 @@ static NEOViewVectors g_NEOViewVectors( Vector(16, 16, 60) //VEC_CROUCH_TRACE_MAX (m_vCrouchTraceMax) ); -struct NeoGameTypeSettings { - const char* gameTypeName; - bool respawns; - bool neoRulesThink; - bool changeTeamClassLoadoutWhenAlive; - bool comp; - bool capPrevent; -}; - -const NeoGameTypeSettings NEO_GAME_TYPE_SETTINGS[NEO_GAME_TYPE__TOTAL] = { -// gametypeName respawns neoRulesThink changeTeamClassLoadoutWhenAlive comp capPrevent -/*NEO_GAME_TYPE_TDM*/ {"TDM", true, true, false, false, false}, -/*NEO_GAME_TYPE_CTG*/ {"CTG", false, true, false, true, true}, -/*NEO_GAME_TYPE_VIP*/ {"VIP", false, true, false, true, true}, -/*NEO_GAME_TYPE_DM*/ {"DM", true, true, false, false, false}, -/*NEO_GAME_TYPE_EMT*/ {"EMT", true, false, true, false, false}, -/*NEO_GAME_TYPE_TUT*/ {"TUT", true, false, false, false, false}, -/*NEO_GAME_TYPE_JGR*/ {"JGR", true, true, false, true, false}, -/*NEO_GAME_TYPE_ATK*/ {"ATK", false, true, false, true, false}, -}; - const char* NEO_GAME_TYPE_CLASS_NAMES[NEO_GAME_TYPE__TOTAL] = { "CNEORulesTDM", @@ -401,40 +376,9 @@ const char* NEO_GAME_TYPE_CLASS_NAMES[NEO_GAME_TYPE__TOTAL] = // convert a velocity in ft/sec and a mass in grains to an impulse in kg in/s #define BULLET_IMPULSE(grains, ftpersec) ((ftpersec)*12*BULLET_MASS_GRAINS_TO_KG(grains)*BULLET_IMPULSE_EXAGGERATION) -extern ConVar neo_score_limit; -extern ConVar neo_round_limit; -extern ConVar sv_neo_ctg_score_limit; -extern ConVar sv_neo_ctg_round_limit; +ConVar sv_neo_round_sudden_death("sv_neo_round_sudden_death", "1", FCVAR_REPLICATED, "If the game is past the round limit, go into sudden death where the match won't end until a team wins.", true, 0.0f, true, 1.0f); -static void neoScoreLimitLegacyCallback(IConVar* var, const char* pOldValue, float flOldValue) -{ - Warning("Using legacy neo_score_limit cvar. Use sv_neo_[gamemode]_score_limit instead!\n"); - sv_neo_ctg_score_limit.SetValue(neo_score_limit.GetInt()); -} - -static void neoRoundLimitLegacyCallback(IConVar* var, const char* pOldValue, float flOldValue) -{ - Warning("Using legacy neo_round_limit cvar. Use sv_neo_[gamemode]_round_limit instead!\n"); - sv_neo_ctg_round_limit.SetValue(neo_round_limit.GetInt()); -} - -ConVar neo_score_limit("neo_score_limit", "7", FCVAR_REPLICATED | FCVAR_HIDDEN, "(Legacy) Neo score limit.", true, 0.0f, true, 99.0f -#ifdef GAME_DLL - , neoScoreLimitLegacyCallback -#endif -); -ConVar neo_round_limit("neo_round_limit", "0", FCVAR_REPLICATED | FCVAR_HIDDEN, "(Legacy) Max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f -#ifdef GAME_DLL - , neoRoundLimitLegacyCallback -#endif -); - -ConVar neo_round_sudden_death("neo_round_sudden_death", "1", FCVAR_REPLICATED, "If neo_round_limit is not 0 and round is past " - "neo_round_limit, go into sudden death where match won't end until a team won.", true, 0.0f, true, 1.0f); - - -ConVar sv_neo_ignore_wep_xp_limit("sv_neo_ignore_wep_xp_limit", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "If true, allow equipping any loadout regardless of player XP.", - true, 0.0f, true, 1.0f); +ConVar sv_neo_ignore_wep_xp_limit("sv_neo_ignore_wep_xp_limit", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "Allow equipping any loadout regardless of player XP.", true, 0.0f, true, 1.0f); #ifdef CLIENT_DLL extern ConVar neo_fov; @@ -604,7 +548,6 @@ CNEORules::CNEORules() } } - m_nGameTypeSelected = NEO_GAME_TYPE_CTG; #endif m_iHiddenHudElements = 0; m_iForcedTeam = -1; @@ -866,24 +809,7 @@ void CNEORules::UpdateFromGameConfig() m_bCyberspaceLevel = pEntGameCfg->m_Cyberspace; } } -#endif - - -// Add a gamemode for background maps -bool CNEORules::CheckShouldNotThink() -{ -#ifdef GAME_DLL - if (gpGlobals->eLoadType == MapLoad_Background || !NEO_GAME_TYPE_SETTINGS[m_nGameTypeSelected].neoRulesThink) -#else // CLIENT_DLL - if (engine->IsLevelMainMenuBackground() || !NEO_GAME_TYPE_SETTINGS[m_nGameTypeSelected].neoRulesThink) -#endif // GAME_DLL || CLIENT_DLL - { - return true; - } - return false; -} -#ifdef GAME_DLL bool CNEORules::RoundStartFromIdleOrPausedThink() { UpdateFromGameConfig(); @@ -1209,6 +1135,8 @@ void CNEORules::Think(void) #ifdef GAME_DLL CGameRules::Think(); + UpdateFromGameConfig(); + if (RoundStartFromIdleOrPausedThink()) return; @@ -1759,7 +1687,7 @@ void CNEORules::CheckChatCommand(CNEO_Player *pNeoCmdPlayer, const char *pSzChat return; } - const bool bNonCmdGameType = !NEO_GAME_TYPE_SETTINGS[GetGameType()].comp; + const bool bNonCmdGameType = !GetCompEnabled(); if (sv_neo_readyup_lobby.GetBool() && (bNonCmdGameType || m_nRoundStatus != NeoRoundStatus::Idle)) { @@ -3073,7 +3001,7 @@ void CNEORules::SetWinningTeam(int team, int iWinReason, bool bForceMapReset, bo if (teamJinrai->GetRoundsWon() == teamNSF->GetRoundsWon()) { // Sudden death - Don't end the match until we get a winning team - if (neo_round_sudden_death.GetBool()) + if (sv_neo_round_sudden_death.GetBool()) { V_sprintf_safe(victoryMsg, "Next round: Sudden death!\n"); isSuddenDeath = true; @@ -3276,7 +3204,7 @@ static CNEO_Player* FetchAssists(CNEO_Player* attacker, CNEO_Player* victim) #ifdef GAME_DLL void CNEORules::CheckIfCapPrevent(CNEO_Player *capPreventerPlayer) { - if (!NEO_GAME_TYPE_SETTINGS[GetGameType()].capPrevent) + if (!GetCapPreventEnabled()) { return; } @@ -3701,14 +3629,7 @@ void CNEORules::ClientDisconnected(edict_t* pClient) BaseClass::ClientDisconnected(pClient); } -#endif -bool CNEORules::GetTeamPlayEnabled() const -{ - return true; -} - -#ifdef GAME_DLL bool CNEORules::FPlayerCanRespawn(CBasePlayer* pPlayer) { CNEO_Player* pNeoPlayer = ToNEOPlayer(pPlayer); @@ -3793,7 +3714,8 @@ NeoRoundStatus CNEORules::GetRoundStatus() const int CNEORules::GetGameType(void) { - return m_nGameTypeSelected; + Assert(false); + return 0; } int CNEORules::GetHiddenHudElements(void) @@ -3826,21 +3748,6 @@ bool CNEORules::IsCyberspace() return m_bCyberspaceLevel; } -inline const char* CNEORules::GetGameTypeName(void) -{ - return NEO_GAME_TYPE_SETTINGS[GetGameType()].gameTypeName; -} - -bool CNEORules::CanChangeTeamClassLoadoutWhenAlive() -{ - return NEO_GAME_TYPE_SETTINGS[GetGameType()].changeTeamClassLoadoutWhenAlive; -} - -bool CNEORules::CanRespawnAnyTime() -{ - return NEO_GAME_TYPE_SETTINGS[GetGameType()].respawns; -} - float CNEORules::GetRemainingPreRoundFreezeTime(const bool clampToZero) const { // If there's no time left, return 0 instead of a negative value. diff --git a/src/game/shared/neo/gamerules/neo_gamerules.h b/src/game/shared/neo/gamerules/neo_gamerules.h index b92c82b454..be8b311733 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules.h +++ b/src/game/shared/neo/gamerules/neo_gamerules.h @@ -282,27 +282,27 @@ friend class C_NEORulesVIP; virtual void ClientSpawned(edict_t* pPlayer) OVERRIDE; virtual void PlayerKilled(CBasePlayer *pVictim, const CTakeDamageInfo &info) override; - virtual void EnemyPlayerKilled(CNEO_Player* pVictim, CNEO_Player* pAttacker, const CTakeDamageInfo& info) {}; + virtual void EnemyPlayerKilled(CNEO_Player* pVictim, CNEO_Player* pAttacker, const CTakeDamageInfo& info) {} virtual void DeathNotice(CBasePlayer* pVictim, const CTakeDamageInfo& info) OVERRIDE; virtual const char* GetGameName() { return NEO_GAME_NAME; } - virtual const char* GetGameTypeName(void) override; + virtual const char* GetGameTypeName(void) override = 0; virtual int GetGameType(void) override; - virtual const char* GetGameDescription(void) override { return NEO_GAME_NAME; }; - virtual bool GetTeamPlayEnabled() const override; + virtual const char* GetGameDescription(void) override { return NEO_GAME_NAME; } + virtual bool GetTeamPlayEnabled() const override { return true; } + virtual bool GetCompEnabled() const { return false; } + virtual bool GetCapPreventEnabled() const { return false; } + virtual bool CanChangeTeamClassLoadoutWhenAlive() const { return false; } + virtual bool CanRespawnAnyTime() const { return false; } int GetHiddenHudElements(); int GetForcedTeam(); int GetForcedClass(); int GetForcedSkin(); int GetForcedWeapon(); bool IsCyberspace(); - bool CanChangeTeamClassLoadoutWhenAlive(); // NEO TODO (Adam) Replace with gamemode specific check wherever used - bool CanRespawnAnyTime(); // NEO TODO (Adam) Replace with gamemode specific check wherever used virtual int DefaultFOV(void) override; - bool CheckShouldNotThink(); // NEO TODO (Adam) Remove - const char *GetTeamClantag(const int iTeamNum) const; inline int roundNumber() const { return m_iRoundNumber; } inline bool roundNumberIsEven() const { return (roundNumber() % 2 == 0); } @@ -314,7 +314,7 @@ friend class C_NEORulesVIP; virtual float GetRoundRemainingTime() const; float GetRoundRemainingTime(float flGameTypeRoundTimeLimit) const; float GetOverTime(float flRoundTimeLimit, float flOvertimeBaseAmount, float flOvertimeGrace, float flGraceDecay) const; - virtual void CheckOvertime() {}; + virtual void CheckOvertime() {} virtual bool CheckGameOver(void) OVERRIDE; // NEO TODO (Adam) this changes map as a side effect, better name? Also is this called client side anywhere? float GetRoundAccumulatedTime() const; #ifdef GAME_DLL @@ -504,7 +504,6 @@ friend class C_NEORulesVIP; CNetworkVar(int, m_iForcedSkin); CNetworkVar(int, m_iForcedWeapon); CNetworkVar(bool, m_bCyberspaceLevel); - CNetworkVar(int, m_nGameTypeSelected); CNetworkVar(int, m_iRoundNumber); CNetworkVar(bool, m_bIsMatchPoint); CNetworkVar(bool, m_bIsDoOrDie); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp index 054e48cedd..529f9e29b0 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp @@ -124,6 +124,8 @@ void CNEORulesATK::Think() { #ifdef GAME_DLL CGameRules::Think(); + + UpdateFromGameConfig(); if (RoundStartFromIdleOrPausedThink()) return; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_atk.h b/src/game/shared/neo/gamerules/neo_gamerules_atk.h index 6aed1abb5c..2872b52441 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_atk.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_atk.h @@ -31,8 +31,14 @@ class CNEORulesATK : public CNEORules, public CGameEventListener // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; - const char* GetGameDescription() override { return "Attack/Defend"; } - virtual bool GetTeamPlayEnabled() const override { return true; }; + virtual int GetGameType() override final { return NEO_GAME_TYPE_ATK; } + virtual const char* GetGameTypeName() override { return "ATK"; } + const char* GetGameDescription() override final { return "Attack / Defend the ghost"; } + virtual bool GetTeamPlayEnabled() const override final { return true; } + virtual bool GetCompEnabled() const override final { return true; } + virtual bool GetCapPreventEnabled() const override final { return false; } + virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } + virtual bool CanRespawnAnyTime() const override final { return false; } virtual void CheckOvertime(); virtual float GetRoundRemainingTime() const override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp index 66d89153d8..193dc4b19c 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp @@ -130,6 +130,8 @@ void CNEORulesCTG::Think() { #ifdef GAME_DLL CGameRules::Think(); + + UpdateFromGameConfig(); if (RoundStartFromIdleOrPausedThink()) return; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_ctg.h b/src/game/shared/neo/gamerules/neo_gamerules_ctg.h index 030b21b2e4..8e26a4023e 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_ctg.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_ctg.h @@ -31,8 +31,14 @@ class CNEORulesCTG : public CNEORules, public CGameEventListener // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; + virtual int GetGameType() override final { return NEO_GAME_TYPE_CTG; } + virtual const char* GetGameTypeName() override { return "CTG"; } const char* GetGameDescription() override { return "Capture the Ghost"; } - virtual bool GetTeamPlayEnabled() const override { return true; }; + virtual bool GetTeamPlayEnabled() const override { return true; } + virtual bool GetCompEnabled() const override final { return true; } + virtual bool GetCapPreventEnabled() const override final { return true; } + virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } + virtual bool CanRespawnAnyTime() const override final { return false; } virtual void CheckOvertime(); virtual float GetRoundRemainingTime() const override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp b/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp index 8672c4f219..a92a900f7a 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp @@ -149,6 +149,8 @@ void CNEORulesDM::Think() { #ifdef GAME_DLL CGameRules::Think(); + + UpdateFromGameConfig(); if (RoundStartFromIdleOrPausedThink()) return; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_dm.h b/src/game/shared/neo/gamerules/neo_gamerules_dm.h index 79f3fc06b8..d77ca06f2d 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_dm.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_dm.h @@ -31,8 +31,14 @@ class CNEORulesDM : public CNEORules, public CGameEventListener // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; + virtual int GetGameType() override final { return NEO_GAME_TYPE_DM; } + virtual const char* GetGameTypeName() override { return "DM"; } const char* GetGameDescription() override { return "Deathmatch"; } - virtual bool GetTeamPlayEnabled() const override { return false; }; + virtual bool GetTeamPlayEnabled() const override { return false; } + virtual bool GetCompEnabled() const override final { return false; } + virtual bool GetCapPreventEnabled() const override final { return false; } + virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } + virtual bool CanRespawnAnyTime() const override final { return true; } virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_emt.h b/src/game/shared/neo/gamerules/neo_gamerules_emt.h index a7f33d0328..c814145e02 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_emt.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_emt.h @@ -31,10 +31,14 @@ class CNEORulesEMT : public CNEORules, public CGameEventListener // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; - - + virtual int GetGameType() override final { return NEO_GAME_TYPE_EMT; } + virtual const char* GetGameTypeName() override { return "EMT"; } virtual float GetRoundRemainingTime() const override final; - virtual bool GetTeamPlayEnabled() const override { return true; }; + virtual bool GetTeamPlayEnabled() const override { return true; } + virtual bool GetCompEnabled() const override final { return false; } + virtual bool GetCapPreventEnabled() const override final { return false; } + virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return true; } + virtual bool CanRespawnAnyTime() const override final { return true; } #ifdef GAME_DLL virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp b/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp index 877ea7ac02..7e412a2f14 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp @@ -205,6 +205,8 @@ void CNEORulesJGR::Think() { #ifdef GAME_DLL CGameRules::Think(); + + UpdateFromGameConfig(); if (RoundStartFromIdleOrPausedThink()) return; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_jgr.h b/src/game/shared/neo/gamerules/neo_gamerules_jgr.h index 53d05fb40a..614b283357 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_jgr.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_jgr.h @@ -31,8 +31,14 @@ class CNEORulesJGR : public CNEORules, public CGameEventListener // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; + virtual int GetGameType() override final { return NEO_GAME_TYPE_JGR; } + virtual const char* GetGameTypeName() override { return "JGR"; } const char* GetGameDescription() override { return "Juggernaut"; } - virtual bool GetTeamPlayEnabled() const override { return true; }; + virtual bool GetTeamPlayEnabled() const override { return true; } + virtual bool GetCompEnabled() const override final { return true; } + virtual bool GetCapPreventEnabled() const override final { return false; } + virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } + virtual bool CanRespawnAnyTime() const override final { return true; } virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp b/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp index 61cd1b5324..006541aad7 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp @@ -138,6 +138,8 @@ void CNEORulesTDM::Think() { #ifdef GAME_DLL CGameRules::Think(); + + UpdateFromGameConfig(); if (RoundStartFromIdleOrPausedThink()) return; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tdm.h b/src/game/shared/neo/gamerules/neo_gamerules_tdm.h index 9e4212a1cb..7cb55a4283 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tdm.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_tdm.h @@ -27,8 +27,14 @@ class CNEORulesTDM : public CNEORules, public CGameEventListener // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; + virtual int GetGameType() override final { return NEO_GAME_TYPE_TDM; } + virtual const char* GetGameTypeName() override { return "TDM"; } const char* GetGameDescription() override { return "Team Deathmatch"; } - virtual bool GetTeamPlayEnabled() const override { return true; }; + virtual bool GetTeamPlayEnabled() const override { return true; } + virtual bool GetCompEnabled() const override final { return false; } + virtual bool GetCapPreventEnabled() const override final { return false; } + virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } + virtual bool CanRespawnAnyTime() const override final { return true; } virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tut.h b/src/game/shared/neo/gamerules/neo_gamerules_tut.h index 4aa297cb9c..f0b9595eec 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tut.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_tut.h @@ -31,8 +31,14 @@ class CNEORulesTUT : public CNEORules, public CGameEventListener // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; - const char* GetGameDescription() override { return "Training"; }; - virtual bool GetTeamPlayEnabled() const override { return true; }; + virtual int GetGameType() override final { return NEO_GAME_TYPE_TUT; } + virtual const char* GetGameTypeName() override { return "TUT"; } + const char* GetGameDescription() override { return "Training"; } + virtual bool GetTeamPlayEnabled() const override { return true; } + virtual bool GetCompEnabled() const override final { return false; } + virtual bool GetCapPreventEnabled() const override final { return false; } + virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } + virtual bool CanRespawnAnyTime() const override final { return true; } virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp b/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp index f64d49b2b1..2bb34f3c5d 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp @@ -104,6 +104,8 @@ void CNEORulesVIP::Think() { #ifdef GAME_DLL CGameRules::Think(); + + UpdateFromGameConfig(); if (RoundStartFromIdleOrPausedThink()) return; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_vip.h b/src/game/shared/neo/gamerules/neo_gamerules_vip.h index e4c15afebb..578011f836 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_vip.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_vip.h @@ -31,8 +31,14 @@ class CNEORulesVIP : public CNEORules, public CGameEventListener // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; + virtual int GetGameType() override final { return NEO_GAME_TYPE_VIP; } + virtual const char* GetGameTypeName() override { return "VIP"; } virtual float GetRoundRemainingTime() const override final; - virtual bool GetTeamPlayEnabled() const override { return true; }; + virtual bool GetTeamPlayEnabled() const override { return true; } + virtual bool GetCompEnabled() const override final { return true; } + virtual bool GetCapPreventEnabled() const override final { return true; } + virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } + virtual bool CanRespawnAnyTime() const override final { return false; } #ifdef GAME_DLL virtual void SetGameRelatedVars() override final; From cbf3ff51b78d02f2d360d9d454a4f8cc6f14b93d Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Sun, 7 Jun 2026 22:22:44 +0100 Subject: [PATCH 13/16] reorder variables --- .../client/neo/ui/neo_hud_round_state.cpp | 2 +- src/game/server/neo/neo_game_config.h | 2 +- src/game/server/neo/neo_player.cpp | 15 +- .../shared/neo/gamerules/neo_gamerules.cpp | 94 +++-- src/game/shared/neo/gamerules/neo_gamerules.h | 333 +++++++++--------- .../neo/gamerules/neo_gamerules_atk.cpp | 40 +-- .../shared/neo/gamerules/neo_gamerules_atk.h | 2 +- .../neo/gamerules/neo_gamerules_ctg.cpp | 40 +-- .../shared/neo/gamerules/neo_gamerules_ctg.h | 2 +- .../shared/neo/gamerules/neo_gamerules_dm.cpp | 9 + .../shared/neo/gamerules/neo_gamerules_dm.h | 1 + .../shared/neo/gamerules/neo_gamerules_emt.h | 1 + .../neo/gamerules/neo_gamerules_jgr.cpp | 14 +- .../shared/neo/gamerules/neo_gamerules_jgr.h | 1 + .../neo/gamerules/neo_gamerules_tdm.cpp | 9 + .../shared/neo/gamerules/neo_gamerules_tdm.h | 1 + .../shared/neo/gamerules/neo_gamerules_vip.h | 1 + 17 files changed, 284 insertions(+), 283 deletions(-) diff --git a/src/game/client/neo/ui/neo_hud_round_state.cpp b/src/game/client/neo/ui/neo_hud_round_state.cpp index 3f553d92f6..ab66f4f6b9 100644 --- a/src/game/client/neo/ui/neo_hud_round_state.cpp +++ b/src/game/client/neo/ui/neo_hud_round_state.cpp @@ -299,7 +299,7 @@ void CNEOHud_RoundState::UpdateStateForNeoHudElementDraw() m_pWszStatusUnicode = L"Capture the Ghost\n"; break; case NEO_GAME_TYPE_VIP: - if (GetLocalPlayerTeam() == NEORules()->m_iEscortingTeam.Get()) + if (GetLocalPlayerTeam() == NEORules()->GetEscortingTeam()) { if (NEORules()->GhostExists()) { diff --git a/src/game/server/neo/neo_game_config.h b/src/game/server/neo/neo_game_config.h index fb08ecc44f..65c0969b36 100644 --- a/src/game/server/neo/neo_game_config.h +++ b/src/game/server/neo/neo_game_config.h @@ -13,7 +13,7 @@ class CNEOGameConfig : public CLogicalEntity ~CNEOGameConfig(); virtual void Spawn() override; - int m_GameType = NEO_GAME_TYPE_TDM; + int m_GameType = NEO_GAME_TYPE_EMT; int m_HiddenHudElements = 0; int m_ForcedTeam = -1; int m_ForcedClass = -1; diff --git a/src/game/server/neo/neo_player.cpp b/src/game/server/neo/neo_player.cpp index 6102275c60..3177e268de 100644 --- a/src/game/server/neo/neo_player.cpp +++ b/src/game/server/neo/neo_player.cpp @@ -156,8 +156,6 @@ extern ConVar sv_stickysprint; extern ConVar sv_neo_dev_loadout; extern ConVar neo_bot_difficulty; -ConVar sv_neo_can_change_classes_anytime("sv_neo_can_change_classes_anytime", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "Can players change classes at any moment, even mid-round?", - true, 0.0f, true, 1.0f); ConVar sv_neo_change_suicide_player("sv_neo_change_suicide_player", "0", FCVAR_REPLICATED, "Kill the player if they change the team and they're alive.", true, 0.0f, true, 1.0f); ConVar sv_neo_change_threshold_interval("sv_neo_change_threshold_interval", "0.25", FCVAR_REPLICATED, "The interval threshold limit in seconds before the player is allowed to change team.", true, 0.0f, true, 1000.0f); ConVar sv_neo_dm_max_class_dur("sv_neo_dm_max_class_dur", "10", FCVAR_REPLICATED, "The time in seconds when the player can change class on respawn during deathmatch.", true, 0.0f, true, 60.0f); @@ -243,12 +241,7 @@ void CNEO_Player::RequestSetClass(int newClass) return; } - const bool bIsTypeDM = (NEORules()->GetGameType() == NEO_GAME_TYPE_TDM || NEORules()->GetGameType() == NEO_GAME_TYPE_DM); - const NeoRoundStatus status = NEORules()->GetRoundStatus(); - if (IsDead() || sv_neo_can_change_classes_anytime.GetBool() || - (!m_bIneligibleForLoadoutPick && NEORules()->GetRemainingPreRoundFreezeTime(false) > 0) || - (bIsTypeDM && !m_bIneligibleForLoadoutPick && GetAliveDuration() < sv_neo_dm_max_class_dur.GetFloat()) || - (status == NeoRoundStatus::Idle || status == NeoRoundStatus::Warmup || status == NeoRoundStatus::Countdown)) + if (NEORules()->PlayerCanChangeLoadout(this)) { m_iNeoClass = newClass; m_iNextSpawnClassChoice = NEO_CLASS_RANDOM; @@ -279,13 +272,9 @@ void CNEO_Player::RequestSetClass(int newClass) void CNEO_Player::RequestSetSkin(int newSkin) { - const NeoRoundStatus roundStatus = NEORules()->GetRoundStatus(); - bool canChangeImmediately = ((roundStatus != NeoRoundStatus::RoundLive) && (roundStatus != NeoRoundStatus::Overtime) && (roundStatus != NeoRoundStatus::PostRound)) || !IsAlive(); - - if (canChangeImmediately) + if (NEORules()->PlayerCanChangeSkin(this)) { m_iNeoSkin = newSkin; - SetPlayerTeamModel(); } //else NEOTODO Set for next spawn diff --git a/src/game/shared/neo/gamerules/neo_gamerules.cpp b/src/game/shared/neo/gamerules/neo_gamerules.cpp index c42405e5f6..a7490bddfc 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules.cpp @@ -47,6 +47,8 @@ ConVar sv_neo_preround_freeze_time("sv_neo_preround_freeze_time", "15", FCVAR_RE ConVar sv_neo_latespawn_max_time("sv_neo_latespawn_max_time", "15", FCVAR_REPLICATED, "How many seconds late are players still allowed to spawn.", true, 0.0, false, 0); ConVar sv_neo_wep_dmg_modifier("sv_neo_wep_dmg_modifier", "1.485", FCVAR_REPLICATED, "Temp global weapon damage modifier.", true, 0.0, true, 100.0); +ConVar sv_neo_can_change_classes_anytime("sv_neo_can_change_classes_anytime", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "Can players change classes at any moment, even mid-round?", + true, 0.0f, true, 1.0f); ConVar sv_neo_player_restore("sv_neo_player_restore", "1", FCVAR_REPLICATED, "If enabled, the server will save players XP and deaths per match session and restore them if they reconnect.", true, 0.0f, true, 1.0f); ConVar sv_neo_spraydisable("sv_neo_spraydisable", "0", FCVAR_REPLICATED, "If enabled, disables the players ability to spray.", true, 0.0f, true, 1.0f); @@ -528,7 +530,6 @@ static void CvarChanged_WeaponStay(IConVar* convar, const char* pOldVal, float f CNEORules::CNEORules() { #ifdef GAME_DLL - m_bNextClientIsFakeClient = false; m_ghostSpawns.EnsureCapacity(10); m_jgrSpawns.EnsureCapacity(10); @@ -548,6 +549,7 @@ CNEORules::CNEORules() } } + ResetMapSessionCommon(); #endif m_iHiddenHudElements = 0; m_iForcedTeam = -1; @@ -556,7 +558,6 @@ CNEORules::CNEORules() m_iForcedWeapon = -1; m_bCyberspaceLevel = false; - ResetMapSessionCommon(); ListenForGameEvent("round_start"); ListenForGameEvent("game_end"); @@ -788,10 +789,12 @@ bool CNEORules::CheckGameOver(void) // Note that this changes the level as side effect const bool gameOver = BaseClass::CheckGameOver(); +#ifdef GAME_DLL if (gameOver) { ResetMapSessionCommon(); } +#endif // GAME_DLL return gameOver; } @@ -901,12 +904,13 @@ void CNEORules::PlayerRespawnThink() } } +static bool bCheckClantags = false; void CNEORules::CheckClantagsThink() { - if (!m_bThinkCheckClantags) + if (!bCheckClantags) return; - m_bThinkCheckClantags = false; + bCheckClantags = false; int iHasClantags[TEAM__TOTAL] = {}; bool bClantagSet[TEAM__TOTAL] = {}; char szTeamClantags[TEAM__TOTAL][NEO_MAX_CLANTAG_LENGTH] = {}; @@ -1992,7 +1996,8 @@ void CNEORules::StartNextRound() { if (sv_neo_readyup_lobby.GetBool()) { - bool bPrintHelpInfo = (m_iPrintHelpCounter == 0); + static int iPrintHelpCounter = 0; + bool bPrintHelpInfo = (0 == iPrintHelpCounter); if (!m_bIgnoreOverThreshold && (readyPlayers.array[TEAM_JINRAI] > iThres || readyPlayers.array[TEAM_NSF] > iThres)) { char szPrint[128]; @@ -2021,7 +2026,7 @@ void CNEORules::StartNextRound() UTIL_ClientPrintAll(HUD_PRINTTALK, szPrint); } static constexpr int HELP_COUNT_NEXT_PRINT = 3; - m_iPrintHelpCounter = LoopAroundInArray(m_iPrintHelpCounter + 1, HELP_COUNT_NEXT_PRINT); + iPrintHelpCounter = LoopAroundInArray(iPrintHelpCounter + 1, HELP_COUNT_NEXT_PRINT); } else { @@ -2200,8 +2205,8 @@ void CNEORules::StartNextRound() FireLegacyEvent_NeoRoundEnd(); - char RoundMsg[27]; - static_assert(sizeof(RoundMsg) == sizeof("- CTG ROUND 99 STARTED -\n\0"), "RoundMsg requires to fit round numbers up to 2 digits"); + char RoundMsg[26]; + static_assert(sizeof(RoundMsg) == sizeof("- KOTH ROUND 99 STARTED -"), "RoundMsg requires to fit round numbers up to 2 digits"); V_sprintf_safe(RoundMsg, "- %s ROUND %d STARTED -\n", GetGameTypeName(), Min(99, m_iRoundNumber.Get())); UTIL_CenterPrintAll(RoundMsg); @@ -2260,6 +2265,18 @@ bool CNEORules::IsRoundLive() const return false; } +bool CNEORules::IsRoundActive() const +{ + switch (m_nRoundStatus) + { + case NeoRoundStatus::RoundLive: + case NeoRoundStatus::Overtime: + case NeoRoundStatus::PostRound: + return true; + } + return false; +} + bool CNEORules::IsRoundOn() const { switch (m_nRoundStatus) @@ -2460,11 +2477,6 @@ void CNEORules::CleanUpMap() } } -void CNEORules::PurgeGhostCapPoints() -{ - m_pGhostCaps.Purge(); -} - void CNEORules::ResetGhostCapPoints() { m_pGhostCaps.Purge(); @@ -2783,7 +2795,7 @@ void CNEORules::ClientSettingsChanged(CBasePlayer *pPlayer) V_strncpy(pNEOPlayer->m_szNeoClantag.GetForModify(), (FStrEq(pszNeoClantag, "#empty") ? "" : pszNeoClantag), NEO_MAX_CLANTAG_LENGTH); - m_bThinkCheckClantags = true; + bCheckClantags = true; } const char *pszClNeoCrosshair = engine->GetClientConVarValue(pNEOPlayer->entindex(), "cl_neo_crosshair"); @@ -3364,6 +3376,24 @@ float CNEORules::FlPlayerFallDamage(CBasePlayer* pPlayer) return pPlayer->m_Local.m_flFallVelocity * DAMAGE_FOR_FALL_SPEED * sv_neo_falldmg_scale.GetFloat(); } +bool CNEORules::PlayerCanChangeLoadout(CNEO_Player* pPlayer) +{ + if (sv_neo_can_change_classes_anytime.GetBool() || + pPlayer->IsDead() || + IsRoundIdle() || + !pPlayer->m_bIneligibleForLoadoutPick && GetRemainingPreRoundFreezeTime(false) > 0) + { + return true; + } + return false; +} + +bool CNEORules::PlayerCanChangeSkin(CNEO_Player* pPlayer) +{ + return (!IsRoundActive() || !pPlayer->IsAlive()); +} + + const char* CNEORules::GetChatFormat(bool bTeamOnly, CBasePlayer* pPlayer) { if (!pPlayer) // dedicated server output @@ -3712,42 +3742,6 @@ NeoRoundStatus CNEORules::GetRoundStatus() const return static_cast(m_nRoundStatus.Get()); } -int CNEORules::GetGameType(void) -{ - Assert(false); - return 0; -} - -int CNEORules::GetHiddenHudElements(void) -{ - return m_iHiddenHudElements; -} - -int CNEORules::GetForcedTeam(void) -{ - return m_iForcedTeam.Get(); -} - -int CNEORules::GetForcedClass(void) -{ - return m_iForcedClass; -} - -int CNEORules::GetForcedSkin(void) -{ - return m_iForcedSkin; -} - -int CNEORules::GetForcedWeapon(void) -{ - return m_iForcedWeapon; -} - -bool CNEORules::IsCyberspace() -{ - return m_bCyberspaceLevel; -} - float CNEORules::GetRemainingPreRoundFreezeTime(const bool clampToZero) const { // If there's no time left, return 0 instead of a negative value. diff --git a/src/game/shared/neo/gamerules/neo_gamerules.h b/src/game/shared/neo/gamerules/neo_gamerules.h index be8b311733..25c25e6504 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules.h +++ b/src/game/shared/neo/gamerules/neo_gamerules.h @@ -1,8 +1,4 @@ -#ifndef NEO_GAMERULES_H -#define NEO_GAMERULES_H -#ifdef _WIN32 #pragma once -#endif #include "gamerules.h" #include "teamplay_gamerules.h" @@ -83,8 +79,6 @@ class CNEO_Player; class CWeaponGhost; class CNEOBotSeekAndDestroy; -extern ConVar sv_neo_mirror_teamdamage_multiplier; -extern ConVar sv_neo_mirror_teamdamage_duration; extern ConVar sv_neo_mirror_teamdamage_immunity; extern ConVar sv_neo_teamdamage_kick; @@ -109,8 +103,6 @@ enum NeoGameType { extern const char* NEO_GAME_TYPE_CLASS_NAMES[NEO_GAME_TYPE__TOTAL]; -struct NeoGameTypeSettings; - extern const SZWSZTexts NEO_GAME_TYPE_DESC_STRS[NEO_GAME_TYPE__TOTAL]; enum NeoRoundStatus { @@ -171,35 +163,25 @@ enum NeoSpectateEvent { NEO_SPECTATE_EVENT_LAST_GHOSTER, }; -class CNEORules : public CHL2MPRules, public CGameEventListener +abstract_class CNEORules : public CHL2MPRules, public CGameEventListener { -#ifdef GAME_DLL -friend class CNEORulesATK; +friend class CNEORulesTDM; friend class CNEORulesCTG; +friend class CNEORulesVIP; friend class CNEORulesDM; friend class CNEORulesEMT; -friend class CNEORulesJGR; -friend class CNEORulesTDM; friend class CNEORulesTUT; -friend class CNEORulesVIP; -#else -friend class C_NEORulesATK; -friend class C_NEORulesCTG; -friend class C_NEORulesDM; -friend class C_NEORulesEMT; -friend class C_NEORulesJGR; -friend class C_NEORulesTDM; -friend class C_NEORulesTUT; -friend class C_NEORulesVIP; -#endif // GAME_DLL +friend class CNEORulesJGR; +friend class CNEORulesATK; + +friend class CNEOGameConfig; // this only exists because we can't add a BEGIN_DATADESC to neogamerules public: DECLARE_CLASS( CNEORules, CHL2MPRules ); // This makes datatables able to access our private vars. DECLARE_NETWORKCLASS_NOBASE(); - CNEORules(); virtual ~CNEORules(); @@ -215,129 +197,125 @@ friend class C_NEORulesVIP; virtual const unsigned char* GetEncryptionKey(void) OVERRIDE { return (unsigned char*)"tBA%-ygc"; } #ifdef GAME_DLL +public: + virtual bool PlayerCanChangeLoadout(CNEO_Player* pPlayer); + bool PlayerCanChangeSkin(CNEO_Player* pPlayer); + + virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) override; + virtual float FlPlayerFallDamage(CBasePlayer* pPlayer) OVERRIDE; + float MirrorDamageMultiplier() const; + + void CheckChatCommand(CNEO_Player *pNeoPlayer, const char *pSzChat); + + virtual bool IsOfficialMap(void) override; + virtual void MarkAchievement ( IRecipientFilter& filter, char const *pchAchievementName ) override; + +private: + virtual void Precache() override; + virtual void InitDefaultAIRelationships(void) override; + void OnNavMeshLoad() override; + bool RoundStartFromIdleOrPausedThink(); virtual void PlayerRespawnThink(); void CheckClantagsThink(); + virtual void CheckOvertime() {} bool GameOverThink(); void TeamDamageThink(); bool RoundOverThink(); void RoundStatusThink(); void CheckWinByElimination(); - - virtual void Precache() override; - virtual void InitDefaultAIRelationships(void); // NEO NOTE (Adam) override? - - + virtual bool ClientConnected(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) override; virtual bool ClientCommand(CBaseEntity* pEdict, const CCommand& args) override; virtual void ClientDisconnected(edict_t* pClient) override; virtual const char* GetChatFormat(bool bTeamOnly, CBasePlayer* pPlayer) OVERRIDE; virtual const char* GetChatPrefix(bool bTeamOnly, CBasePlayer* pPlayer) OVERRIDE { return ""; } // handled by GetChatFormat virtual const char* GetChatLocation(bool bTeamOnly, CBasePlayer* pPlayer) OVERRIDE { return NULL; } // unimplemented - - virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) override; - virtual float FlPlayerFallDamage(CBasePlayer* pPlayer) OVERRIDE; - - + virtual void SetWinningTeam(int team, int iWinReason, bool bForceMapReset = true, bool bSwitchTeams = false, bool bDontAddScore = false, bool bFinal = false) OVERRIDE; void AwardRankUp(CNEO_Player *pClient); void SetRoundStatus(NeoRoundStatus status); - // NEOGameConfig is a logic entity, which is a server only entity. To access config values client side, we need to copy values to a networked entity void UpdateFromGameConfig(); void StartNextRound(); virtual void RoundTimeout() {}; - struct ReadyPlayers { int array[TEAM__TOTAL]; }; - void CheckChatCommand(CNEO_Player *pNeoPlayer, const char *pSzChat); ReadyPlayers FetchReadyPlayers() const; // NEO TODO (Adam) This needs to be shown in the ui somewhere instead, ready up button CUtlHashtable m_readyAccIDs; // NEO NOTE (Adam) What's wrong with player ent index bool m_bIgnoreOverThreshold = false; bool ReadyUpPlayerIsReady(CNEO_Player *pNeoPlayer) const; - virtual void CleanUpMap() OVERRIDE; virtual void RestartGame() OVERRIDE; virtual void ChangeLevel(void) OVERRIDE; + virtual void SetGameRelatedVars() {}; + void ResetTeamScores(); +#else // #ifdef CLIENT_DLL +public: +private: +#endif // GAME_DLL - virtual bool IsOfficialMap(void) override; - virtual void MarkAchievement ( IRecipientFilter& filter, char const *pchAchievementName ) override; -#endif - -#ifdef CLIENT_DLL -#endif // CLIENT_DLL - - virtual void CreateStandardEntities( void ) OVERRIDE; +public: virtual const CViewVectors* GetViewVectors() const OVERRIDE; const NEOViewVectors* GetNEOViewVectors() const; - - virtual void ClientSettingsChanged(CBasePlayer *pPlayer) OVERRIDE; - virtual void ClientSpawned(edict_t* pPlayer) OVERRIDE; - - virtual void PlayerKilled(CBasePlayer *pVictim, const CTakeDamageInfo &info) override; - virtual void EnemyPlayerKilled(CNEO_Player* pVictim, CNEO_Player* pAttacker, const CTakeDamageInfo& info) {} - virtual void DeathNotice(CBasePlayer* pVictim, const CTakeDamageInfo& info) OVERRIDE; - - virtual const char* GetGameName() { return NEO_GAME_NAME; } virtual const char* GetGameTypeName(void) override = 0; - virtual int GetGameType(void) override; - virtual const char* GetGameDescription(void) override { return NEO_GAME_NAME; } - virtual bool GetTeamPlayEnabled() const override { return true; } + virtual int GetGameType(void) override = 0; + virtual const char* GetGameDescription(void) override = 0; + virtual bool GetTeamPlayEnabled() const override = 0; virtual bool GetCompEnabled() const { return false; } virtual bool GetCapPreventEnabled() const { return false; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const { return false; } virtual bool CanRespawnAnyTime() const { return false; } - int GetHiddenHudElements(); - int GetForcedTeam(); - int GetForcedClass(); - int GetForcedSkin(); - int GetForcedWeapon(); - bool IsCyberspace(); + inline int GetHiddenHudElements() const { return m_iHiddenHudElements; } + inline int GetForcedTeam() const { return m_iForcedTeam; } + inline int GetForcedClass() const { return m_iForcedClass; } + inline int GetForcedSkin() const { return m_iForcedSkin; } + inline int GetForcedWeapon() const { return m_iForcedWeapon; } + inline bool IsCyberspace() const { return m_bCyberspaceLevel; } virtual int DefaultFOV(void) override; - const char *GetTeamClantag(const int iTeamNum) const; - inline int roundNumber() const { return m_iRoundNumber; } - inline bool roundNumberIsEven() const { return (roundNumber() % 2 == 0); } NeoRoundStatus GetRoundStatus() const; - int GetAttackingTeam() const; - int GetDefendingTeam() const; - float GetRemainingPreRoundFreezeTime(const bool clampToZero) const; - float GetMapRemainingTime(); - virtual float GetRoundRemainingTime() const; - float GetRoundRemainingTime(float flGameTypeRoundTimeLimit) const; - float GetOverTime(float flRoundTimeLimit, float flOvertimeBaseAmount, float flOvertimeGrace, float flGraceDecay) const; - virtual void CheckOvertime() {} - virtual bool CheckGameOver(void) OVERRIDE; // NEO TODO (Adam) this changes map as a side effect, better name? Also is this called client side anywhere? - float GetRoundAccumulatedTime() const; -#ifdef GAME_DLL - float MirrorDamageMultiplier() const; -#endif bool RoundIsInSuddenDeath() const; bool RoundIsMatchPoint() const; bool RoundIsDoOrDie() const; bool IsRoundPreRoundFreeze() const; + // Round winner not determined yet bool IsRoundLive() const; + // Can score points + bool IsRoundActive() const; + // Round timer is ticking down bool IsRoundOn() const; bool IsRoundOver() const; bool IsRoundIdle() const; inline bool IsRoundPaused() const; - int GetOpposingTeam(const int team) const // NEO TODO (Adam) move to .cpp and / or gamemode specific gamerules + inline int roundNumber() const { return m_iRoundNumber; } + inline bool roundNumberIsEven() const { return (roundNumber() % 2 == 0); } + float GetRemainingPreRoundFreezeTime(const bool clampToZero) const; + float GetMapRemainingTime(); + virtual float GetRoundRemainingTime() const; + float GetRoundRemainingTime(float flGameTypeRoundTimeLimit) const; + float GetOverTime(float flRoundTimeLimit, float flOvertimeBaseAmount, float flOvertimeGrace, float flGraceDecay) const; + virtual bool CheckGameOver(void) OVERRIDE; + float GetRoundAccumulatedTime() const; + + int GetAttackingTeam() const; + int GetDefendingTeam() const; + int GetOpposingTeam(const int team) const { if (team == TEAM_JINRAI) { return TEAM_NSF; } if (team == TEAM_NSF) { return TEAM_JINRAI; } Assert(false); return TEAM_SPECTATOR; } - - int GetOpposingTeam(const CBaseCombatCharacter* player) const // NEO TODO (Adam) move to .cpp and / or gamemode specific gamerules + int GetOpposingTeam(const CBaseCombatCharacter* player) const { if (!player) { @@ -370,48 +348,22 @@ friend class C_NEORulesVIP; } } #endif + const char *GetTeamClantag(const int iTeamNum) const; +private: + void ResetMapSessionCommon(); + virtual void CreateStandardEntities( void ) OVERRIDE; + virtual void ClientSettingsChanged(CBasePlayer *pPlayer) OVERRIDE; + virtual void ClientSpawned(edict_t* pPlayer) OVERRIDE; + + virtual void PlayerKilled(CBasePlayer *pVictim, const CTakeDamageInfo &info) override; + virtual void EnemyPlayerKilled(CNEO_Player* pVictim, CNEO_Player* pAttacker, const CTakeDamageInfo& info) {} + virtual void DeathNotice(CBasePlayer* pVictim, const CTakeDamageInfo& info) OVERRIDE; + virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 ) OVERRIDE; - - void PurgeGhostCapPoints(); // NEO TODO (Adam) move to ctg / vip gamerules - void ResetGhostCapPoints(); // NEO TODO (Adam) move to ctg / vip gamerules - -#ifdef GAME_DLL - virtual void SetGameRelatedVars() {}; - void ResetTeamScores(); -#endif // GAME_DLL - void ResetGhost(); // NEO TODO (Adam) move to related gamerules - void ResetVIP(); // NEO TODO (Adam) move to related gamerules - void ResetJGR(); // NEO TODO (Adam) move to related gamerules - - -#ifdef GAME_DLL - void CheckIfCapPrevent(CNEO_Player *capPreventerPlayer); // NEO TODO (Adam) move to related gamerules -#endif - - // NEO TODO (Adam) Move to gamemode specific gamerules - int GetGhosterTeam() const { return m_iGhosterTeam; } - int GetGhosterPlayer() const { return m_iGhosterPlayer; } - bool GhostExists() const { return m_bGhostExists; } - const Vector& GetGhostPos() const; - Vector GetGhostMarkerPos() const; - - // NEO TODO (Adam) Move to gamemode specific gamerules - int GetJuggernautPlayer() const { return m_iJuggernautPlayerIndex; } - bool JuggernautItemExists() const; - const Vector& GetJuggernautMarkerPos() const; - bool IsJuggernautLocked() const; - - -#ifdef GAME_DLL - void OnNavMeshLoad() override; -#endif // GAME_DL: - public: #ifdef GAME_DLL - // Workaround for bot spawning. See Bot_f() for details. - bool m_bNextClientIsFakeClient; struct RestoreInfo { int xp; @@ -430,23 +382,12 @@ friend class C_NEORulesVIP; bool m_bThinkCheckClantags = false; bool m_bRotatingMapRightNow = false; #endif - CNetworkVar(float, m_flPauseEnd); -private: - void ResetMapSessionCommon(); // NEO TODO (Adam) Is this needed client side + virtual const int GetScoreLimit() const { return 0; }; + virtual const int GetRoundLimit() const { return 0; }; #ifdef GAME_DLL - virtual const int GetScoreLimit() const { Assert(false); return 0; }; - virtual const int GetRoundLimit() const { Assert(false); return 0; }; - - void SpawnTheGhost(const Vector *origin = nullptr); - void SpawnTheJuggernaut(const Vector *origin = nullptr); - void SelectTheVIP(); public: - void JuggernautActivated(CNEO_Player *pPlayer); - void JuggernautDeactivated(CNEO_Juggernaut *pJuggernaut); - void JuggernautTotalRemoval(CNEO_Juggernaut *pJuggernaut); - void SetLastHurt(const int index) { m_iLastHurt = index; } void SetLastShooter(const int index) { m_iLastShooter = index; } void SetLastAttacker(const int index) { m_iLastAttacker = m_iLastEvent = index; } @@ -462,87 +403,133 @@ friend class C_NEORulesVIP; const int GetLastGhoster() const { return m_iLastGhoster; } #ifdef GAME_DLL private: - CNEO_Juggernaut *m_pJuggernautItem = nullptr; - CNEO_Player *m_pJuggernautPlayer = nullptr; - float m_flJuggernautDeathTime = 0.0f; - int m_iLastJuggernautTeam = TEAM_INVALID; - - // For looking up capture zone locations - friend class CNEOBotCtgCarrier; - friend class CNEOBotCtgEscort; - friend class CNEOBotCtgLoneWolf; - friend class CNEOBotSeekAndDestroy; - CUtlVector m_pGhostCaps; - CWeaponGhost *m_pGhost = nullptr; - CNEO_Player *m_pVIP = nullptr; - int m_iVIPPreviousClass = 0; float m_flPrevThinkKick = 0.0f; float m_flPrevThinkMirrorDmg = 0.0f; bool m_bTeamBeenAwardedDueToCapPrevent = false; int m_arrayiEntPrevCap[MAX_PLAYERS + 1]; // This is to check for cap-prevention workaround attempts int m_iEntPrevCapSize = 0; - int m_iPrintHelpCounter = 0; - bool m_bGamemodeTypeBeenInitialized = false; bool m_bServerIsCurrentlyAutoRecording = false; - friend class CNEO_GhostBoundary; - friend class CNEOGhostSpawnPoint; - friend class CNEOJuggernautSpawnPoint; friend class CMultiplayRules; - CUtlVector> m_ghostSpawns; CUtlVector> m_jgrSpawns; - Vector m_vecPreviousGhostSpawn = vec3_origin; Vector m_vecPreviousJuggernautSpawn = vec3_origin; bool m_bGotMatchWinner = false; int m_iMatchWinner = TEAM_UNASSIGNED; #endif - CNetworkVar(int, m_nRoundStatus); + + // neo_game_config variables CNetworkVar(int, m_iHiddenHudElements); CNetworkVar(int, m_iForcedTeam); CNetworkVar(int, m_iForcedClass); CNetworkVar(int, m_iForcedSkin); CNetworkVar(int, m_iForcedWeapon); CNetworkVar(bool, m_bCyberspaceLevel); + + CNetworkVar(int, m_nRoundStatus); CNetworkVar(int, m_iRoundNumber); CNetworkVar(bool, m_bIsMatchPoint); CNetworkVar(bool, m_bIsDoOrDie); CNetworkVar(bool, m_bIsInSuddenDeath); + CNetworkVar(float, m_flNeoRoundStartTime); + CNetworkVar(float, m_flNeoNextRoundStartTime); + CNetworkVar(float, m_flPauseEnd); CNetworkString(m_szNeoJinraiClantag, NEO_MAX_CLANTAG_LENGTH); CNetworkString(m_szNeoNSFClantag, NEO_MAX_CLANTAG_LENGTH); - // Ghost networked variables + // For spectator commands. Networked so can be saved in demos for hltv + CNetworkVar(int, m_iLastHurt); + CNetworkVar(int, m_iLastShooter); + CNetworkVar(int, m_iLastEvent); + CNetworkVar(int, m_iLastAttacker); + CNetworkVar(int, m_iLastKiller); + CNetworkVar(int, m_iLastGhoster); + + ////////////////////// + // Ghost game logic // + ////////////////////// + +private: + friend class CNEO_GhostBoundary; + friend class CNEOGhostSpawnPoint; + // For looking up capture zone locations + friend class CNEOBotCtgCarrier; + friend class CNEOBotCtgEscort; + friend class CNEOBotCtgLoneWolf; + + CNetworkVar(bool, m_bGhostExists); CNetworkVar(int, m_iGhosterTeam); CNetworkVar(int, m_iGhosterPlayer); - CNetworkVector(m_vecGhostMarkerPos); - CNetworkVar(bool, m_bGhostExists); CNetworkVar(float, m_flGhostLastHeld); + CNetworkVector(m_vecGhostMarkerPos); CNetworkHandle( CWeaponGhost, m_hGhost ); - // Juggernaut networked variables +#ifdef GAME_DLL + CWeaponGhost *m_pGhost = nullptr; + CUtlVector m_pGhostCaps; + CUtlVector> m_ghostSpawns; + Vector m_vecPreviousGhostSpawn = vec3_origin; + + void SpawnTheGhost(const Vector *origin = nullptr); + void ResetGhostCapPoints(); + void CheckIfCapPrevent(CNEO_Player *capPreventerPlayer); +#endif // GAME_DLL +public: + void ResetGhost(); + inline bool GhostExists() const { return m_bGhostExists; } + inline int GetGhosterTeam() const { return m_iGhosterTeam; } + inline int GetGhosterPlayer() const { return m_iGhosterPlayer; } + const Vector& GetGhostPos() const; + Vector GetGhostMarkerPos() const; + + /////////////////////////// + // Juggernaut game logic // + /////////////////////////// + +private: + friend class CNEOJuggernautSpawnPoint; + CNetworkVar(int, m_iJuggernautPlayerIndex); CNetworkVar(bool, m_bJuggernautItemExists); CNetworkHandle( CBaseEntity, m_hJuggernaut ); - CNetworkVar(float, m_flNeoRoundStartTime); - CNetworkVar(float, m_flNeoNextRoundStartTime); - - // For spectator commands. Networked so can be saved in demos for hltv - CNetworkVar(int, m_iLastHurt); - CNetworkVar(int, m_iLastShooter); - CNetworkVar(int, m_iLastEvent); - CNetworkVar(int, m_iLastAttacker); - CNetworkVar(int, m_iLastKiller); - CNetworkVar(int, m_iLastGhoster); +#ifdef GAME_DLL + CNEO_Juggernaut *m_pJuggernautItem = nullptr; + CNEO_Player *m_pJuggernautPlayer = nullptr; + float m_flJuggernautDeathTime = 0.0f; + int m_iLastJuggernautTeam = TEAM_INVALID; + void SpawnTheJuggernaut(const Vector *origin = nullptr); + void ResetJGR(); +#endif // GAME_DLL public: - // VIP networked variables + void JuggernautTotalRemoval(CNEO_Juggernaut *pJuggernaut); + void JuggernautActivated(CNEO_Player *pPlayer); + void JuggernautDeactivated(CNEO_Juggernaut *pJuggernaut); + bool JuggernautItemExists() const; + bool IsJuggernautLocked() const; + int GetJuggernautPlayer() const { return m_iJuggernautPlayerIndex; } + const Vector& GetJuggernautMarkerPos() const; + + //////////////////// + // VIP game logic // + //////////////////// + +private: CNetworkVar(int, m_iEscortingTeam); + +#ifdef GAME_DLL + CNEO_Player *m_pVIP = nullptr; + int m_iVIPPreviousClass = NEO_CLASS_RECON; + + void SelectTheVIP(); + void ResetVIP(); +#endif // GAME_DLL +public: + inline int GetEscortingTeam() const { return m_iEscortingTeam; } }; inline CNEORules *NEORules() { return static_cast(g_pGameRules); } - -#endif // NEO_GAMERULES_H diff --git a/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp index 529f9e29b0..10bda870b0 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp @@ -65,26 +65,6 @@ void CNEORulesATK::FireGameEvent(IGameEvent* event) BaseClass::FireGameEvent(event); } -void CNEORulesATK::CheckOvertime() -{ - if (!sv_neo_atk_ghost_overtime_enabled.GetBool()) - return; - - float overtimeGrace = sv_neo_atk_round_timelimit.GetFloat() * 60; - float roundTimeLimit = sv_neo_atk_ghost_overtime_grace.GetFloat(); - - if (NeoRoundStatus::RoundLive == m_nRoundStatus && m_iGhosterPlayer && GetAttackingTeam() == m_iGhosterTeam && - (m_flNeoRoundStartTime + roundTimeLimit - overtimeGrace) < gpGlobals->curtime) - { - m_nRoundStatus = NeoRoundStatus::Overtime; - } - - if (NeoRoundStatus::Overtime == m_nRoundStatus && m_iGhosterPlayer) - { - m_flGhostLastHeld = gpGlobals->curtime; - } -} - float CNEORulesATK::GetRoundRemainingTime() const { if (NeoRoundStatus::Overtime == m_nRoundStatus) @@ -118,6 +98,26 @@ void CNEORulesATK::RoundTimeout() { SetWinningTeam(GetDefendingTeam(), NEO_VICTORY_ATK_TIMEOUT, false, true, false, false); } + +void CNEORulesATK::CheckOvertime() +{ + if (!sv_neo_atk_ghost_overtime_enabled.GetBool()) + return; + + float overtimeGrace = sv_neo_atk_round_timelimit.GetFloat() * 60; + float roundTimeLimit = sv_neo_atk_ghost_overtime_grace.GetFloat(); + + if (NeoRoundStatus::RoundLive == m_nRoundStatus && m_iGhosterPlayer && GetAttackingTeam() == m_iGhosterTeam && + (m_flNeoRoundStartTime + roundTimeLimit - overtimeGrace) < gpGlobals->curtime) + { + m_nRoundStatus = NeoRoundStatus::Overtime; + } + + if (NeoRoundStatus::Overtime == m_nRoundStatus && m_iGhosterPlayer) + { + m_flGhostLastHeld = gpGlobals->curtime; + } +} #endif // GAME_DLL void CNEORulesATK::Think() diff --git a/src/game/shared/neo/gamerules/neo_gamerules_atk.h b/src/game/shared/neo/gamerules/neo_gamerules_atk.h index 2872b52441..a24b965ac0 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_atk.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_atk.h @@ -40,12 +40,12 @@ class CNEORulesATK : public CNEORules, public CGameEventListener virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } virtual bool CanRespawnAnyTime() const override final { return false; } - virtual void CheckOvertime(); virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL virtual void SetGameRelatedVars() override final; virtual const int GetScoreLimit() const override final; virtual const int GetRoundLimit() const override final; + virtual void CheckOvertime(); virtual void RoundTimeout() override final; #endif // GAME_DLL virtual void Think() override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp index 193dc4b19c..bd40c7b9c0 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp @@ -71,26 +71,6 @@ void CNEORulesCTG::FireGameEvent(IGameEvent* event) BaseClass::FireGameEvent(event); } -void CNEORulesCTG::CheckOvertime() -{ - if (!sv_neo_ctg_ghost_overtime_enabled.GetBool()) - return; - - float overtimeGrace = sv_neo_ctg_round_timelimit.GetFloat() * 60; - float roundTimeLimit = sv_neo_ctg_ghost_overtime_grace.GetFloat(); - - if (NeoRoundStatus::RoundLive == m_nRoundStatus && m_iGhosterPlayer && - (m_flNeoRoundStartTime + roundTimeLimit - overtimeGrace) < gpGlobals->curtime) - { - m_nRoundStatus = NeoRoundStatus::Overtime; - } - - if (m_nRoundStatus == NeoRoundStatus::Overtime && m_iGhosterPlayer) - { - m_flGhostLastHeld = gpGlobals->curtime; - } -} - float CNEORulesCTG::GetRoundRemainingTime() const { if (NeoRoundStatus::Overtime == m_nRoundStatus) @@ -120,6 +100,26 @@ const int CNEORulesCTG::GetRoundLimit() const return sv_neo_ctg_round_limit.GetInt(); } +void CNEORulesCTG::CheckOvertime() +{ + if (!sv_neo_ctg_ghost_overtime_enabled.GetBool()) + return; + + float overtimeGrace = sv_neo_ctg_round_timelimit.GetFloat() * 60; + float roundTimeLimit = sv_neo_ctg_ghost_overtime_grace.GetFloat(); + + if (NeoRoundStatus::RoundLive == m_nRoundStatus && m_iGhosterPlayer && + (m_flNeoRoundStartTime + roundTimeLimit - overtimeGrace) < gpGlobals->curtime) + { + m_nRoundStatus = NeoRoundStatus::Overtime; + } + + if (m_nRoundStatus == NeoRoundStatus::Overtime && m_iGhosterPlayer) + { + m_flGhostLastHeld = gpGlobals->curtime; + } +} + void CNEORulesCTG::RoundTimeout() { SetWinningTeam(TEAM_SPECTATOR, NEO_VICTORY_STALEMATE, false, false, true, false); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_ctg.h b/src/game/shared/neo/gamerules/neo_gamerules_ctg.h index 8e26a4023e..b4591aa398 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_ctg.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_ctg.h @@ -40,12 +40,12 @@ class CNEORulesCTG : public CNEORules, public CGameEventListener virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } virtual bool CanRespawnAnyTime() const override final { return false; } - virtual void CheckOvertime(); virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL virtual void SetGameRelatedVars() override final; virtual const int GetScoreLimit() const override final; virtual const int GetRoundLimit() const override final; + virtual void CheckOvertime(); virtual void RoundTimeout() override final; #endif // GAME_DLL virtual void Think() override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp b/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp index a92a900f7a..eae9f6d8e7 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp @@ -108,6 +108,15 @@ bool CNEORulesDM::FPlayerCanRespawn(CBasePlayer* pPlayer) return true; } +extern ConVar sv_neo_dm_max_class_dur; +bool CNEORulesDM::PlayerCanChangeLoadout(CNEO_Player* pPlayer) +{ + if (!pPlayer->m_bIneligibleForLoadoutPick && pPlayer->GetAliveDuration() < sv_neo_dm_max_class_dur.GetFloat()) + return true; + + return BaseClass::PlayerCanChangeLoadout(pPlayer); +} + void CNEORulesDM::SetGameRelatedVars() { for (int i = 1; i <= gpGlobals->maxClients; ++i) diff --git a/src/game/shared/neo/gamerules/neo_gamerules_dm.h b/src/game/shared/neo/gamerules/neo_gamerules_dm.h index d77ca06f2d..775916027d 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_dm.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_dm.h @@ -43,6 +43,7 @@ class CNEORulesDM : public CNEORules, public CGameEventListener virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) override final; + virtual bool PlayerCanChangeLoadout(CNEO_Player* pPlayer) override final; virtual void SetGameRelatedVars() override final; virtual const int GetScoreLimit() const override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_emt.h b/src/game/shared/neo/gamerules/neo_gamerules_emt.h index c814145e02..90a70fb82b 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_emt.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_emt.h @@ -33,6 +33,7 @@ class CNEORulesEMT : public CNEORules, public CGameEventListener virtual int GetGameType() override final { return NEO_GAME_TYPE_EMT; } virtual const char* GetGameTypeName() override { return "EMT"; } + const char* GetGameDescription() override { return "Empty Gamemode"; } virtual float GetRoundRemainingTime() const override final; virtual bool GetTeamPlayEnabled() const override { return true; } virtual bool GetCompEnabled() const override final { return false; } diff --git a/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp b/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp index 7e412a2f14..156f204fab 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp @@ -120,6 +120,15 @@ bool CNEORulesJGR::FPlayerCanRespawn(CBasePlayer* pPlayer) return true; } +extern ConVar sv_neo_dm_max_class_dur; +bool CNEORulesJGR::PlayerCanChangeLoadout(CNEO_Player* pPlayer) +{ + if (!pPlayer->m_bIneligibleForLoadoutPick && pPlayer->GetAliveDuration() < sv_neo_dm_max_class_dur.GetFloat()) + return true; + + return BaseClass::PlayerCanChangeLoadout(pPlayer); +} + void CNEORulesJGR::EnemyPlayerKilled(CNEO_Player* pVictim, CNEO_Player* pAttacker, const CTakeDamageInfo& info) { if (!IsRoundLive()) @@ -128,7 +137,7 @@ void CNEORulesJGR::EnemyPlayerKilled(CNEO_Player* pVictim, CNEO_Player* pAttacke if (pAttacker->GetClass() == NEO_CLASS_JUGGERNAUT) { auto jgrTeam = pAttacker->GetTeam(); - jgrTeam->SetScore(jgrTeam->GetScore()); + jgrTeam->SetScore(Min(jgrTeam->GetScore() + 2, sv_neo_jgr_max_points.GetInt())); } else if (m_pJuggernautPlayer) { @@ -144,6 +153,7 @@ void CNEORulesJGR::EnemyPlayerKilled(CNEO_Player* pVictim, CNEO_Player* pAttacke void CNEORulesJGR::SetGameRelatedVars() { + ResetTeamScores(); ResetJGR(); SpawnTheJuggernaut(); } @@ -220,8 +230,6 @@ void CNEORulesJGR::Think() GameOverThink(); - CheckOvertime(); - if (CHL2MPRulesThink()) return; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_jgr.h b/src/game/shared/neo/gamerules/neo_gamerules_jgr.h index 614b283357..0162e8841c 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_jgr.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_jgr.h @@ -43,6 +43,7 @@ class CNEORulesJGR : public CNEORules, public CGameEventListener virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) override final; + virtual bool PlayerCanChangeLoadout(CNEO_Player* pPlayer) override final; virtual void EnemyPlayerKilled(CNEO_Player* pVictim, CNEO_Player* pAttacker, const CTakeDamageInfo& info) override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp b/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp index 006541aad7..79e50c8c5c 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp @@ -102,6 +102,15 @@ bool CNEORulesTDM::FPlayerCanRespawn(CBasePlayer* pPlayer) return true; } +extern ConVar sv_neo_dm_max_class_dur; +bool CNEORulesTDM::PlayerCanChangeLoadout(CNEO_Player* pPlayer) +{ + if (!pPlayer->m_bIneligibleForLoadoutPick && pPlayer->GetAliveDuration() < sv_neo_dm_max_class_dur.GetFloat()) + return true; + + return BaseClass::PlayerCanChangeLoadout(pPlayer); +} + void CNEORulesTDM::SetGameRelatedVars() { ResetTeamScores(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tdm.h b/src/game/shared/neo/gamerules/neo_gamerules_tdm.h index 7cb55a4283..a7c194029e 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tdm.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_tdm.h @@ -39,6 +39,7 @@ class CNEORulesTDM : public CNEORules, public CGameEventListener virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) override final; + virtual bool PlayerCanChangeLoadout(CNEO_Player* pPlayer) override final; virtual void SetGameRelatedVars() override final; virtual const int GetScoreLimit() const override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_vip.h b/src/game/shared/neo/gamerules/neo_gamerules_vip.h index 578011f836..88b8bdcc41 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_vip.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_vip.h @@ -33,6 +33,7 @@ class CNEORulesVIP : public CNEORules, public CGameEventListener virtual int GetGameType() override final { return NEO_GAME_TYPE_VIP; } virtual const char* GetGameTypeName() override { return "VIP"; } + const char* GetGameDescription() override { return "Protect or Eliminate the VIP"; } virtual float GetRoundRemainingTime() const override final; virtual bool GetTeamPlayEnabled() const override { return true; } virtual bool GetCompEnabled() const override final { return true; } From 65f32d97a3e3b138b752dbc31be5cf00ebcdf984 Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Mon, 8 Jun 2026 12:11:53 +0100 Subject: [PATCH 14/16] fix atk --- .../client/neo/ui/neo_hud_round_state.cpp | 17 +++- .../shared/neo/gamerules/neo_gamerules.cpp | 96 +++++++++++++++++++ src/game/shared/neo/gamerules/neo_gamerules.h | 7 +- .../neo/gamerules/neo_gamerules_atk.cpp | 3 + .../neo/gamerules/neo_gamerules_ctg.cpp | 73 +------------- 5 files changed, 121 insertions(+), 75 deletions(-) diff --git a/src/game/client/neo/ui/neo_hud_round_state.cpp b/src/game/client/neo/ui/neo_hud_round_state.cpp index ab66f4f6b9..9609db4f0f 100644 --- a/src/game/client/neo/ui/neo_hud_round_state.cpp +++ b/src/game/client/neo/ui/neo_hud_round_state.cpp @@ -259,6 +259,7 @@ void CNEOHud_RoundState::UpdateStateForNeoHudElementDraw() const bool inDoOrDie = NEORules()->RoundIsDoOrDie(); const bool inMatchPoint = !inDoOrDie && NEORules()->RoundIsMatchPoint(); // we don't care about matchpoint if in do or die + // NEO TODO (Adam) move this to neogamerules? m_pWszStatusUnicode = L""; if (roundStatus == NeoRoundStatus::Idle) { @@ -310,7 +311,7 @@ void CNEOHud_RoundState::UpdateStateForNeoHudElementDraw() m_pWszStatusUnicode = L"Escort the VIP\n"; } } - else + else // NEO TODO (Adam) check if opposite team to escorting team, else different message for spectators { if (NEORules()->GhostExists()) { @@ -325,6 +326,20 @@ void CNEOHud_RoundState::UpdateStateForNeoHudElementDraw() case NEO_GAME_TYPE_JGR: m_pWszStatusUnicode = L"Control the Juggernaut\n"; break; + case NEO_GAME_TYPE_ATK: + if (GetLocalPlayerTeam() == NEORules()->GetAttackingTeam()) + { + m_pWszStatusUnicode = L"Capture the Ghost\n"; + } + else if (GetLocalPlayerTeam() == NEORules()->GetDefendingTeam()) + { + m_pWszStatusUnicode = L"Protect the Ghost\n"; + } + else + { + m_pWszStatusUnicode = L"Capture/Protect the Ghost\n"; + } + break; default: m_pWszStatusUnicode = L"Await further orders\n"; break; diff --git a/src/game/shared/neo/gamerules/neo_gamerules.cpp b/src/game/shared/neo/gamerules/neo_gamerules.cpp index a7490bddfc..6090bc4fb9 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules.cpp @@ -533,6 +533,26 @@ CNEORules::CNEORules() m_ghostSpawns.EnsureCapacity(10); m_jgrSpawns.EnsureCapacity(10); + CBaseEntity* ghostSpawn = nullptr; + do + { + ghostSpawn = gEntList.FindEntityByClassname(ghostSpawn, "neo_ghostspawnpoint"); + if (ghostSpawn) + { + m_ghostSpawns.AddToTail(static_cast(ghostSpawn)); + } + } while (ghostSpawn); + + CBaseEntity* jgrSpawn = nullptr; + do + { + jgrSpawn = gEntList.FindEntityByClassname(jgrSpawn, "neo_juggernautspawnpoint"); + if (jgrSpawn) + { + m_jgrSpawns.AddToTail(static_cast(jgrSpawn)); + } + } while (jgrSpawn); + Q_strncpy(g_Teams[TEAM_JINRAI]->m_szTeamname.GetForModify(), TEAM_STR_JINRAI, MAX_TEAM_NAME_LENGTH); @@ -3272,6 +3292,82 @@ void CNEORules::CheckIfCapPrevent(CNEO_Player *capPreventerPlayer) m_bTeamBeenAwardedDueToCapPrevent = (bOtherTeamPlayingGhost && iTallyAlive[iPreventerTeam] == 0 && iTallyAlive[iOppositeTeam] > 0); } + +bool CNEORules::GhostTeamUpdateWinCondition() +{ + if (!m_pGhost) + return false; + + // Update ghosting team info + int nextGhosterTeam = TEAM_UNASSIGNED; + int nextGhosterPlayerIdx = 0; + CNEO_Player *pGhosterPlayer = static_cast(m_pGhost->GetOwner()); + if (pGhosterPlayer) + { + nextGhosterTeam = pGhosterPlayer->GetTeamNumber(); + nextGhosterPlayerIdx = pGhosterPlayer->entindex(); + Assert(nextGhosterTeam == TEAM_JINRAI || nextGhosterTeam == TEAM_NSF); + m_pGhost->UpdateNearestGhostBeaconDist(); + } + m_iGhosterTeam = nextGhosterTeam; + m_iGhosterPlayer = nextGhosterPlayerIdx; + + Assert(UTIL_IsValidEntity(m_pGhost)); + + if (m_pGhost->GetAbsOrigin().IsValid()) + { + // Someone's carrying it + m_vecGhostMarkerPos = (nextGhosterTeam == TEAM_JINRAI || nextGhosterTeam == TEAM_NSF) ? GetGhostMarkerPos() + : m_pGhost->GetAbsOrigin(); + } + else + { + Assert(false); + } + + // Check if the ghost was capped during this Think + int captorTeam, captorClient; + for (int i = 0; i < m_pGhostCaps.Count(); i++) + { + auto pGhostCap = dynamic_cast(UTIL_EntityByIndex(m_pGhostCaps[i])); + if (!pGhostCap) + { + Assert(false); + continue; + } + + // If a ghost was captured + if (pGhostCap->IsGhostCaptured(captorTeam, captorClient)) + { + // Turn off all capzones + for (int i = 0; i < m_pGhostCaps.Count(); i++) + { + auto pGhostCap = dynamic_cast(UTIL_EntityByIndex(m_pGhostCaps[i])); + if (!pGhostCap) + { + Assert(false); + continue; + } + pGhostCap->SetActive(false); + } + + IGameEvent* event = gameeventmanager->CreateEvent("ghost_capture"); + if (event) + { + CBasePlayer* pCaptorClient = UTIL_PlayerByIndex(captorClient); + event->SetInt("userid", pCaptorClient ? pCaptorClient->GetUserID() : INVALID_USER_ID); + gameeventmanager->FireEvent(event); + } + + // And then announce team victory + SetWinningTeam(captorTeam, NEO_VICTORY_GHOST_CAPTURE, false, true, false, false); + + return true; + } + } + + return false; +} #endif void CNEORules::PlayerKilled(CBasePlayer *pVictim, const CTakeDamageInfo &info) diff --git a/src/game/shared/neo/gamerules/neo_gamerules.h b/src/game/shared/neo/gamerules/neo_gamerules.h index 25c25e6504..f95184263c 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules.h +++ b/src/game/shared/neo/gamerules/neo_gamerules.h @@ -404,6 +404,7 @@ friend class CNEOGameConfig; // this only exists because we can't add a BEGIN_DA #ifdef GAME_DLL private: friend class CNEOBotSeekAndDestroy; + friend class CMultiplayRules; float m_flPrevThinkKick = 0.0f; float m_flPrevThinkMirrorDmg = 0.0f; @@ -411,9 +412,6 @@ friend class CNEOGameConfig; // this only exists because we can't add a BEGIN_DA int m_arrayiEntPrevCap[MAX_PLAYERS + 1]; // This is to check for cap-prevention workaround attempts int m_iEntPrevCapSize = 0; bool m_bServerIsCurrentlyAutoRecording = false; - friend class CMultiplayRules; - CUtlVector> m_jgrSpawns; - Vector m_vecPreviousJuggernautSpawn = vec3_origin; bool m_bGotMatchWinner = false; int m_iMatchWinner = TEAM_UNASSIGNED; #endif @@ -473,6 +471,7 @@ friend class CNEOGameConfig; // this only exists because we can't add a BEGIN_DA void SpawnTheGhost(const Vector *origin = nullptr); void ResetGhostCapPoints(); void CheckIfCapPrevent(CNEO_Player *capPreventerPlayer); + bool GhostTeamUpdateWinCondition(); #endif // GAME_DLL public: void ResetGhost(); @@ -494,6 +493,8 @@ friend class CNEOGameConfig; // this only exists because we can't add a BEGIN_DA CNetworkHandle( CBaseEntity, m_hJuggernaut ); #ifdef GAME_DLL + CUtlVector> m_jgrSpawns; + Vector m_vecPreviousJuggernautSpawn = vec3_origin; CNEO_Juggernaut *m_pJuggernautItem = nullptr; CNEO_Player *m_pJuggernautPlayer = nullptr; float m_flJuggernautDeathTime = 0.0f; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp index 10bda870b0..2a9a55f1ab 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp @@ -150,6 +150,9 @@ void CNEORulesATK::Think() return; RoundStatusThink(); + + if (GhostTeamUpdateWinCondition()) + return; CheckWinByElimination(); #endif // GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp index bd40c7b9c0..0904e64763 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp @@ -157,77 +157,8 @@ void CNEORulesCTG::Think() RoundStatusThink(); - if (m_pGhost) - { - // Update ghosting team info - int nextGhosterTeam = TEAM_UNASSIGNED; - int nextGhosterPlayerIdx = 0; - CNEO_Player *pGhosterPlayer = static_cast(m_pGhost->GetOwner()); - if (pGhosterPlayer) - { - nextGhosterTeam = pGhosterPlayer->GetTeamNumber(); - nextGhosterPlayerIdx = pGhosterPlayer->entindex(); - Assert(nextGhosterTeam == TEAM_JINRAI || nextGhosterTeam == TEAM_NSF); - m_pGhost->UpdateNearestGhostBeaconDist(); - } - m_iGhosterTeam = nextGhosterTeam; - m_iGhosterPlayer = nextGhosterPlayerIdx; - - Assert(UTIL_IsValidEntity(m_pGhost)); - - if (m_pGhost->GetAbsOrigin().IsValid()) - { - // Someone's carrying it - // NEO NOTE (Adam) GetGhostMarkerPos() can return m_vecGhostMarkerPos if m_pGhost is invalid, but we've checked for m_pGhost above so should be fine? - m_vecGhostMarkerPos = (nextGhosterTeam == TEAM_JINRAI || nextGhosterTeam == TEAM_NSF) ? GetGhostMarkerPos() - : m_pGhost->GetAbsOrigin(); - } - else - { - Assert(false); - } - - // Check if the ghost was capped during this Think - int captorTeam, captorClient; - for (int i = 0; i < m_pGhostCaps.Count(); i++) - { - auto pGhostCap = dynamic_cast(UTIL_EntityByIndex(m_pGhostCaps[i])); - if (!pGhostCap) - { - Assert(false); - continue; - } - - // If a ghost was captured - if (pGhostCap->IsGhostCaptured(captorTeam, captorClient)) - { - // Turn off all capzones - for (int i = 0; i < m_pGhostCaps.Count(); i++) - { - auto pGhostCap = dynamic_cast(UTIL_EntityByIndex(m_pGhostCaps[i])); - if (!pGhostCap) - { - Assert(false); - continue; - } - pGhostCap->SetActive(false); - } - - IGameEvent* event = gameeventmanager->CreateEvent("ghost_capture"); - if (event) - { - CBasePlayer* pCaptorClient = UTIL_PlayerByIndex(captorClient); - event->SetInt("userid", pCaptorClient ? pCaptorClient->GetUserID() : INVALID_USER_ID); - gameeventmanager->FireEvent(event); - } - - // And then announce team victory - SetWinningTeam(captorTeam, NEO_VICTORY_GHOST_CAPTURE, false, true, false, false); - - break; - } - } - } + if (GhostTeamUpdateWinCondition()) + return; CheckWinByElimination(); #endif // GAME_DLL From fedd228e5000141748725b2ecc361959350766e8 Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Tue, 9 Jun 2026 09:57:19 +0100 Subject: [PATCH 15/16] cleanup --- src/game/server/neo/neo_player.cpp | 6 +- src/game/server/neo/neo_spawn_manager.cpp | 2 +- .../shared/neo/gamerules/neo_gamerules.cpp | 2 +- src/game/shared/neo/gamerules/neo_gamerules.h | 11 +- .../neo/gamerules/neo_gamerules_atk.cpp | 10 +- .../shared/neo/gamerules/neo_gamerules_atk.h | 9 +- .../neo/gamerules/neo_gamerules_ctg.cpp | 10 +- .../shared/neo/gamerules/neo_gamerules_ctg.h | 9 +- .../shared/neo/gamerules/neo_gamerules_dm.cpp | 8 -- .../shared/neo/gamerules/neo_gamerules_dm.h | 9 +- .../neo/gamerules/neo_gamerules_emt.cpp | 8 -- .../shared/neo/gamerules/neo_gamerules_emt.h | 9 +- .../neo/gamerules/neo_gamerules_jgr.cpp | 126 +++++++++--------- .../shared/neo/gamerules/neo_gamerules_jgr.h | 10 +- .../neo/gamerules/neo_gamerules_tdm.cpp | 9 -- .../shared/neo/gamerules/neo_gamerules_tdm.h | 5 +- .../neo/gamerules/neo_gamerules_tut.cpp | 8 -- .../shared/neo/gamerules/neo_gamerules_tut.h | 9 +- .../neo/gamerules/neo_gamerules_vip.cpp | 8 -- .../shared/neo/gamerules/neo_gamerules_vip.h | 10 +- .../weapons/weapon_neobasecombatweapon.cpp | 2 +- 21 files changed, 88 insertions(+), 192 deletions(-) diff --git a/src/game/server/neo/neo_player.cpp b/src/game/server/neo/neo_player.cpp index 3177e268de..616868e98e 100644 --- a/src/game/server/neo/neo_player.cpp +++ b/src/game/server/neo/neo_player.cpp @@ -2535,7 +2535,7 @@ void CNEO_Player::SpawnSpecificGibs(float vMinVelocity, float vMaxVelocity, cons { CGib* pGib = CREATE_ENTITY(CGib, "gib"); - if (NEORules()->CanRespawnAnyTime()) + if (NEORules()->RespawnsEnabled()) { constexpr float GIB_LIFETIME = 30.f; pGib->Spawn(cModelName, GIB_LIFETIME); @@ -3088,10 +3088,10 @@ bool CNEO_Player::ProcessTeamSwitchRequest(int iTeam) changedTeams = true; // Spawn the player immediately if its a single life game mode - spawnImmediately = !NEORules()->CanRespawnAnyTime() && NEORules()->FPlayerCanRespawn(this); + spawnImmediately = !NEORules()->RespawnsEnabled() && NEORules()->FPlayerCanRespawn(this); if (!spawnImmediately) { - if (NEORules()->CanRespawnAnyTime() || IsFakeClient()) + if (NEORules()->RespawnsEnabled() || IsFakeClient()) { // Stop observer mode so we spawn in anyway after a short delay, bots crash when transitioning to observer mode StopObserverMode(); } diff --git a/src/game/server/neo/neo_spawn_manager.cpp b/src/game/server/neo/neo_spawn_manager.cpp index 6c1a92ea48..ba751756ad 100644 --- a/src/game/server/neo/neo_spawn_manager.cpp +++ b/src/game/server/neo/neo_spawn_manager.cpp @@ -122,7 +122,7 @@ namespace NeoSpawnManager return backup; } - if (!rules->CanRespawnAnyTime()) + if (!rules->RespawnsEnabled()) { // We only care if it's been used before or not if there are no respawns manager.m_spawns[idx].isUsed = true; diff --git a/src/game/shared/neo/gamerules/neo_gamerules.cpp b/src/game/shared/neo/gamerules/neo_gamerules.cpp index 6090bc4fb9..1579ff8dc3 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules.cpp @@ -3293,7 +3293,7 @@ void CNEORules::CheckIfCapPrevent(CNEO_Player *capPreventerPlayer) iTallyAlive[iPreventerTeam] == 0 && iTallyAlive[iOppositeTeam] > 0); } -bool CNEORules::GhostTeamUpdateWinCondition() +bool CNEORules::GhostTeamUpdateCheckWinCondition() { if (!m_pGhost) return false; diff --git a/src/game/shared/neo/gamerules/neo_gamerules.h b/src/game/shared/neo/gamerules/neo_gamerules.h index f95184263c..cfb81e05ec 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules.h +++ b/src/game/shared/neo/gamerules/neo_gamerules.h @@ -273,7 +273,7 @@ friend class CNEOGameConfig; // this only exists because we can't add a BEGIN_DA virtual bool GetCompEnabled() const { return false; } virtual bool GetCapPreventEnabled() const { return false; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const { return false; } - virtual bool CanRespawnAnyTime() const { return false; } + virtual bool RespawnsEnabled() const { return false; } inline int GetHiddenHudElements() const { return m_iHiddenHudElements; } inline int GetForcedTeam() const { return m_iForcedTeam; } inline int GetForcedClass() const { return m_iForcedClass; } @@ -471,7 +471,7 @@ friend class CNEOGameConfig; // this only exists because we can't add a BEGIN_DA void SpawnTheGhost(const Vector *origin = nullptr); void ResetGhostCapPoints(); void CheckIfCapPrevent(CNEO_Player *capPreventerPlayer); - bool GhostTeamUpdateWinCondition(); + bool GhostTeamUpdateCheckWinCondition(); #endif // GAME_DLL public: void ResetGhost(); @@ -528,6 +528,13 @@ friend class CNEOGameConfig; // this only exists because we can't add a BEGIN_DA #endif // GAME_DLL public: inline int GetEscortingTeam() const { return m_iEscortingTeam; } + + ///////////////////// + // KOTH game logic // + ///////////////////// + +private: + }; inline CNEORules *NEORules() diff --git a/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp index 2a9a55f1ab..16e8c367e7 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_atk.cpp @@ -52,14 +52,6 @@ ConVar sv_neo_atk_ghost_overtime("sv_neo_atk_ghost_overtime", "45", FCVAR_REPLIC ConVar sv_neo_atk_ghost_overtime_grace("sv_neo_atk_ghost_overtime_grace", "10", FCVAR_REPLICATED, "Number of seconds left in the round when the ghost is dropped in overtime.", true, 0, true, 30); ConVar sv_neo_atk_ghost_overtime_grace_decay("sv_neo_atk_ghost_overtime_grace_decay", "0", FCVAR_REPLICATED, "Slowly reduce the grace time as overtime goes on.", true, 0, true, 1); -//CNEORulesATK::CNEORulesATK() -//{ -//} -// -//CNEORulesATK::~CNEORulesATK() -//{ -//} - void CNEORulesATK::FireGameEvent(IGameEvent* event) { BaseClass::FireGameEvent(event); @@ -151,7 +143,7 @@ void CNEORulesATK::Think() RoundStatusThink(); - if (GhostTeamUpdateWinCondition()) + if (GhostTeamUpdateCheckWinCondition()) return; CheckWinByElimination(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_atk.h b/src/game/shared/neo/gamerules/neo_gamerules_atk.h index a24b965ac0..51b2b66f99 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_atk.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_atk.h @@ -7,10 +7,6 @@ #define CNEORulesATK C_NEORulesATK #define CNEOGameRulesATKProxy C_NEOGameRulesATKProxy #endif -// -//ConVar sv_neo_atk_score_limit("sv_neo_atk_score_limit", "1", FCVAR_REPLICATED, "ATK score limit", true, 0.0f, true, 99.0f); -//ConVar sv_neo_atk_round_limit("sv_neo_atk_round_limit", "0", FCVAR_REPLICATED, "ATK max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); -//ConVar sv_neo_atk_round_timelimit("neo_atk_round_timelimit", "10.25", FCVAR_REPLICATED, "ATK round timelimit, in minutes.", true, 0.0f, false, 600.0f); class CNEOGameRulesATKProxy : public CNEOGameRulesProxy { @@ -25,9 +21,6 @@ class CNEORulesATK : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesATK, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - //CNEORulesATK(); - //virtual ~CNEORulesATK(); - // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; @@ -38,7 +31,7 @@ class CNEORulesATK : public CNEORules, public CGameEventListener virtual bool GetCompEnabled() const override final { return true; } virtual bool GetCapPreventEnabled() const override final { return false; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } - virtual bool CanRespawnAnyTime() const override final { return false; } + virtual bool RespawnsEnabled() const override final { return false; } virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp index 0904e64763..b6b4e4de32 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_ctg.cpp @@ -58,14 +58,6 @@ ConVar sv_neo_ctg_ghost_overtime("sv_neo_ctg_ghost_overtime", "45", FCVAR_REPLIC ConVar sv_neo_ctg_ghost_overtime_grace("sv_neo_ctg_ghost_overtime_grace", "10", FCVAR_REPLICATED, "Number of seconds left in the round when the ghost is dropped in overtime.", true, 0, true, 30); ConVar sv_neo_ctg_ghost_overtime_grace_decay("sv_neo_ctg_ghost_overtime_grace_decay", "0", FCVAR_REPLICATED, "Slowly reduce the grace time as overtime goes on.", true, 0, true, 1); -//CNEORulesCTG::CNEORulesCTG() -//{ -//} -// -//CNEORulesCTG::~CNEORulesCTG() -//{ -//} - void CNEORulesCTG::FireGameEvent(IGameEvent* event) { BaseClass::FireGameEvent(event); @@ -157,7 +149,7 @@ void CNEORulesCTG::Think() RoundStatusThink(); - if (GhostTeamUpdateWinCondition()) + if (GhostTeamUpdateCheckWinCondition()) return; CheckWinByElimination(); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_ctg.h b/src/game/shared/neo/gamerules/neo_gamerules_ctg.h index b4591aa398..310bf8cac1 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_ctg.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_ctg.h @@ -7,10 +7,6 @@ #define CNEORulesCTG C_NEORulesCTG #define CNEOGameRulesCTGProxy C_NEOGameRulesCTGProxy #endif -// -//ConVar sv_neo_ctg_score_limit("sv_neo_ctg_score_limit", "1", FCVAR_REPLICATED, "CTG score limit", true, 0.0f, true, 99.0f); -//ConVar sv_neo_ctg_round_limit("sv_neo_ctg_round_limit", "0", FCVAR_REPLICATED, "CTG max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); -//ConVar sv_neo_ctg_round_timelimit("neo_ctg_round_timelimit", "10.25", FCVAR_REPLICATED, "CTG round timelimit, in minutes.", true, 0.0f, false, 600.0f); class CNEOGameRulesCTGProxy : public CNEOGameRulesProxy { @@ -25,9 +21,6 @@ class CNEORulesCTG : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesCTG, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - //CNEORulesCTG(); - //virtual ~CNEORulesCTG(); - // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; @@ -38,7 +31,7 @@ class CNEORulesCTG : public CNEORules, public CGameEventListener virtual bool GetCompEnabled() const override final { return true; } virtual bool GetCapPreventEnabled() const override final { return true; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } - virtual bool CanRespawnAnyTime() const override final { return false; } + virtual bool RespawnsEnabled() const override final { return false; } virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp b/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp index eae9f6d8e7..5d0b3b13bc 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_dm.cpp @@ -56,14 +56,6 @@ ConVar sv_neo_dm_win_xp("sv_neo_dm_win_xp", "50", FCVAR_REPLICATED, "The XP limi extern bool RespawnWithRet(CBaseEntity *pEdict, bool fCopyCorpse); -//CNEORulesDM::CNEORulesDM() -//{ -//} -// -//CNEORulesDM::~CNEORulesDM() -//{ -//} - void CNEORulesDM::FireGameEvent(IGameEvent* event) { BaseClass::FireGameEvent(event); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_dm.h b/src/game/shared/neo/gamerules/neo_gamerules_dm.h index 775916027d..fa9f7f9796 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_dm.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_dm.h @@ -7,10 +7,6 @@ #define CNEORulesDM C_NEORulesDM #define CNEOGameRulesDMProxy C_NEOGameRulesDMProxy #endif -// -//ConVar sv_neo_dm_score_limit("sv_neo_dm_score_limit", "1", FCVAR_REPLICATED, "DM score limit", true, 0.0f, true, 99.0f); -//ConVar sv_neo_dm_round_limit("sv_neo_dm_round_limit", "0", FCVAR_REPLICATED, "DM max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); -//ConVar sv_neo_dm_round_timelimit("neo_dm_round_timelimit", "10.25", FCVAR_REPLICATED, "DM round timelimit, in minutes.", true, 0.0f, false, 600.0f); class CNEOGameRulesDMProxy : public CNEOGameRulesProxy { @@ -25,9 +21,6 @@ class CNEORulesDM : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesDM, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - //CNEORulesDM(); - //virtual ~CNEORulesDM(); - // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; @@ -38,7 +31,7 @@ class CNEORulesDM : public CNEORules, public CGameEventListener virtual bool GetCompEnabled() const override final { return false; } virtual bool GetCapPreventEnabled() const override final { return false; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } - virtual bool CanRespawnAnyTime() const override final { return true; } + virtual bool RespawnsEnabled() const override final { return true; } virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp b/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp index b28775fcf6..ce8db14284 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_emt.cpp @@ -43,14 +43,6 @@ IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesEMTProxy, DT_NEOGameRulesEMTProxy ); END_SEND_TABLE() #endif -//CNEORulesEMT::CNEORulesEMT() -//{ -//} -// -//CNEORulesEMT::~CNEORulesEMT() -//{ -//} - void CNEORulesEMT::FireGameEvent(IGameEvent* event) { BaseClass::FireGameEvent(event); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_emt.h b/src/game/shared/neo/gamerules/neo_gamerules_emt.h index 90a70fb82b..f95137ef89 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_emt.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_emt.h @@ -7,10 +7,6 @@ #define CNEORulesEMT C_NEORulesEMT #define CNEOGameRulesEMTProxy C_NEOGameRulesEMTProxy #endif -// -//ConVar sv_neo_emt_score_limit("sv_neo_emt_score_limit", "1", FCVAR_REPLICATED, "EMT score limit", true, 0.0f, true, 99.0f); -//ConVar sv_neo_emt_round_limit("sv_neo_emt_round_limit", "0", FCVAR_REPLICATED, "EMT max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); -//ConVar sv_neo_emt_round_timelimit("neo_emt_round_timelimit", "10.25", FCVAR_REPLICATED, "EMT round timelimit, in minutes.", true, 0.0f, false, 600.0f); class CNEOGameRulesEMTProxy : public CNEOGameRulesProxy { @@ -25,9 +21,6 @@ class CNEORulesEMT : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesEMT, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - //CNEORulesEMT(); - //virtual ~CNEORulesEMT(); - // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; @@ -39,7 +32,7 @@ class CNEORulesEMT : public CNEORules, public CGameEventListener virtual bool GetCompEnabled() const override final { return false; } virtual bool GetCapPreventEnabled() const override final { return false; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return true; } - virtual bool CanRespawnAnyTime() const override final { return true; } + virtual bool RespawnsEnabled() const override final { return true; } #ifdef GAME_DLL virtual bool FPlayerCanRespawn(CBasePlayer* pPlayer) override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp b/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp index 156f204fab..9aca87f60e 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_jgr.cpp @@ -50,45 +50,11 @@ ConVar sv_neo_jgr_max_points("sv_neo_jgr_max_points", "20", FCVAR_GAMEDLL, "Maxi extern bool RespawnWithRet(CBaseEntity *pEdict, bool fCopyCorpse); -//CNEORulesJGR::CNEORulesJGR() -//{ -// -//} -// -//CNEORulesJGR::~CNEORulesJGR() -//{ -//} - void CNEORulesJGR::FireGameEvent(IGameEvent* event) { BaseClass::FireGameEvent(event); } -#ifdef GAME_DLL -void CNEORulesJGR::PlayerRespawnThink() -{ - for (int i = 1; i <= gpGlobals->maxClients; i++) - { - auto player = static_cast(UTIL_PlayerByIndex(i)); - if (player && player->IsDead() && (IsRoundPaused() || player->DeathCount() > 0)) - { - const int playerTeam = player->GetTeamNumber(); - if ((playerTeam == TEAM_JINRAI || playerTeam == TEAM_NSF) && RespawnWithRet(player, false)) - { - player->m_bInAim = false; - player->m_bCarryingGhost = false; - player->m_bInThermOpticCamo = false; - player->m_bInVision = false; - player->m_bIneligibleForLoadoutPick = false; - player->SetTestMessageVisible(false); - - engine->ClientCommand(player->edict(), "loadoutmenu"); - } - } - } -} -#endif // GAME_DLL - float CNEORulesJGR::GetRoundRemainingTime() const { return BaseClass::GetRoundRemainingTime(sv_neo_jgr_round_timelimit.GetFloat()); @@ -240,44 +206,76 @@ void CNEORulesJGR::Think() RoundStatusThink(); - if (IsRoundLive()) + JuggernautUnlockCheckWinCondition(); + +#endif // GAME_DLL +} + +#ifdef GAME_DLL +void CNEORulesJGR::PlayerRespawnThink() +{ + for (int i = 1; i <= gpGlobals->maxClients; i++) { - // Unlock the Juggernaut - if (m_pJuggernautItem && (gpGlobals->curtime > (m_flNeoRoundStartTime + sv_neo_preround_freeze_time.GetFloat()) + 20.0f) && IsJuggernautLocked()) + auto player = static_cast(UTIL_PlayerByIndex(i)); + if (player && player->IsDead() && (IsRoundPaused() || player->DeathCount() > 0)) { - UTIL_CenterPrintAll("- JUGGERNAUT ENABLED -\n"); + const int playerTeam = player->GetTeamNumber(); + if ((playerTeam == TEAM_JINRAI || playerTeam == TEAM_NSF) && RespawnWithRet(player, false)) + { + player->m_bInAim = false; + player->m_bCarryingGhost = false; + player->m_bInThermOpticCamo = false; + player->m_bInVision = false; + player->m_bIneligibleForLoadoutPick = false; + player->SetTestMessageVisible(false); - EmitSound_t soundParams; - soundParams.m_pSoundName = "HUD.GhostPickUp"; - soundParams.m_nChannel = CHAN_USER_BASE; - soundParams.m_bWarnOnDirectWaveReference = false; - soundParams.m_bEmitCloseCaption = false; - soundParams.m_SoundLevel = ATTN_TO_SNDLVL(ATTN_NONE); + engine->ClientCommand(player->edict(), "loadoutmenu"); + } + } + } +} - CRecipientFilter soundFilter; - soundFilter.AddAllPlayers(); - soundFilter.MakeReliable(); - m_pJuggernautItem->EmitSound(soundFilter, m_pJuggernautItem->entindex(), soundParams); +bool CNEORulesJGR::JuggernautUnlockCheckWinCondition() +{ + if (!IsRoundLive()) + return false; - m_pJuggernautItem->m_bLocked = false; - } + // Unlock the Juggernaut + if (m_pJuggernautItem && (gpGlobals->curtime > (m_flNeoRoundStartTime + sv_neo_preround_freeze_time.GetFloat()) + 20.0f) && IsJuggernautLocked()) + { + UTIL_CenterPrintAll("- JUGGERNAUT ENABLED -\n"); + + EmitSound_t soundParams; + soundParams.m_pSoundName = "HUD.GhostPickUp"; + soundParams.m_nChannel = CHAN_USER_BASE; + soundParams.m_bWarnOnDirectWaveReference = false; + soundParams.m_bEmitCloseCaption = false; + soundParams.m_SoundLevel = ATTN_TO_SNDLVL(ATTN_NONE); + + CRecipientFilter soundFilter; + soundFilter.AddAllPlayers(); + soundFilter.MakeReliable(); + m_pJuggernautItem->EmitSound(soundFilter, m_pJuggernautItem->entindex(), soundParams); + + m_pJuggernautItem->m_bLocked = false; + } - // Check win condition + // Check win condition + { + const int maxPoints = sv_neo_jgr_max_points.GetInt(); + if (GetGlobalTeam(TEAM_JINRAI)->GetScore() >= maxPoints) { - const int maxPoints = sv_neo_jgr_max_points.GetInt(); - if (GetGlobalTeam(TEAM_JINRAI)->GetScore() >= maxPoints) - { - SetWinningTeam(TEAM_JINRAI, NEO_VICTORY_POINTS, false, true, false, false); - return; - } + SetWinningTeam(TEAM_JINRAI, NEO_VICTORY_POINTS, false, true, false, false); + return true; + } - if (GetGlobalTeam(TEAM_NSF)->GetScore() >= maxPoints) - { - SetWinningTeam(TEAM_NSF, NEO_VICTORY_POINTS, false, true, false, false); - return; - } + if (GetGlobalTeam(TEAM_NSF)->GetScore() >= maxPoints) + { + SetWinningTeam(TEAM_NSF, NEO_VICTORY_POINTS, false, true, false, false); + return true; } } + return false; +} -#endif // GAME_DLL -} \ No newline at end of file +#endif // GAME_DLL \ No newline at end of file diff --git a/src/game/shared/neo/gamerules/neo_gamerules_jgr.h b/src/game/shared/neo/gamerules/neo_gamerules_jgr.h index 0162e8841c..81a33ca275 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_jgr.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_jgr.h @@ -7,10 +7,6 @@ #define CNEORulesJGR C_NEORulesJGR #define CNEOGameRulesJGRProxy C_NEOGameRulesJGRProxy #endif -// -//ConVar sv_neo_jgr_score_limit("sv_neo_jgr_score_limit", "1", FCVAR_REPLICATED, "JGR score limit", true, 0.0f, true, 99.0f); -//ConVar sv_neo_jgr_round_limit("sv_neo_jgr_round_limit", "0", FCVAR_REPLICATED, "JGR max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); -//ConVar sv_neo_jgr_round_timelimit("neo_jgr_round_timelimit", "10.25", FCVAR_REPLICATED, "JGR round timelimit, in minutes.", true, 0.0f, false, 600.0f); class CNEOGameRulesJGRProxy : public CNEOGameRulesProxy { @@ -25,9 +21,6 @@ class CNEORulesJGR : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesJGR, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - //CNEORulesJGR(); - //virtual ~CNEORulesJGR(); - // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; @@ -38,7 +31,7 @@ class CNEORulesJGR : public CNEORules, public CGameEventListener virtual bool GetCompEnabled() const override final { return true; } virtual bool GetCapPreventEnabled() const override final { return false; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } - virtual bool CanRespawnAnyTime() const override final { return true; } + virtual bool RespawnsEnabled() const override final { return true; } virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL @@ -55,6 +48,7 @@ class CNEORulesJGR : public CNEORules, public CGameEventListener virtual void Think() override final; #ifdef GAME_DLL virtual void PlayerRespawnThink() override final; + bool JuggernautUnlockCheckWinCondition(); #endif // GAME_DLL }; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp b/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp index 79e50c8c5c..1175869456 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_tdm.cpp @@ -43,21 +43,12 @@ IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesTDMProxy, DT_NEOGameRulesTDMProxy ); END_SEND_TABLE() #endif - ConVar sv_neo_tdm_score_limit("sv_neo_tdm_score_limit", "1", FCVAR_REPLICATED, "TDM score limit", true, 0.0f, true, 99.0f); ConVar sv_neo_tdm_round_limit("sv_neo_tdm_round_limit", "0", FCVAR_REPLICATED, "TDM max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); ConVar sv_neo_tdm_round_timelimit("sv_neo_tdm_round_timelimit", "10.25", FCVAR_REPLICATED, "TDM round timelimit, in minutes.", true, 0.0f, false, 0.0f); extern bool RespawnWithRet(CBaseEntity *pEdict, bool fCopyCorpse); -//CNEORulesTDM::CNEORulesTDM() -//{ -//} -// -//CNEORulesTDM::~CNEORulesTDM() -//{ -//} - void CNEORulesTDM::FireGameEvent(IGameEvent* event) { BaseClass::FireGameEvent(event); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tdm.h b/src/game/shared/neo/gamerules/neo_gamerules_tdm.h index a7c194029e..1ab1ab6c77 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tdm.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_tdm.h @@ -21,9 +21,6 @@ class CNEORulesTDM : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesTDM, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - //CNEORulesTDM(); - //virtual ~CNEORulesTDM(); - // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; @@ -34,7 +31,7 @@ class CNEORulesTDM : public CNEORules, public CGameEventListener virtual bool GetCompEnabled() const override final { return false; } virtual bool GetCapPreventEnabled() const override final { return false; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } - virtual bool CanRespawnAnyTime() const override final { return true; } + virtual bool RespawnsEnabled() const override final { return true; } virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp b/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp index 97787cb107..e66b35f4d6 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_tut.cpp @@ -43,14 +43,6 @@ IMPLEMENT_NETWORKCLASS_ALIASED( NEOGameRulesTUTProxy, DT_NEOGameRulesTUTProxy ); END_SEND_TABLE() #endif -//CNEORulesTUT::CNEORulesTUT() -//{ -//} -// -//CNEORulesTUT::~CNEORulesTUT() -//{ -//} - void CNEORulesTUT::FireGameEvent(IGameEvent* event) { BaseClass::FireGameEvent(event); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tut.h b/src/game/shared/neo/gamerules/neo_gamerules_tut.h index f0b9595eec..a141e62faa 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tut.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_tut.h @@ -7,10 +7,6 @@ #define CNEORulesTUT C_NEORulesTUT #define CNEOGameRulesTUTProxy C_NEOGameRulesTUTProxy #endif -// -//ConVar sv_neo_tut_score_limit("sv_neo_tut_score_limit", "1", FCVAR_REPLICATED, "TUT score limit", true, 0.0f, true, 99.0f); -//ConVar sv_neo_tut_round_limit("sv_neo_tut_round_limit", "0", FCVAR_REPLICATED, "TUT max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); -//ConVar sv_neo_tut_round_timelimit("neo_tut_round_timelimit", "10.25", FCVAR_REPLICATED, "TUT round timelimit, in minutes.", true, 0.0f, false, 600.0f); class CNEOGameRulesTUTProxy : public CNEOGameRulesProxy { @@ -25,9 +21,6 @@ class CNEORulesTUT : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesTUT, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - //CNEORulesTUT(); - //virtual ~CNEORulesTUT(); - // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; @@ -38,7 +31,7 @@ class CNEORulesTUT : public CNEORules, public CGameEventListener virtual bool GetCompEnabled() const override final { return false; } virtual bool GetCapPreventEnabled() const override final { return false; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } - virtual bool CanRespawnAnyTime() const override final { return true; } + virtual bool RespawnsEnabled() const override final { return true; } virtual float GetRoundRemainingTime() const override final; #ifdef GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp b/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp index 2bb34f3c5d..bf19babca0 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules_vip.cpp @@ -54,14 +54,6 @@ ConVar sv_neo_vip_score_limit("sv_neo_vip_score_limit", "7", FCVAR_REPLICATED, " ConVar sv_neo_vip_ctg_on_death("sv_neo_vip_ctg_on_death", "0", FCVAR_ARCHIVE, "Spawn Ghost when VIP dies, continue the game", true, 0, true, 1); -//CNEORulesVIP::CNEORulesVIP() -//{ -//} -// -//CNEORulesVIP::~CNEORulesVIP() -//{ -//} - void CNEORulesVIP::FireGameEvent(IGameEvent* event) { BaseClass::FireGameEvent(event); diff --git a/src/game/shared/neo/gamerules/neo_gamerules_vip.h b/src/game/shared/neo/gamerules/neo_gamerules_vip.h index 88b8bdcc41..3059fbfd7f 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_vip.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_vip.h @@ -7,10 +7,6 @@ #define CNEORulesVIP C_NEORulesVIP #define CNEOGameRulesVIPProxy C_NEOGameRulesVIPProxy #endif -// -//ConVar sv_neo_vip_score_limit("sv_neo_vip_score_limit", "1", FCVAR_REPLICATED, "VIP score limit", true, 0.0f, true, 99.0f); -//ConVar sv_neo_vip_round_limit("sv_neo_vip_round_limit", "0", FCVAR_REPLICATED, "VIP max amount of rounds, 0 for no limit.", true, 0.0f, false, 0.0f); -//ConVar sv_neo_vip_round_timelimit("neo_vip_round_timelimit", "10.25", FCVAR_REPLICATED, "VIP round timelimit, in minutes.", true, 0.0f, false, 600.0f); class CNEOGameRulesVIPProxy : public CNEOGameRulesProxy { @@ -25,9 +21,6 @@ class CNEORulesVIP : public CNEORules, public CGameEventListener DECLARE_CLASS(CNEORulesVIP, CNEORules); DECLARE_NETWORKCLASS_NOBASE(); - //CNEORulesVIP(); - //virtual ~CNEORulesVIP(); - // IGameEventListener interface: virtual void FireGameEvent(IGameEvent *event) override; @@ -39,13 +32,12 @@ class CNEORulesVIP : public CNEORules, public CGameEventListener virtual bool GetCompEnabled() const override final { return true; } virtual bool GetCapPreventEnabled() const override final { return true; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } - virtual bool CanRespawnAnyTime() const override final { return false; } + virtual bool RespawnsEnabled() const override final { return false; } #ifdef GAME_DLL virtual void SetGameRelatedVars() override final; virtual const int GetScoreLimit() const override final; virtual const int GetRoundLimit() const override final; - //virtual void RoundTimeout() override final; #endif // GAME_DLL virtual void Think() override final; }; diff --git a/src/game/shared/neo/weapons/weapon_neobasecombatweapon.cpp b/src/game/shared/neo/weapons/weapon_neobasecombatweapon.cpp index d9783b1b2c..37ce211b5a 100644 --- a/src/game/shared/neo/weapons/weapon_neobasecombatweapon.cpp +++ b/src/game/shared/neo/weapons/weapon_neobasecombatweapon.cpp @@ -1356,7 +1356,7 @@ void CNEOBaseCombatWeapon::SetPickupTouch(void) return; } - if (!weaponstay.GetBool() || NEORules()->CanRespawnAnyTime()) + if (!weaponstay.GetBool() || NEORules()->RespawnsEnabled()) { // regardless of the value of mp_weaponstay, disappear weapons in game modes with respawns enabled. Otherwise things can get too chaotic BaseClass::SetPickupTouch(); return; From 5b4d521258a45a395bdfb32b30f98236b6c78caf Mon Sep 17 00:00:00 2001 From: AdamTadeusz Date: Tue, 9 Jun 2026 11:53:24 +0100 Subject: [PATCH 16/16] cleanup 2 --- src/game/shared/hl2mp/hl2mp_gamerules.h | 4 ++-- src/game/shared/multiplay_gamerules.cpp | 3 +++ src/game/shared/neo/gamerules/neo_gamerules.cpp | 9 +-------- src/game/shared/neo/gamerules/neo_gamerules_atk.h | 4 ++-- src/game/shared/neo/gamerules/neo_gamerules_ctg.h | 8 ++++---- src/game/shared/neo/gamerules/neo_gamerules_dm.h | 9 ++++----- src/game/shared/neo/gamerules/neo_gamerules_emt.h | 6 +++--- src/game/shared/neo/gamerules/neo_gamerules_jgr.h | 6 +++--- src/game/shared/neo/gamerules/neo_gamerules_tdm.h | 6 +++--- src/game/shared/neo/gamerules/neo_gamerules_tut.h | 6 +++--- src/game/shared/neo/gamerules/neo_gamerules_vip.h | 6 +++--- 11 files changed, 31 insertions(+), 36 deletions(-) diff --git a/src/game/shared/hl2mp/hl2mp_gamerules.h b/src/game/shared/hl2mp/hl2mp_gamerules.h index 308213c38b..f3ce6683c6 100644 --- a/src/game/shared/hl2mp/hl2mp_gamerules.h +++ b/src/game/shared/hl2mp/hl2mp_gamerules.h @@ -181,7 +181,7 @@ class CHL2MPRules : public CTeamplayRules bool IsTeamplay( void ) { #ifdef NEO - return GetTeamPlayEnabled(); // NEO TODO (Adam) Just make this virtual instead + return GetTeamPlayEnabled(); #else return m_bTeamPlayEnabled; #endif @@ -193,7 +193,7 @@ class CHL2MPRules : public CTeamplayRules #ifdef NEO protected: - CNetworkVar(float, m_flGameStartTime); // NEO TODO (Adam) Make a protected getter instead? + CNetworkVar(float, m_flGameStartTime); #else private: CNetworkVar(float, m_flGameStartTime); diff --git a/src/game/shared/multiplay_gamerules.cpp b/src/game/shared/multiplay_gamerules.cpp index 1ed5244286..bb95ec3aa9 100644 --- a/src/game/shared/multiplay_gamerules.cpp +++ b/src/game/shared/multiplay_gamerules.cpp @@ -92,6 +92,9 @@ void MPTimeLimitCallback( IConVar *var, const char *pOldString, float flOldValue #endif ConVar mp_timelimit( "mp_timelimit", "0", FCVAR_NOTIFY|FCVAR_REPLICATED, "game time per map in minutes" +#ifdef NEO + , true, 0.0f, false, 0.0f +#endif // NEO #ifdef GAME_DLL , MPTimeLimitCallback #endif diff --git a/src/game/shared/neo/gamerules/neo_gamerules.cpp b/src/game/shared/neo/gamerules/neo_gamerules.cpp index 1579ff8dc3..d27b5df9ad 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules.cpp +++ b/src/game/shared/neo/gamerules/neo_gamerules.cpp @@ -794,7 +794,7 @@ void CNEORules::ChangeLevel(void) ResetMapSessionCommon(); if (!m_bRotatingMapRightNow && sv_neo_readyup_lobby.GetBool() && !sv_neo_readyup_autointermission.GetBool()) { - m_bChangelevelDone = false; // NEO TODO (Adam) Is this really necessary? Why is the gamerules object thinking when the map begins to change + m_bChangelevelDone = false; } else { @@ -809,12 +809,10 @@ bool CNEORules::CheckGameOver(void) // Note that this changes the level as side effect const bool gameOver = BaseClass::CheckGameOver(); -#ifdef GAME_DLL if (gameOver) { ResetMapSessionCommon(); } -#endif // GAME_DLL return gameOver; } @@ -2591,11 +2589,6 @@ void CNEORules::ResetJGR() void CNEORules::RestartGame() { - // bounds check - if (mp_timelimit.GetInt() < 0) // NEO NOTE (Adam) Just give mp_timelimit cvar a lower bound of 0? - { - mp_timelimit.SetValue(0); - } m_flGameStartTime = gpGlobals->curtime; if (!IsFinite(m_flGameStartTime.Get())) { diff --git a/src/game/shared/neo/gamerules/neo_gamerules_atk.h b/src/game/shared/neo/gamerules/neo_gamerules_atk.h index 51b2b66f99..98abd99190 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_atk.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_atk.h @@ -25,7 +25,7 @@ class CNEORulesATK : public CNEORules, public CGameEventListener virtual void FireGameEvent(IGameEvent *event) override; virtual int GetGameType() override final { return NEO_GAME_TYPE_ATK; } - virtual const char* GetGameTypeName() override { return "ATK"; } + virtual const char* GetGameTypeName() override final { return "ATK"; } const char* GetGameDescription() override final { return "Attack / Defend the ghost"; } virtual bool GetTeamPlayEnabled() const override final { return true; } virtual bool GetCompEnabled() const override final { return true; } @@ -38,7 +38,7 @@ class CNEORulesATK : public CNEORules, public CGameEventListener virtual void SetGameRelatedVars() override final; virtual const int GetScoreLimit() const override final; virtual const int GetRoundLimit() const override final; - virtual void CheckOvertime(); + virtual void CheckOvertime() override final; virtual void RoundTimeout() override final; #endif // GAME_DLL virtual void Think() override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_ctg.h b/src/game/shared/neo/gamerules/neo_gamerules_ctg.h index 310bf8cac1..8fadefd2e1 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_ctg.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_ctg.h @@ -25,9 +25,9 @@ class CNEORulesCTG : public CNEORules, public CGameEventListener virtual void FireGameEvent(IGameEvent *event) override; virtual int GetGameType() override final { return NEO_GAME_TYPE_CTG; } - virtual const char* GetGameTypeName() override { return "CTG"; } - const char* GetGameDescription() override { return "Capture the Ghost"; } - virtual bool GetTeamPlayEnabled() const override { return true; } + virtual const char* GetGameTypeName() override final { return "CTG"; } + const char* GetGameDescription() override final { return "Capture the Ghost"; } + virtual bool GetTeamPlayEnabled() const override final { return true; } virtual bool GetCompEnabled() const override final { return true; } virtual bool GetCapPreventEnabled() const override final { return true; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } @@ -38,7 +38,7 @@ class CNEORulesCTG : public CNEORules, public CGameEventListener virtual void SetGameRelatedVars() override final; virtual const int GetScoreLimit() const override final; virtual const int GetRoundLimit() const override final; - virtual void CheckOvertime(); + virtual void CheckOvertime() override final; virtual void RoundTimeout() override final; #endif // GAME_DLL virtual void Think() override final; diff --git a/src/game/shared/neo/gamerules/neo_gamerules_dm.h b/src/game/shared/neo/gamerules/neo_gamerules_dm.h index fa9f7f9796..738ecee87f 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_dm.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_dm.h @@ -25,9 +25,9 @@ class CNEORulesDM : public CNEORules, public CGameEventListener virtual void FireGameEvent(IGameEvent *event) override; virtual int GetGameType() override final { return NEO_GAME_TYPE_DM; } - virtual const char* GetGameTypeName() override { return "DM"; } - const char* GetGameDescription() override { return "Deathmatch"; } - virtual bool GetTeamPlayEnabled() const override { return false; } + virtual const char* GetGameTypeName() override final { return "DM"; } + const char* GetGameDescription() override final { return "Deathmatch"; } + virtual bool GetTeamPlayEnabled() const override final { return false; } virtual bool GetCompEnabled() const override final { return false; } virtual bool GetCapPreventEnabled() const override final { return false; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } @@ -52,8 +52,7 @@ class CNEORulesDM : public CNEORules, public CGameEventListener #ifdef GAME_DLL CNEO_Player *(*pHighestPlayers)[MAX_PLAYERS + 1], #endif - int *iHighestPlayersTotal, - int *iHighestXP) const; + int *iHighestPlayersTotal, int *iHighestXP) const; #ifdef GAME_DLL void SetWinningDMPlayer(CNEO_Player *pWinner); #endif // GAME_DLL diff --git a/src/game/shared/neo/gamerules/neo_gamerules_emt.h b/src/game/shared/neo/gamerules/neo_gamerules_emt.h index f95137ef89..3851b3c3fb 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_emt.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_emt.h @@ -25,10 +25,10 @@ class CNEORulesEMT : public CNEORules, public CGameEventListener virtual void FireGameEvent(IGameEvent *event) override; virtual int GetGameType() override final { return NEO_GAME_TYPE_EMT; } - virtual const char* GetGameTypeName() override { return "EMT"; } - const char* GetGameDescription() override { return "Empty Gamemode"; } + virtual const char* GetGameTypeName() override final { return "EMT"; } + const char* GetGameDescription() override final { return "Empty Gamemode"; } virtual float GetRoundRemainingTime() const override final; - virtual bool GetTeamPlayEnabled() const override { return true; } + virtual bool GetTeamPlayEnabled() const override final { return true; } virtual bool GetCompEnabled() const override final { return false; } virtual bool GetCapPreventEnabled() const override final { return false; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return true; } diff --git a/src/game/shared/neo/gamerules/neo_gamerules_jgr.h b/src/game/shared/neo/gamerules/neo_gamerules_jgr.h index 81a33ca275..40640b6a0a 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_jgr.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_jgr.h @@ -25,9 +25,9 @@ class CNEORulesJGR : public CNEORules, public CGameEventListener virtual void FireGameEvent(IGameEvent *event) override; virtual int GetGameType() override final { return NEO_GAME_TYPE_JGR; } - virtual const char* GetGameTypeName() override { return "JGR"; } - const char* GetGameDescription() override { return "Juggernaut"; } - virtual bool GetTeamPlayEnabled() const override { return true; } + virtual const char* GetGameTypeName() override final { return "JGR"; } + const char* GetGameDescription() override final { return "Juggernaut"; } + virtual bool GetTeamPlayEnabled() const override final { return true; } virtual bool GetCompEnabled() const override final { return true; } virtual bool GetCapPreventEnabled() const override final { return false; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tdm.h b/src/game/shared/neo/gamerules/neo_gamerules_tdm.h index 1ab1ab6c77..ea9882610c 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tdm.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_tdm.h @@ -25,9 +25,9 @@ class CNEORulesTDM : public CNEORules, public CGameEventListener virtual void FireGameEvent(IGameEvent *event) override; virtual int GetGameType() override final { return NEO_GAME_TYPE_TDM; } - virtual const char* GetGameTypeName() override { return "TDM"; } - const char* GetGameDescription() override { return "Team Deathmatch"; } - virtual bool GetTeamPlayEnabled() const override { return true; } + virtual const char* GetGameTypeName() override final { return "TDM"; } + const char* GetGameDescription() override final { return "Team Deathmatch"; } + virtual bool GetTeamPlayEnabled() const override final { return true; } virtual bool GetCompEnabled() const override final { return false; } virtual bool GetCapPreventEnabled() const override final { return false; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } diff --git a/src/game/shared/neo/gamerules/neo_gamerules_tut.h b/src/game/shared/neo/gamerules/neo_gamerules_tut.h index a141e62faa..32712f2f65 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_tut.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_tut.h @@ -25,9 +25,9 @@ class CNEORulesTUT : public CNEORules, public CGameEventListener virtual void FireGameEvent(IGameEvent *event) override; virtual int GetGameType() override final { return NEO_GAME_TYPE_TUT; } - virtual const char* GetGameTypeName() override { return "TUT"; } - const char* GetGameDescription() override { return "Training"; } - virtual bool GetTeamPlayEnabled() const override { return true; } + virtual const char* GetGameTypeName() override final { return "TUT"; } + const char* GetGameDescription() override final { return "Training"; } + virtual bool GetTeamPlayEnabled() const override final { return true; } virtual bool GetCompEnabled() const override final { return false; } virtual bool GetCapPreventEnabled() const override final { return false; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; } diff --git a/src/game/shared/neo/gamerules/neo_gamerules_vip.h b/src/game/shared/neo/gamerules/neo_gamerules_vip.h index 3059fbfd7f..79ab3b3529 100644 --- a/src/game/shared/neo/gamerules/neo_gamerules_vip.h +++ b/src/game/shared/neo/gamerules/neo_gamerules_vip.h @@ -25,10 +25,10 @@ class CNEORulesVIP : public CNEORules, public CGameEventListener virtual void FireGameEvent(IGameEvent *event) override; virtual int GetGameType() override final { return NEO_GAME_TYPE_VIP; } - virtual const char* GetGameTypeName() override { return "VIP"; } - const char* GetGameDescription() override { return "Protect or Eliminate the VIP"; } + virtual const char* GetGameTypeName() override final { return "VIP"; } + const char* GetGameDescription() override final { return "Protect or Eliminate the VIP"; } virtual float GetRoundRemainingTime() const override final; - virtual bool GetTeamPlayEnabled() const override { return true; } + virtual bool GetTeamPlayEnabled() const override final { return true; } virtual bool GetCompEnabled() const override final { return true; } virtual bool GetCapPreventEnabled() const override final { return true; } virtual bool CanChangeTeamClassLoadoutWhenAlive() const override final { return false; }