/* * G_CheckVote */ static void G_CheckVote(void) { int i, count = 0; if (!g_voting->value) return; if (g_level.vote_time == 0) return; if (g_level.time - g_level.vote_time > MAX_VOTE_TIME) { gi.BroadcastPrint(PRINT_HIGH, "Vote \"%s\" expired\n", g_level.vote_cmd); G_ResetVote(); return; } for (i = 0; i < sv_max_clients->integer; i++) { if (!g_game.edicts[i + 1].in_use) continue; count++; } if (g_level.votes[VOTE_YES] >= count * VOTE_MAJORITY) { // vote passed gi.BroadcastPrint(PRINT_HIGH, "Vote \"%s\" passed\n", g_level.vote_cmd); if (!strncmp(g_level.vote_cmd, "map ", 4)) { // special case for map G_BeginIntermission(g_level.vote_cmd + 4); } else if (!strcmp(g_level.vote_cmd, "restart")) { // and restart G_RestartGame(false); } else if (!strncmp(g_level.vote_cmd, "mute ", 5)) { // and mute G_MuteClient(g_level.vote_cmd + 5, true); } else if (!strncmp(g_level.vote_cmd, "unmute ", 7)) { G_MuteClient(g_level.vote_cmd + 7, false); } else { // general case, just execute the command gi.AddCommandString(g_level.vote_cmd); } G_ResetVote(); } else if (g_level.votes[VOTE_NO] >= count * VOTE_MAJORITY) { // vote failed gi.BroadcastPrint(PRINT_HIGH, "Vote \"%s\" failed\n", g_level.vote_cmd); G_ResetVote(); } }
/** * @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(); }
/* * @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) { g_edict_t *ent; int32_t inhibit; char *com_token; int32_t i; gi.FreeTag(Z_TAG_GAME_LEVEL); memset(&g_level, 0, sizeof(g_level)); memset(g_game.edicts, 0, g_max_entities->value * sizeof(g_game.edicts[0])); g_strlcpy(g_level.name, name, sizeof(g_level.name)); // set client fields on player ents for (i = 0; i < sv_max_clients->integer; i++) { g_game.edicts[i + 1].client = g_game.clients + i; } ge.num_edicts = sv_max_clients->integer + 1; ent = NULL; inhibit = 0; // parse ents while (true) { // parse the opening brace com_token = ParseToken(&entities); if (!entities) break; if (com_token[0] != '{') gi.Error("Found \"%s\" when expecting \"{\"", com_token); if (!ent) ent = g_game.edicts; else ent = G_Spawn(); entities = G_ParseEntity(entities, ent); // some ents don't belong in deathmatch if (ent != g_game.edicts) { // legacy levels may require this if (ent->locals.spawn_flags & SF_NOT_DEATHMATCH) { G_FreeEdict(ent); inhibit++; continue; } // emits and models are client sided if (!g_strcmp0(ent->class_name, "misc_emit") || !g_strcmp0(ent->class_name, "misc_model")) { G_FreeEdict(ent); inhibit++; continue; } // lights aren't even used if (!g_strcmp0(ent->class_name, "light") || !g_strcmp0(ent->class_name, "light_spot")) { G_FreeEdict(ent); inhibit++; continue; } // strip away unsupported flags ent->locals.spawn_flags &= ~(SF_NOT_EASY | SF_NOT_MEDIUM | SF_NOT_HARD | SF_NOT_COOP | SF_NOT_DEATHMATCH); } // retain the map-specified origin for respawns VectorCopy(ent->s.origin, ent->locals.map_origin); G_SpawnEntity(ent); if (g_level.gameplay > 1 && ent->locals.item) { // now that we've spawned them, hide them ent->sv_flags |= SVF_NO_CLIENT; ent->solid = SOLID_NOT; ent->locals.next_think = 0; } } gi.Debug("%i entities inhibited\n", inhibit); G_InitEntityTeams(); G_InitMedia(); G_ResetTeams(); G_ResetVote(); }