diff --git a/src/action/a_esp.h b/src/action/a_esp.h index 501e32d42..53f13cc5b 100644 --- a/src/action/a_esp.h +++ b/src/action/a_esp.h @@ -1,10 +1,6 @@ // This is set to 1 if either atl or etv are 1 extern cvar_t *esp; -// Discrete game modes -extern cvar_t *atl; -extern cvar_t *etv; - #define IS_LEADER(ent) (teams[(ent)->client->resp.team].leader == (ent)) #define HAVE_LEADER(teamNum) (teams[(teamNum)].leader) #define MAX_ESP_STRLEN 32 diff --git a/src/action/g_local.h b/src/action/g_local.h index 409384ad5..1d7bc17e3 100644 --- a/src/action/g_local.h +++ b/src/action/g_local.h @@ -976,6 +976,7 @@ typedef struct int timeoutFrames; float matchTime; float emptyTime; + float quit_empty_time; // LRCON quit_on_empty: level.time when server first emptied, or -1 if not empty. Separate from emptyTime which empty_rotate uses as an accumulator. int abandonFrames; // Countdown for abandon forfeit int weapon_sound_framenum; int pic_teamplay_timer_icon; @@ -1396,8 +1397,6 @@ extern cvar_t *medkit_value; // BEGIN AQ2 ETE extern cvar_t *esp; // Enable or disable Espionage mode -extern cvar_t *atl; // Enable or disable Assassinate the Leader mode (do not set this manually) -extern cvar_t *etv; // Enable or disable Escort the VIP mode (do not set this manually) extern cvar_t *esp_atl; // Prefer ATL mode even if ETV mode is available extern cvar_t *esp_punish; // Enable or disable punishment for losing the around extern cvar_t *esp_etv_halftime; // Enable or disable halftime in ETV mode diff --git a/src/action/g_main.c b/src/action/g_main.c index 3077f82cc..be5bc212b 100644 --- a/src/action/g_main.c +++ b/src/action/g_main.c @@ -533,8 +533,6 @@ cvar_t *jump; // jumping mod // BEGIN AQ2 ETE cvar_t *esp; -cvar_t *atl; -cvar_t *etv; cvar_t *esp_atl; cvar_t *esp_punish; cvar_t *esp_etv_halftime; @@ -1344,18 +1342,24 @@ void G_RunFrame (void) return; } - // LRCON quit_on_empty logic + // LRCON quit_on_empty logic. + // Uses its own quit_empty_time field — sharing level.emptyTime with the + // empty_rotate accumulator above caused the old comparison + // `level.time - level.emptyTime > 5.0` to fire after one frame when a + // player left a long-running server (level.time was already large but + // emptyTime had just incremented from 0). Sentinel -1.0f means "not + // currently empty" so we can distinguish from level.time == 0 at start. if (game.lrcon_config.quit_on_empty) { if (empty) { - if (level.emptyTime == 0) { - level.emptyTime = level.time; + if (level.quit_empty_time < 0) { + level.quit_empty_time = level.time; gi.dprintf("LRCON: Server empty, will quit in 5 seconds\n"); - } else if (level.time - level.emptyTime > 5.0) { + } else if (level.time - level.quit_empty_time > 5.0f) { gi.dprintf("LRCON: Quitting server (empty for 5+ seconds)\n"); gi.AddCommandString("quit\n"); } } else { - level.emptyTime = 0; + level.quit_empty_time = -1.0f; } } diff --git a/src/action/g_save.c b/src/action/g_save.c index 4d93bdd3f..d4b2a68a4 100644 --- a/src/action/g_save.c +++ b/src/action/g_save.c @@ -618,7 +618,7 @@ void InitGame( void ) esp_matchmode = gi.cvar("esp_matchmode", "0", 0); esp_respawn_uvtime = gi.cvar("esp_respawn_uvtime", "10", 0); if (esp_respawn_uvtime->value > 20) { - gi.dprintf("esp_respawn_uvtime was set too high, setting to 2 seconds\n"); + gi.dprintf("esp_respawn_uvtime was set too high, setting to 20 seconds\n"); gi.cvar_forceset("esp_respawn_uvtime", "20"); } esp_debug = gi.cvar("esp_debug", "0", 0); // Set to 1 to enable debug messages for Espionage diff --git a/src/action/g_spawn.c b/src/action/g_spawn.c index 804326367..94683a5d9 100644 --- a/src/action/g_spawn.c +++ b/src/action/g_spawn.c @@ -1580,6 +1580,10 @@ void SpawnEntities (const char *mapname, const char *entities, const char *spawn memset(&level, 0, sizeof (level)); memset(g_edicts, 0, game.maxentities * sizeof (g_edicts[0])); + // quit_empty_time uses -1 as the "not currently empty" sentinel (0 is a + // valid level.time at start of map). + level.quit_empty_time = -1.0f; + Q_strncpyz(level.mapname, mapname, sizeof(level.mapname)); Q_strncpyz(game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)); diff --git a/src/server/init.c b/src/server/init.c index 818145ee3..432d64593 100644 --- a/src/server/init.c +++ b/src/server/init.c @@ -481,6 +481,11 @@ void SV_InitGame(unsigned mvd_spawn) SV_MvdPostInit(); } + // Reset bot client slots on game (re)initialization. Cold-start gets + // zeroed bot_clients[] via BSS, but SV_InitGame can be called on + // restart/map-change where in-progress state could otherwise persist. + SV_BotInit(); + if (svs.csr.extended && IS_NEW_GAME_API) PmoveEnableExt(&svs.pmp);