X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fg_world.qc;h=ce25dfa522772b08e3f1dfb41dcc2a536a2f4902;hb=7e5268799e95d0dd6f2b77ed4e097b0adc755f2b;hp=70174b0deaf3c4040d5622d61116532c9b0df483;hpb=4adf0fe8d4165a98befcda3a82fa7ae7a5a7e505;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index 70174b0de..522f4f041 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -13,14 +13,16 @@ #include "g_hook.qh" #include "ipban.qh" #include "mapvoting.qh" -#include "mutators/_mod.qh" +#include #include "race.qh" #include "scores.qh" +#include "scores_rules.qh" #include "teamplay.qh" #include "weapons/weaponstats.qh" #include "../common/constants.qh" #include #include "../common/deathtypes/all.qh" +#include "../common/gamemodes/sv_rules.qh" #include "../common/mapinfo.qh" #include "../common/monsters/_mod.qh" #include "../common/monsters/sv_monsters.qh" @@ -30,8 +32,8 @@ #include "../common/playerstats.qh" #include "../common/stats.qh" #include "../common/teams.qh" -#include "../common/triggers/trigger/secret.qh" -#include "../common/triggers/target/music.qh" +#include "../common/mapobjects/trigger/secret.qh" +#include "../common/mapobjects/target/music.qh" #include "../common/util.qh" #include "../common/items/_mod.qh" #include @@ -53,21 +55,21 @@ void PingPLReport_Think(entity this) this.nextthink = time + delta; e = edict_num(this.cnt + 1); - if(IS_REAL_CLIENT(e)) + if(IS_CLIENT(e) && IS_REAL_CLIENT(e)) { WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT); WriteByte(MSG_BROADCAST, this.cnt); - WriteShort(MSG_BROADCAST, bound(1, e.ping, 65535)); - WriteByte(MSG_BROADCAST, min(ceil(e.ping_packetloss * 255), 255)); - WriteByte(MSG_BROADCAST, min(ceil(e.ping_movementloss * 255), 255)); + WriteShort(MSG_BROADCAST, bound(1, CS(e).ping, 65535)); + WriteByte(MSG_BROADCAST, min(ceil(CS(e).ping_packetloss * 255), 255)); + WriteByte(MSG_BROADCAST, min(ceil(CS(e).ping_movementloss * 255), 255)); // record latency times for clients throughout the match so we can report it to playerstats - if(time > (e.latency_time + LATENCY_THINKRATE)) + if(time > (CS(e).latency_time + LATENCY_THINKRATE)) { - e.latency_sum += e.ping; - e.latency_cnt += 1; - e.latency_time = time; - //print("sum: ", ftos(e.latency_sum), ", cnt: ", ftos(e.latency_cnt), ", avg: ", ftos(e.latency_sum / e.latency_cnt), ".\n"); + CS(e).latency_sum += CS(e).ping; + CS(e).latency_cnt += 1; + CS(e).latency_time = time; + //print("sum: ", ftos(CS(e).latency_sum), ", cnt: ", ftos(CS(e).latency_cnt), ", avg: ", ftos(CS(e).latency_sum / CS(e).latency_cnt), ".\n"); } } else @@ -91,9 +93,6 @@ const float SPAWNFLAG_NO_WAYPOINTS_FOR_ITEMS = 1; string redirection_target; float world_initialized; -string GetGametype(); -void ShuffleMaplist(); - void SetDefaultAlpha() { if (!MUTATOR_CALLHOOK(SetDefaultAlpha)) @@ -135,7 +134,7 @@ void GotoFirstMap(entity this) else { this.nextthink = time + 1; - LOG_INFO("Waiting for _sv_init being set to 1 by initialization scripts...\n"); + LOG_INFO("Waiting for _sv_init being set to 1 by initialization scripts..."); } } @@ -145,12 +144,8 @@ void cvar_changes_init() string k, v, d; float n, i, adding, pureadding; - if(cvar_changes) - strunzone(cvar_changes); - cvar_changes = string_null; - if(cvar_purechanges) - strunzone(cvar_purechanges); - cvar_purechanges = string_null; + strfree(cvar_changes); + strfree(cvar_purechanges); cvar_purechanges_count = 0; h = buf_create(); @@ -252,6 +247,10 @@ void cvar_changes_init() // these can contain player IDs, so better hide BADPREFIX("g_forced_team_"); + BADCVAR("sv_muteban_list"); + BADCVAR("sv_voteban_list"); + BADCVAR("sv_allow_customplayermodels_idlist"); + BADCVAR("sv_allow_customplayermodels_speciallist"); // mapinfo BADCVAR("fraglimit"); @@ -266,9 +265,11 @@ void cvar_changes_init() BADCVAR("g_dm"); BADCVAR("g_domination"); BADCVAR("g_domination_default_teams"); + BADCVAR("g_duel"); BADCVAR("g_freezetag"); BADCVAR("g_freezetag_teams"); BADCVAR("g_invasion_teams"); + BADCVAR("g_invasion_type"); BADCVAR("g_jailbreak"); BADCVAR("g_jailbreak_teams"); BADCVAR("g_keepaway"); @@ -281,6 +282,7 @@ void cvar_changes_init() BADCVAR("g_race_laps_limit"); BADCVAR("g_race_qualifying_timelimit"); BADCVAR("g_race_qualifying_timelimit_override"); + BADCVAR("g_runematch"); BADCVAR("g_snafu"); BADCVAR("g_tdm"); BADCVAR("g_tdm_teams"); @@ -356,10 +358,12 @@ void cvar_changes_init() BADCVAR("sv_stepheight"); BADCVAR("sv_timeout"); BADCVAR("sv_weapons_modeloverride"); + BADCVAR("w_prop_interval"); BADPREFIX("crypto_"); BADPREFIX("gameversion_"); BADPREFIX("g_chat_"); BADPREFIX("g_ctf_captimerecord_"); + BADPREFIX("g_hats_"); BADPREFIX("g_maplist_"); BADPREFIX("g_mod_"); BADPREFIX("g_respawn_"); @@ -459,6 +463,7 @@ void cvar_changes_init() BADCVAR("teamplay_mode"); BADCVAR("timelimit_override"); BADPREFIX("g_warmup_"); + BADPREFIX("sv_info_"); BADPREFIX("sv_ready_restart_"); // mutators that announce themselves properly to the server browser @@ -502,38 +507,6 @@ void cvar_changes_init() cvar_purechanges = strzone(cvar_purechanges); } -void detect_maptype() -{ -#if 0 - vector o, v; - float i; - - for (;;) - { - o = world.mins; - o.x += random() * (world.maxs.x - world.mins.x); - o.y += random() * (world.maxs.y - world.mins.y); - o.z += random() * (world.maxs.z - world.mins.z); - - tracebox(o, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), o - '0 0 32768', MOVE_WORLDONLY, NULL); - if(trace_fraction == 1) - continue; - - v = trace_endpos; - - for(i = 0; i < 64; i += 4) - { - tracebox(o, '-1 -1 -1' * i, '1 1 1' * i, o - '0 0 32768', MOVE_WORLDONLY, NULL); - if(trace_fraction == 1) - continue; - LOG_INFO(ftos(i), " -> ", vtos(trace_endpos), "\n"); - } - - break; - } -#endif -} - entity randomseed; bool RandomSeed_Send(entity this, entity to, int sf) { @@ -574,7 +547,15 @@ spawnfunc(__init_dedicated_server) e = new(info_player_deathmatch); // safeguard against player joining - this.classname = "worldspawn"; // safeguard against various stuff ;) + // assign reflectively to avoid "assignment to world" warning + for (int i = 0, n = numentityfields(); i < n; ++i) { + string k = entityfieldname(i); + if (k == "classname") { + // safeguard against various stuff ;) + putentityfieldstring(i, this, "worldspawn"); + break; + } + } // needs to be done so early because of the constants they create static_init(); @@ -591,24 +572,67 @@ void __init_dedicated_server_shutdown() { MapInfo_Shutdown(); } -void SetLimits(int fraglimit_override, int leadlimit_override, float timelimit_override, float qualifying_override) +STATIC_INIT_EARLY(maxclients) +{ + maxclients = 0; + for (entity head = nextent(NULL); head; head = nextent(head)) { + ++maxclients; + } +} + +void default_delayedinit(entity this) +{ + if(!scores_initialized) + ScoreRules_generic(); +} + +void InitGameplayMode() { - if(!autocvar_g_campaign) + VoteReset(); + + // find out good world mins/maxs bounds, either the static bounds found by looking for solid, or the mapinfo specified bounds + get_mi_min_max(1); + // assign reflectively to avoid "assignment to world" warning + int done = 0; for (int i = 0, n = numentityfields(); i < n; ++i) { + string k = entityfieldname(i); vector v = (k == "mins") ? mi_min : (k == "maxs") ? mi_max : '0 0 0'; + if (v) { + putentityfieldstring(i, world, sprintf("%v", v)); + if (++done == 2) break; + } + } + // currently, NetRadiant's limit is 131072 qu for each side + // distance from one corner of a 131072qu cube to the opposite corner is approx. 227023 qu + // set the distance according to map size but don't go over the limit to avoid issues with float precision + // in case somebody makes extremely large maps + max_shot_distance = min(230000, vlen(world.maxs - world.mins)); + + MapInfo_LoadMapSettings(mapname); + GameRules_teams(false); + + if (!cvar_value_issafe(world.fog)) { - if(fraglimit_override >= 0) cvar_set("fraglimit", ftos(fraglimit_override)); - if(timelimit_override >= 0) cvar_set("timelimit", ftos(timelimit_override)); - if(leadlimit_override >= 0) cvar_set("leadlimit", ftos(leadlimit_override)); - if(qualifying_override >= 0) cvar_set("g_race_qualifying_timelimit", ftos(qualifying_override)); + LOG_INFO("The current map contains a potentially harmful fog setting, ignored"); + world.fog = string_null; } - limits_are_set = true; + if(MapInfo_Map_fog != "") + if(MapInfo_Map_fog == "none") + world.fog = string_null; + else + world.fog = strzone(MapInfo_Map_fog); + clientstuff = strzone(MapInfo_Map_clientstuff); + + MapInfo_ClearTemps(); + + gamemode_name = MapInfo_Type_ToText(MapInfo_LoadedGametype); + + cache_mutatormsg = strzone(""); + cache_lastmutatormsg = strzone(""); + + InitializeEntity(NULL, default_delayedinit, INITPRIO_GAMETYPE_FALLBACK); } void Map_MarkAsRecent(string m); float world_already_spawned; -void Nagger_Init(); -void ClientInit_Spawn(); -void WeaponStats_Init(); -void WeaponStats_Shutdown(); spawnfunc(worldspawn) { server_is_dedicated = boolean(stof(cvar_defstring("is_dedicated"))); @@ -647,7 +671,7 @@ spawnfunc(worldspawn) fclose(sentinel); if (switchversion != "" && switchversion != WATERMARK) { - LOG_INFOF("Switching progs: " WATERMARK " -> %s\n", switchversion); + LOG_INFOF("Switching progs: " WATERMARK " -> %s", switchversion); // if it doesn't exist, assume either: // a) the current program was overwritten // b) this is a client only update @@ -668,7 +692,7 @@ spawnfunc(worldspawn) } if (wantrestart) { - LOG_INFOF("Restart requested\n"); + LOG_INFOF("Restart requested"); changelevel(mapname); // let initialization continue, shutdown depends on it } @@ -686,12 +710,6 @@ spawnfunc(worldspawn) cvar_changes_init(); // do this very early now so it REALLY matches the server config - maxclients = 0; - for (entity head = nextent(NULL); head; head = nextent(head)) - { - ++maxclients; - } - // needs to be done so early because of the constants they create static_init(); @@ -753,8 +771,7 @@ spawnfunc(worldspawn) readlevelcvars(); GrappleHookInit(); - if(!limits_are_set) - SetLimits(autocvar_fraglimit_override, autocvar_leadlimit_override, autocvar_timelimit_override, -1); + GameRules_limit_fallbacks(); if(warmup_limit == 0) warmup_limit = (autocvar_timelimit > 0) ? autocvar_timelimit * 60 : autocvar_timelimit; @@ -840,23 +857,23 @@ spawnfunc(worldspawn) continue; if(argv(0) == "cd") { - LOG_INFO("Found ^1UNSUPPORTED^7 cd loop command in .cfg file; put this line in mapinfo instead:\n"); - LOG_INFO(" cdtrack ", argv(2), "\n"); + LOG_INFO("Found ^1UNSUPPORTED^7 cd loop command in .cfg file; put this line in mapinfo instead:"); + LOG_INFO(" cdtrack ", argv(2)); } else if(argv(0) == "fog") { - LOG_INFO("Found ^1UNSUPPORTED^7 fog command in .cfg file; put this line in worldspawn in the .map/.bsp/.ent file instead:\n"); - LOG_INFO(" \"fog\" \"", s, "\"\n"); + LOG_INFO("Found ^1UNSUPPORTED^7 fog command in .cfg file; put this line in worldspawn in the .map/.bsp/.ent file instead:"); + LOG_INFO(" \"fog\" \"", s, "\""); } else if(argv(0) == "set") { - LOG_INFO("Found ^1UNSUPPORTED^7 set command in .cfg file; put this line in mapinfo instead:\n"); - LOG_INFO(" clientsettemp_for_type all ", argv(1), " ", argv(2), "\n"); + LOG_INFO("Found ^1UNSUPPORTED^7 set command in .cfg file; put this line in mapinfo instead:"); + LOG_INFO(" clientsettemp_for_type all ", argv(1), " ", argv(2)); } else if(argv(0) != "//") { - LOG_INFO("Found ^1UNSUPPORTED^7 set command in .cfg file; put this line in mapinfo instead:\n"); - LOG_INFO(" clientsettemp_for_type all ", argv(0), " ", argv(1), "\n"); + LOG_INFO("Found ^1UNSUPPORTED^7 set command in .cfg file; put this line in mapinfo instead:"); + LOG_INFO(" clientsettemp_for_type all ", argv(0), " ", argv(1)); } } fclose(fd); @@ -869,8 +886,6 @@ spawnfunc(worldspawn) next_pingtime = time + 5; - detect_maptype(); - // set up information replies for clients and server to use maplist_reply = strzone(getmaplist()); lsmaps_reply = strzone(getlsmaps()); @@ -943,6 +958,7 @@ spawnfunc(worldspawn) WinningConditionHelper(this); // set worldstatus world_initialized = 1; + __spawnfunc_spawn_all(); } spawnfunc(light) @@ -986,45 +1002,43 @@ float GetMaplistPosition() return idx; } -float MapHasRightSize(string map) +bool MapHasRightSize(string map) { - float fh; if(currentbots || autocvar_bot_number || player_count < autocvar_minplayers) if(autocvar_g_maplist_check_waypoints) { - LOG_TRACE("checkwp "); LOG_TRACE(map); + string checkwp_msg = strcat("checkwp ", map); if(!fexists(strcat("maps/", map, ".waypoints"))) { - LOG_TRACE(": no waypoints"); + LOG_TRACE(checkwp_msg, ": no waypoints"); return false; } - LOG_TRACE(": has waypoints"); + LOG_TRACE(checkwp_msg, ": has waypoints"); } // open map size restriction file - LOG_TRACE("opensize "); LOG_TRACE(map); - fh = fopen(strcat("maps/", map, ".sizes"), FILE_READ); + string opensize_msg = strcat("opensize ", map); + float fh = fopen(strcat("maps/", map, ".sizes"), FILE_READ); if(fh >= 0) { - float mapmin, mapmax; - LOG_TRACE(": ok, "); - mapmin = stof(fgets(fh)); - mapmax = stof(fgets(fh)); + opensize_msg = strcat(opensize_msg, ": ok, "); + int mapmin = stoi(fgets(fh)); + int mapmax = stoi(fgets(fh)); fclose(fh); if(player_count < mapmin) { - LOG_TRACE("not enough"); + LOG_TRACE(opensize_msg, "not enough"); return false; } - if(player_count > mapmax) + if(mapmax && player_count > mapmax) { - LOG_TRACE("too many"); + LOG_TRACE(opensize_msg, "too many"); return false; } - LOG_TRACE("right size"); + LOG_TRACE(opensize_msg, "right size"); return true; } - LOG_TRACE(": not found"); + LOG_TRACE(opensize_msg, ": not found"); return true; } @@ -1092,7 +1106,7 @@ void Map_Goto(float reinit) // return codes of map selectors: // -1 = temporary failure (that is, try some method that is guaranteed to succeed) // -2 = permanent failure -float() MaplistMethod_Iterate = // usual method +float MaplistMethod_Iterate() // usual method { float pass, i; @@ -1111,7 +1125,7 @@ float() MaplistMethod_Iterate = // usual method return -1; } -float() MaplistMethod_Repeat = // fallback method +float MaplistMethod_Repeat() // fallback method { LOG_TRACE("Trying MaplistMethod_Repeat"); @@ -1120,7 +1134,7 @@ float() MaplistMethod_Repeat = // fallback method return -2; } -float() MaplistMethod_Random = // random map selection +float MaplistMethod_Random() // random map selection { float i, imax; @@ -1138,7 +1152,7 @@ float() MaplistMethod_Random = // random map selection return -1; } -float(float exponent) MaplistMethod_Shuffle = // more clever shuffling +float MaplistMethod_Shuffle(float exponent) // more clever shuffling // the exponent sets a bias on the map selection: // the higher the exponent, the less likely "shortly repeated" same maps are { @@ -1197,9 +1211,7 @@ void Maplist_Init() error("empty maplist, cannot select a new map"); Map_Current = bound(0, GetMaplistPosition(), Map_Count - 1); - if(Map_Current_Name) - strunzone(Map_Current_Name); - Map_Current_Name = strzone(argv(Map_Current)); // will be automatically freed on exit thanks to DP + strcpy(Map_Current_Name, argv(Map_Current)); // will be automatically freed on exit thanks to DP // this may or may not be correct, but who cares, in the worst case a map // isn't chosen in the first pass that should have been } @@ -1325,8 +1337,8 @@ void IntermissionThink(entity this) { FixIntermissionClient(this); - float server_screenshot = (autocvar_sv_autoscreenshot && this.cvar_cl_autoscreenshot); - float client_screenshot = (this.cvar_cl_autoscreenshot == 2); + float server_screenshot = (autocvar_sv_autoscreenshot && CS(this).cvar_cl_autoscreenshot); + float client_screenshot = (CS(this).cvar_cl_autoscreenshot == 2); if( (server_screenshot || client_screenshot) && ((this.autoscreenshot > 0) && (time > this.autoscreenshot)) ) @@ -1432,7 +1444,7 @@ void DumpStats(float final) s = strcat(s, GetGametype(), "_", GetMapname(), ":", ftos(rint(time))); if(to_console) - LOG_INFO(s, "\n"); + LOG_INFO(s); if(to_eventlog) GameLogEcho(s); @@ -1448,33 +1460,33 @@ void DumpStats(float final) s = strcat(":labels:player:", GetPlayerScoreString(NULL, 0)); if(to_console) - LOG_INFO(s, "\n"); + LOG_INFO(s); if(to_eventlog) GameLogEcho(s); if(to_file) fputs(file, strcat(s, "\n")); - FOREACH_CLIENT(IS_REAL_CLIENT(it) || (IS_BOT_CLIENT(it) && autocvar_sv_logscores_bots), LAMBDA( + FOREACH_CLIENT(IS_REAL_CLIENT(it) || (IS_BOT_CLIENT(it) && autocvar_sv_logscores_bots), { s = strcat(":player:see-labels:", GetPlayerScoreString(it, 0), ":"); - s = strcat(s, ftos(rint(time - it.jointime)), ":"); + s = strcat(s, ftos(rint(time - CS(it).jointime)), ":"); if(IS_PLAYER(it) || MUTATOR_CALLHOOK(GetPlayerStatus, it)) s = strcat(s, ftos(it.team), ":"); else s = strcat(s, "spectator:"); if(to_console) - LOG_INFO(s, playername(it, false), "\n"); + LOG_INFO(s, playername(it, false)); if(to_eventlog) GameLogEcho(strcat(s, ftos(it.playerid), ":", playername(it, false))); if(to_file) fputs(file, strcat(s, playername(it, false), "\n")); - )); + }); if(teamplay) { s = strcat(":labels:teamscores:", GetTeamScoreString(0, 0)); if(to_console) - LOG_INFO(s, "\n"); + LOG_INFO(s); if(to_eventlog) GameLogEcho(s); if(to_file) @@ -1485,7 +1497,7 @@ void DumpStats(float final) s = strcat(":teamscores:see-labels:", GetTeamScoreString(i, 0)); s = strcat(s, ":", ftos(i)); if(to_console) - LOG_INFO(s, "\n"); + LOG_INFO(s); if(to_eventlog) GameLogEcho(s); if(to_file) @@ -1494,7 +1506,7 @@ void DumpStats(float final) } if(to_console) - LOG_INFO(":end\n"); + LOG_INFO(":end"); if(to_eventlog) GameLogEcho(":end"); if(to_file) @@ -1509,7 +1521,7 @@ void FixIntermissionClient(entity e) if(!e.autoscreenshot) // initial call { e.autoscreenshot = time + 0.8; // used for autoscreenshot - e.health = -2342; + SetResourceAmountExplicit(e, RESOURCE_HEALTH, -2342); // first intermission phase; voting phase has positive health (used to decide whether to send SVC_FINALE or not) for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { @@ -1525,9 +1537,9 @@ void FixIntermissionClient(entity e) { stuffcmd(e, "\nscr_printspeed 1000000\n"); RandomSelection_Init(); - FOREACH_WORD(autocvar_sv_intermission_cdtrack, true, LAMBDA( + FOREACH_WORD(autocvar_sv_intermission_cdtrack, true, { RandomSelection_AddString(it, 1, 1); - )); + }); if (RandomSelection_chosen_string != "") { stuffcmd(e, sprintf("\ncd loop %s\n", RandomSelection_chosen_string)); @@ -1577,11 +1589,11 @@ void NextLevel() GameLogClose(); - FOREACH_CLIENT(IS_PLAYER(it), LAMBDA( + FOREACH_CLIENT(IS_PLAYER(it), { FixIntermissionClient(it); if(it.winning) bprint(playername(it, false), " ^7wins.\n"); - )); + }); target_music_kill(); @@ -1593,25 +1605,6 @@ void NextLevel() localcmd("\nsv_hook_gameend\n"); } -/* -============ -CheckRules_Player - -Exit deathmatch games upon conditions -============ -*/ -void CheckRules_Player(entity this) -{ - if (game_stopped) // someone else quit the game already - return; - - if(!IS_DEAD(this)) - this.play_time += frametime; - - // fixme: don't check players; instead check spawnfunc_dom_team and spawnfunc_ctf_team entities - // (div0: and that in CheckRules_World please) -} - float InitiateSuddenDeath() { @@ -1619,7 +1612,9 @@ float InitiateSuddenDeath() // - for this timelimit_overtime needs to be >0 of course // - also check the winning condition calculated in the previous frame and only add normal overtime // again, if at the point at which timelimit would be extended again, still no winner was found - if (!autocvar_g_campaign && (checkrules_overtimesadded >= 0) && (checkrules_overtimesadded < autocvar_timelimit_overtimes || autocvar_timelimit_overtimes < 0) && autocvar_timelimit_overtime && !(g_race && !g_race_qualifying)) + if (!autocvar_g_campaign && checkrules_overtimesadded >= 0 + && (checkrules_overtimesadded < autocvar_timelimit_overtimes || autocvar_timelimit_overtimes < 0) + && autocvar_timelimit_overtime && !(g_race && !g_race_qualifying)) { return 1; // need to call InitiateOvertime later } @@ -1642,11 +1637,7 @@ void InitiateOvertime() // ONLY call this if InitiateSuddenDeath returned true { ++checkrules_overtimesadded; //add one more overtime by simply extending the timelimit - float tl; - tl = autocvar_timelimit; - tl += autocvar_timelimit_overtime; - cvar_set("timelimit", ftos(tl)); - + cvar_set("timelimit", ftos(autocvar_timelimit + autocvar_timelimit_overtime)); Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60); } @@ -1674,22 +1665,22 @@ float GetWinningCode(float fraglimitreached, float equality) // set the .winning flag for exactly those players with a given field value void SetWinners(.float field, float value) { - FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(it.winning = (it.(field) == value))); + FOREACH_CLIENT(IS_PLAYER(it), { it.winning = (it.(field) == value); }); } // set the .winning flag for those players with a given field value void AddWinners(.float field, float value) { - FOREACH_CLIENT(IS_PLAYER(it), LAMBDA( + FOREACH_CLIENT(IS_PLAYER(it), { if(it.(field) == value) it.winning = 1; - )); + }); } // clear the .winning flags void ClearWinners() { - FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(it.winning = 0)); + FOREACH_CLIENT(IS_PLAYER(it), { it.winning = 0; }); } void ShuffleMaplist() @@ -1707,10 +1698,11 @@ float WinningCondition_Scores(float limit, float leadlimit) if(teamplay) { - team1_score = TeamScore_GetCompareValue(NUM_TEAM_1); - team2_score = TeamScore_GetCompareValue(NUM_TEAM_2); - team3_score = TeamScore_GetCompareValue(NUM_TEAM_3); - team4_score = TeamScore_GetCompareValue(NUM_TEAM_4); + for (int i = 1; i < 5; ++i) + { + Team_SetTeamScore(Team_GetTeamFromIndex(i), + TeamScore_GetCompareValue(Team_IndexToTeam(i))); + } } ClearWinners(); @@ -1780,30 +1772,32 @@ float WinningCondition_RanOutOfSpawns() if(!some_spawn_has_been_used) return WINNING_NO; - team1_score = team2_score = team3_score = team4_score = 0; + for (int i = 1; i < 5; ++i) + { + Team_SetTeamScore(Team_GetTeamFromIndex(i), 0); + } - FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), LAMBDA( - switch(it.team) + FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), + { + if (Team_IsValidTeam(it.team)) { - case NUM_TEAM_1: team1_score = 1; break; - case NUM_TEAM_2: team2_score = 1; break; - case NUM_TEAM_3: team3_score = 1; break; - case NUM_TEAM_4: team4_score = 1; break; + Team_SetTeamScore(Team_GetTeam(it.team), 1); } - )); + }); IL_EACH(g_spawnpoints, true, { - switch(it.team) + if (Team_IsValidTeam(it.team)) { - case NUM_TEAM_1: team1_score = 1; break; - case NUM_TEAM_2: team2_score = 1; break; - case NUM_TEAM_3: team3_score = 1; break; - case NUM_TEAM_4: team4_score = 1; break; + Team_SetTeamScore(Team_GetTeam(it.team), 1); } }); ClearWinners(); + float team1_score = Team_GetTeamScore(Team_GetTeamFromIndex(1)); + float team2_score = Team_GetTeamScore(Team_GetTeamFromIndex(2)); + float team3_score = Team_GetTeamScore(Team_GetTeamFromIndex(3)); + float team4_score = Team_GetTeamScore(Team_GetTeamFromIndex(4)); if(team1_score + team2_score + team3_score + team4_score == 0) { checkrules_equality = true; @@ -1813,20 +1807,28 @@ float WinningCondition_RanOutOfSpawns() { float t, i; if(team1_score) - t = NUM_TEAM_1; + t = 1; else if(team2_score) - t = NUM_TEAM_2; + t = 2; else if(team3_score) - t = NUM_TEAM_3; + t = 3; else // if(team4_score) - t = NUM_TEAM_4; - CheckAllowedTeams(NULL); + t = 4; + entity balance = TeamBalance_CheckAllowedTeams(NULL); for(i = 0; i < MAX_TEAMSCORE; ++i) { - if(t != NUM_TEAM_1) if(c1 >= 0) TeamScore_AddToTeam(NUM_TEAM_1, i, -1000); - if(t != NUM_TEAM_2) if(c2 >= 0) TeamScore_AddToTeam(NUM_TEAM_2, i, -1000); - if(t != NUM_TEAM_3) if(c3 >= 0) TeamScore_AddToTeam(NUM_TEAM_3, i, -1000); - if(t != NUM_TEAM_4) if(c4 >= 0) TeamScore_AddToTeam(NUM_TEAM_4, i, -1000); + for (int j = 1; j <= NUM_TEAMS; ++j) + { + if (t == j) + { + continue; + } + if (!TeamBalance_IsTeamAllowed(balance, j)) + { + continue; + } + TeamScore_AddToTeam(Team_IndexToTeam(j), i, -1000); + } } AddWinners(team, t); @@ -1916,13 +1918,13 @@ void CheckRules_World() float playerswithlaps; float readyplayers; totalplayers = playerswithlaps = readyplayers = 0; - FOREACH_CLIENT(IS_PLAYER(it), LAMBDA( + FOREACH_CLIENT(IS_PLAYER(it), { ++totalplayers; - if(PlayerScore_Add(it, SP_RACE_FASTEST, 0)) + if(GameRules_scoring_add(it, RACE_FASTEST, 0)) ++playerswithlaps; if(it.ready) ++readyplayers; - )); + }); // at least 2 of the players have completed a lap: start the RACE // otherwise, the players should end the qualifying on their own @@ -2084,12 +2086,12 @@ void EndFrame() FOREACH_CLIENT(IS_REAL_CLIENT(it), { entity e = IS_SPEC(it) ? it.enemy : it; if (e.typehitsound) { - it.typehit_time = time; + STAT(TYPEHIT_TIME, it) = time; } else if (e.killsound) { - it.kill_time = time; + STAT(KILL_TIME, it) = time; } else if (e.damage_dealt) { - it.hit_time = time; - it.damage_dealt_total += ceil(e.damage_dealt); + STAT(HIT_TIME, it) = time; + STAT(DAMAGE_DEALT_TOTAL, it) += ceil(e.damage_dealt); } }); // add 1 frametime because after this, engine SV_Physics @@ -2108,6 +2110,10 @@ void EndFrame() { antilag_record(it, it, altime); }); + IL_EACH(g_projectiles, it.classname == "nade", + { + antilag_record(it, it, altime); + }); systems_update(); IL_ENDFRAME(); } @@ -2142,17 +2148,17 @@ float RedirectionThink() redirection_nextthink = time + 1; clients_found = 0; - FOREACH_CLIENT(IS_REAL_CLIENT(it), LAMBDA( + FOREACH_CLIENT(IS_REAL_CLIENT(it), { // TODO add timer - LOG_INFO("Redirecting: sending connect command to ", it.netname, "\n"); + LOG_INFO("Redirecting: sending connect command to ", it.netname); if(redirection_target == "self") stuffcmd(it, "\ndisconnect; defer ", ftos(autocvar_quit_and_redirect_timer), " reconnect\n"); else stuffcmd(it, strcat("\ndisconnect; defer ", ftos(autocvar_quit_and_redirect_timer), " \"connect ", redirection_target, "\"\n")); ++clients_found; - )); + }); - LOG_INFO("Redirecting: ", ftos(clients_found), " clients left.\n"); + LOG_INFO("Redirecting: ", ftos(clients_found), " clients left."); if(time > redirection_timeout || clients_found == 0) localcmd("\nwait; wait; wait; quit\n"); @@ -2160,7 +2166,6 @@ float RedirectionThink() return true; } -void TargetMusic_RestoreGame(); void RestoreGame() { // Loaded from a save game @@ -2217,7 +2222,7 @@ void Shutdown() } else if(world_initialized == 0) { - LOG_INFO("NOTE: crashed before even initializing the world, not saving persistent data\n"); + LOG_INFO("NOTE: crashed before even initializing the world, not saving persistent data"); } else {