X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fg_world.qc;h=27fe5c1ef395653d8b296185b1c01794c7fac772;hb=a73f79e356dd25b6ea678379e7884ee45cc1977b;hp=d31166a2579759d35c25a1fd126cdd4e8414cdab;hpb=45f093092d689eaacc6ad91771a5609e9d4b8614;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index d31166a25..27fe5c1ef 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -2,7 +2,7 @@ #include "anticheat.qh" #include "antilag.qh" -#include "bot/bot.qh" +#include "bot/api.qh" #include "campaign.qh" #include "cheats.qh" #include "cl_client.qh" @@ -24,7 +24,7 @@ #include "../common/monsters/all.qh" #include "../common/monsters/sv_monsters.qh" #include "../common/vehicles/all.qh" -#include "../common/notifications.qh" +#include "../common/notifications/all.qh" #include "../common/physics/player.qh" #include "../common/playerstats.qh" #include "../common/stats.qh" @@ -34,27 +34,28 @@ #include "../common/util.qh" #include "../common/items/all.qh" #include "../common/weapons/all.qh" +#include "../common/state.qh" const float LATENCY_THINKRATE = 10; .float latency_sum; .float latency_cnt; .float latency_time; entity pingplreport; -void PingPLReport_Think() -{SELFPARAM(); +void PingPLReport_Think(entity this) +{ float delta; entity e; delta = 3 / maxclients; if(delta < sys_frametime) delta = 0; - self.nextthink = time + delta; + this.nextthink = time + delta; - e = edict_num(self.cnt + 1); + e = edict_num(this.cnt + 1); if(IS_REAL_CLIENT(e)) { WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT); - WriteByte(MSG_BROADCAST, self.cnt); + WriteByte(MSG_BROADCAST, this.cnt); WriteShort(MSG_BROADCAST, max(1, e.ping)); WriteByte(MSG_BROADCAST, ceil(e.ping_packetloss * 255)); WriteByte(MSG_BROADCAST, ceil(e.ping_movementloss * 255)); @@ -71,18 +72,17 @@ void PingPLReport_Think() else { WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT); - WriteByte(MSG_BROADCAST, self.cnt); + WriteByte(MSG_BROADCAST, this.cnt); WriteShort(MSG_BROADCAST, 0); WriteByte(MSG_BROADCAST, 0); WriteByte(MSG_BROADCAST, 0); } - self.cnt = (self.cnt + 1) % maxclients; + this.cnt = (this.cnt + 1) % maxclients; } void PingPLReport_Spawn() { - pingplreport = new(pingplreport); - make_pure(pingplreport); - pingplreport.think = PingPLReport_Think; + pingplreport = new_pure(pingplreport); + setthink(pingplreport, PingPLReport_Think); pingplreport.nextthink = time; } @@ -104,8 +104,8 @@ void SetDefaultAlpha() } } -void GotoFirstMap() -{SELFPARAM(); +void GotoFirstMap(entity this) +{ float n; if(autocvar__sv_init) { @@ -129,11 +129,11 @@ void GotoFirstMap() if(time < 5) { - self.nextthink = time; + this.nextthink = time; } else { - self.nextthink = time + 1; + this.nextthink = time + 1; LOG_INFO("Waiting for _sv_init being set to 1 by initialization scripts...\n"); } } @@ -232,7 +232,6 @@ void cvar_changes_init() BADPREFIX("g_chat_flood_"); BADPREFIX("g_ghost_items"); BADPREFIX("g_playerstats_"); - BADPREFIX("g_respawn_ghosts"); BADPREFIX("g_voice_flood_"); BADPREFIX("log_file"); BADPREFIX("rcon_"); @@ -305,6 +304,7 @@ void cvar_changes_init() // does nothing gameplay relevant BADCVAR("captureleadlimit_override"); BADCVAR("gameversion"); + BADCVAR("g_allow_oldvortexbeam"); BADCVAR("g_balance_kill_delay"); BADCVAR("g_campcheck_distance"); BADCVAR("g_ca_point_leadlimit"); @@ -338,6 +338,7 @@ void cvar_changes_init() BADPREFIX("g_ctf_captimerecord_"); BADPREFIX("g_maplist_votable_"); BADPREFIX("g_mod_"); + BADPREFIX("g_respawn_"); BADPREFIX("net_"); BADPREFIX("prvm_"); BADPREFIX("skill_"); @@ -393,6 +394,7 @@ void cvar_changes_init() BADCVAR("g_powerups"); BADCVAR("g_spawnshieldtime"); BADCVAR("g_start_delay"); + BADCVAR("g_superspectate"); BADCVAR("g_tdm_teams_override"); BADCVAR("g_warmup"); BADCVAR("g_weapon_stay"); BADPRESUFFIX("g_", "_weapon_stay"); @@ -411,6 +413,7 @@ void cvar_changes_init() BADCVAR("sv_autotaunt"); BADCVAR("sv_curl_defaulturl"); BADCVAR("sv_defaultcharacter"); + BADCVAR("sv_defaultcharacterskin"); BADCVAR("sv_defaultplayercolors"); BADCVAR("sv_defaultplayermodel"); BADCVAR("sv_defaultplayerskin"); @@ -486,7 +489,7 @@ void detect_maptype() 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, world); + tracebox(o, STAT(PL_MIN, NULL), STAT(PL_MAX, NULL), o - '0 0 32768', MOVE_WORLDONLY, NULL); if(trace_fraction == 1) continue; @@ -494,7 +497,7 @@ void detect_maptype() for(i = 0; i < 64; i += 4) { - tracebox(o, '-1 -1 -1' * i, '1 1 1' * i, o - '0 0 32768', MOVE_WORLDONLY, world); + 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"); @@ -509,24 +512,23 @@ entity randomseed; bool RandomSeed_Send(entity this, entity to, int sf) { WriteHeader(MSG_ENTITY, ENT_CLIENT_RANDOMSEED); - WriteShort(MSG_ENTITY, self.cnt); + WriteShort(MSG_ENTITY, this.cnt); return true; } -void RandomSeed_Think() -{SELFPARAM(); - self.cnt = bound(0, floor(random() * 65536), 65535); - self.nextthink = time + 5; +void RandomSeed_Think(entity this) +{ + this.cnt = bound(0, floor(random() * 65536), 65535); + this.nextthink = time + 5; - self.SendFlags |= 1; + this.SendFlags |= 1; } void RandomSeed_Spawn() -{SELFPARAM(); - randomseed = new(randomseed); - make_pure(randomseed); - randomseed.think = RandomSeed_Think; +{ + randomseed = new_pure(randomseed); + setthink(randomseed, RandomSeed_Think); Net_LinkEntity(randomseed, false, 0, RandomSeed_Send); - WITH(entity, self, randomseed, randomseed.think()); // sets random seed and nextthink + getthink(randomseed)(randomseed); // sets random seed and nextthink } spawnfunc(__init_dedicated_server) @@ -538,15 +540,15 @@ spawnfunc(__init_dedicated_server) cvar_string = cvar_string_normal; cvar_set = cvar_set_normal; - remove = remove_unsafely; + delete_fn = remove_unsafely; entity e = spawn(); - e.think = GotoFirstMap; + setthink(e, GotoFirstMap); e.nextthink = time; // this is usually 1 at this point e = new(info_player_deathmatch); // safeguard against player joining - self.classname = "worldspawn"; // safeguard against various stuff ;) + this.classname = "worldspawn"; // safeguard against various stuff ;) // needs to be done so early because of the constants they create static_init(); @@ -561,6 +563,18 @@ void __init_dedicated_server_shutdown() { MapInfo_Shutdown(); } +void SetLimits(int fraglimit_override, int leadlimit_override, float timelimit_override, float qualifying_override) +{ + if(!autocvar_g_campaign) + { + 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)); + } + limits_are_set = true; +} + void Map_MarkAsRecent(string m); float world_already_spawned; void Nagger_Init(); @@ -571,9 +585,8 @@ spawnfunc(worldspawn) { server_is_dedicated = boolean(stof(cvar_defstring("is_dedicated"))); + bool wantrestart = false; { - bool wantrestart = false; - if (!server_is_dedicated) { // force unloading of server pk3 files when starting a listen server @@ -633,9 +646,6 @@ spawnfunc(worldspawn) } } - float fd, l; - string s; - cvar = cvar_normal; cvar_string = cvar_string_normal; cvar_set = cvar_set_normal; @@ -644,14 +654,12 @@ spawnfunc(worldspawn) error("world already spawned - you may have EXACTLY ONE worldspawn!"); world_already_spawned = true; - remove = remove_safely; // during spawning, watch what you remove! + delete_fn = remove_safely; // during spawning, watch what you remove! cvar_changes_init(); // do this very early now so it REALLY matches the server config - compressShortVector_init(); - maxclients = 0; - for (entity head = nextent(world); head; head = nextent(head)) + for (entity head = nextent(NULL); head; head = nextent(head)) { ++maxclients; } @@ -717,10 +725,16 @@ spawnfunc(worldspawn) readlevelcvars(); GrappleHookInit(); + if(!limits_are_set) + SetLimits(autocvar_fraglimit_override, autocvar_leadlimit_override, autocvar_timelimit_override, -1); + + if(warmup_limit == 0) + warmup_limit = (autocvar_timelimit > 0) ? autocvar_timelimit * 60 : autocvar_timelimit; + player_count = 0; bot_waypoints_for_items = autocvar_g_waypoints_for_items; if(bot_waypoints_for_items == 1) - if(self.spawnflags & SPAWNFLAG_NO_WAYPOINTS_FOR_ITEMS) + if(this.spawnflags & SPAWNFLAG_NO_WAYPOINTS_FOR_ITEMS) bot_waypoints_for_items = 0; precache(); @@ -734,14 +748,14 @@ spawnfunc(worldspawn) // character set: ASCII 33-126 without the following characters: : ; ' " \ $ if(autocvar_sv_eventlog) { - s = sprintf("%d.%s.%06d", itos(autocvar_sv_eventlog_files_counter), strftime(false, "%s"), floor(random() * 1000000)); + string s = sprintf("%d.%s.%06d", itos(autocvar_sv_eventlog_files_counter), strftime(false, "%s"), floor(random() * 1000000)); matchid = strzone(s); GameLogEcho(strcat(":gamestart:", GetGametype(), "_", GetMapname(), ":", s)); s = ":gameinfo:mutators:LIST"; MUTATOR_CALLHOOK(BuildMutatorsString, s); - s = ret_string; + s = M_ARGV(0, string); // initialiation stuff, not good in the mutator system if(!autocvar_g_use_ammunition) @@ -787,12 +801,13 @@ spawnfunc(worldspawn) if(whichpack(strcat("maps/", mapname, ".cfg")) != "") { - fd = fopen(strcat("maps/", mapname, ".cfg"), FILE_READ); + int fd = fopen(strcat("maps/", mapname, ".cfg"), FILE_READ); if(fd != -1) { + string s; while((s = fgets(fd))) { - l = tokenize_console(s); + int l = tokenize_console(s); if(l < 2) continue; if(argv(0) == "cd") @@ -834,7 +849,7 @@ spawnfunc(worldspawn) monsterlist_reply = strzone(getmonsterlist()); for(int i = 0; i < 10; ++i) { - s = getrecords(i); + string s = getrecords(i); if (s) records_reply[i] = strzone(s); } @@ -848,12 +863,12 @@ spawnfunc(worldspawn) CheatInit(); - localcmd("\n_sv_hook_gamestart ", GetGametype(), "\n"); + if (!wantrestart) localcmd("\n_sv_hook_gamestart ", GetGametype(), "\n"); // fill sv_curl_serverpackages from .serverpackage files if (autocvar_sv_curl_serverpackages_auto) { - s = "csprogs-" WATERMARK ".txt"; + string s = "csprogs-" WATERMARK ".txt"; // remove automatically managed files from the list to prevent duplicates for (int i = 0, n = tokenize_console(cvar_string("sv_curl_serverpackages")); i < n; ++i) { @@ -865,7 +880,7 @@ spawnfunc(worldspawn) } // add automatically managed files to the list #define X(match) MACRO_BEGIN { \ - fd = search_begin(match, true, false); \ + int fd = search_begin(match, true, false); \ if (fd >= 0) \ { \ for (int i = 0, j = search_getsize(fd); i < j; ++i) \ @@ -896,15 +911,15 @@ spawnfunc(worldspawn) // save it for later modname = strzone(modname); - WinningConditionHelper(); // set worldstatus + WinningConditionHelper(this); // set worldstatus world_initialized = 1; } spawnfunc(light) { - //makestatic (self); // Who the f___ did that? - remove(self); + //makestatic (this); // Who the f___ did that? + delete(this); } string GetGametype() @@ -951,10 +966,10 @@ float MapHasRightSize(string map) LOG_TRACE("checkwp "); LOG_TRACE(map); if(!fexists(strcat("maps/", map, ".waypoints"))) { - LOG_TRACE(": no waypoints\n"); + LOG_TRACE(": no waypoints"); return false; } - LOG_TRACE(": has waypoints\n"); + LOG_TRACE(": has waypoints"); } // open map size restriction file @@ -969,18 +984,18 @@ float MapHasRightSize(string map) fclose(fh); if(player_count < mapmin) { - LOG_TRACE("not enough\n"); + LOG_TRACE("not enough"); return false; } if(player_count > mapmax) { - LOG_TRACE("too many\n"); + LOG_TRACE("too many"); return false; } - LOG_TRACE("right size\n"); + LOG_TRACE("right size"); return true; } - LOG_TRACE(": not found\n"); + LOG_TRACE(": not found"); return true; } @@ -1019,7 +1034,7 @@ float Map_Check(float position, float pass) return 0; } else - LOG_TRACE( "Couldn't select '", filename, "'..\n" ); + LOG_DEBUG( "Couldn't select '", filename, "'..." ); return 0; } @@ -1052,7 +1067,7 @@ float() MaplistMethod_Iterate = // usual method { float pass, i; - LOG_TRACE("Trying MaplistMethod_Iterate\n"); + LOG_TRACE("Trying MaplistMethod_Iterate"); for(pass = 1; pass <= 2; ++pass) { @@ -1069,7 +1084,7 @@ float() MaplistMethod_Iterate = // usual method float() MaplistMethod_Repeat = // fallback method { - LOG_TRACE("Trying MaplistMethod_Repeat\n"); + LOG_TRACE("Trying MaplistMethod_Repeat"); if(Map_Check(Map_Current, 2)) return Map_Current; @@ -1080,7 +1095,7 @@ float() MaplistMethod_Random = // random map selection { float i, imax; - LOG_TRACE("Trying MaplistMethod_Random\n"); + LOG_TRACE("Trying MaplistMethod_Random"); imax = 42; @@ -1100,7 +1115,7 @@ float(float exponent) MaplistMethod_Shuffle = // more clever shuffling { float i, j, imax, insertpos; - LOG_TRACE("Trying MaplistMethod_Shuffle\n"); + LOG_TRACE("Trying MaplistMethod_Shuffle"); imax = 42; @@ -1112,7 +1127,7 @@ float(float exponent) MaplistMethod_Shuffle = // more clever shuffling insertpos = pow(random(), 1 / exponent); // ]0, 1] insertpos = insertpos * (Map_Count - 1); // ]0, Map_Count - 1] insertpos = ceil(insertpos) + 1; // {2, 3, 4, ..., Map_Count} - LOG_TRACE("SHUFFLE: insert pos = ", ftos(insertpos), "\n"); + LOG_TRACE("SHUFFLE: insert pos = ", ftos(insertpos)); // insert the current map there newlist = ""; @@ -1277,18 +1292,19 @@ When the player presses attack or jump, change to the next level ============ */ .float autoscreenshot; -void IntermissionThink() -{SELFPARAM(); - FixIntermissionClient(self); +void IntermissionThink(entity this) +{ + FixIntermissionClient(this); + CSQCMODEL_AUTOUPDATE(this); // PlayerPostThink returns before calling this during intermission, so run it here - float server_screenshot = (autocvar_sv_autoscreenshot && self.cvar_cl_autoscreenshot); - float client_screenshot = (self.cvar_cl_autoscreenshot == 2); + float server_screenshot = (autocvar_sv_autoscreenshot && this.cvar_cl_autoscreenshot); + float client_screenshot = (this.cvar_cl_autoscreenshot == 2); if( (server_screenshot || client_screenshot) - && ((self.autoscreenshot > 0) && (time > self.autoscreenshot)) ) + && ((this.autoscreenshot > 0) && (time > this.autoscreenshot)) ) { - self.autoscreenshot = -1; - if(IS_REAL_CLIENT(self)) { stuffcmd(self, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"\n", GetMapname(), strftime(false, "%s"))); } + this.autoscreenshot = -1; + if(IS_REAL_CLIENT(this)) { stuffcmd(this, sprintf("\nscreenshot screenshots/autoscreenshot/%s-%s.jpg; echo \"^5A screenshot has been taken at request of the server.\"\n", GetMapname(), strftime(false, "%s"))); } return; } @@ -1296,7 +1312,7 @@ void IntermissionThink() return; if(!mapvote_initialized) - if (time < intermission_exittime + 10 && !(self.BUTTON_ATCK || self.BUTTON_JUMP || self.BUTTON_ATCK2 || self.BUTTON_HOOK || self.BUTTON_USE)) + if (time < intermission_exittime + 10 && !(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this) || PHYS_INPUT_BUTTON_ATCK2(this) || PHYS_INPUT_BUTTON_HOOK(this) || PHYS_INPUT_BUTTON_USE(this))) return; MapVote_Start(); @@ -1316,7 +1332,7 @@ entity FindIntermission() local float cyc; // look for info_intermission first - spot = find (world, classname, "info_intermission"); + spot = find (NULL, classname, "info_intermission"); if (spot) { // pick a random one cyc = random() * 4; @@ -1331,22 +1347,22 @@ entity FindIntermission() } // then look for the start position - spot = find (world, classname, "info_player_start"); + spot = find (NULL, classname, "info_player_start"); if (spot) return spot; // testinfo_player_start is only found in regioned levels - spot = find (world, classname, "testplayerstart"); + spot = find (NULL, classname, "testplayerstart"); if (spot) return spot; // then look for the start position - spot = find (world, classname, "info_player_deathmatch"); + spot = find (NULL, classname, "info_player_deathmatch"); if (spot) return spot; //objerror ("FindIntermission: no spot"); - return world; + return NULL; } */ @@ -1402,7 +1418,7 @@ void DumpStats(float final) fputs(file, strcat(s, "\n")); } - s = strcat(":labels:player:", GetPlayerScoreString(world, 0)); + s = strcat(":labels:player:", GetPlayerScoreString(NULL, 0)); if(to_console) LOG_INFO(s, "\n"); if(to_eventlog) @@ -1413,7 +1429,7 @@ void DumpStats(float final) FOREACH_CLIENT(IS_REAL_CLIENT(it) || (IS_BOT_CLIENT(it) && autocvar_sv_logscores_bots), LAMBDA( s = strcat(":player:see-labels:", GetPlayerScoreString(it, 0), ":"); s = strcat(s, ftos(rint(time - it.jointime)), ":"); - if(IS_PLAYER(it) || MUTATOR_CALLHOOK(GetPlayerStatus, it, s)) + if(IS_PLAYER(it) || MUTATOR_CALLHOOK(GetPlayerStatus, it)) s = strcat(s, ftos(it.team), ":"); else s = strcat(s, "spectator:"); @@ -1468,7 +1484,7 @@ void FixIntermissionClient(entity e) e.health = -2342; // first intermission phase; voting phase has positive health (used to decide whether to send SVC_FINALE or not) e.solid = SOLID_NOT; - e.movetype = MOVETYPE_NONE; + set_movetype(e, MOVETYPE_NONE); e.takedamage = DAMAGE_NO; for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { @@ -1530,7 +1546,7 @@ void NextLevel() PlayerStats_GameReport(true); WeaponStats_Shutdown(); - Kill_Notification(NOTIF_ALL, world, MSG_CENTER, 0); // kill all centerprints now + Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_Null); // kill all centerprints now if(autocvar_sv_eventlog) GameLogEcho(":gameover"); @@ -1543,9 +1559,7 @@ void NextLevel() bprint(it.netname, " ^7wins.\n"); )); - entity oldself = self; target_music_kill(); - self = oldself; if(autocvar_g_campaign) CampaignPreIntermission(); @@ -1562,13 +1576,13 @@ CheckRules_Player Exit deathmatch games upon conditions ============ */ -void CheckRules_Player() -{SELFPARAM(); +void CheckRules_Player(entity this) +{ if (gameover) // someone else quit the game already return; - if(!IS_DEAD(self)) - self.play_time += frametime; + 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) @@ -1609,7 +1623,7 @@ void InitiateOvertime() // ONLY call this if InitiateSuddenDeath returned true tl += autocvar_timelimit_overtime; cvar_set("timelimit", ftos(tl)); - Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60); + Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60); } float GetWinningCode(float fraglimitreached, float equality) @@ -1665,7 +1679,7 @@ float WinningCondition_Scores(float limit, float leadlimit) float limitreached; // TODO make everything use THIS winning condition (except LMS) - WinningConditionHelper(); + WinningConditionHelper(NULL); if(teamplay) { @@ -1700,11 +1714,11 @@ float WinningCondition_Scores(float limit, float leadlimit) if (limit) if (leaderfrags == limit - 1) - Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_REMAINING_FRAG_1); + Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_REMAINING_FRAG_1); else if (leaderfrags == limit - 2) - Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_REMAINING_FRAG_2); + Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_REMAINING_FRAG_2); else if (leaderfrags == limit - 3) - Send_Notification(NOTIF_ALL, world, MSG_ANNCE, ANNCE_REMAINING_FRAG_3); + Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_REMAINING_FRAG_3); } } @@ -1781,7 +1795,7 @@ float WinningCondition_RanOutOfSpawns() t = NUM_TEAM_3; else // if(team4_score) t = NUM_TEAM_4; - CheckAllowedTeams(world); + CheckAllowedTeams(NULL); for(i = 0; i < MAX_TEAMSCORE; ++i) { if(t != NUM_TEAM_1) if(c1 >= 0) TeamScore_AddToTeam(NUM_TEAM_1, i, -1000); @@ -1862,9 +1876,9 @@ void CheckRules_World() { checkrules_suddendeathwarning = true; if(g_race && !g_race_qualifying) - Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_RACE_FINISHLAP); + Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_RACE_FINISHLAP); else - Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_FRAG); + Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_FRAG); } } else @@ -1911,7 +1925,7 @@ void CheckRules_World() if(checkrules_status == WINNING_YES) bprint("Hey! Someone ran out of spawns!\n"); else if(MUTATOR_CALLHOOK(CheckRules_World, checkrules_status, timelimit, fraglimit)) - checkrules_status = ret_float; + checkrules_status = M_ARGV(0, float); else checkrules_status = WinningCondition_Scores(fraglimit, leadlimit); @@ -1966,42 +1980,84 @@ string GotoMap(string m) return "Map switch will happen after scoreboard."; } +bool autocvar_sv_freezenonclients; +bool autocvar_sv_gameplayfix_delayprojectiles; +void Physics_Frame() +{ + if(autocvar_sv_freezenonclients) + return; + + FOREACH_ENTITY_FLOAT(pure_data, false, + { + if(IS_CLIENT(it) || it.classname == "" || it.move_movetype == MOVETYPE_PUSH || it.move_movetype == MOVETYPE_FAKEPUSH || it.move_movetype == MOVETYPE_PHYSICS) + continue; + + int mt = it.move_movetype; + if(mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH || mt == MOVETYPE_PHYSICS) + { + it.move_qcphysics = false; + set_movetype(it, mt); + continue; + } + + set_movetype(it, ((it.move_qcphysics) ? MOVETYPE_NONE : it.move_movetype)); + + if(it.move_movetype == MOVETYPE_NONE) + continue; + + if(it.move_qcphysics) + Movetype_Physics_NoMatchTicrate(it, PHYS_INPUT_TIMELENGTH, false); + }); + + if(autocvar_sv_gameplayfix_delayprojectiles >= 0) + return; + + FOREACH_ENTITY_FLOAT(move_qcphysics, true, + { + if(IS_CLIENT(it) || is_pure(it) || it.classname == "" || it.move_movetype == MOVETYPE_NONE) + continue; + Movetype_Physics_NoMatchTicrate(it, PHYS_INPUT_TIMELENGTH, false); + }); +} + +void systems_update(); void EndFrame() -{SELFPARAM(); +{ anticheat_endframe(); - float altime; - FOREACH_CLIENT(IS_REAL_CLIENT(it), LAMBDA( + Physics_Frame(); + + FOREACH_CLIENT(IS_REAL_CLIENT(it), { entity e = IS_SPEC(it) ? it.enemy : it; - if(e.typehitsound) + if (e.typehitsound) { it.typehit_time = time; - else if(e.damage_dealt) - { + } else if (e.damage_dealt) { it.hit_time = time; it.damage_dealt_total += ceil(e.damage_dealt); } - )); - altime = time + frametime * (1 + autocvar_g_antilag_nudge); + }); // add 1 frametime because after this, engine SV_Physics // increases time by a frametime and then networks the frame // add another frametime because client shows everything with // 1 frame of lag (cl_nolerp 0). The last +1 however should not be // needed! - FOREACH_CLIENT(true, LAMBDA( + float altime = time + frametime * (1 + autocvar_g_antilag_nudge); + FOREACH_CLIENT(true, { it.typehitsound = false; it.damage_dealt = 0; - setself(it); - antilag_record(it, altime); - )); - FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, LAMBDA( - setself(it); - antilag_record(it, altime); - )); - FOREACH_CLIENT(PS(it), LAMBDA( + antilag_record(it, CS(it), altime); + }); + IL_EACH(g_monsters, true, + { + antilag_record(it, it, altime); + }); + FOREACH_CLIENT(PS(it), { PlayerState s = PS(it); s.ps_push(s, it); - )); + }); + systems_update(); + IL_ENDFRAME(); } @@ -2012,7 +2068,7 @@ void EndFrame() float redirection_timeout; float redirection_nextthink; float RedirectionThink() -{SELFPARAM(); +{ float clients_found; if(redirection_target == "") @@ -2035,13 +2091,12 @@ float RedirectionThink() clients_found = 0; FOREACH_CLIENT(IS_REAL_CLIENT(it), LAMBDA( - setself(it); // TODO add timer - LOG_INFO("Redirecting: sending connect command to ", self.netname, "\n"); + LOG_INFO("Redirecting: sending connect command to ", it.netname, "\n"); if(redirection_target == "self") - stuffcmd(self, "\ndisconnect; defer ", ftos(autocvar_quit_and_redirect_timer), " reconnect\n"); + stuffcmd(it, "\ndisconnect; defer ", ftos(autocvar_quit_and_redirect_timer), " reconnect\n"); else - stuffcmd(self, strcat("\ndisconnect; defer ", ftos(autocvar_quit_and_redirect_timer), " \"connect ", redirection_target, "\"\n")); + stuffcmd(it, strcat("\ndisconnect; defer ", ftos(autocvar_quit_and_redirect_timer), " \"connect ", redirection_target, "\"\n")); ++clients_found; )); @@ -2078,7 +2133,7 @@ void Shutdown() if(world_initialized > 0) { world_initialized = 0; - LOG_TRACE("Saving persistent data...\n"); + LOG_TRACE("Saving persistent data..."); Ban_SaveBans(); // playerstats with unfinished match @@ -2101,7 +2156,7 @@ void Shutdown() CheatShutdown(); // must be after cheatcount check db_close(ServerProgsDB); db_close(TemporaryDB); - LOG_TRACE("Saving persistent data... done!\n"); + LOG_TRACE("Saving persistent data... done!"); // tell the bot system the game is ending now bot_endgame();