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
SelectSpawnPoint( ent->client->ps.origin, origin, angles );
SelectSpawnPoint( ent->client->ps.origin, origin, angles, qfalse );
TeleportPlayer( ent, origin, angles );
break;

View file

@ -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;

View file

@ -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);

View file

@ -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);

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
================
@ -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);

View file

@ -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 );