/** * @brief Creates a server's entity / program execution context by * parsing textual entity definitions out of an ent file. */ void G_SpawnEntities(const char *name, const char *entities) { gi.FreeTag(MEM_TAG_GAME_LEVEL); memset(&g_level, 0, sizeof(g_level)); g_strlcpy(g_level.name, name, sizeof(g_level.name)); // see if we have bots to keep if (aix) { g_game.ai_fill_slots = 0; g_game.ai_left_to_spawn = 0; if (g_ai_max_clients->integer) { if (g_ai_max_clients->integer == -1) { g_game.ai_fill_slots = sv_max_clients->integer; } else { g_game.ai_fill_slots = Clamp(g_ai_max_clients->integer, 0, sv_max_clients->integer); } g_game.ai_left_to_spawn = g_game.ai_fill_slots; g_ai_max_clients->modified = false; } else { for (int32_t i = 0; i < sv_max_clients->integer; i++) { if (g_game.entities[i + 1].client && g_game.entities[i + 1].client->ai) { g_game.ai_left_to_spawn++; } } } } memset(g_game.entities, 0, g_max_entities->value * sizeof(g_entity_t)); memset(g_game.clients, 0, sv_max_clients->value * sizeof(g_client_t)); for (int32_t i = 0; i < sv_max_clients->integer; i++) { g_game.entities[i + 1].client = g_game.clients + i; } ge.num_entities = sv_max_clients->integer + 1; g_entity_t *ent = NULL; gchar **inhibit = g_strsplit(g_inhibit->string, " ", -1); int32_t inhibited = 0; parser_t parser; char tok[MAX_QPATH]; Parse_Init(&parser, entities, PARSER_NO_COMMENTS); // parse the entity definition string while (true) { if (!Parse_Token(&parser, PARSE_DEFAULT, tok, sizeof(tok))) { break; } if (tok[0] != '{') { gi.Error("Found \"%s\" when expecting \"{\"", tok); } if (ent == NULL) { ent = g_game.entities; } else { ent = G_AllocEntity(); } G_ParseEntity(&parser, ent); if (ent != g_game.entities) { // enforce entity inhibiting for (size_t i = 0; i < g_strv_length(inhibit); i++) { if (g_strcmp0(ent->class_name, inhibit[i]) == 0) { G_FreeEntity(ent); inhibited++; continue; } } // handle legacy spawn flags if (ent->locals.spawn_flags & SF_NOT_DEATHMATCH) { G_FreeEntity(ent); inhibited++; continue; } // strip away unsupported flags ent->locals.spawn_flags &= ~(SF_NOT_EASY | SF_NOT_MEDIUM | SF_NOT_HARD | SF_NOT_COOP); } if (!G_SpawnEntity(ent)) { G_FreeEntity(ent); inhibited++; } } g_strfreev(inhibit); gi.Debug("%i entities inhibited\n", inhibited); G_InitMedia(); G_InitEntityTeams(); G_CheckHook(); G_CheckTechs(); G_ResetTeams(); G_InitSpawnPoints(); G_ResetSpawnPoints(); G_ResetVote(); G_ResetItems(); }
/* * G_RestartGame * * For normal games, this just means reset scores and respawn. * For match games, this means cancel the match and force everyone * to ready again. Teams are only reset when teamz is true. */ static void G_RestartGame(boolean_t teamz) { int i; g_edict_t *ent; g_client_t *cl; if (g_level.match_time) g_level.match_num++; if (g_level.round_time) g_level.round_num++; for (i = 0; i < sv_max_clients->integer; i++) { // reset clients if (!g_game.edicts[i + 1].in_use) continue; ent = &g_game.edicts[i + 1]; cl = ent->client; cl->persistent.ready = false; // back to warmup cl->persistent.score = 0; cl->persistent.captures = 0; if (teamz) // reset teams cl->persistent.team = NULL; // determine spectator or team affiliations if (g_level.match) { if (cl->persistent.match_num == g_level.match_num) cl->persistent.spectator = false; else cl->persistent.spectator = true; } else if (g_level.rounds) { if (cl->persistent.round_num == g_level.round_num) cl->persistent.spectator = false; else cl->persistent.spectator = true; } if (g_level.teams || g_level.ctf) { if (!cl->persistent.team) { if (g_auto_join->value) G_AddClientToTeam(ent, G_SmallestTeam()->name); else cl->persistent.spectator = true; } } G_ClientRespawn(ent, false); } G_ResetItems(); g_level.match_time = g_level.round_time = 0; g_team_good.score = g_team_evil.score = 0; g_team_good.captures = g_team_evil.captures = 0; gi.BroadcastPrint(PRINT_HIGH, "Game restarted\n"); gi.Sound(&g_game.edicts[0], gi.SoundIndex("world/teleport"), ATTN_NONE); }