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

This commit is contained in:
Thilo Schulz 2009-11-03 13:28:52 +00:00
parent 018de1dd2e
commit f5d79ea066
6 changed files with 89 additions and 62 deletions

View file

@ -625,7 +625,7 @@ void ClientEvents( gentity_t *ent, int oldEventSequence ) {
} }
} }
#endif #endif
SelectSpawnPoint( ent->client->ps.origin, origin, angles ); SelectSpawnPoint( ent->client->ps.origin, origin, angles, qfalse );
TeleportPlayer( ent, origin, angles ); TeleportPlayer( ent, origin, angles );
break; break;

View file

@ -140,7 +140,7 @@ go to a random point that doesn't telefrag
================ ================
*/ */
#define MAX_SPAWN_POINTS 128 #define MAX_SPAWN_POINTS 128
gentity_t *SelectRandomDeathmatchSpawnPoint( void ) { gentity_t *SelectRandomDeathmatchSpawnPoint(qboolean isbot) {
gentity_t *spot; gentity_t *spot;
int count; int count;
int selection; int selection;
@ -149,10 +149,18 @@ gentity_t *SelectRandomDeathmatchSpawnPoint( void ) {
count = 0; count = 0;
spot = NULL; spot = NULL;
while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { while((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL && count < MAX_SPAWN_POINTS)
if ( SpotWouldTelefrag( spot ) ) { {
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; continue;
} }
spots[count] = spot; spots[count] = spot;
count++; count++;
} }
@ -172,49 +180,68 @@ SelectRandomFurthestSpawnPoint
Chooses a player start, deathmatch start, etc 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; gentity_t *spot;
vec3_t delta; vec3_t delta;
float dist; float dist;
float list_dist[64]; float list_dist[MAX_SPAWN_POINTS];
gentity_t *list_spot[64]; gentity_t *list_spot[MAX_SPAWN_POINTS];
int numSpots, rnd, i, j; int numSpots, rnd, i, j;
numSpots = 0; numSpots = 0;
spot = NULL; spot = NULL;
while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { while((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
if ( SpotWouldTelefrag( spot ) ) { {
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; continue;
} }
VectorSubtract( spot->s.origin, avoidPoint, delta ); VectorSubtract( spot->s.origin, avoidPoint, delta );
dist = VectorLength( delta ); dist = VectorLength( delta );
for (i = 0; i < numSpots; i++) {
if ( dist > list_dist[i] ) { for (i = 0; i < numSpots; i++)
if ( numSpots >= 64 ) {
numSpots = 64-1; if(dist > list_dist[i])
for (j = numSpots; j > i; j--) { {
if (numSpots >= MAX_SPAWN_POINTS)
numSpots = MAX_SPAWN_POINTS - 1;
for(j = numSpots; j > i; j--)
{
list_dist[j] = list_dist[j-1]; list_dist[j] = list_dist[j-1];
list_spot[j] = list_spot[j-1]; list_spot[j] = list_spot[j-1];
} }
list_dist[i] = dist; list_dist[i] = dist;
list_spot[i] = spot; list_spot[i] = spot;
numSpots++; numSpots++;
if (numSpots > 64)
numSpots = 64;
break; break;
} }
} }
if (i >= numSpots && numSpots < 64) {
if(i >= numSpots && numSpots < MAX_SPAWN_POINTS)
{
list_dist[numSpots] = dist; list_dist[numSpots] = dist;
list_spot[numSpots] = spot; list_spot[numSpots] = spot;
numSpots++; numSpots++;
} }
} }
if (!numSpots) {
if(!numSpots)
{
spot = G_Find(NULL, FOFS(classname), "info_player_deathmatch"); spot = G_Find(NULL, FOFS(classname), "info_player_deathmatch");
if (!spot) if (!spot)
G_Error( "Couldn't find a spawn point" ); G_Error( "Couldn't find a spawn point" );
VectorCopy (spot->s.origin, origin); VectorCopy (spot->s.origin, origin);
origin[2] += 9; origin[2] += 9;
VectorCopy (spot->s.angles, angles); VectorCopy (spot->s.angles, angles);
@ -238,8 +265,8 @@ SelectSpawnPoint
Chooses a player start, deathmatch start, etc Chooses a player start, deathmatch start, etc
============ ============
*/ */
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 ) {
return SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles ); return SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles, isbot );
/* /*
gentity_t *spot; gentity_t *spot;
@ -278,20 +305,26 @@ Try to find a spawn point marked 'initial', otherwise
use normal spawn selection. 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; gentity_t *spot;
spot = NULL; spot = NULL;
while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) {
if ( spot->spawnflags & 1 ) { while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL)
break; {
} if(((spot->flags & FL_NO_BOTS) && isbot) ||
((spot->flags & FL_NO_HUMANS) && !isbot))
{
continue;
} }
if ( !spot || SpotWouldTelefrag( spot ) ) { if((spot->spawnflags & 0x01))
return SelectSpawnPoint( vec3_origin, origin, angles ); break;
} }
if (!spot || SpotWouldTelefrag(spot))
return SelectSpawnPoint(vec3_origin, origin, angles, isbot);
VectorCopy (spot->s.origin, origin); VectorCopy (spot->s.origin, origin);
origin[2] += 9; origin[2] += 9;
VectorCopy (spot->s.angles, angles); VectorCopy (spot->s.angles, angles);
@ -1050,6 +1083,8 @@ void ClientSpawn(gentity_t *ent) {
index = ent - g_entities; index = ent - g_entities;
client = ent->client; client = ent->client;
VectorClear(spawn_origin);
// find a spawn point // find a spawn point
// do it before setting health back up, so farthest // do it before setting health back up, so farthest
// ranging doesn't count this client // ranging doesn't count this client
@ -1061,33 +1096,25 @@ void ClientSpawn(gentity_t *ent) {
spawnPoint = SelectCTFSpawnPoint ( spawnPoint = SelectCTFSpawnPoint (
client->sess.sessionTeam, client->sess.sessionTeam,
client->pers.teamState.state, client->pers.teamState.state,
spawn_origin, spawn_angles); spawn_origin, spawn_angles,
} else { !!(ent->r.svFlags & SVF_BOT));
do { }
else
{
// the first spawn should be at a good looking spot // the first spawn should be at a good looking spot
if ( !client->pers.initialSpawn && client->pers.localClient ) { if ( !client->pers.initialSpawn && client->pers.localClient )
{
client->pers.initialSpawn = qtrue; client->pers.initialSpawn = qtrue;
spawnPoint = SelectInitialSpawnPoint( spawn_origin, spawn_angles ); spawnPoint = SelectInitialSpawnPoint(spawn_origin, spawn_angles,
} else { !!(ent->r.svFlags & SVF_BOT));
}
else
{
// don't spawn near existing origin if possible // don't spawn near existing origin if possible
spawnPoint = SelectSpawnPoint ( spawnPoint = SelectSpawnPoint (
client->ps.origin, client->ps.origin,
spawn_origin, spawn_angles); spawn_origin, spawn_angles, !!(ent->r.svFlags & SVF_BOT));
} }
// 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 );
} }
client->pers.teamState.state = TEAM_ACTIVE; client->pers.teamState.state = TEAM_ACTIVE;

View file

@ -572,7 +572,7 @@ team_t TeamCount( int ignoreClientNum, int team );
int TeamLeader( int team ); int TeamLeader( int team );
team_t PickTeam( int ignoreClientNum ); team_t PickTeam( int ignoreClientNum );
void SetClientViewAngle( gentity_t *ent, vec3_t angle ); 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 CopyToBodyQue( gentity_t *ent );
void respawn (gentity_t *ent); void respawn (gentity_t *ent);
void BeginIntermission (void); void BeginIntermission (void);

View file

@ -934,7 +934,7 @@ void FindIntermissionPoint( void ) {
// find the intermission spot // find the intermission spot
ent = G_Find (NULL, FOFS(classname), "info_player_intermission"); ent = G_Find (NULL, FOFS(classname), "info_player_intermission");
if ( !ent ) { // the map creator forgot to put in an intermission point... 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 { } else {
VectorCopy (ent->s.origin, level.intermission_origin); VectorCopy (ent->s.origin, level.intermission_origin);
VectorCopy (ent->s.angles, level.intermission_angle); VectorCopy (ent->s.angles, level.intermission_angle);

View file

@ -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 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; gentity_t *spot;
spot = SelectRandomTeamSpawnPoint ( teamstate, team ); spot = SelectRandomTeamSpawnPoint ( teamstate, team );
if (!spot) { if (!spot) {
return SelectSpawnPoint( vec3_origin, origin, angles ); return SelectSpawnPoint( vec3_origin, origin, angles, isbot );
} }
VectorCopy (spot->s.origin, origin); VectorCopy (spot->s.origin, origin);

View file

@ -79,7 +79,7 @@ void Team_CheckHurtCarrier(gentity_t *targ, gentity_t *attacker);
void Team_InitGame(void); void Team_InitGame(void);
void Team_ReturnFlag(int team); void Team_ReturnFlag(int team);
void Team_FreeEntity(gentity_t *ent); 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); gentity_t *Team_GetLocation(gentity_t *ent);
qboolean Team_GetLocationMsg(gentity_t *ent, char *loc, int loclen); qboolean Team_GetLocationMsg(gentity_t *ent, char *loc, int loclen);
void TeamplayInfoMessage( gentity_t *ent ); void TeamplayInfoMessage( gentity_t *ent );