Exemplo n.º 1
0
/*QUAKED worldspawn (0 0 0) ?
 The worldspawn entity defines global conditions and behavior for the entire level. All brushes not belonging to an explicit entity implicitly belong to worldspawn.
 -------- KEYS --------
 message : The map title.
 sky : The sky environment map (default unit1_).
 ambient_light : The ambient light level (e.g. 0.14 0.11 0.12).
 sun_light : Sun light intensity, a single scalar value 0 - 255.
 sun_color : Sun light color (e.g. 0.8 0.4 0.7).
 sun_angles : Sun light angles as "pitch yaw roll" (e.g. 85 225 0).
 brightness : Global light scale, a single positive scalar value (e.g. 1.125).
 saturation : Global light saturation, a single positive scalar value (e.g. 0.9).
 contrast : Global light contrast, a single positive scalar value (e.g. 1.17).
 patch_size : Surface light patch size (default 64).
 weather : Weather effects, one of "none, rain, snow" followed optionally by "fog r g b."
 gravity : Gravity for the level (default 800).
 gameplay : The gameplay mode, one of "deathmatch, instagib, arena."
 hook : Enables the grappling hook (unset for gameplay default, 0 = disabled, 1 = enabled)."
 teams : Enables and enforces teams play (enabled = 1, auto-balance = 2).
 num_teams : Enforces number of teams (disabled = -1, must be between 2 and 4)
 ctf : Enables CTF play (enabled = 1, auto-balance = 2).
 match : Enables match play (round-based elimination with warmup) (enabled = 1).
 fraglimit : The frag limit (default 20).
 roundlimit : The round limit (default 20).
 capturelimit : The capture limit (default 8).
 timelimit : The time limit in minutes (default 20).
 give : A comma-delimited item string to give each player on spawn.
 */
static void G_worldspawn(g_entity_t *ent) {

	ent->solid = SOLID_BSP;
	ent->locals.move_type = MOVE_TYPE_NONE;
	ent->in_use = true; // since the world doesn't use G_Spawn()
	ent->s.model1 = 0; // world model is always index 1

	const g_map_list_map_t *map = G_MapList_Find(NULL, g_level.name);

	if (ent->locals.message && *ent->locals.message) {
		g_strlcpy(g_level.title, ent->locals.message, sizeof(g_level.title));
	} else
		// or just the level name
	{
		g_strlcpy(g_level.title, g_level.name, sizeof(g_level.title));
	}
	gi.SetConfigString(CS_NAME, g_level.title);

	if (map && *map->sky) { // prefer maps.lst sky
		gi.SetConfigString(CS_SKY, map->sky);
	} else { // or fall back on worldspawn
		if (g_game.spawn.sky && *g_game.spawn.sky) {
			gi.SetConfigString(CS_SKY, g_game.spawn.sky);
		} else
			// or default to unit1_
		{
			gi.SetConfigString(CS_SKY, "unit1_");
		}
	}

	if (map && *map->weather) { // prefer maps.lst weather
		gi.SetConfigString(CS_WEATHER, map->weather);
	} else { // or fall back on worldspawn
		if (g_game.spawn.weather && *g_game.spawn.weather) {
			gi.SetConfigString(CS_WEATHER, g_game.spawn.weather);
		} else
			// or default to none
		{
			gi.SetConfigString(CS_WEATHER, "none");
		}
	}

	if (map && map->gravity > 0) { // prefer maps.lst gravity
		g_level.gravity = map->gravity;
	} else { // or fall back on worldspawn
		if (g_game.spawn.gravity && *g_game.spawn.gravity) {
			g_level.gravity = atoi(g_game.spawn.gravity);
		} else {
			g_level.gravity = DEFAULT_GRAVITY;
		}
	}

	if (g_strcmp0(g_gameplay->string, "default")) { // perfer g_gameplay
		g_level.gameplay = G_GameplayByName(g_gameplay->string);
	} else if (map && map->gameplay > -1) { // then maps.lst gameplay
		g_level.gameplay = map->gameplay;
	} else { // or fall back on worldspawn
		if (g_game.spawn.gameplay && *g_game.spawn.gameplay) {
			g_level.gameplay = G_GameplayByName(g_game.spawn.gameplay);
		} else {
			g_level.gameplay = GAME_DEATHMATCH;
		}
	}

	gi.SetConfigString(CS_GAMEPLAY, va("%d", g_level.gameplay));

	if (map && map->teams > -1) { // prefer maps.lst teams
		g_level.teams = map->teams;
	} else { // or fall back on worldspawn
		if (g_game.spawn.teams && *g_game.spawn.teams) {
			g_level.teams = atoi(g_game.spawn.teams);
		} else {
			g_level.teams = g_teams->integer;
		}
	}

	if (map && map->num_teams > -1) { // prefer maps.lst teams
		g_level.num_teams = map->num_teams;
	} else { // or fall back on worldspawn
		if (g_game.spawn.num_teams && *g_game.spawn.num_teams) {
			g_level.num_teams = atoi(g_game.spawn.num_teams);
		} else {
			if (g_strcmp0(g_num_teams->string, "default")) {
				g_level.num_teams = g_num_teams->integer;
			} else {
				g_level.num_teams = -1; // spawn point function will do this
			}
		}
	}

	if (g_level.num_teams != -1) {
		g_level.num_teams = Clamp(g_level.num_teams, 2, MAX_TEAMS);
	}

	if (map && map->ctf > -1) { // prefer maps.lst ctf
		g_level.ctf = map->ctf;
	} else { // or fall back on worldspawn
		if (g_game.spawn.ctf && *g_game.spawn.ctf) {
			g_level.ctf = atoi(g_game.spawn.ctf);
		} else {
			g_level.ctf = g_ctf->integer;
		}
	}

	if (map && map->hook > -1) {
		g_level.hook_map = map->hook;
	} else {
		g_level.hook_map = -1;
	}

	if (map && map->techs > -1) {
		g_level.techs_map = map->techs;
	} else {
		g_level.techs_map = -1;
	}

	if (g_level.teams && g_level.ctf) { // ctf overrides teams
		g_level.teams = 0;
	}

	gi.SetConfigString(CS_CTF, va("%d", g_level.ctf));
	gi.SetConfigString(CS_HOOK_PULL_SPEED, g_hook_pull_speed->string);

	if (map && map->match > -1) { // prefer maps.lst match
		g_level.match = map->match;
	} else { // or fall back on worldspawn
		if (g_game.spawn.match && *g_game.spawn.match) {
			g_level.match = atoi(g_game.spawn.match);
		} else {
			g_level.match = g_match->integer;
		}
	}

	if (map && map->rounds > -1) { // prefer maps.lst rounds
		g_level.rounds = map->rounds;
	} else { // or fall back on worldspawn
		if (g_game.spawn.rounds && *g_game.spawn.rounds) {
			g_level.rounds = atoi(g_game.spawn.rounds);
		} else {
			g_level.rounds = g_rounds->integer;
		}
	}

	if (g_level.match && g_level.rounds) { // rounds overrides match
		g_level.match = 0;
	}

	gi.SetConfigString(CS_MATCH, va("%d", g_level.match));
	gi.SetConfigString(CS_ROUNDS, va("%d", g_level.rounds));

	if (map && map->frag_limit > -1) { // prefer maps.lst frag_limit
		g_level.frag_limit = map->frag_limit;
	} else { // or fall back on worldspawn
		if (g_game.spawn.frag_limit && *g_game.spawn.frag_limit) {
			g_level.frag_limit = atoi(g_game.spawn.frag_limit);
		} else {
			g_level.frag_limit = g_frag_limit->integer;
		}
	}

	if (map && map->round_limit > -1) { // prefer maps.lst round_limit
		g_level.round_limit = map->round_limit;
	} else { // or fall back on worldspawn
		if (g_game.spawn.round_limit && *g_game.spawn.round_limit) {
			g_level.round_limit = atoi(g_game.spawn.round_limit);
		} else {
			g_level.round_limit = g_round_limit->integer;
		}
	}

	if (map && map->capture_limit > -1) { // prefer maps.lst capture_limit
		g_level.capture_limit = map->capture_limit;
	} else { // or fall back on worldspawn
		if (g_game.spawn.capture_limit && *g_game.spawn.capture_limit) {
			g_level.capture_limit = atoi(g_game.spawn.capture_limit);
		} else {
			g_level.capture_limit = g_capture_limit->integer;
		}
	}

	vec_t time_limit;
	if (map && map->time_limit > -1) { // prefer maps.lst time_limit
		time_limit = map->time_limit;
	} else { // or fall back on worldspawn
		if (g_game.spawn.time_limit && *g_game.spawn.time_limit) {
			time_limit = atof(g_game.spawn.time_limit);
		} else {
			time_limit = g_time_limit->value;
		}
	}
	g_level.time_limit = time_limit * 60 * 1000;

	if (map && *map->give) { // prefer maps.lst give
		g_strlcpy(g_level.give, map->give, sizeof(g_level.give));
	} else { // or fall back on worldspawn
		if (g_game.spawn.give && *g_game.spawn.give) {
			g_strlcpy(g_level.give, g_game.spawn.give, sizeof(g_level.give));
		} else {
			g_level.give[0] = '\0';
		}
	}

	if (map && *map->music) { // prefer maps.lst music
		g_strlcpy(g_level.music, map->music, sizeof(g_level.music));
	} else { // or fall back on worldspawn
		if (g_game.spawn.music && *g_game.spawn.music) {
			g_strlcpy(g_level.music, g_game.spawn.music, sizeof(g_level.music));
		} else {
			g_level.music[0] = '\0';
		}
	}

	G_WorldspawnMusic();

	gi.SetConfigString(CS_VOTE, "");
}
Exemplo n.º 2
0
/*
 * G_CheckRules
 */
static void G_CheckRules(void) {
	int i, seconds;
	g_client_t *cl;

	if (g_level.intermission_time)
		return;

	// match mode, no match, or countdown underway
	g_level.warmup = g_level.match && (!g_level.match_time
			|| g_level.match_time > g_level.time);

	// arena mode, no round, or countdown underway
	g_level.warmup |= g_level.rounds && (!g_level.round_time
			|| g_level.round_time > g_level.time);

	if (g_level.start_match && g_level.time >= g_level.match_time) { // players have readied, begin match
		g_level.start_match = false;
		g_level.warmup = false;

		for (i = 0; i < sv_max_clients->integer; i++) {
			if (!g_game.edicts[i + 1].in_use)
				continue;
			G_ClientRespawn(&g_game.edicts[i + 1], false);
		}

		gi.Sound(&g_game.edicts[0], gi.SoundIndex("world/teleport"), ATTN_NONE);
		gi.BroadcastPrint(PRINT_HIGH, "Match has started\n");
	}

	if (g_level.start_round && g_level.time >= g_level.round_time) { // pre-game expired, begin round
		g_level.start_round = false;
		g_level.warmup = false;

		for (i = 0; i < sv_max_clients->integer; i++) {
			if (!g_game.edicts[i + 1].in_use)
				continue;
			G_ClientRespawn(&g_game.edicts[i + 1], false);
		}

		gi.Sound(&g_game.edicts[0], gi.SoundIndex("world/teleport"), ATTN_NONE);
		gi.BroadcastPrint(PRINT_HIGH, "Round has started\n");
	}

	seconds = g_level.time;

	if (g_level.rounds) {
		if (g_level.round_time > g_level.time) // round about to start, show pre-game countdown
			seconds = g_level.round_time - g_level.time;
		else if (g_level.round_time)
			seconds = g_level.time - g_level.round_time; // round started, count up
		else
			seconds = -1;
	} else if (g_level.match) {
		if (g_level.match_time > g_level.time) // match about to start, show pre-game countdown
			seconds = g_level.match_time - g_level.time;
		else if (g_level.match_time) {
			if (g_level.time_limit) // count down to time_limit
				seconds = g_level.match_time + g_level.time_limit * 60
						- g_level.time;
			else
				seconds = g_level.time - g_level.match_time; // count up
		} else
			seconds = -1;
	}

	if (g_level.time_limit) { // check time_limit
		float t = g_level.time;

		if (g_level.match) // for matches
			t = g_level.time - g_level.match_time;
		else if (g_level.rounds) // and for rounds
			t = g_level.time - g_level.round_time;

		if (t >= g_level.time_limit * 60) {
			gi.BroadcastPrint(PRINT_HIGH, "Timelimit hit\n");
			G_EndLevel();
			return;
		}
		seconds = g_level.time_limit * 60 - t; // count down
	}

	if (g_level.frame_num % gi.frame_rate == 0) // send time updates once per second
		gi.ConfigString(CS_TIME,
				(g_level.warmup ? "Warmup" : G_FormatTime(seconds)));

	if (!g_level.ctf && g_level.frag_limit) { // check frag_limit

		if (g_level.teams) { // check team scores
			if (g_team_good.score >= g_level.frag_limit ||
					g_team_evil.score >= g_level.frag_limit) {
				gi.BroadcastPrint(PRINT_HIGH, "Fraglimit hit\n");
				G_EndLevel();
				return;
			}
		} else { // or individual scores
			for (i = 0; i < sv_max_clients->integer; i++) {
				cl = g_game.clients + i;
				if (!g_game.edicts[i + 1].in_use)
					continue;

				if (cl->persistent.score >= g_level.frag_limit) {
					gi.BroadcastPrint(PRINT_HIGH, "Fraglimit hit\n");
					G_EndLevel();
					return;
				}
			}
		}
	}

	if (g_level.ctf && g_level.capture_limit) { // check capture limit

		if (g_team_good.captures >= g_level.capture_limit || g_team_evil.captures
				>= g_level.capture_limit) {
			gi.BroadcastPrint(PRINT_HIGH, "Capturelimit hit\n");
			G_EndLevel();
			return;
		}
	}

	if (g_gameplay->modified) { // change gameplay, fix items, respawn clients
		g_gameplay->modified = false;

		g_level.gameplay = G_GameplayByName(g_gameplay->string);
		gi.ConfigString(CS_GAMEPLAY, va("%d", g_level.gameplay));

		G_RestartGame(false); // reset all clients

		gi.BroadcastPrint(PRINT_HIGH, "Gameplay has changed to %s\n",
				G_GameplayName(g_level.gameplay));
	}

	if (g_gravity->modified) { // send gravity config string
		g_gravity->modified = false;

		g_level.gravity = g_gravity->integer;
		gi.ConfigString(CS_GRAVITY, va("%d", g_level.gravity));
	}

	if (g_teams->modified) { // reset teams, scores
		g_teams->modified = false;

		g_level.teams = g_teams->integer;
		gi.ConfigString(CS_TEAMS, va("%d", g_level.teams));

		gi.BroadcastPrint(PRINT_HIGH, "Teams have been %s\n",
				g_level.teams ? "enabled" : "disabled");

		G_RestartGame(true);
	}

	if (g_ctf->modified) { // reset teams, scores
		g_ctf->modified = false;

		g_level.ctf = g_ctf->integer;
		gi.ConfigString(CS_CTF, va("%d", g_level.ctf));

		gi.BroadcastPrint(PRINT_HIGH, "CTF has been %s\n",
				g_level.ctf ? "enabled" : "disabled");

		G_RestartGame(true);
	}

	if (g_match->modified) { // reset scores
		g_match->modified = false;

		g_level.match = g_match->integer;
		gi.ConfigString(CS_MATCH, va("%d", g_level.match));

		g_level.warmup = g_level.match; // toggle warmup

		gi.BroadcastPrint(PRINT_HIGH, "Match has been %s\n",
				g_level.match ? "enabled" : "disabled");

		G_RestartGame(false);
	}

	if (g_rounds->modified) { // reset scores
		g_rounds->modified = false;

		g_level.rounds = g_rounds->integer;
		gi.ConfigString(CS_ROUNDS, va("%d", g_level.rounds));

		g_level.warmup = g_level.rounds; // toggle warmup

		gi.BroadcastPrint(PRINT_HIGH, "Rounds have been %s\n",
				g_level.rounds ? "enabled" : "disabled");

		G_RestartGame(false);
	}

	if (g_cheats->modified) { // notify when cheats changes
		g_cheats->modified = false;

		gi.BroadcastPrint(PRINT_HIGH, "Cheats have been %s\n",
				g_cheats->integer ? "enabled" : "disabled");
	}

	if (g_frag_limit->modified) {
		g_frag_limit->modified = false;
		g_level.frag_limit = g_frag_limit->integer;

		gi.BroadcastPrint(PRINT_HIGH, "Fraglimit has been changed to %d\n",
				g_level.frag_limit);
	}

	if (g_round_limit->modified) {
		g_round_limit->modified = false;
		g_level.round_limit = g_round_limit->integer;

		gi.BroadcastPrint(PRINT_HIGH, "Roundlimit has been changed to %d\n",
				g_level.round_limit);
	}

	if (g_capture_limit->modified) {
		g_capture_limit->modified = false;
		g_level.capture_limit = g_capture_limit->integer;

		gi.BroadcastPrint(PRINT_HIGH, "Capturelimit has been changed to %d\n",
				g_level.capture_limit);
	}

	if (g_time_limit->modified) {
		g_time_limit->modified = false;
		g_level.time_limit = g_time_limit->value;

		gi.BroadcastPrint(PRINT_HIGH, "Timelimit has been changed to %d\n",
				(int) g_level.time_limit);
	}
}
Exemplo n.º 3
0
/*
 * G_ParseMapList
 *
 * Populates a g_map_list_t from a text file.  See default/maps.lst
 */
static void G_ParseMapList(const char *file_name) {
	void *buf;
	const char *buffer;
	unsigned int i, j, k, l;
	const char *c;
	boolean_t map;
	g_map_list_elt_t *elt;

	G_InitMapList();

	if (gi.LoadFile(file_name, &buf) == -1) {
		gi.Print("Couldn't open %s\n", file_name);
		return;
	}

	buffer = (char *) buf;

	i = 0;
	map = false;
	while (true) {

		c = ParseToken(&buffer);

		if (*c == '\0')
			break;

		if (*c == '{')
			map = true;

		if (!map) // skip any whitespace between maps
			continue;

		elt = &g_map_list.maps[i];

		if (!strcmp(c, "name")) {
			strncpy(elt->name, ParseToken(&buffer), sizeof(elt->name) - 1);
			continue;
		}

		if (!strcmp(c, "title")) {
			strncpy(elt->title, ParseToken(&buffer), sizeof(elt->title) - 1);
			continue;
		}

		if (!strcmp(c, "sky")) {
			strncpy(elt->sky, ParseToken(&buffer), sizeof(elt->sky) - 1);
			continue;
		}

		if (!strcmp(c, "weather")) {
			strncpy(elt->weather, ParseToken(&buffer), sizeof(elt->weather) - 1);
			continue;
		}

		if (!strcmp(c, "gravity")) {
			elt->gravity = atoi(ParseToken(&buffer));
			continue;
		}

		if (!strcmp(c, "gameplay")) {
			elt->gameplay = G_GameplayByName(ParseToken(&buffer));
			continue;
		}

		if (!strcmp(c, "teams")) {
			elt->teams = strtoul(ParseToken(&buffer), NULL, 0);
			continue;
		}

		if (!strcmp(c, "ctf")) {
			elt->ctf = strtoul(ParseToken(&buffer), NULL, 0);
			continue;
		}

		if (!strcmp(c, "match")) {
			elt->match = strtoul(ParseToken(&buffer), NULL, 0);
			continue;
		}

		if (!strcmp(c, "rounds")) {
			elt->rounds = strtoul(ParseToken(&buffer), NULL, 0);
			continue;
		}

		if (!strcmp(c, "frag_limit")) {
			elt->frag_limit = strtoul(ParseToken(&buffer), NULL, 0);
			continue;
		}

		if (!strcmp(c, "round_limit")) {
			elt->round_limit = strtoul(ParseToken(&buffer), NULL, 0);
			continue;
		}

		if (!strcmp(c, "capture_limit")) {
			elt->capture_limit = strtoul(ParseToken(&buffer), NULL, 0);
			continue;
		}

		if (!strcmp(c, "time_limit")) {
			elt->time_limit = atof(ParseToken(&buffer));
			continue;
		}

		if (!strcmp(c, "give")) {
			strncpy(elt->give, ParseToken(&buffer), sizeof(elt->give) - 1);
			continue;
		}

		if (!strcmp(c, "music")) {
			strncpy(elt->music, ParseToken(&buffer), sizeof(elt->music) - 1);
			continue;
		}

		if (!strcmp(c, "weight")) {
			elt->weight = atof(ParseToken(&buffer));
			continue;
		}

		if (*c == '}') { // close it out
			map = false;

			/*printf("Loaded map %s:\n"
			 "title: %s\n"
			 "sky: %s\n"
			 "weather: %s\n"
			 "gravity: %d\n"
			 "gameplay: %ud\n"
			 "teams: %ud\n"
			 "ctf: %ud\n"
			 "match: %ud\n"
			 "rounds: %ud\n"
			 "frag_limit: %ud\n"
			 "round_limit: %ud\n"
			 "capture_limit: %ud\n"
			 "time_limit: %f\n"
			 "give: %s\n"
			 "music: %s\n"
			 "weight: %f\n",
			 map->name, map->title, map->sky, map->weather, map->gravity,
			 map->gameplay, map->teams, map->ctf, map->match, map->rounds,
			 map->frag_limit, map->round_limit, map->capture_limit,
			 map->time_limit, map->give, map->music, map->weight);*/

			// accumulate total weight
			g_map_list.total_weight += elt->weight;

			if (++i == MAX_MAP_LIST_ELTS)
				break;
		}
	}

	g_map_list.count = i;
	g_map_list.index = 0;

	gi.TagFree(buf);

	// thou shalt not divide by zero
	if (!g_map_list.total_weight)
		g_map_list.total_weight = 1.0;

	// compute the weighted index list
	for (i = 0, l = 0; i < g_map_list.count; i++) {

		elt = &g_map_list.maps[i];
		k = (elt->weight / g_map_list.total_weight) * MAP_LIST_WEIGHT;

		for (j = 0; j < k; j++)
			g_map_list.weighted_index[l++] = i;
	}
}
Exemplo n.º 4
0
/*QUAKED worldspawn(0 0 0) ?

 Only used for the world.
 "message"			"Stress Fractures by Jester"
 "sky"				unit1_
 "weather"			none, rain, snow, fog 0.5 0.8 0.7
 "gravity"			800
 "gameplay"			deathmatch, instagib, rocket arena
 "teams"			0 off, 1 on, 2 balanced
 "ctf"				0 off, 1 on, 2 balanced
 "match"			0 off, 1 on
 "round"			0 off, 1 on
 "frag_limit" 		20 frags
 "round_limit" 		20 rounds
 "capture_limit" 	8 captures
 "time_limit"		20 minutes
 "give"				comma-delimited items list
 "music"			comma-delimited track list
 */
static void G_worldspawn(g_edict_t *ent) {
	uint32_t i;
	g_map_list_elt_t *map;

	ent->locals.move_type = MOVE_TYPE_PUSH;
	ent->solid = SOLID_BSP;
	ent->in_use = true; // since the world doesn't use G_Spawn()
	ent->s.model1 = 0; // world model is always index 1

	map = NULL; // resolve the maps.lst entry for this level
	for (i = 0; i < g_map_list.count; i++) {
		if (!g_strcmp0(g_level.name, g_map_list.maps[i].name)) {
			map = &g_map_list.maps[i];
			break;
		}
	}

	if (ent->locals.message && *ent->locals.message)
		g_strlcpy(g_level.title, ent->locals.message, sizeof(g_level.title));
	else
		// or just the level name
		g_strlcpy(g_level.title, g_level.name, sizeof(g_level.title));
	gi.ConfigString(CS_NAME, g_level.title);

	if (map && *map->sky) // prefer maps.lst sky
		gi.ConfigString(CS_SKY, map->sky);
	else { // or fall back on worldspawn
		if (g_game.spawn.sky && *g_game.spawn.sky)
			gi.ConfigString(CS_SKY, g_game.spawn.sky);
		else
			// or default to unit1_
			gi.ConfigString(CS_SKY, "unit1_");
	}

	if (map && *map->weather) // prefer maps.lst weather
		gi.ConfigString(CS_WEATHER, map->weather);
	else { // or fall back on worldspawn
		if (g_game.spawn.weather && *g_game.spawn.weather)
			gi.ConfigString(CS_WEATHER, g_game.spawn.weather);
		else
			// or default to none
			gi.ConfigString(CS_WEATHER, "none");
	}

	if (map && map->gravity > 0) // prefer maps.lst gravity
		g_level.gravity = map->gravity;
	else { // or fall back on worldspawn
		if (g_game.spawn.gravity && *g_game.spawn.gravity)
			g_level.gravity = atoi(g_game.spawn.gravity);
		else
			// or default to 800
			g_level.gravity = 800;
	}

	if (g_strcmp0(g_gameplay->string, "default")) { // perfer g_gameplay
		g_level.gameplay = G_GameplayByName(g_gameplay->string);
	} else if (map && map->gameplay > -1) { // then maps.lst gameplay
		g_level.gameplay = map->gameplay;
	} else { // or fall back on worldspawn
		if (g_game.spawn.gameplay && *g_game.spawn.gameplay)
			g_level.gameplay = G_GameplayByName(g_game.spawn.gameplay);
		else
			// or default to deathmatch
			g_level.gameplay = DEATHMATCH;
	}
	if (g_level.gameplay == DEFAULT)
		g_level.gameplay = DEATHMATCH;
	gi.ConfigString(CS_GAMEPLAY, va("%d", g_level.gameplay));

	if (map && map->teams > -1) // prefer maps.lst teams
		g_level.teams = map->teams;
	else { // or fall back on worldspawn
		if (g_game.spawn.teams && *g_game.spawn.teams)
			g_level.teams = atoi(g_game.spawn.teams);
		else
			// or default to cvar
			g_level.teams = g_teams->integer;
	}

	if (map && map->ctf > -1) // prefer maps.lst ctf
		g_level.ctf = map->ctf;
	else { // or fall back on worldspawn
		if (g_game.spawn.ctf && *g_game.spawn.ctf)
			g_level.ctf = atoi(g_game.spawn.ctf);
		else
			// or default to cvar
			g_level.ctf = g_ctf->integer;
	}

	if (g_level.teams && g_level.ctf) // ctf overrides teams
		g_level.teams = 0;

	gi.ConfigString(CS_TEAMS, va("%d", g_level.teams));
	gi.ConfigString(CS_CTF, va("%d", g_level.ctf));

	if (map && map->match > -1) // prefer maps.lst match
		g_level.match = map->match;
	else { // or fall back on worldspawn
		if (g_game.spawn.match && *g_game.spawn.match)
			g_level.match = atoi(g_game.spawn.match);
		else
			// or default to cvar
			g_level.match = g_match->integer;
	}

	if (map && map->rounds > -1) // prefer maps.lst rounds
		g_level.rounds = map->rounds;
	else { // or fall back on worldspawn
		if (g_game.spawn.rounds && *g_game.spawn.rounds)
			g_level.rounds = atoi(g_game.spawn.rounds);
		else
			// or default to cvar
			g_level.rounds = g_rounds->integer;
	}

	if (g_level.match && g_level.rounds) // rounds overrides match
		g_level.match = 0;

	gi.ConfigString(CS_MATCH, va("%d", g_level.match));
	gi.ConfigString(CS_ROUNDS, va("%d", g_level.rounds));

	if (map && map->frag_limit > -1) // prefer maps.lst frag_limit
		g_level.frag_limit = map->frag_limit;
	else { // or fall back on worldspawn
		if (g_game.spawn.frag_limit && *g_game.spawn.frag_limit)
			g_level.frag_limit = atoi(g_game.spawn.frag_limit);
		else
			// or default to cvar
			g_level.frag_limit = g_frag_limit->integer;
	}

	if (map && map->round_limit > -1) // prefer maps.lst round_limit
		g_level.round_limit = map->round_limit;
	else { // or fall back on worldspawn
		if (g_game.spawn.round_limit && *g_game.spawn.round_limit)
			g_level.round_limit = atoi(g_game.spawn.round_limit);
		else
			// or default to cvar
			g_level.round_limit = g_round_limit->integer;
	}

	if (map && map->capture_limit > -1) // prefer maps.lst capture_limit
		g_level.capture_limit = map->capture_limit;
	else { // or fall back on worldspawn
		if (g_game.spawn.capture_limit && *g_game.spawn.capture_limit)
			g_level.capture_limit = atoi(g_game.spawn.capture_limit);
		else
			// or default to cvar
			g_level.capture_limit = g_capture_limit->integer;
	}

	vec_t time_limit;
	if (map && map->time_limit > -1) // prefer maps.lst time_limit
		time_limit = map->time_limit;
	else { // or fall back on worldspawn
		if (g_game.spawn.time_limit && *g_game.spawn.time_limit)
			time_limit = atof(g_game.spawn.time_limit);
		else
			// or default to cvar
			time_limit = g_time_limit->value;
	}
	g_level.time_limit = time_limit * 60 * 1000;

	if (map && *map->give) // prefer maps.lst give
		g_strlcpy(g_level.give, map->give, sizeof(g_level.give));
	else { // or fall back on worldspawn
		if (g_game.spawn.give && *g_game.spawn.give)
			g_strlcpy(g_level.give, g_game.spawn.give, sizeof(g_level.give));
		else
			// or clean it
			g_level.give[0] = '\0';
	}

	if (map && *map->music) // prefer maps.lst music
		g_strlcpy(g_level.music, map->music, sizeof(g_level.music));
	else { // or fall back on worldspawn
		if (g_game.spawn.music && *g_game.spawn.music)
			g_strlcpy(g_level.music, g_game.spawn.music, sizeof(g_level.music));
		else
			g_level.music[0] = '\0';
	}

	G_WorldspawnMusic();

	G_PrecacheItem(G_FindItem("Blaster"));
	G_PrecacheItem(G_FindItem("Shotgun"));
	G_PrecacheItem(G_FindItem("Shuper Shotgun"));
	G_PrecacheItem(G_FindItem("Machinegun"));
	G_PrecacheItem(G_FindItem("Grenade Launcher"));
	G_PrecacheItem(G_FindItem("Rocket Launcher"));
	G_PrecacheItem(G_FindItem("Hyperblaster"));
	G_PrecacheItem(G_FindItem("Lightning"));
	G_PrecacheItem(G_FindItem("Railgun"));
	G_PrecacheItem(G_FindItem("BFG10K"));

	gi.SoundIndex("world/water_in");
	gi.SoundIndex("world/water_out");

	gi.SoundIndex("weapons/common/no_ammo");
	gi.SoundIndex("weapons/common/pickup");
	gi.SoundIndex("weapons/common/switch");

	gi.ConfigString(CS_VOTE, "");
	gi.ConfigString(CS_TEAM_GOOD, g_team_good.name);
	gi.ConfigString(CS_TEAM_EVIL, g_team_evil.name);
}