]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/command/vote.qc
Give bots genuine ready status, fixes not appearing ready until a human is ready
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / command / vote.qc
index b360f34d3f325133ee88629f26110d54a5f508d8..53f9a1715604065e8f7d500125df0681e4b1c8f2 100644 (file)
@@ -86,7 +86,7 @@ bool Nagger_SendEntity(entity this, entity to, float sendflags)
                for (i = 1; i <= maxclients; i += 8)
                {
                        for (f = 0, e = edict_num(i), b = BIT(0); b < BIT(8); b <<= 1, e = nextent(e))
-                               if (!IS_REAL_CLIENT(e) || e.ready)
+                               if (e.ready)
                                        f |= b;
                        WriteByte(MSG_ENTITY, f);
                }
@@ -419,7 +419,8 @@ void reset_map(bool dorespawn, bool is_fake_round_start)
 // Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown is set)
 void ReadyRestart_think(entity this)
 {
-       reset_map(true, false);
+       if (!warmup_stage) // if the countdown was not aborted
+               reset_map(true, false);
        delete(this);
 }
 
@@ -455,8 +456,8 @@ void ReadyRestart_force(bool is_fake_round_start)
        if(!is_fake_round_start && !warmup_stage)
                localcmd("\nsv_hook_warmupend\n");
 
-       // reset the .ready status of all players (also spectators)
-       FOREACH_CLIENT(IS_REAL_CLIENT(it), { it.ready = false; });
+       // reset the .ready status of all clients (including spectators and bots)
+       FOREACH_CLIENT(true, { it.ready = false; });
        readycount = 0;
        Nagger_ReadyCounted();  // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
 
@@ -498,7 +499,7 @@ void ReadyRestart(bool forceWarmupEnd)
        if(forceWarmupEnd || autocvar_g_campaign)
                warmup_stage = 0; // forcefully end warmup and go to match stage
        else
-               warmup_stage = cvar("g_warmup"); // go into warmup if it's enabled, otherwise restart into match stage
+               warmup_stage = autocvar_g_warmup; // go into warmup if it's enabled, otherwise restart into match stage
 
        ReadyRestart_force(false);
 }
@@ -513,30 +514,41 @@ void ReadyCount()
        // cannot reset the game while a timeout is active or pending
        if (timeout_status) return;
 
-       float ready_needed_factor, ready_needed_count;
-       float t_players = 0;
+       int total_players = 0, human_players = 0, humans_ready = 0;
        readycount = 0;
 
-       FOREACH_CLIENT(IS_REAL_CLIENT(it) && (IS_PLAYER(it) || INGAME_JOINED(it)), {
-               ++t_players;
+       FOREACH_CLIENT(IS_PLAYER(it) || INGAME_JOINED(it), {
+               ++total_players;
                if (it.ready) ++readycount;
+               if (IS_REAL_CLIENT(it))
+               {
+                       ++human_players;
+                       if (it.ready) ++humans_ready;
+               }
        });
 
        Nagger_ReadyCounted();
 
-       if (t_players < map_minplayers) // map_minplayers will only be set if g_warmup -1 at worldspawn
+       // can't read warmup_stage here as it could have been set to 0 by ReadyRestart()
+       // and we need to use this when checking if we should abort the countdown
+       // map_minplayers can only be > 0 if g_warmup was -1 at worldspawn
+       int minplayers = autocvar_g_warmup > 1 ? autocvar_g_warmup : map_minplayers;
+
+       if (total_players < minplayers)
        {
                if (game_starttime > time) // someone bailed during countdown, back to warmup
                {
-                       warmup_stage = -1; // CAN change it AFTER calling Nagger_ReadyCounted() this frame
+                       warmup_stage = autocvar_g_warmup; // CAN change it AFTER calling Nagger_ReadyCounted() this frame
                        game_starttime = time;
-                       Send_Notification(NOTIF_ALL, NULL, MSG_MULTI, COUNTDOWN_STOP, map_minplayers);
+                       Send_Notification(NOTIF_ALL, NULL, MSG_MULTI, COUNTDOWN_STOP, minplayers);
+                       if (!sv_ready_restart_after_countdown) // if we ran reset_map() at start of countdown
+                               FOREACH_CLIENT(IS_PLAYER(it), { GiveWarmupResources(it); });
                }
                if (warmup_limit > 0)
                        warmup_limit = -1;
                return; // don't ReadyRestart if players are ready but too few
        }
-       else if (map_minplayers && warmup_limit <= 0)
+       else if (minplayers && warmup_limit <= 0)
        {
                // there's enough players now but we're still in infinite warmup
                warmup_limit = cvar("g_warmup_limit");
@@ -548,10 +560,8 @@ void ReadyCount()
                // warmup continues until enough players AND enough RUPs (no time limit)
        }
 
-       ready_needed_factor = bound(0.5, cvar("g_warmup_majority_factor"), 1);
-       ready_needed_count = ceil(t_players * ready_needed_factor);
-
-       if (readycount >= ready_needed_count) ReadyRestart(true);
+       if (humans_ready && humans_ready >= rint(human_players * bound(0.5, cvar("g_warmup_majority_factor"), 1)))
+               ReadyRestart(true);
 }