]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/g_world.qc
Merge branch 'master' into Lyberta/TeamplayOverhaul
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / g_world.qc
index f00db073e47e1b805fd1bf5ac90a85cffb2e5a3a..7cbbb95d59fa20b848b0ee8a1cfa53d1db4433e1 100644 (file)
@@ -53,7 +53,7 @@ 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);
@@ -135,7 +135,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 +145,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();
@@ -253,6 +249,7 @@ 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");
 
@@ -272,6 +269,7 @@ void cvar_changes_init()
                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");
@@ -520,7 +518,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, NULL);
+               tracebox(o, STAT(PL_MIN), STAT(PL_MAX), o - '0 0 32768', MOVE_WORLDONLY, NULL);
                if(trace_fraction == 1)
                        continue;
 
@@ -531,7 +529,7 @@ void detect_maptype()
                        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");
+                       LOG_INFO(ftos(i), " -> ", vtos(trace_endpos));
                }
 
                break;
@@ -579,7 +577,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();
@@ -596,16 +602,63 @@ 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)
 {
-       if(!autocvar_g_campaign)
+       maxclients = 0;
+       for (entity head = nextent(NULL); head; head = nextent(head)) {
+               ++maxclients;
+       }
+}
+
+void default_delayedinit(entity this)
+{
+       if(!scores_initialized)
+               ScoreRules_generic();
+}
+
+void InitGameplayMode()
+{
+       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);
@@ -652,7 +705,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
@@ -673,7 +726,7 @@ spawnfunc(worldspawn)
                }
                if (wantrestart)
                {
-                       LOG_INFOF("Restart requested\n");
+                       LOG_INFOF("Restart requested");
                        changelevel(mapname);
                        // let initialization continue, shutdown depends on it
                }
@@ -691,12 +744,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();
 
@@ -758,8 +805,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;
@@ -845,23 +891,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);
@@ -948,6 +994,7 @@ spawnfunc(worldspawn)
        WinningConditionHelper(this); // set worldstatus
 
        world_initialized = 1;
+       __spawnfunc_spawn_all();
 }
 
 spawnfunc(light)
@@ -991,45 +1038,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;
 }
 
@@ -1202,9 +1247,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
 }
@@ -1330,8 +1373,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)) )
@@ -1437,7 +1480,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);
 
@@ -1453,7 +1496,7 @@ 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)
@@ -1468,7 +1511,7 @@ void DumpStats(float final)
                        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)
@@ -1479,7 +1522,7 @@ void DumpStats(float final)
        {
                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)
@@ -1490,7 +1533,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)
@@ -1499,7 +1542,7 @@ void DumpStats(float final)
        }
 
        if(to_console)
-               LOG_INFO(":end\n");
+               LOG_INFO(":end");
        if(to_eventlog)
                GameLogEcho(":end");
        if(to_file)
@@ -1693,10 +1736,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();
@@ -1766,30 +1810,32 @@ float WinningCondition_RanOutOfSpawns()
        if(!some_spawn_has_been_used)
                return WINNING_NO;
 
-       team1_score = team2_score = team3_score = team4_score = 0;
-
-       FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
-               switch(it.team)
+       for (int i = 1; i < 5; ++i)
+       {
+               Team_SetTeamScore(Team_GetTeamFromIndex(i), 0);
+       }
+       
+       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;
@@ -1799,20 +1845,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);
@@ -1904,7 +1958,7 @@ void CheckRules_World()
                                totalplayers = playerswithlaps = readyplayers = 0;
                                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;
@@ -2070,12 +2124,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
@@ -2094,6 +2148,10 @@ void EndFrame()
        {
                antilag_record(it, it, altime);
        });
+       IL_EACH(g_projectiles, it.classname == "nade",
+       {
+               antilag_record(it, it, altime);
+       });
        systems_update();
        IL_ENDFRAME();
 }
@@ -2130,7 +2188,7 @@ float RedirectionThink()
        clients_found = 0;
        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
@@ -2138,7 +2196,7 @@ float RedirectionThink()
                ++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");
@@ -2203,7 +2261,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
        {