]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
iterate through clients in random order
authorMartin Taibr <taibr.martin@gmail.com>
Fri, 28 Oct 2016 18:36:00 +0000 (20:36 +0200)
committerMartin Taibr <taibr.martin@gmail.com>
Fri, 28 Oct 2016 18:36:00 +0000 (20:36 +0200)
qcsrc/common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qc
qcsrc/server/_all.qh

index 2e4802d3883f8510704e946673972f8fd558a636..d58ef38a994d1e0aa966448435571b9733049d49 100644 (file)
@@ -84,7 +84,7 @@ MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerSpawn)
                entity best_mate = NULL;
                vector best_pos = '0 0 0';
                float best_dist = 0;
-               FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
+               FOREACH_CLIENT_RANDOM(IS_PLAYER(it), LAMBDA(
                        //LOG_INFOF("  for client: %s %v\n", it.netname, it.origin);
                        if (!SAME_TEAM(player, it)) continue;
                        if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health >= 0 && it.health < autocvar_g_balance_health_regenstable) continue;
@@ -172,7 +172,7 @@ MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerSpawn)
                                                best_mate = it;
                                        }
                                }
-                               else // TODO randomize to avoid favoring players who joined early
+                               else
                                {
                                        setorigin(player, vectical_trace_endpos);
                                        player.angles = it.angles;
index ed3083a1203fd94c69943efb17341c80c45127d1..794638dea233933516ffc1ecf48c666a03929fa1 100644 (file)
@@ -43,6 +43,33 @@ const string STR_OBSERVER = "observer";
 
 #define FOREACH_CLIENT(cond, body) FOREACH_CLIENTSLOT(IS_CLIENT(it) && (cond), body)
 
+// using the "inside out" version of knuth-fisher-yates shuffle
+// https://en.wikipedia.org/wiki/Fisher–Yates_shuffle
+#define FOREACH_CLIENT_RANDOM(cond, body) \
+       MACRO_BEGIN { \
+               float _clients[255]; \
+               int _cnt = 0; \
+               FOREACH_CLIENT(cond, LAMBDA( \
+                       int _j = floor(random() * (_cnt + 1)); \
+                       if (_j == _cnt) \
+                       { \
+                               _clients[_cnt] = etof(it); \
+                       } \
+                       else \
+                       { \
+                               _clients[_cnt] = _clients[_j]; \
+                               _clients[_j] = etof(it); \
+                       } \
+                       _cnt++; \
+               )); \
+               for (int _i = 0; _i < _cnt; ++_i) \
+               { \
+                       const noref int i = _clients[_i]; \
+                       ITER_CONST noref entity it = ftoe(i); \
+                       if (cond) { LAMBDA(body) } \
+               } \
+       } MACRO_END
+
 // NOTE: FOR_EACH_MONSTER deprecated! Use the following instead: IL_EACH(g_monsters, true, { code; });
 
 #include <common/effects/all.qh>