Skip to content

Commit 49c20da

Browse files
CTG & JGR Overtime (#1342)
* ghost overtime * keep original timer, fade out inactive timer * jgr overtime * major streamline - Overtime starts at 0 seconds - Grace period always starts at the same amount of time - HUD simplified to a single timer, turns red if in grace time - Overtime timer stays the same (will continue counting) but will override the grace timer if it goes lower than the base grace time * red outside of ctg * undo overtime start point change * fix - prevent grace timer being overriden by overtime timer when ghost is not held - fix the overtime starting when it shouldnt * grace decay returns * cleanup * ditch unnecessary network var --------- Co-authored-by: AdamTadeusz <adam.tomaszewski@hotmail.co.uk>
1 parent 204e841 commit 49c20da

File tree

4 files changed

+141
-21
lines changed

4 files changed

+141
-21
lines changed

src/game/client/neo/ui/neo_hud_round_state.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ extern ConVar cl_neo_streamermode;
4141
extern ConVar snd_victory_volume;
4242
extern ConVar sv_neo_readyup_countdown;
4343
extern ConVar cl_neo_hud_scoreboard_hide_others;
44+
extern ConVar sv_neo_ctg_ghost_overtime_grace;
4445

4546
namespace {
4647
constexpr int Y_POS = 0;
@@ -319,6 +320,10 @@ void CNEOHud_RoundState::UpdateStateForNeoHudElementDraw()
319320
{
320321
m_iWszRoundUCSize = V_swprintf_safe(m_wszRoundUnicode, L"STARTING");
321322
}
323+
else if (NEORules()->GetRoundStatus() == NeoRoundStatus::Overtime)
324+
{
325+
m_iWszRoundUCSize = V_swprintf_safe(m_wszRoundUnicode, L"OVERTIME");
326+
}
322327
else
323328
{
324329
if (NEORules()->GetGameType() == NEO_GAME_TYPE_DM)
@@ -334,7 +339,16 @@ void CNEOHud_RoundState::UpdateStateForNeoHudElementDraw()
334339
if (roundStatus == NeoRoundStatus::PreRoundFreeze)
335340
roundTimeLeft = NEORules()->GetRemainingPreRoundFreezeTime(true);
336341

337-
const int secsTotal = RoundFloatToInt(roundTimeLeft);
342+
int secsTotal = 0.0f;
343+
if (roundStatus == NeoRoundStatus::Overtime && NEORules()->GetGameType() == NEO_GAME_TYPE_CTG)
344+
{
345+
secsTotal = RoundFloatToInt(NEORules()->GetCTGOverTime());
346+
}
347+
else
348+
{
349+
secsTotal = RoundFloatToInt(roundTimeLeft);
350+
}
351+
338352
const int secsRemainder = secsTotal % 60;
339353
const int minutes = (secsTotal - secsRemainder) / 60;
340354
V_snwprintf(m_wszTime, 6, L"%02d:%02d", minutes, secsRemainder);
@@ -465,9 +479,15 @@ void CNEOHud_RoundState::DrawNeoHudElement()
465479
// Draw time
466480
surface()->DrawSetTextFont(m_hOCRFont);
467481
surface()->GetTextSize(m_hOCRFont, m_wszTime, fontWidth, fontHeight);
468-
surface()->DrawSetTextColor((NEORules()->GetRoundStatus() == NeoRoundStatus::PreRoundFreeze ||
469-
NEORules()->GetRoundStatus() == NeoRoundStatus::Countdown) ?
470-
COLOR_RED : COLOR_WHITE);
482+
if (NEORules()->GetRoundStatus() == NeoRoundStatus::PreRoundFreeze || NEORules()->GetRoundStatus() == NeoRoundStatus::Countdown || NEORules()->GetGameType() == NEO_GAME_TYPE_CTG ?
483+
(NEORules()->GetRoundStatus() == NeoRoundStatus::Overtime && (NEORules()->GetRoundRemainingTime() < sv_neo_ctg_ghost_overtime_grace.GetFloat())) : NEORules()->GetRoundStatus() == NeoRoundStatus::Overtime)
484+
{
485+
surface()->DrawSetTextColor(COLOR_RED);
486+
}
487+
else
488+
{
489+
surface()->DrawSetTextColor(COLOR_WHITE);
490+
}
471491
surface()->DrawSetTextPos(m_iXpos - (fontWidth / 2), m_iBoxYEnd / 2 - fontHeight / 2);
472492
surface()->DrawPrintText(m_wszTime, 6);
473493

src/game/server/neo/neo_player.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ void CNEO_Player::RequestSetClass(int newClass)
189189
void CNEO_Player::RequestSetSkin(int newSkin)
190190
{
191191
const NeoRoundStatus roundStatus = NEORules()->GetRoundStatus();
192-
bool canChangeImmediately = ((roundStatus != NeoRoundStatus::RoundLive) && (roundStatus != NeoRoundStatus::PostRound)) || !IsAlive();
192+
bool canChangeImmediately = ((roundStatus != NeoRoundStatus::RoundLive) && (roundStatus != NeoRoundStatus::Overtime) && (roundStatus != NeoRoundStatus::PostRound)) || !IsAlive();
193193

194194
if (canChangeImmediately)
195195
{
@@ -2854,7 +2854,7 @@ int CNEO_Player::OnTakeDamage_Alive(const CTakeDamageInfo& info)
28542854
m_rfAttackersAccumlator.Set(attackerIdx, flDmgAccumlator);
28552855
m_rfAttackersHits.GetForModify(attackerIdx) += 1;
28562856

2857-
if (bIsTeamDmg && sv_neo_teamdamage_kick.GetBool() && NEORules()->GetRoundStatus() == NeoRoundStatus::RoundLive)
2857+
if (bIsTeamDmg && sv_neo_teamdamage_kick.GetBool() && NEORules()->IsRoundLive())
28582858
{
28592859
attacker->m_iTeamDamageInflicted += iDamage;
28602860
}

src/game/shared/neo/neo_gamerules.cpp

Lines changed: 112 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ ConVar neo_vip_eligible("cl_neo_vip_eligible", "1", FCVAR_ARCHIVE, "Eligible for
6565
#endif // CLIENT_DLL
6666
#ifdef GAME_DLL
6767
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);
68-
ConVar sv_neo_jgr_max_points("sv_neo_jgr_max_points", "100", FCVAR_ARCHIVE, "Maximum points required for a team to win in JGR", true, 1, false, 0);
68+
ConVar sv_neo_jgr_max_points("sv_neo_jgr_max_points", "100", FCVAR_REPLICATED, "Maximum points required for a team to win in JGR", true, 1, false, 0);
69+
ConVar sv_neo_jgr_point_interval("sv_neo_jgr_point_interval", "1.5", FCVAR_REPLICATED, "Amount of time required to score a point whilst holding the Juggernaut", true, 0.1f, false, 0);
6970
#endif
7071

7172
#ifdef GAME_DLL
@@ -230,6 +231,7 @@ BEGIN_NETWORK_TABLE_NOBASE( CNEORules, DT_NEORules )
230231
RecvPropInt(RECVINFO(m_iGhosterPlayer)),
231232
RecvPropInt(RECVINFO(m_iEscortingTeam)),
232233
RecvPropBool(RECVINFO(m_bGhostExists)),
234+
RecvPropFloat(RECVINFO(m_flGhostLastHeld)),
233235
RecvPropVector(RECVINFO(m_vecGhostMarkerPos)),
234236
RecvPropInt(RECVINFO(m_iJuggernautPlayerIndex)),
235237
RecvPropBool(RECVINFO(m_bJuggernautItemExists)),
@@ -252,6 +254,7 @@ BEGIN_NETWORK_TABLE_NOBASE( CNEORules, DT_NEORules )
252254
SendPropInt(SENDINFO(m_iGhosterPlayer)),
253255
SendPropInt(SENDINFO(m_iEscortingTeam)),
254256
SendPropBool(SENDINFO(m_bGhostExists)),
257+
SendPropFloat(SENDINFO(m_flGhostLastHeld)),
255258
SendPropVector(SENDINFO(m_vecGhostMarkerPos), -1, SPROP_COORD_MP_LOWPRECISION | SPROP_CHANGES_OFTEN, MIN_COORD_FLOAT, MAX_COORD_FLOAT),
256259
SendPropInt(SENDINFO(m_iJuggernautPlayerIndex)),
257260
SendPropBool(SENDINFO(m_bJuggernautItemExists)),
@@ -375,6 +378,10 @@ ConVar sv_neo_ignore_wep_xp_limit("sv_neo_ignore_wep_xp_limit", "0", FCVAR_CHEAT
375378
ConVar sv_neo_dm_win_xp("sv_neo_dm_win_xp", "50", FCVAR_REPLICATED, "The XP limit to win the match.",
376379
true, 0.0f, true, 1000.0f);
377380

381+
ConVar sv_neo_ctg_ghost_overtime_enabled("sv_neo_ctg_ghost_overtime_enabled", "0", FCVAR_REPLICATED, "Enable ghost overtime.", true, 0, true, 1);
382+
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);
383+
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);
384+
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);
378385

379386
#ifdef CLIENT_DLL
380387
extern ConVar neo_fov;
@@ -676,6 +683,7 @@ void CNEORules::ResetMapSessionCommon()
676683
m_vecJuggernautMarkerPos = vec3_origin;
677684
m_flNeoRoundStartTime = 0.0f;
678685
m_flNeoNextRoundStartTime = 0.0f;
686+
m_flGhostLastHeld = 0.0f;
679687
#ifdef GAME_DLL
680688
m_pRestoredInfos.Purge();
681689
m_readyAccIDs.Purge();
@@ -1055,6 +1063,20 @@ void CNEORules::Think(void)
10551063
return;
10561064
}
10571065

1066+
if (m_nGameTypeSelected == NEO_GAME_TYPE_CTG)
1067+
{
1068+
if (sv_neo_ctg_ghost_overtime_enabled.GetBool() && m_nRoundStatus == NeoRoundStatus::RoundLive && m_iGhosterPlayer &&
1069+
(m_flNeoRoundStartTime + (neo_ctg_round_timelimit.GetFloat() * 60) - sv_neo_ctg_ghost_overtime_grace.GetFloat()) < gpGlobals->curtime)
1070+
{
1071+
m_nRoundStatus = NeoRoundStatus::Overtime;
1072+
}
1073+
1074+
if (m_nRoundStatus == NeoRoundStatus::Overtime && m_iGhosterPlayer)
1075+
{
1076+
m_flGhostLastHeld = gpGlobals->curtime;
1077+
}
1078+
}
1079+
10581080
if (g_fGameOver) // someone else quit the game already
10591081
{
10601082
// check to see if we should change levels now
@@ -1089,7 +1111,7 @@ void CNEORules::Think(void)
10891111
m_flPrevThinkMirrorDmg = gpGlobals->curtime;
10901112
}
10911113

1092-
if (sv_neo_teamdamage_kick.GetBool() && m_nRoundStatus == NeoRoundStatus::RoundLive &&
1114+
if (sv_neo_teamdamage_kick.GetBool() && IsRoundLive() &&
10931115
gpGlobals->curtime > (m_flPrevThinkKick + 0.5f))
10941116
{
10951117
const int iThresKickHp = sv_neo_teamdamage_kick_hp.GetInt();
@@ -1145,7 +1167,7 @@ void CNEORules::Think(void)
11451167
// Note that exactly zero here means infinite round time.
11461168
else if (GetRoundRemainingTime() < 0)
11471169
{
1148-
if (GetGameType() == NEO_GAME_TYPE_TDM || GetGameType() == NEO_GAME_TYPE_JGR)
1170+
if (GetGameType() == NEO_GAME_TYPE_TDM)
11491171
{
11501172
if (GetGlobalTeam(TEAM_JINRAI)->GetScore() > GetGlobalTeam(TEAM_NSF)->GetScore())
11511173
{
@@ -1173,6 +1195,47 @@ void CNEORules::Think(void)
11731195
}
11741196
// Otherwise go into overtime
11751197
}
1198+
else if (GetGameType() == NEO_GAME_TYPE_JGR)
1199+
{
1200+
if (!m_pJuggernautPlayer)
1201+
{
1202+
if (GetGlobalTeam(TEAM_JINRAI)->GetScore() > GetGlobalTeam(TEAM_NSF)->GetScore())
1203+
{
1204+
SetWinningTeam(TEAM_JINRAI, NEO_VICTORY_POINTS, false, true, false, false);
1205+
return;
1206+
}
1207+
1208+
if (GetGlobalTeam(TEAM_NSF)->GetScore() > GetGlobalTeam(TEAM_JINRAI)->GetScore())
1209+
{
1210+
SetWinningTeam(TEAM_NSF, NEO_VICTORY_POINTS, false, true, false, false);
1211+
return;
1212+
}
1213+
}
1214+
else
1215+
{
1216+
if (m_nRoundStatus == NeoRoundStatus::RoundLive)
1217+
{
1218+
m_nRoundStatus = NeoRoundStatus::Overtime;
1219+
}
1220+
1221+
int jgrTeam = m_pJuggernautPlayer->GetTeamNumber();
1222+
int oppositeTeam = (m_pJuggernautPlayer->GetTeamNumber() == TEAM_JINRAI ? TEAM_NSF : TEAM_JINRAI);
1223+
if (GetGlobalTeam(jgrTeam)->GetScore() > GetGlobalTeam(oppositeTeam)->GetScore())
1224+
{
1225+
SetWinningTeam(jgrTeam, NEO_VICTORY_POINTS, false, true, false, false);
1226+
return;
1227+
}
1228+
1229+
if (gpGlobals->curtime >= m_flLastPointTime)
1230+
{
1231+
m_flLastPointTime = gpGlobals->curtime + sv_neo_jgr_point_interval.GetFloat();
1232+
1233+
GetGlobalTeam(jgrTeam)->AddScore(1);
1234+
}
1235+
1236+
return;
1237+
}
1238+
}
11761239

11771240
if (IsTeamplay())
11781241
{
@@ -1306,13 +1369,11 @@ void CNEORules::Think(void)
13061369
m_bJuggernautItemExists = false;
13071370
}
13081371

1309-
#define JGR_POINT_INTERVAL 1.5f
1310-
1311-
if (GetGameType() == NEO_GAME_TYPE_JGR && m_nRoundStatus == NeoRoundStatus::RoundLive && m_pJuggernautPlayer)
1372+
if (GetGameType() == NEO_GAME_TYPE_JGR && IsRoundLive() && m_pJuggernautPlayer)
13121373
{
13131374
if (gpGlobals->curtime >= m_flLastPointTime)
13141375
{
1315-
m_flLastPointTime = gpGlobals->curtime + JGR_POINT_INTERVAL;
1376+
m_flLastPointTime = gpGlobals->curtime + sv_neo_jgr_point_interval.GetFloat();
13161377

13171378
if (m_pJuggernautPlayer->GetTeamNumber() == TEAM_JINRAI)
13181379
{
@@ -1337,7 +1398,7 @@ void CNEORules::Think(void)
13371398
}
13381399
}
13391400

1340-
if (GetGameType() == NEO_GAME_TYPE_VIP && m_nRoundStatus == NeoRoundStatus::RoundLive && !m_pGhost)
1401+
if (GetGameType() == NEO_GAME_TYPE_VIP && IsRoundLive() && !m_pGhost)
13411402
{
13421403
if (!m_pVIP)
13431404
{
@@ -1429,7 +1490,7 @@ void CNEORules::Think(void)
14291490
}
14301491
}
14311492
}
1432-
else if (m_nRoundStatus != NeoRoundStatus::RoundLive)
1493+
else if (!IsRoundLive())
14331494
{
14341495
if (!IsRoundOver())
14351496
{
@@ -1441,7 +1502,7 @@ void CNEORules::Think(void)
14411502
}
14421503
else
14431504
{
1444-
if (m_nRoundStatus == NeoRoundStatus::RoundLive)
1505+
if (IsRoundLive())
14451506
{
14461507
COMPILE_TIME_ASSERT(TEAM_JINRAI == 2 && TEAM_NSF == 3);
14471508
if (GetGameType() != NEO_GAME_TYPE_TDM && GetGameType() != NEO_GAME_TYPE_DM && GetGameType() != NEO_GAME_TYPE_JGR)
@@ -1596,6 +1657,10 @@ float CNEORules::GetRoundRemainingTime() const
15961657
break;
15971658
case NEO_GAME_TYPE_CTG:
15981659
roundTimeLimit = neo_ctg_round_timelimit.GetFloat() * 60.f;
1660+
if (m_nRoundStatus == NeoRoundStatus::Overtime)
1661+
{
1662+
return GetCTGOverTime();
1663+
}
15991664
break;
16001665
case NEO_GAME_TYPE_VIP:
16011666
roundTimeLimit = neo_vip_round_timelimit.GetFloat() * 60.f;
@@ -1614,6 +1679,37 @@ float CNEORules::GetRoundRemainingTime() const
16141679
return (m_flNeoRoundStartTime + roundTimeLimit) - gpGlobals->curtime;
16151680
}
16161681

1682+
float CNEORules::GetCTGOverTime() const
1683+
{
1684+
float roundTimeLimit = neo_ctg_round_timelimit.GetFloat() * 60.f;
1685+
float overtime = (m_flNeoRoundStartTime + roundTimeLimit + sv_neo_ctg_ghost_overtime.GetFloat()) - gpGlobals->curtime;
1686+
1687+
if (sv_neo_ctg_ghost_overtime_grace_decay.GetBool())
1688+
{
1689+
if (m_iGhosterPlayer)
1690+
{
1691+
return overtime;
1692+
}
1693+
else
1694+
{
1695+
float overtimeAtGhostDrop = (m_flNeoRoundStartTime + roundTimeLimit + sv_neo_ctg_ghost_overtime.GetFloat()) - m_flGhostLastHeld;
1696+
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);
1697+
}
1698+
}
1699+
else
1700+
{
1701+
float grace = sv_neo_ctg_ghost_overtime_grace.GetFloat() - (gpGlobals->curtime - m_flGhostLastHeld);
1702+
if (m_iGhosterPlayer || overtime < grace)
1703+
{
1704+
return overtime;
1705+
}
1706+
else
1707+
{
1708+
return grace;
1709+
}
1710+
}
1711+
}
1712+
16171713
float CNEORules::GetRoundAccumulatedTime() const
16181714
{
16191715
return gpGlobals->curtime - (m_flNeoRoundStartTime + sv_neo_preround_freeze_time.GetFloat());
@@ -1622,7 +1718,7 @@ float CNEORules::GetRoundAccumulatedTime() const
16221718
#ifdef GAME_DLL
16231719
float CNEORules::MirrorDamageMultiplier() const
16241720
{
1625-
if (m_nRoundStatus != NeoRoundStatus::RoundLive)
1721+
if (!IsRoundLive())
16261722
{
16271723
return 0.0f;
16281724
}
@@ -2414,6 +2510,7 @@ void CNEORules::StartNextRound()
24142510

24152511
m_flNeoRoundStartTime = gpGlobals->curtime;
24162512
m_flNeoNextRoundStartTime = 0;
2513+
m_flGhostLastHeld = 0;
24172514

24182515
CleanUpMap();
24192516
const bool bFromStarting = (m_nRoundStatus == NeoRoundStatus::Warmup
@@ -2547,12 +2644,12 @@ bool CNEORules::IsRoundOver() const
25472644

25482645
bool CNEORules::IsRoundLive() const
25492646
{
2550-
return m_nRoundStatus == NeoRoundStatus::RoundLive;
2647+
return (m_nRoundStatus == NeoRoundStatus::RoundLive || m_nRoundStatus == NeoRoundStatus::Overtime);
25512648
}
25522649

25532650
bool CNEORules::IsRoundOn() const
25542651
{
2555-
return (m_nRoundStatus == NeoRoundStatus::PreRoundFreeze) || (m_nRoundStatus == NeoRoundStatus::RoundLive) || (m_nRoundStatus == NeoRoundStatus::PostRound);
2652+
return (m_nRoundStatus == NeoRoundStatus::PreRoundFreeze) || IsRoundLive() || (m_nRoundStatus == NeoRoundStatus::PostRound);
25562653
}
25572654

25582655
void CNEORules::CreateStandardEntities(void)
@@ -3491,7 +3588,7 @@ void CNEORules::CheckIfCapPrevent(CNEO_Player *capPreventerPlayer)
34913588
// If this is the only player alive left before the suicide/disconnect and the other team was holding
34923589
// the ghost, reward the other team an XP to the next rank as a ghost cap was prevented.
34933590
const bool bShouldCheck = (sv_neo_suicide_prevent_cap_punish.GetBool()
3494-
&& m_nRoundStatus == NeoRoundStatus::RoundLive
3591+
&& IsRoundLive()
34953592
&& !m_bTeamBeenAwardedDueToCapPrevent);
34963593
if (!bShouldCheck)
34973594
{
@@ -3585,7 +3682,7 @@ void CNEORules::PlayerKilled(CBasePlayer *pVictim, const CTakeDamageInfo &info)
35853682
{
35863683
attacker->AddPoints(-1, true);
35873684
#ifdef GAME_DLL
3588-
if (sv_neo_teamdamage_kick.GetBool() && m_nRoundStatus == NeoRoundStatus::RoundLive)
3685+
if (sv_neo_teamdamage_kick.GetBool() && IsRoundLive())
35893686
{
35903687
++attacker->m_iTeamKillsInflicted;
35913688
}

src/game/shared/neo/neo_gamerules.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ enum NeoRoundStatus {
108108
Warmup,
109109
PreRoundFreeze,
110110
RoundLive,
111+
Overtime,
111112
PostRound,
112113
Pause,
113114
Countdown,
@@ -258,6 +259,7 @@ class CNEORules : public CHL2MPRules, public CGameEventListener
258259
virtual bool CheckGameOver(void) OVERRIDE;
259260

260261
float GetRoundRemainingTime() const;
262+
float GetCTGOverTime() const;
261263
float GetRoundAccumulatedTime() const;
262264
#ifdef GAME_DLL
263265
float MirrorDamageMultiplier() const;
@@ -445,6 +447,7 @@ class CNEORules : public CHL2MPRules, public CGameEventListener
445447
CNetworkVar(int, m_iGhosterPlayer);
446448
CNetworkVector(m_vecGhostMarkerPos);
447449
CNetworkVar(bool, m_bGhostExists);
450+
CNetworkVar(float, m_flGhostLastHeld);
448451

449452
// Juggernaut networked variables
450453
CNetworkVar(int, m_iJuggernautPlayerIndex);

0 commit comments

Comments
 (0)