diff --git a/src/g_ai.c b/src/g_ai.c index f9bf069..5a0d43f 100644 --- a/src/g_ai.c +++ b/src/g_ai.c @@ -1596,8 +1596,15 @@ ai_run(edict_t *self, float dist) return; } + tempgoal = G_SpawnOptional(); + + if (!tempgoal) + { + M_MoveToGoal(self, dist); + return; + } + save = self->goalentity; - tempgoal = G_Spawn(); self->goalentity = tempgoal; new = false; diff --git a/src/g_misc.c b/src/g_misc.c index 59e9625..2dfb34a 100644 --- a/src/g_misc.c +++ b/src/g_misc.c @@ -178,14 +178,19 @@ ThrowGib(edict_t *self, char *gibname, int damage, int type) return; } - gibsthisframe++; - if (gibsthisframe > MAX_GIBS) { return; } - gib = G_Spawn(); + gib = G_SpawnOptional(); + + if (!gib) + { + return; + } + + gibsthisframe++; VectorScale(self->size, 0.5, size); VectorAdd(self->absmin, size, origin); @@ -353,14 +358,20 @@ ThrowDebris(edict_t *self, char *modelname, float speed, vec3_t origin) return; } - debristhisframe++; - if (debristhisframe > MAX_DEBRIS) { return; } - chunk = G_Spawn(); + chunk = G_SpawnOptional(); + + if (!chunk) + { + return; + } + + debristhisframe++; + VectorCopy(origin, chunk->s.origin); gi.setmodel(chunk, modelname); v[0] = 100 * crandom(); diff --git a/src/g_utils.c b/src/g_utils.c index 5f20871..ca3f008 100644 --- a/src/g_utils.c +++ b/src/g_utils.c @@ -669,40 +669,66 @@ G_InitEdict(edict_t *e) } /* - * Either finds a free edict, or allocates a new one. - * Try to avoid reusing an entity that was recently freed, - * because it can cause the client to think the entity - * morphed into something else instead of being removed - * and recreated, which can cause interpolated angles and - * bad trails. + * Either finds a free edict, or allocates a + * new one. Try to avoid reusing an entity + * that was recently freed, because it can + * cause the client to think the entity + * morphed into something else instead of + * being removed and recreated, which can + * cause interpolated angles and bad trails. */ -edict_t * -G_Spawn(void) +#define POLICY_DEFAULT 0 +#define POLICY_DESPERATE 1 + +static edict_t * +G_FindFreeEdict(int policy) { - int i; edict_t *e; - e = &g_edicts[(int)maxclients->value + 1]; - - for (i = maxclients->value + 1; i < globals.num_edicts; i++, e++) + for (e = g_edicts + game.maxclients + 1 ; e < &g_edicts[globals.num_edicts] ; e++) { /* the first couple seconds of server time can involve a lot of - freeing and allocating, so relax the replacement policy */ - if (!e->inuse && - ((e->freetime < 2) || (level.time - e->freetime > 0.5))) + freeing and allocating, so relax the replacement policy + */ + if (!e->inuse && (policy == POLICY_DESPERATE || e->freetime < 2.0f || (level.time - e->freetime) > 0.5f)) { - G_InitEdict(e); + G_InitEdict (e); return e; } } - if (i == game.maxentities) + return NULL; +} + +edict_t * +G_SpawnOptional(void) +{ + edict_t *e = G_FindFreeEdict (POLICY_DEFAULT); + + if (e) { - gi.error("ED_Alloc: no free edicts"); + return e; } - globals.num_edicts++; - G_InitEdict(e); + if (globals.num_edicts >= game.maxentities) + { + return G_FindFreeEdict (POLICY_DESPERATE); + } + + e = &g_edicts[globals.num_edicts++]; + G_InitEdict (e); + + return e; +} + +edict_t * +G_Spawn(void) +{ + edict_t *e = G_SpawnOptional(); + + if (!e) + gi.error ("ED_Alloc: no free edicts"); + return e; } diff --git a/src/header/local.h b/src/header/local.h index ec37ed8..a32ec85 100644 --- a/src/header/local.h +++ b/src/header/local.h @@ -722,6 +722,7 @@ void G_UseTargets(edict_t *ent, edict_t *activator); void G_SetMovedir(vec3_t angles, vec3_t movedir); void G_InitEdict(edict_t *e); +edict_t *G_SpawnOptional(void); edict_t *G_Spawn(void); void G_FreeEdict(edict_t *e);