/** * @brief Find valid actor spawn fields for this player. * @note Already used spawn-point are not found because ent->type is changed in G_ClientTeamInfo. * @param[in] player The player to spawn the actors for. * @param[in] spawnType The type of spawn-point so search for (ET_ACTORSPAWN or ET_ACTOR2x2SPAWN) * @return A pointer to a found spawn point or NULL if nothing was found or on error. */ static edict_t *G_ClientGetFreeSpawnPoint (const player_t * player, int spawnType) { edict_t *ent = NULL; /* Abort for non-spawnpoints */ assert(spawnType == ET_ACTORSPAWN || spawnType == ET_ACTOR2x2SPAWN); if (level.randomSpawn) { edict_t *list[MAX_EDICTS]; int count = 0; while ((ent = G_EdictsGetNext(ent))) if (ent->type == spawnType && player->pers.team == ent->team) { if (G_GetLivingActorFromPos(ent->pos)) continue; list[count++] = ent; } if (count) return list[rand() % count]; } else { while ((ent = G_EdictsGetNext(ent))) if (ent->type == spawnType && player->pers.team == ent->team) { if (G_GetLivingActorFromPos(ent->pos)) continue; return ent; } } return NULL; }
/** * @brief Iterate through the entities that are in use * @note we can hopefully get rid of this function once we know when it makes sense * to iterate through entities that are NOT in use * @param lastEnt The entity found in the previous iteration; if nullptr, we start at the beginning */ Edict* G_EdictsGetNextInUse (Edict* lastEnt) { Edict* ent = lastEnt; while ((ent = G_EdictsGetNext(ent))) { if (ent->inuse) break; } return ent; }
/** * @brief Searches the edict that has the given target as @c targetname set * @param target The target name of the edict that you are searching * @return @c NULL if no edict with the given target name was found, otherwise * the edict that has the targetname set you were looking for. */ edict_t *G_FindTargetEntity (const char *target) { edict_t *ent = NULL; while ((ent = G_EdictsGetNext(ent))) { const char *n = ent->targetname; if (n && Q_streq(n, target)) return ent; } return NULL; }
/** * @brief Find an entity that is not in use */ Edict* G_EdictsGetNewEdict (void) { Edict* ent = nullptr; /* try to recycle an edict */ while ((ent = G_EdictsGetNext(ent))) { if (!ent->inuse) return ent; } /* no unused edict found, create a new one */ ent = &g_edicts[globals.num_edicts]; globals.num_edicts++; if (globals.num_edicts > game.sv_maxentities) return nullptr; return ent; }
static void SVCmd_ListEdicts_f (void) { Edict* ent = nullptr; int i = 0; Com_Printf("number | entnum | mapnum | type | inuse | pnum | team | size | HP | state | classname | model/ptl | pos\n"); while ((ent = G_EdictsGetNext(ent))) { char buf[128]; const char* model; if (ent->type == ET_PARTICLE) model = ent->particle; else if (ent->model) model = ent->model; else model = "no mdl"; Com_sprintf(buf, sizeof(buf), "#%5i | #%5i | #%5i | %4i | %5i | %4i | %4i | %4i | %3i | %5i | %14s | %21s | %i:%i:%i", i, ent->getIdNum(), ent->mapNum, ent->type, ent->inuse, ent->getPlayerNum(), ent->getTeam(), ent->fieldSize, ent->HP, ent->state, ent->classname, model, ent->pos[0], ent->pos[1], ent->pos[2]); Com_Printf("%s\n", buf); i++; } }
/** * @brief calculate how much check is "visible" from @c from * @param[in] from The world coordinate to check from * @param[in] ent The source edict of the check * @param[in] check The edict to check how good (or if at all) it is visible * @param[in] full Perform a full check in different directions. If this is * @c false the actor is fully visible if one vis check returned @c true. With * @c true this function can also return a value != 0.0 and != 1.0. Try to only * use @c true if you really need the full check. Full checks are of course * more expensive. * @return a value between 0.0 and 1.0 which reflects the visibility from 0 * to 100 percent * @note This call isn't cheap - try to do this only if you really need the * visibility check or the statement whether one particular actor see another * particular actor. * @sa CL_ActorVis */ float G_ActorVis (const vec3_t from, const edict_t *ent, const edict_t *check, bool full) { vec3_t test, dir; float delta; int i, n; const float distance = VectorDist(check->origin, ent->origin); /* units that are very close are visible in the smoke */ if (distance > UNIT_SIZE * 1.5f) { vec3_t eyeEnt; edict_t *e = NULL; G_ActorGetEyeVector(ent, eyeEnt); while ((e = G_EdictsGetNext(e))) { if (G_IsSmoke(e)) { if (RayIntersectAABB(eyeEnt, check->absmin, e->absmin, e->absmax) || RayIntersectAABB(eyeEnt, check->absmax, e->absmin, e->absmax)) { return ACTOR_VIS_0; } } } } /* start on eye height */ VectorCopy(check->origin, test); if (G_IsDead(check)) { test[2] += PLAYER_DEAD; delta = 0; } else if (G_IsCrouched(check)) { test[2] += PLAYER_CROUCH - 2; delta = (PLAYER_CROUCH - PLAYER_MIN) / 2 - 2; } else { test[2] += PLAYER_STAND; delta = (PLAYER_STAND - PLAYER_MIN) / 2 - 2; } /* side shifting -> better checks */ dir[0] = from[1] - check->origin[1]; dir[1] = check->origin[0] - from[0]; dir[2] = 0; VectorNormalizeFast(dir); VectorMA(test, -7, dir, test); /* do 3 tests */ n = 0; for (i = 0; i < 3; i++) { if (!G_LineVis(from, test)) { if (full) n++; else return ACTOR_VIS_100; } /* look further down or stop */ if (!delta) { if (n > 0) return ACTOR_VIS_100; else return ACTOR_VIS_0; } VectorMA(test, 7, dir, test); test[2] -= delta; } /* return factor */ switch (n) { case 0: return ACTOR_VIS_0; case 1: return ACTOR_VIS_10; case 2: return ACTOR_VIS_50; default: return ACTOR_VIS_100; } }