]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote-tracking branch 'origin/master' into samual/respawn_improvements
authorSamual Lenks <samual@xonotic.org>
Tue, 7 May 2013 17:04:11 +0000 (13:04 -0400)
committerSamual Lenks <samual@xonotic.org>
Tue, 7 May 2013 17:04:11 +0000 (13:04 -0400)
Conflicts:
qcsrc/server/cl_client.qc

qcsrc/client/Main.qc
qcsrc/common/constants.qh
qcsrc/server/cl_client.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/progs.src
qcsrc/server/spawnpoints.qc [new file with mode: 0644]
qcsrc/server/spawnpoints.qh [new file with mode: 0644]

index 7a11300ea9f1487a177a00192964bfda94413a34..3d1a012d94620bf8d9d75298118500312edc649d 100644 (file)
@@ -696,6 +696,34 @@ void Ent_ReadAccuracy(void)
        }
 }
 
+void Spawn_Draw(void)
+{
+       pointparticles(particleeffectnum("EF_STARDUST"), self.origin, '0 0 2', bound(0, frametime, 0.1));
+}
+
+void Ent_ReadSpawnPoint(float is_new)
+{
+       self.team = ReadByte();
+       self.origin_x = ReadShort();
+       self.origin_y = ReadShort();
+       self.origin_z = ReadShort();
+
+       self.colormod = '200 0 0'; //colormapPaletteColor(self.team - 1, FALSE);
+
+       //setsize(self, PL_MIN, PL_MAX);
+
+       //droptofloor();
+
+       //self.mdl = "models/domination/dom_unclaimed.md3";
+       //precache_model(self.mdl);
+       //setmodel(self, self.mdl);
+       self.drawmask = MASK_NORMAL;
+       self.movetype = MOVETYPE_NOCLIP;
+       self.draw = Spawn_Draw;
+
+       print(sprintf("Ent_ReadSpawnPoint(is_new = %d); origin = %s, team = %d (%s)\n", is_new, vtos(self.origin), self.team, "foobar"));
+}
+
 // CSQC_Ent_Update : Called every frame that the server has indicated an update to the SSQC / CSQC entity has occured.
 // The only parameter reflects if the entity is "new" to the client, meaning it just came into the client's PVS.
 void Ent_RadarLink();
@@ -781,7 +809,9 @@ void CSQC_Ent_Update(float bIsNewEntity)
                case ENT_CLIENT_MODEL: CSQCModel_Read(bIsNewEntity); break;
                case ENT_CLIENT_ITEM: ItemRead(bIsNewEntity); break;  
                case ENT_CLIENT_BUMBLE_RAYGUN: bumble_raygun_read(bIsNewEntity); break;
+               case ENT_CLIENT_SPAWNPOINT: Ent_ReadSpawnPoint(bIsNewEntity); break;
                case ENT_CLIENT_NOTIFICATION: Read_Notification(bIsNewEntity); break;
+
                default:
                        //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype));
                        error(sprintf(_("Unknown entity type in CSQC_Ent_Update (enttype: %d, edict: %d, classname: %s)\n"), self.enttype, num_for_edict(self), self.classname));
index cbda9dcdd5232bfbb6d50753844cddcaf996c18a..1aa635b455c3bd4395c49b9c7d66611ebf332a33 100644 (file)
@@ -95,7 +95,8 @@ const float ENT_CLIENT_WARPZONE_TELEPORTED = 32;
 const float ENT_CLIENT_MODEL = 33;
 const float ENT_CLIENT_ITEM = 34;
 const float ENT_CLIENT_BUMBLE_RAYGUN = 35;
-const float ENT_CLIENT_NOTIFICATION = 36;
+const float ENT_CLIENT_SPAWNPOINT = 36;
+const float ENT_CLIENT_NOTIFICATION = 37;
 
 const float ENT_CLIENT_TURRET = 40;
 const float ENT_CLIENT_AUXILIARYXHAIR = 50;
index 075280c264e2094c8ecd40785ad946c00736dec2..f99bdec56b550ac99b6e231537de9bcd41388937 100644 (file)
@@ -74,239 +74,8 @@ void ClientData_Touch(entity e)
        }
 }
 
-
-.vector spawnpoint_score;
 .string netname_previous;
 
-void spawnfunc_info_player_survivor (void)
-{
-       spawnfunc_info_player_deathmatch();
-}
-
-void spawnfunc_info_player_start (void)
-{
-       spawnfunc_info_player_deathmatch();
-}
-
-void spawnfunc_info_player_deathmatch (void)
-{
-       self.classname = "info_player_deathmatch";
-       relocate_spawnpoint();
-}
-
-void spawnpoint_use()
-{
-       if(teamplay)
-       if(have_team_spawns > 0)
-       {
-               self.team = activator.team;
-               some_spawn_has_been_used = 1;
-       }
-}
-
-// Returns:
-//   _x: prio (-1 if unusable)
-//   _y: weight
-vector Spawn_Score(entity spot, float mindist, float teamcheck)
-{
-       float shortest, thisdist;
-       float prio;
-       entity player;
-
-       prio = 0;
-
-       // filter out spots for the wrong team
-       if(teamcheck >= 0)
-               if(spot.team != teamcheck)
-                       return '-1 0 0';
-
-       if(race_spawns)
-               if(spot.target == "")
-                       return '-1 0 0';
-
-       if(clienttype(self) == CLIENTTYPE_REAL)
-       {
-               if(spot.restriction == 1)
-                       return '-1 0 0';
-       }
-       else
-       {
-               if(spot.restriction == 2)
-                       return '-1 0 0';
-       }
-
-       shortest = vlen(world.maxs - world.mins);
-       FOR_EACH_PLAYER(player) if (player != self)
-       {
-               thisdist = vlen(player.origin - spot.origin);
-               if (thisdist < shortest)
-                       shortest = thisdist;
-       }
-       if(shortest > mindist)
-               prio += SPAWN_PRIO_GOOD_DISTANCE;
-
-       spawn_score = prio * '1 0 0' + shortest * '0 1 0';
-       spawn_spot = spot;
-
-       // filter out spots for assault
-       if(spot.target != "") {
-               entity ent;
-               float found;
-
-               found = 0;
-               for(ent = world; (ent = find(ent, targetname, spot.target)); )
-               {
-                       ++found;
-                       if(ent.spawn_evalfunc)
-                       {
-                               entity oldself = self;
-                               self = ent;
-                               spawn_score = ent.spawn_evalfunc(oldself, spot, spawn_score);
-                               self = oldself;
-                               if(spawn_score_x < 0)
-                                       return spawn_score;
-                       }
-               }
-
-               if(!found)
-               {
-                       dprint("WARNING: spawnpoint at ", vtos(spot.origin), " could not find its target ", spot.target, "\n");
-                       return '-1 0 0';
-               }
-       }
-
-       MUTATOR_CALLHOOK(Spawn_Score);
-       return spawn_score;
-}
-
-void Spawn_ScoreAll(entity firstspot, float mindist, float teamcheck)
-{
-       entity spot;
-       for(spot = firstspot; spot; spot = spot.chain)
-               spot.spawnpoint_score = Spawn_Score(spot, mindist, teamcheck);
-}
-
-entity Spawn_FilterOutBadSpots(entity firstspot, float mindist, float teamcheck)
-{
-       entity spot, spotlist, spotlistend;
-
-       spotlist = world;
-       spotlistend = world;
-
-       Spawn_ScoreAll(firstspot, mindist, teamcheck);
-
-       for(spot = firstspot; spot; spot = spot.chain)
-       {
-               if(spot.spawnpoint_score_x >= 0) // spawning allowed here
-               {
-                       if(spotlistend)
-                               spotlistend.chain = spot;
-                       spotlistend = spot;
-                       if(!spotlist)
-                               spotlist = spot;
-               }
-       }
-       if(spotlistend)
-               spotlistend.chain = world;
-
-       return spotlist;
-}
-
-entity Spawn_WeightedPoint(entity firstspot, float lower, float upper, float exponent)
-{
-       // weight of a point: bound(lower, mindisttoplayer, upper)^exponent
-       // multiplied by spot.cnt (useful if you distribute many spawnpoints in a small area)
-       entity spot;
-
-       RandomSelection_Init();
-       for(spot = firstspot; spot; spot = spot.chain)
-               RandomSelection_Add(spot, 0, string_null, pow(bound(lower, spot.spawnpoint_score_y, upper), exponent) * spot.cnt, (spot.spawnpoint_score_y >= lower) * 0.5 + spot.spawnpoint_score_x);
-
-       return RandomSelection_chosen_ent;
-}
-
-/*
-=============
-SelectSpawnPoint
-
-Finds a point to respawn
-=============
-*/
-entity SelectSpawnPoint (float anypoint)
-{
-       float teamcheck;
-       entity spot, firstspot;
-
-       spot = find (world, classname, "testplayerstart");
-       if (spot)
-               return spot;
-
-       if(anypoint || autocvar_g_spawn_useallspawns)
-               teamcheck = -1;
-       else if(have_team_spawns > 0)
-       {
-               if(have_team_spawns_forteam[self.team] == 0)
-               {
-                       // we request a spawn for a team, and we have team
-                       // spawns, but that team has no spawns?
-                       if(have_team_spawns_forteam[0])
-                               // try noteam spawns
-                               teamcheck = 0;
-                       else
-                               // if not, any spawn has to do
-                               teamcheck = -1;
-               }
-               else
-                       teamcheck = self.team; // MUST be team
-       }
-       else if(have_team_spawns == 0 && have_team_spawns_forteam[0])
-               teamcheck = 0; // MUST be noteam
-       else
-               teamcheck = -1;
-               // if we get here, we either require team spawns but have none, or we require non-team spawns and have none; use any spawn then
-
-
-       // get the entire list of spots
-       firstspot = findchain(classname, "info_player_deathmatch");
-       // filter out the bad ones
-       // (note this returns the original list if none survived)
-       if(anypoint)
-       {
-               spot = Spawn_WeightedPoint(firstspot, 1, 1, 1);
-       }
-       else
-       {
-               float mindist;
-               if (g_arena && arena_roundbased)
-                       mindist = 800;
-               else
-                       mindist = 100;
-               firstspot = Spawn_FilterOutBadSpots(firstspot, mindist, teamcheck);
-
-               // there is 50/50 chance of choosing a random spot or the furthest spot
-               // (this means that roughly every other spawn will be furthest, so you
-               // usually won't get fragged at spawn twice in a row)
-               if (random() > autocvar_g_spawn_furthest)
-                       spot = Spawn_WeightedPoint(firstspot, 1, 1, 1);
-               else
-                       spot = Spawn_WeightedPoint(firstspot, 1, 5000, 5); // chooses a far far away spawnpoint
-       }
-
-       if (!spot)
-       {
-               if(autocvar_spawn_debug)
-                       GotoNextMap(0);
-               else
-               {
-                       if(some_spawn_has_been_used)
-                               return world; // team can't spawn any more, because of actions of other team
-                       else
-                               error("Cannot find a spawn point - please fix the map!");
-               }
-       }
-
-       return spot;
-}
 
 /*
 =============
index 13eb647dbdeb36d83aeebb371d88a44e4bcef1f4..e79fb5a4e9a0eceb3f9c0cb7a02e46c62a104ba9 100644 (file)
@@ -155,63 +155,6 @@ void GameLogClose()
     }
 }
 
-float spawnpoint_nag;
-void relocate_spawnpoint()
-{
-    // nudge off the floor
-    setorigin(self, self.origin + '0 0 1');
-
-    tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
-    if (trace_startsolid)
-    {
-        vector o;
-        o = self.origin;
-        self.mins = PL_MIN;
-        self.maxs = PL_MAX;
-        if (!move_out_of_solid(self))
-            objerror("could not get out of solid at all!");
-        print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
-        print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
-        print(" ", ftos(self.origin_y - o_y));
-        print(" ", ftos(self.origin_z - o_z), "'\n");
-        if (autocvar_g_spawnpoints_auto_move_out_of_solid)
-        {
-            if (!spawnpoint_nag)
-                print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
-            spawnpoint_nag = 1;
-        }
-        else
-        {
-            setorigin(self, o);
-            self.mins = self.maxs = '0 0 0';
-            objerror("player spawn point in solid, mapper sucks!\n");
-            return;
-        }
-    }
-
-    self.use = spawnpoint_use;
-    self.team_saved = self.team;
-    if (!self.cnt)
-        self.cnt = 1;
-
-    if (have_team_spawns != 0)
-        if (self.team)
-            have_team_spawns = 1;
-    have_team_spawns_forteam[self.team] = 1;
-
-    if (autocvar_r_showbboxes)
-    {
-        // show where spawnpoints point at too
-        makevectors(self.angles);
-        entity e;
-        e = spawn();
-        e.classname = "info_player_foo";
-        setorigin(e, self.origin + v_forward * 24);
-        setsize(e, '-8 -8 -8', '8 8 8');
-        e.solid = SOLID_TRIGGER;
-    }
-}
-
 #define strstr strstrofs
 /*
 // NOTE: DO NOT USE THIS FUNCTION TOO OFTEN.
index b3cc22ddaa7a785c9a44472025a74e1b0cde3cb3..b7d8ad7b5d8901eb69f83f1fa12eb81cc6fb78e6 100644 (file)
@@ -81,6 +81,8 @@ w_laser.qh
 
 scores.qh
 
+spawnpoints.qh
+
 ipban.qh
 
 race.qh
@@ -197,6 +199,8 @@ vehicles/vehicles.qh
 
 scores.qc
 
+spawnpoints.qc
+
 portals.qc
 
 target_spawn.qc
diff --git a/qcsrc/server/spawnpoints.qc b/qcsrc/server/spawnpoints.qc
new file mode 100644 (file)
index 0000000..6dd97f4
--- /dev/null
@@ -0,0 +1,327 @@
+float Spawn_Send(entity to, float sf)
+{
+       WriteByte(MSG_ENTITY, ENT_CLIENT_SPAWNPOINT);
+       WriteByte(MSG_ENTITY, sf);
+       
+       if(sf & 1)
+       {
+               WriteByte(MSG_ENTITY, self.team);
+               WriteShort(MSG_ENTITY, self.origin_x);
+               WriteShort(MSG_ENTITY, self.origin_y);
+               WriteShort(MSG_ENTITY, self.origin_z);
+       }
+       if(sf & 2)
+       {
+               WriteLong(MSG_ENTITY, self.last_spawn_time);
+       }
+       
+       return TRUE;
+}
+
+void Spawn_Think(void)
+{
+       self.nextthink = 0;
+       if(self.send_spawn < 0)
+       {
+               self.SendFlags |= 1;
+       }
+       else
+       {
+               self.last_spawn_time = self.send_spawn;
+               self.SendFlags |= 2;
+       }
+}
+
+void spawnpoint_use()
+{
+       if(teamplay)
+       if(have_team_spawns > 0)
+       {
+               self.team = activator.team;
+               some_spawn_has_been_used = 1;
+       }
+       print("spawnpoint was used!\n");
+       self.send_spawn = time;
+       self.nextthink = time;
+}
+
+void relocate_spawnpoint()
+{
+    // nudge off the floor
+    setorigin(self, self.origin + '0 0 1');
+
+    tracebox(self.origin, PL_MIN, PL_MAX, self.origin, TRUE, self);
+    if (trace_startsolid)
+    {
+        vector o;
+        o = self.origin;
+        self.mins = PL_MIN;
+        self.maxs = PL_MAX;
+        if (!move_out_of_solid(self))
+            objerror("could not get out of solid at all!");
+        print("^1NOTE: this map needs FIXING. Spawnpoint at ", vtos(o - '0 0 1'));
+        print(" needs to be moved out of solid, e.g. by '", ftos(self.origin_x - o_x));
+        print(" ", ftos(self.origin_y - o_y));
+        print(" ", ftos(self.origin_z - o_z), "'\n");
+        if (autocvar_g_spawnpoints_auto_move_out_of_solid)
+        {
+            if (!spawnpoint_nag)
+                print("\{1}^1NOTE: this map needs FIXING (it contains spawnpoints in solid, see server log)\n");
+            spawnpoint_nag = 1;
+        }
+        else
+        {
+            setorigin(self, o);
+            self.mins = self.maxs = '0 0 0';
+            objerror("player spawn point in solid, mapper sucks!\n");
+            return;
+        }
+    }
+
+    self.use = spawnpoint_use;
+    self.team_saved = self.team;
+    if (!self.cnt)
+        self.cnt = 1;
+
+    if (have_team_spawns != 0)
+        if (self.team)
+            have_team_spawns = 1;
+    have_team_spawns_forteam[self.team] = 1;
+
+    if (autocvar_r_showbboxes)
+    {
+        // show where spawnpoints point at too
+        makevectors(self.angles);
+        entity e;
+        e = spawn();
+        e.classname = "info_player_foo";
+        setorigin(e, self.origin + v_forward * 24);
+        setsize(e, '-8 -8 -8', '8 8 8');
+        e.solid = SOLID_TRIGGER;
+    }
+
+       self.think = Spawn_Think;
+       self.nextthink = time;
+
+    Net_LinkEntity(self, FALSE, 0, Spawn_Send);
+}
+
+void spawnfunc_info_player_survivor (void)
+{
+       spawnfunc_info_player_deathmatch();
+}
+
+void spawnfunc_info_player_start (void)
+{
+       spawnfunc_info_player_deathmatch();
+}
+
+void spawnfunc_info_player_deathmatch (void)
+{
+       self.classname = "info_player_deathmatch";
+       relocate_spawnpoint();
+}
+
+// Returns:
+//   _x: prio (-1 if unusable)
+//   _y: weight
+vector Spawn_Score(entity spot, float mindist, float teamcheck)
+{
+       float shortest, thisdist;
+       float prio;
+       entity player;
+
+       prio = 0;
+
+       // filter out spots for the wrong team
+       if(teamcheck >= 0)
+               if(spot.team != teamcheck)
+                       return '-1 0 0';
+
+       if(race_spawns)
+               if(spot.target == "")
+                       return '-1 0 0';
+
+       if(clienttype(self) == CLIENTTYPE_REAL)
+       {
+               if(spot.restriction == 1)
+                       return '-1 0 0';
+       }
+       else
+       {
+               if(spot.restriction == 2)
+                       return '-1 0 0';
+       }
+
+       shortest = vlen(world.maxs - world.mins);
+       FOR_EACH_PLAYER(player) if (player != self)
+       {
+               thisdist = vlen(player.origin - spot.origin);
+               if (thisdist < shortest)
+                       shortest = thisdist;
+       }
+       if(shortest > mindist)
+               prio += SPAWN_PRIO_GOOD_DISTANCE;
+
+       spawn_score = prio * '1 0 0' + shortest * '0 1 0';
+       spawn_spot = spot;
+
+       // filter out spots for assault
+       if(spot.target != "") {
+               entity ent;
+               float found;
+
+               found = 0;
+               for(ent = world; (ent = find(ent, targetname, spot.target)); )
+               {
+                       ++found;
+                       if(ent.spawn_evalfunc)
+                       {
+                               entity oldself = self;
+                               self = ent;
+                               spawn_score = ent.spawn_evalfunc(oldself, spot, spawn_score);
+                               self = oldself;
+                               if(spawn_score_x < 0)
+                                       return spawn_score;
+                       }
+               }
+
+               if(!found)
+               {
+                       dprint("WARNING: spawnpoint at ", vtos(spot.origin), " could not find its target ", spot.target, "\n");
+                       return '-1 0 0';
+               }
+       }
+
+       MUTATOR_CALLHOOK(Spawn_Score);
+       return spawn_score;
+}
+
+void Spawn_ScoreAll(entity firstspot, float mindist, float teamcheck)
+{
+       entity spot;
+       for(spot = firstspot; spot; spot = spot.chain)
+               spot.spawnpoint_score = Spawn_Score(spot, mindist, teamcheck);
+}
+
+entity Spawn_FilterOutBadSpots(entity firstspot, float mindist, float teamcheck)
+{
+       entity spot, spotlist, spotlistend;
+
+       spotlist = world;
+       spotlistend = world;
+
+       Spawn_ScoreAll(firstspot, mindist, teamcheck);
+
+       for(spot = firstspot; spot; spot = spot.chain)
+       {
+               if(spot.spawnpoint_score_x >= 0) // spawning allowed here
+               {
+                       if(spotlistend)
+                               spotlistend.chain = spot;
+                       spotlistend = spot;
+                       if(!spotlist)
+                               spotlist = spot;
+               }
+       }
+       if(spotlistend)
+               spotlistend.chain = world;
+
+       return spotlist;
+}
+
+entity Spawn_WeightedPoint(entity firstspot, float lower, float upper, float exponent)
+{
+       // weight of a point: bound(lower, mindisttoplayer, upper)^exponent
+       // multiplied by spot.cnt (useful if you distribute many spawnpoints in a small area)
+       entity spot;
+
+       RandomSelection_Init();
+       for(spot = firstspot; spot; spot = spot.chain)
+               RandomSelection_Add(spot, 0, string_null, pow(bound(lower, spot.spawnpoint_score_y, upper), exponent) * spot.cnt, (spot.spawnpoint_score_y >= lower) * 0.5 + spot.spawnpoint_score_x);
+
+       return RandomSelection_chosen_ent;
+}
+
+/*
+=============
+SelectSpawnPoint
+
+Finds a point to respawn
+=============
+*/
+entity SelectSpawnPoint (float anypoint)
+{
+       float teamcheck;
+       entity spot, firstspot;
+
+       spot = find (world, classname, "testplayerstart");
+       if (spot)
+               return spot;
+
+       if(anypoint || autocvar_g_spawn_useallspawns)
+               teamcheck = -1;
+       else if(have_team_spawns > 0)
+       {
+               if(have_team_spawns_forteam[self.team] == 0)
+               {
+                       // we request a spawn for a team, and we have team
+                       // spawns, but that team has no spawns?
+                       if(have_team_spawns_forteam[0])
+                               // try noteam spawns
+                               teamcheck = 0;
+                       else
+                               // if not, any spawn has to do
+                               teamcheck = -1;
+               }
+               else
+                       teamcheck = self.team; // MUST be team
+       }
+       else if(have_team_spawns == 0 && have_team_spawns_forteam[0])
+               teamcheck = 0; // MUST be noteam
+       else
+               teamcheck = -1;
+               // if we get here, we either require team spawns but have none, or we require non-team spawns and have none; use any spawn then
+
+
+       // get the entire list of spots
+       firstspot = findchain(classname, "info_player_deathmatch");
+       // filter out the bad ones
+       // (note this returns the original list if none survived)
+       if(anypoint)
+       {
+               spot = Spawn_WeightedPoint(firstspot, 1, 1, 1);
+       }
+       else
+       {
+               float mindist;
+               if(g_arena && arena_roundbased)
+                       mindist = 800;
+               else
+                       mindist = 100;
+               firstspot = Spawn_FilterOutBadSpots(firstspot, mindist, teamcheck);
+
+               // there is 50/50 chance of choosing a random spot or the furthest spot
+               // (this means that roughly every other spawn will be furthest, so you
+               // usually won't get fragged at spawn twice in a row)
+               if (random() > autocvar_g_spawn_furthest)
+                       spot = Spawn_WeightedPoint(firstspot, 1, 1, 1);
+               else
+                       spot = Spawn_WeightedPoint(firstspot, 1, 5000, 5); // chooses a far far away spawnpoint
+       }
+
+       if (!spot)
+       {
+               if(autocvar_spawn_debug)
+                       GotoNextMap(0);
+               else
+               {
+                       if(some_spawn_has_been_used)
+                               return world; // team can't spawn any more, because of actions of other team
+                       else
+                               error("Cannot find a spawn point - please fix the map!");
+               }
+       }
+
+       return spot;
+}
diff --git a/qcsrc/server/spawnpoints.qh b/qcsrc/server/spawnpoints.qh
new file mode 100644 (file)
index 0000000..b256f4c
--- /dev/null
@@ -0,0 +1,12 @@
+.vector spawnpoint_score;
+float spawnpoint_nag;
+//void spawnpoint_use();
+//void relocate_spawnpoint();
+//void spawnfunc_info_player_survivor (void);
+//void spawnfunc_info_player_start (void);
+//void spawnfunc_info_player_deathmatch (void);
+//vector Spawn_Score(entity spot, float mindist, float teamcheck);
+//void Spawn_ScoreAll(entity firstspot, float mindist, float teamcheck);
+entity Spawn_FilterOutBadSpots(entity firstspot, float mindist, float teamcheck);
+//entity Spawn_WeightedPoint(entity firstspot, float lower, float upper, float exponent);
+//entity SelectSpawnPoint (float anypoint);