diff --git a/src/g_ai.c b/src/g_ai.c index 0037dff..78e87e3 100644 --- a/src/g_ai.c +++ b/src/g_ai.c @@ -1156,8 +1156,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 9dc39fc..d71f370 100644 --- a/src/g_misc.c +++ b/src/g_misc.c @@ -181,14 +181,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); @@ -478,14 +483,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 0e4c578..105de55 100644 --- a/src/g_utils.c +++ b/src/g_utils.c @@ -462,38 +462,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 767ad1f..e52a6c5 100644 --- a/src/header/local.h +++ b/src/header/local.h @@ -621,6 +621,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);