From f5d79ea066c1f742ff8c98dd5d9c484b9db122e3 Mon Sep 17 00:00:00 2001 From: Thilo Schulz Date: Tue, 3 Nov 2009 13:28:52 +0000 Subject: [PATCH] Fix bug where game freezes in infinite loop because it doesn't find a spawn point on maps with many bot/human-only spawnpoints. Thanks Pan for reporting this --- code/game/g_active.c | 2 +- code/game/g_client.c | 137 ++++++++++++++++++++++++++----------------- code/game/g_local.h | 2 +- code/game/g_main.c | 2 +- code/game/g_team.c | 6 +- code/game/g_team.h | 2 +- 6 files changed, 89 insertions(+), 62 deletions(-) diff --git a/code/game/g_active.c b/code/game/g_active.c index c830a5bd..aa48c80e 100644 --- a/code/game/g_active.c +++ b/code/game/g_active.c @@ -625,7 +625,7 @@ void ClientEvents( gentity_t *ent, int oldEventSequence ) { } } #endif - SelectSpawnPoint( ent->client->ps.origin, origin, angles ); + SelectSpawnPoint( ent->client->ps.origin, origin, angles, qfalse ); TeleportPlayer( ent, origin, angles ); break; diff --git a/code/game/g_client.c b/code/game/g_client.c index 7160e31d..1c9dbd73 100644 --- a/code/game/g_client.c +++ b/code/game/g_client.c @@ -140,7 +140,7 @@ go to a random point that doesn't telefrag ================ */ #define MAX_SPAWN_POINTS 128 -gentity_t *SelectRandomDeathmatchSpawnPoint( void ) { +gentity_t *SelectRandomDeathmatchSpawnPoint(qboolean isbot) { gentity_t *spot; int count; int selection; @@ -149,11 +149,19 @@ gentity_t *SelectRandomDeathmatchSpawnPoint( void ) { count = 0; spot = NULL; - while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { - if ( SpotWouldTelefrag( spot ) ) { + while((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL && count < MAX_SPAWN_POINTS) + { + if(SpotWouldTelefrag(spot)) + continue; + + if(((spot->flags & FL_NO_BOTS) && isbot) || + ((spot->flags & FL_NO_HUMANS) && !isbot)) + { + // spot is not for this human/bot player continue; } - spots[ count ] = spot; + + spots[count] = spot; count++; } @@ -172,49 +180,68 @@ SelectRandomFurthestSpawnPoint Chooses a player start, deathmatch start, etc ============ */ -gentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) { +gentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles, qboolean isbot ) { gentity_t *spot; vec3_t delta; float dist; - float list_dist[64]; - gentity_t *list_spot[64]; + float list_dist[MAX_SPAWN_POINTS]; + gentity_t *list_spot[MAX_SPAWN_POINTS]; int numSpots, rnd, i, j; numSpots = 0; spot = NULL; - while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { - if ( SpotWouldTelefrag( spot ) ) { + while((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) + { + if(SpotWouldTelefrag(spot)) + continue; + + if(((spot->flags & FL_NO_BOTS) && isbot) || + ((spot->flags & FL_NO_HUMANS) && !isbot)) + { + // spot is not for this human/bot player continue; } + VectorSubtract( spot->s.origin, avoidPoint, delta ); dist = VectorLength( delta ); - for (i = 0; i < numSpots; i++) { - if ( dist > list_dist[i] ) { - if ( numSpots >= 64 ) - numSpots = 64-1; - for (j = numSpots; j > i; j--) { + + for (i = 0; i < numSpots; i++) + { + if(dist > list_dist[i]) + { + if (numSpots >= MAX_SPAWN_POINTS) + numSpots = MAX_SPAWN_POINTS - 1; + + for(j = numSpots; j > i; j--) + { list_dist[j] = list_dist[j-1]; list_spot[j] = list_spot[j-1]; } + list_dist[i] = dist; list_spot[i] = spot; + numSpots++; - if (numSpots > 64) - numSpots = 64; break; } } - if (i >= numSpots && numSpots < 64) { + + if(i >= numSpots && numSpots < MAX_SPAWN_POINTS) + { list_dist[numSpots] = dist; list_spot[numSpots] = spot; numSpots++; } } - if (!numSpots) { - spot = G_Find( NULL, FOFS(classname), "info_player_deathmatch"); + + if(!numSpots) + { + spot = G_Find(NULL, FOFS(classname), "info_player_deathmatch"); + if (!spot) G_Error( "Couldn't find a spawn point" ); + VectorCopy (spot->s.origin, origin); origin[2] += 9; VectorCopy (spot->s.angles, angles); @@ -238,8 +265,8 @@ SelectSpawnPoint Chooses a player start, deathmatch start, etc ============ */ -gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) { - return SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles ); +gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles, qboolean isbot ) { + return SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles, isbot ); /* gentity_t *spot; @@ -278,19 +305,25 @@ Try to find a spawn point marked 'initial', otherwise use normal spawn selection. ============ */ -gentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles ) { +gentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles, qboolean isbot ) { gentity_t *spot; spot = NULL; - while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { - if ( spot->spawnflags & 1 ) { - break; + + while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) + { + if(((spot->flags & FL_NO_BOTS) && isbot) || + ((spot->flags & FL_NO_HUMANS) && !isbot)) + { + continue; } + + if((spot->spawnflags & 0x01)) + break; } - if ( !spot || SpotWouldTelefrag( spot ) ) { - return SelectSpawnPoint( vec3_origin, origin, angles ); - } + if (!spot || SpotWouldTelefrag(spot)) + return SelectSpawnPoint(vec3_origin, origin, angles, isbot); VectorCopy (spot->s.origin, origin); origin[2] += 9; @@ -1050,6 +1083,8 @@ void ClientSpawn(gentity_t *ent) { index = ent - g_entities; client = ent->client; + VectorClear(spawn_origin); + // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client @@ -1061,33 +1096,25 @@ void ClientSpawn(gentity_t *ent) { spawnPoint = SelectCTFSpawnPoint ( client->sess.sessionTeam, client->pers.teamState.state, - spawn_origin, spawn_angles); - } else { - do { - // the first spawn should be at a good looking spot - if ( !client->pers.initialSpawn && client->pers.localClient ) { - client->pers.initialSpawn = qtrue; - spawnPoint = SelectInitialSpawnPoint( spawn_origin, spawn_angles ); - } else { - // don't spawn near existing origin if possible - spawnPoint = SelectSpawnPoint ( - client->ps.origin, - spawn_origin, spawn_angles); - } - - // Tim needs to prevent bots from spawning at the initial point - // on q3dm0... - if ( ( spawnPoint->flags & FL_NO_BOTS ) && ( ent->r.svFlags & SVF_BOT ) ) { - continue; // try again - } - // just to be symetric, we have a nohumans option... - if ( ( spawnPoint->flags & FL_NO_HUMANS ) && !( ent->r.svFlags & SVF_BOT ) ) { - continue; // try again - } - - break; - - } while ( 1 ); + spawn_origin, spawn_angles, + !!(ent->r.svFlags & SVF_BOT)); + } + else + { + // the first spawn should be at a good looking spot + if ( !client->pers.initialSpawn && client->pers.localClient ) + { + client->pers.initialSpawn = qtrue; + spawnPoint = SelectInitialSpawnPoint(spawn_origin, spawn_angles, + !!(ent->r.svFlags & SVF_BOT)); + } + else + { + // don't spawn near existing origin if possible + spawnPoint = SelectSpawnPoint ( + client->ps.origin, + spawn_origin, spawn_angles, !!(ent->r.svFlags & SVF_BOT)); + } } client->pers.teamState.state = TEAM_ACTIVE; diff --git a/code/game/g_local.h b/code/game/g_local.h index 076ad525..3698a2c9 100644 --- a/code/game/g_local.h +++ b/code/game/g_local.h @@ -572,7 +572,7 @@ team_t TeamCount( int ignoreClientNum, int team ); int TeamLeader( int team ); team_t PickTeam( int ignoreClientNum ); void SetClientViewAngle( gentity_t *ent, vec3_t angle ); -gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ); +gentity_t *SelectSpawnPoint (vec3_t avoidPoint, vec3_t origin, vec3_t angles, qboolean isbot); void CopyToBodyQue( gentity_t *ent ); void respawn (gentity_t *ent); void BeginIntermission (void); diff --git a/code/game/g_main.c b/code/game/g_main.c index 5073fe0b..583479b3 100644 --- a/code/game/g_main.c +++ b/code/game/g_main.c @@ -934,7 +934,7 @@ void FindIntermissionPoint( void ) { // find the intermission spot ent = G_Find (NULL, FOFS(classname), "info_player_intermission"); if ( !ent ) { // the map creator forgot to put in an intermission point... - SelectSpawnPoint ( vec3_origin, level.intermission_origin, level.intermission_angle ); + SelectSpawnPoint ( vec3_origin, level.intermission_origin, level.intermission_angle, qfalse ); } else { VectorCopy (ent->s.origin, level.intermission_origin); VectorCopy (ent->s.angles, level.intermission_angle); diff --git a/code/game/g_team.c b/code/game/g_team.c index 4bcd5bd6..0191f55d 100644 --- a/code/game/g_team.c +++ b/code/game/g_team.c @@ -977,7 +977,7 @@ qboolean Team_GetLocationMsg(gentity_t *ent, char *loc, int loclen) /* ================ -SelectRandomDeathmatchSpawnPoint +SelectRandomTeamSpawnPoint go to a random point that doesn't telefrag ================ @@ -1033,13 +1033,13 @@ SelectCTFSpawnPoint ============ */ -gentity_t *SelectCTFSpawnPoint ( team_t team, int teamstate, vec3_t origin, vec3_t angles ) { +gentity_t *SelectCTFSpawnPoint ( team_t team, int teamstate, vec3_t origin, vec3_t angles, qboolean isbot ) { gentity_t *spot; spot = SelectRandomTeamSpawnPoint ( teamstate, team ); if (!spot) { - return SelectSpawnPoint( vec3_origin, origin, angles ); + return SelectSpawnPoint( vec3_origin, origin, angles, isbot ); } VectorCopy (spot->s.origin, origin); diff --git a/code/game/g_team.h b/code/game/g_team.h index d8aae28f..ca54caf8 100644 --- a/code/game/g_team.h +++ b/code/game/g_team.h @@ -79,7 +79,7 @@ void Team_CheckHurtCarrier(gentity_t *targ, gentity_t *attacker); void Team_InitGame(void); void Team_ReturnFlag(int team); void Team_FreeEntity(gentity_t *ent); -gentity_t *SelectCTFSpawnPoint ( team_t team, int teamstate, vec3_t origin, vec3_t angles ); +gentity_t *SelectCTFSpawnPoint ( team_t team, int teamstate, vec3_t origin, vec3_t angles, qboolean isbot ); gentity_t *Team_GetLocation(gentity_t *ent); qboolean Team_GetLocationMsg(gentity_t *ent, char *loc, int loclen); void TeamplayInfoMessage( gentity_t *ent );