@@ -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
6767ConVar 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
375378ConVar 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
380387extern 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+
16171713float 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
16231719float 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
25482645bool CNEORules::IsRoundLive () const
25492646{
2550- return m_nRoundStatus == NeoRoundStatus::RoundLive;
2647+ return ( m_nRoundStatus == NeoRoundStatus::RoundLive || m_nRoundStatus == NeoRoundStatus::Overtime) ;
25512648}
25522649
25532650bool 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
25582655void 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 }
0 commit comments