From b8466c26cb78ad380f63f08cdba9a0724a2438ff Mon Sep 17 00:00:00 2001 From: Dino <8dino2@gmail.com> Date: Sat, 23 May 2026 19:19:01 -0400 Subject: [PATCH 1/2] fix(matchmode): mm_timeoutcount default 1 -> 2 to match docs (#316 FIX-05) Source default was 1; doc/action.md documented 2. Admins reading the docs configured servers expecting 2 timeouts per team per match but actually got 1. Align source to the documented value. Refs #316 --- src/action/g_save.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/action/g_save.c b/src/action/g_save.c index 4d93bdd3f..0d0414b33 100644 --- a/src/action/g_save.c +++ b/src/action/g_save.c @@ -490,7 +490,7 @@ void InitGame( void ) mm_allowlock = gi.cvar( "mm_allowlock", "1", CVAR_LATCH ); mm_pausecount = gi.cvar( "mm_allowcount", "3", CVAR_LATCH ); mm_pausetime = gi.cvar( "mm_pausetime", "2", CVAR_LATCH ); - mm_timeoutcount = gi.cvar( "mm_timeoutcount", "1", CVAR_LATCH ); // 1 timeout + mm_timeoutcount = gi.cvar( "mm_timeoutcount", "2", CVAR_LATCH ); // 2 timeouts per team per match mm_timeouttime = gi.cvar( "mm_timeouttime", "60", CVAR_LATCH ); // 60 seconds use_forfeit = gi.cvar( "use_forfeit", "0", 0 ); // Enable forfeit command forfeit_abandon_time = gi.cvar( "forfeit_abandon_time", "60", 0 ); // Abandon timer in seconds From 4ce1fb1bdb4af77656e2e7618a77186c0e71c3c0 Mon Sep 17 00:00:00 2001 From: Dino <8dino2@gmail.com> Date: Sat, 23 May 2026 19:20:21 -0400 Subject: [PATCH 2/2] fix(matchmode): timeout and abandon guards for edge values (#316 FIX-06, FIX-07) FIX-06: Cmd_CallTimeout_f compared matchTime >= timelimit->value * 60 to detect the last round. With timelimit=0 (unlimited), the comparison is always true, blocking all timeouts permanently on unlimited-time servers. Skip the check when timelimit is unset/zero. FIX-07: CheckAbandon set abandonFrames to forfeit_abandon_time * HZ without guarding against zero. Setting forfeit_abandon_time=0 caused the outer !abandonFrames branch to re-fire every tick, spamming the abandonment-detected log indefinitely. Treat forfeit_abandon_time <= 0 as "abandonment detection disabled" and return early. Refs #316 --- src/action/a_match.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/action/a_match.c b/src/action/a_match.c index 1ba9adb27..87069106d 100644 --- a/src/action/a_match.c +++ b/src/action/a_match.c @@ -421,6 +421,13 @@ qboolean CheckAbandon(void) if (!matchmode->value || !use_forfeit->value) return false; + /* Treat forfeit_abandon_time <= 0 as "abandonment detection disabled". + * Without this guard, abandonFrames becomes 0 in the registration path, + * the `!level.abandonFrames` branch fires every server tick, and the + * announcement spams the log forever. */ + if (forfeit_abandon_time->value <= 0) + return false; + if (!team_game_going) return false; @@ -908,7 +915,10 @@ void Cmd_CallTimeout_f(edict_t * ent) return; } - if (level.matchTime >= timelimit->value * 60) { + /* Skip the last-round guard when timelimit is unlimited (0). Otherwise + * `matchTime >= 0` is always true and timeouts are blocked permanently + * on unlimited-time servers. */ + if (timelimit->value > 0 && level.matchTime >= timelimit->value * 60) { gi.cprintf(ent, PRINT_HIGH, "You cannot call for a timeout on the last round of the match\n"); return; }