If no valid spawnpoints exist in the map, perform another check without targets,...
authorMario <mario.mario@y7mail.com>
Sat, 23 May 2020 15:00:11 +0000 (01:00 +1000)
committerMario <mario.mario@y7mail.com>
Sat, 23 May 2020 15:00:11 +0000 (01:00 +1000)
qcsrc/server/race.qc
qcsrc/server/spawnpoints.qc
qcsrc/server/spawnpoints.qh

index 9a12a04..32fdbba 100644 (file)
@@ -767,7 +767,7 @@ void trigger_race_checkpoint_verify(entity this)
                        // race only (middle of the race)
                        g_race_qualifying = false;
                        pl_race_place = 0;
-                       if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false)) {
+                       if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false, true)) {
                                error(strcat("Checkpoint ", ftos(i), " misses a spawnpoint with race_place==", ftos(pl_race_place), " (used for respawning in race) - bailing out"));
             }
 
@@ -775,7 +775,7 @@ void trigger_race_checkpoint_verify(entity this)
                                // qualifying only
                                g_race_qualifying = 1;
                                pl_race_place = race_lowest_place_spawn;
-                               if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false)) {
+                               if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false, true)) {
                                        error(strcat("Checkpoint ", ftos(i), " misses a spawnpoint with race_place==", ftos(pl_race_place), " (used for qualifying) - bailing out"));
                 }
 
@@ -783,7 +783,7 @@ void trigger_race_checkpoint_verify(entity this)
                                g_race_qualifying = 0;
                                for (int p = 1; p <= race_highest_place_spawn; ++p) {
                                        pl_race_place = p;
-                                       if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false)) {
+                                       if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false, true)) {
                                                error(strcat("Checkpoint ", ftos(i), " misses a spawnpoint with race_place==", ftos(pl_race_place), " (used for initially spawning in race) - bailing out"));
                     }
                                }
@@ -794,7 +794,7 @@ void trigger_race_checkpoint_verify(entity this)
                pl_race_checkpoint = race_NextCheckpoint(0);
                g_race_qualifying = 1;
                pl_race_place = race_lowest_place_spawn;
-               if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false)) {
+               if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false, true)) {
                        error(strcat("Checkpoint 0 misses a spawnpoint with race_place==", ftos(pl_race_place), " (used for qualifying) - bailing out"));
         }
        } else {
index e2c5ab3..616824b 100644 (file)
@@ -222,7 +222,7 @@ spawnfunc(info_player_team4)
 // Returns:
 //   _x: prio (-1 if unusable)
 //   _y: weight
-vector Spawn_Score(entity this, entity spot, float mindist, float teamcheck)
+vector Spawn_Score(entity this, entity spot, float mindist, float teamcheck, bool targetcheck)
 {
        // filter out spots for the wrong team
        if(teamcheck >= 0)
@@ -230,7 +230,7 @@ vector Spawn_Score(entity this, entity spot, float mindist, float teamcheck)
                        return '-1 0 0';
 
        if(race_spawns)
-               if(spot.target == "")
+               if(!spot.target || spot.target == "")
                        return '-1 0 0';
 
        if(IS_REAL_CLIENT(this))
@@ -257,7 +257,7 @@ vector Spawn_Score(entity this, entity spot, float mindist, float teamcheck)
        vector spawn_score = prio * '1 0 0' + shortest * '0 1 0';
 
        // filter out spots for assault
-       if(spot.target && spot.target != "")
+       if(spot.target && spot.target != "" && targetcheck)
        {
                int found = 0;
                for(entity targ = findchain(targetname, spot.target); targ; targ = targ.chain)
@@ -283,21 +283,21 @@ vector Spawn_Score(entity this, entity spot, float mindist, float teamcheck)
        return spawn_score;
 }
 
-void Spawn_ScoreAll(entity this, entity firstspot, float mindist, float teamcheck)
+void Spawn_ScoreAll(entity this, entity firstspot, float mindist, float teamcheck, bool targetcheck)
 {
        entity spot;
        for(spot = firstspot; spot; spot = spot.chain)
-               spot.spawnpoint_score = Spawn_Score(this, spot, mindist, teamcheck);
+               spot.spawnpoint_score = Spawn_Score(this, spot, mindist, teamcheck, targetcheck);
 }
 
-entity Spawn_FilterOutBadSpots(entity this, entity firstspot, float mindist, float teamcheck)
+entity Spawn_FilterOutBadSpots(entity this, entity firstspot, float mindist, float teamcheck, bool targetcheck)
 {
        entity spot, spotlist, spotlistend;
 
        spotlist = NULL;
        spotlistend = NULL;
 
-       Spawn_ScoreAll(this, firstspot, mindist, teamcheck);
+       Spawn_ScoreAll(this, firstspot, mindist, teamcheck, targetcheck);
 
        for(spot = firstspot; spot; spot = spot.chain)
        {
@@ -399,7 +399,23 @@ entity SelectSpawnPoint(entity this, bool anypoint)
        }
        else
        {
-               firstspot = Spawn_FilterOutBadSpots(this, firstspot, 100, teamcheck);
+               firstspot = Spawn_FilterOutBadSpots(this, firstspot, 100, teamcheck, true);
+
+               // emergency fallback! double check without targets
+               // fixes some crashes with improperly repacked maps
+               if(!firstspot)
+               {
+                       firstspot = IL_FIRST(g_spawnpoints);
+                       prev = NULL;
+                       IL_EACH(g_spawnpoints, true,
+                       {
+                               if(prev)
+                                       prev.chain = it;
+                               it.chain = NULL;
+                               prev = it;
+                       });
+                       firstspot = Spawn_FilterOutBadSpots(this, firstspot, 100, teamcheck, false);
+               }
 
                // 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
index 92af8df..fe6adae 100644 (file)
@@ -9,7 +9,7 @@ const int SPAWN_PRIO_GOOD_DISTANCE = 10;
 .vector spawnpoint_score;
 float spawnpoint_nag;
 bool SpawnEvent_Send(entity this, entity to, int sf);
-entity Spawn_FilterOutBadSpots(entity this, entity firstspot, float mindist, float teamcheck);
+entity Spawn_FilterOutBadSpots(entity this, entity firstspot, float mindist, float teamcheck, bool targetcheck);
 entity SelectSpawnPoint(entity this, bool anypoint);
 spawnfunc(info_player_deathmatch);
 void spawnpoint_use(entity this, entity actor, entity trigger);