]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/g_world.qc
Merge branch 'master' into TimePath/debug_draw
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / g_world.qc
index 2ad5af5ac6b9e5fa55215f2e36e7ef26ac389293..b89f361506f6b6a8a05e2a61bf87bfbb8a5b688f 100644 (file)
@@ -1,5 +1,4 @@
 #include "g_world.qh"
-#include "_all.qh"
 
 #include "anticheat.qh"
 #include "antilag.qh"
 #include "g_hook.qh"
 #include "ipban.qh"
 #include "mapvoting.qh"
-#include "mutators/mutators_include.qh"
+#include "mutators/all.qh"
 #include "race.qh"
 #include "scores.qh"
 #include "teamplay.qh"
 #include "weapons/weaponstats.qh"
-#include "../common/buffs.qh"
+#include "../common/buffs/all.qh"
 #include "../common/constants.qh"
-#include "../common/deathtypes.qh"
-#include "../common/effects.qh"
+#include "../common/deathtypes/all.qh"
 #include "../common/mapinfo.qh"
 #include "../common/monsters/all.qh"
 #include "../common/monsters/sv_monsters.qh"
 #include "../common/vehicles/all.qh"
 #include "../common/notifications.qh"
+#include "../common/physics.qh"
 #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/util.qh"
 #include "../common/items/all.qh"
 #include "../common/weapons/all.qh"
@@ -41,7 +42,7 @@ const float LATENCY_THINKRATE = 10;
 .float latency_time;
 entity pingplreport;
 void PingPLReport_Think()
-{
+{SELFPARAM();
        float delta;
        entity e;
 
@@ -82,8 +83,8 @@ void PingPLReport_Think()
 }
 void PingPLReport_Spawn()
 {
-       pingplreport = spawn();
-       pingplreport.classname = "pingplreport";
+       pingplreport = new(pingplreport);
+       make_pure(pingplreport);
        pingplreport.think = PingPLReport_Think;
        pingplreport.nextthink = time;
 }
@@ -117,7 +118,7 @@ void SetDefaultAlpha()
 }
 
 void GotoFirstMap()
-{
+{SELFPARAM();
        float n;
        if(autocvar__sv_init)
        {
@@ -146,7 +147,7 @@ void GotoFirstMap()
        else
        {
                self.nextthink = time + 1;
-               print("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...\n");
        }
 }
 
@@ -503,7 +504,7 @@ void detect_maptype()
                        tracebox(o, '-1 -1 -1' * i, '1 1 1' * i, o - '0 0 32768', MOVE_WORLDONLY, world);
        if(trace_fraction == 1)
                continue;
-                       print(ftos(i), " -> ", vtos(trace_endpos), "\n");
+                       LOG_INFO(ftos(i), " -> ", vtos(trace_endpos), "\n");
                }
 
                break;
@@ -512,33 +513,30 @@ void detect_maptype()
 }
 
 entity randomseed;
-float RandomSeed_Send(entity to, int sf)
+bool RandomSeed_Send(entity this, entity to, int sf)
 {
        WriteByte(MSG_ENTITY, ENT_CLIENT_RANDOMSEED);
        WriteShort(MSG_ENTITY, self.cnt);
        return true;
 }
 void RandomSeed_Think()
-{
+{SELFPARAM();
        self.cnt = bound(0, floor(random() * 65536), 65535);
        self.nextthink = time + 5;
 
        self.SendFlags |= 1;
 }
 void RandomSeed_Spawn()
-{
-       randomseed = spawn();
+{SELFPARAM();
+       randomseed = new(randomseed);
+       make_pure(randomseed);
        randomseed.think = RandomSeed_Think;
        Net_LinkEntity(randomseed, false, 0, RandomSeed_Send);
 
-       entity oldself;
-       oldself = self;
-       self = randomseed;
-       self.think(); // sets random seed and nextthink
-       self = oldself;
+       WITH(entity, self, randomseed, randomseed.think()); // sets random seed and nextthink
 }
 
-void spawnfunc___init_dedicated_server(void)
+spawnfunc(__init_dedicated_server)
 {
        // handler for _init/_init map (only for dedicated server initialization)
 
@@ -549,22 +547,18 @@ void spawnfunc___init_dedicated_server(void)
 
        remove = remove_unsafely;
 
-       entity e;
-       e = spawn();
+       entity e = spawn();
        e.think = GotoFirstMap;
        e.nextthink = time; // this is usually 1 at this point
 
-       e = spawn();
-       e.classname = "info_player_deathmatch"; // safeguard against player joining
+       e = new(info_player_deathmatch);  // safeguard against player joining
 
        self.classname = "worldspawn"; // safeguard against various stuff ;)
 
        // needs to be done so early because of the constants they create
        static_init();
-       CALL_ACCUMULATED_FUNCTION(RegisterTurrets);
-       CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
-       CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
-       CALL_ACCUMULATED_FUNCTION(RegisterEffects);
+       static_init_late();
+       static_init_precache();
 
        MapInfo_Enumerate();
        MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
@@ -577,7 +571,7 @@ void ClientInit_Spawn();
 void WeaponStats_Init();
 void WeaponStats_Shutdown();
 void Physics_AddStats();
-void spawnfunc_worldspawn (void)
+spawnfunc(worldspawn)
 {
        float fd, l, j, n;
        string s;
@@ -609,12 +603,6 @@ void spawnfunc_worldspawn (void)
 
        // needs to be done so early because of the constants they create
        static_init();
-       CALL_ACCUMULATED_FUNCTION(RegisterTurrets);
-       CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
-       CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
-       CALL_ACCUMULATED_FUNCTION(RegisterEffects);
-
-       initialize_minigames();
 
        ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid));
 
@@ -668,8 +656,9 @@ void spawnfunc_worldspawn (void)
 
        PlayerStats_GameReport_Init(); // we need this to be initiated before InitGameplayMode
 
-       precache_model ("null"); // we need this one before InitGameplayMode
        InitGameplayMode();
+       static_init_late();
+       static_init_precache();
        readlevelcvars();
        GrappleHookInit();
 
@@ -699,10 +688,6 @@ void spawnfunc_worldspawn (void)
                MUTATOR_CALLHOOK(BuildMutatorsString, s);
                s = ret_string;
 
-               // simple, probably not good in the mutator system
-               if(autocvar_g_grappling_hook)
-                       s = strcat(s, ":grappling_hook");
-
                // initialiation stuff, not good in the mutator system
                if(!autocvar_g_use_ammunition)
                        s = strcat(s, ":no_use_ammunition");
@@ -757,23 +742,23 @@ void spawnfunc_worldspawn (void)
                                        continue;
                                if(argv(0) == "cd")
                                {
-                                       print("Found ^1UNSUPPORTED^7 cd loop command in .cfg file; put this line in mapinfo instead:\n");
-                                       print("  cdtrack ", argv(2), "\n");
+                                       LOG_INFO("Found ^1UNSUPPORTED^7 cd loop command in .cfg file; put this line in mapinfo instead:\n");
+                                       LOG_INFO("  cdtrack ", argv(2), "\n");
                                }
                                else if(argv(0) == "fog")
                                {
-                                       print("Found ^1UNSUPPORTED^7 fog command in .cfg file; put this line in worldspawn in the .map/.bsp/.ent file instead:\n");
-                                       print("  \"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:\n");
+                                       LOG_INFO("  \"fog\" \"", s, "\"\n");
                                }
                                else if(argv(0) == "set")
                                {
-                                       print("Found ^1UNSUPPORTED^7 set command in .cfg file; put this line in mapinfo instead:\n");
-                                       print("  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:\n");
+                                       LOG_INFO("  clientsettemp_for_type all ", argv(1), " ", argv(2), "\n");
                                }
                                else if(argv(0) != "//")
                                {
-                                       print("Found ^1UNSUPPORTED^7 set command in .cfg file; put this line in mapinfo instead:\n");
-                                       print("  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:\n");
+                                       LOG_INFO("  clientsettemp_for_type all ", argv(0), " ", argv(1), "\n");
                                }
                        }
                        fclose(fd);
@@ -927,7 +912,7 @@ void spawnfunc_worldspawn (void)
        world_initialized = 1;
 }
 
-void spawnfunc_light (void)
+spawnfunc(light)
 {
        //makestatic (self); // Who the f___ did that?
        remove(self);
@@ -974,39 +959,39 @@ float MapHasRightSize(string map)
        if(currentbots || autocvar_bot_number || player_count < autocvar_minplayers)
        if(autocvar_g_maplist_check_waypoints)
        {
-               dprint("checkwp "); dprint(map);
+               LOG_TRACE("checkwp "); LOG_TRACE(map);
                if(!fexists(strcat("maps/", map, ".waypoints")))
                {
-                       dprint(": no waypoints\n");
+                       LOG_TRACE(": no waypoints\n");
                        return false;
                }
-               dprint(": has waypoints\n");
+               LOG_TRACE(": has waypoints\n");
        }
 
        // open map size restriction file
-       dprint("opensize "); dprint(map);
+       LOG_TRACE("opensize "); LOG_TRACE(map);
        fh = fopen(strcat("maps/", map, ".sizes"), FILE_READ);
        if(fh >= 0)
        {
                float mapmin, mapmax;
-               dprint(": ok, ");
+               LOG_TRACE(": ok, ");
                mapmin = stof(fgets(fh));
                mapmax = stof(fgets(fh));
                fclose(fh);
                if(player_count < mapmin)
                {
-                       dprint("not enough\n");
+                       LOG_TRACE("not enough\n");
                        return false;
                }
                if(player_count > mapmax)
                {
-                       dprint("too many\n");
+                       LOG_TRACE("too many\n");
                        return false;
                }
-               dprint("right size\n");
+               LOG_TRACE("right size\n");
                return true;
        }
-       dprint(": not found\n");
+       LOG_TRACE(": not found\n");
        return true;
 }
 
@@ -1015,22 +1000,6 @@ string Map_Filename(float position)
        return strcat("maps/", argv(position), ".bsp");
 }
 
-string strwords(string s, float w)
-{
-       float endpos;
-       for(endpos = 0; w && endpos >= 0; --w)
-               endpos = strstrofs(s, " ", endpos + 1);
-       if(endpos < 0)
-               return s;
-       else
-               return substring(s, 0, endpos);
-}
-
-float strhasword(string s, string w)
-{
-       return strstrofs(strcat(" ", s, " "), strcat(" ", w, " "), 0) >= 0;
-}
-
 void Map_MarkAsRecent(string m)
 {
        cvar_set("g_maplist_mostrecent", strwords(strcat(m, " ", autocvar_g_maplist_mostrecent), max(0, autocvar_g_maplist_mostrecent_count)));
@@ -1061,7 +1030,7 @@ float Map_Check(float position, float pass)
                return 0;
        }
        else
-               dprint( "Couldn't select '", filename, "'..\n" );
+               LOG_TRACE( "Couldn't select '", filename, "'..\n" );
 
        return 0;
 }
@@ -1094,7 +1063,7 @@ float() MaplistMethod_Iterate = // usual method
 {
        float pass, i;
 
-       dprint("Trying MaplistMethod_Iterate\n");
+       LOG_TRACE("Trying MaplistMethod_Iterate\n");
 
        for(pass = 1; pass <= 2; ++pass)
        {
@@ -1111,7 +1080,7 @@ float() MaplistMethod_Iterate = // usual method
 
 float() MaplistMethod_Repeat = // fallback method
 {
-       dprint("Trying MaplistMethod_Repeat\n");
+       LOG_TRACE("Trying MaplistMethod_Repeat\n");
 
        if(Map_Check(Map_Current, 2))
                return Map_Current;
@@ -1122,7 +1091,7 @@ float() MaplistMethod_Random = // random map selection
 {
        float i, imax;
 
-       dprint("Trying MaplistMethod_Random\n");
+       LOG_TRACE("Trying MaplistMethod_Random\n");
 
        imax = 42;
 
@@ -1142,7 +1111,7 @@ float(float exponent) MaplistMethod_Shuffle = // more clever shuffling
 {
        float i, j, imax, insertpos;
 
-       dprint("Trying MaplistMethod_Shuffle\n");
+       LOG_TRACE("Trying MaplistMethod_Shuffle\n");
 
        imax = 42;
 
@@ -1154,7 +1123,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}
-               dprint("SHUFFLE: insert pos = ", ftos(insertpos), "\n");
+               LOG_TRACE("SHUFFLE: insert pos = ", ftos(insertpos), "\n");
 
                // insert the current map there
                newlist = "";
@@ -1320,7 +1289,7 @@ When the player presses attack or jump, change to the next level
 */
 .float autoscreenshot;
 void IntermissionThink()
-{
+{SELFPARAM();
        FixIntermissionClient(self);
 
        float server_screenshot = (autocvar_sv_autoscreenshot && self.cvar_cl_autoscreenshot);
@@ -1430,7 +1399,7 @@ void DumpStats(float final)
        s = strcat(s, GetGametype(), "_", GetMapname(), ":", ftos(rint(time)));
 
        if(to_console)
-               print(s, "\n");
+               LOG_INFO(s, "\n");
        if(to_eventlog)
                GameLogEcho(s);
 
@@ -1446,7 +1415,7 @@ void DumpStats(float final)
 
        s = strcat(":labels:player:", GetPlayerScoreString(world, 0));
        if(to_console)
-               print(s, "\n");
+               LOG_INFO(s, "\n");
        if(to_eventlog)
                GameLogEcho(s);
        if(to_file)
@@ -1458,13 +1427,13 @@ void DumpStats(float final)
                {
                        s = strcat(":player:see-labels:", GetPlayerScoreString(other, 0), ":");
                        s = strcat(s, ftos(rint(time - other.jointime)), ":");
-                       if(IS_PLAYER(other) || other.caplayer == 1 || g_lms)
+                       if(IS_PLAYER(other) || MUTATOR_CALLHOOK(GetPlayerStatus, other, s))
                                s = strcat(s, ftos(other.team), ":");
                        else
                                s = strcat(s, "spectator:");
 
                        if(to_console)
-                               print(s, other.netname, "\n");
+                               LOG_INFO(s, other.netname, "\n");
                        if(to_eventlog)
                                GameLogEcho(strcat(s, ftos(other.playerid), ":", other.netname));
                        if(to_file)
@@ -1476,7 +1445,7 @@ void DumpStats(float final)
        {
                s = strcat(":labels:teamscores:", GetTeamScoreString(0, 0));
                if(to_console)
-                       print(s, "\n");
+                       LOG_INFO(s, "\n");
                if(to_eventlog)
                        GameLogEcho(s);
                if(to_file)
@@ -1487,7 +1456,7 @@ void DumpStats(float final)
                        s = strcat(":teamscores:see-labels:", GetTeamScoreString(i, 0));
                        s = strcat(s, ":", ftos(i));
                        if(to_console)
-                               print(s, "\n");
+                               LOG_INFO(s, "\n");
                        if(to_eventlog)
                                GameLogEcho(s);
                        if(to_file)
@@ -1496,7 +1465,7 @@ void DumpStats(float final)
        }
 
        if(to_console)
-               print(":end\n");
+               LOG_INFO(":end\n");
        if(to_eventlog)
                GameLogEcho(":end");
        if(to_file)
@@ -1517,11 +1486,14 @@ void FixIntermissionClient(entity e)
                e.solid = SOLID_NOT;
                e.movetype = MOVETYPE_NONE;
                e.takedamage = DAMAGE_NO;
-               if(e.weaponentity)
+               for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
-                       e.weaponentity.effects = EF_NODRAW;
-                       if (e.weaponentity.weaponentity)
-                               e.weaponentity.weaponentity.effects = EF_NODRAW;
+                       if(e.weaponentity[slot])
+                       {
+                               e.weaponentity[slot].effects = EF_NODRAW;
+                               if (e.weaponentity[slot].weaponentity[slot])
+                                       e.weaponentity[slot].weaponentity[slot].effects = EF_NODRAW;
+                       }
                }
                if(IS_REAL_CLIENT(e))
                {
@@ -1581,6 +1553,10 @@ void NextLevel()
                        bprint(other.netname, " ^7wins.\n");
        }
 
+       entity oldself = self;
+       target_music_kill();
+       self = oldself;
+
        if(autocvar_g_campaign)
                CampaignPreIntermission();
 
@@ -1597,7 +1573,7 @@ Exit deathmatch games upon conditions
 ============
 */
 void CheckRules_Player()
-{
+{SELFPARAM();
        if (gameover)   // someone else quit the game already
                return;
 
@@ -1696,7 +1672,7 @@ void ClearWinners(void)
 // they win. Otherwise the defending team wins once the timelimit passes.
 void assault_new_round();
 float WinningCondition_Assault()
-{
+{SELFPARAM();
        float status;
 
        WinningConditionHelper(); // set worldstatus
@@ -1729,11 +1705,7 @@ float WinningCondition_Assault()
                        }
                        else
                        {
-                               entity oldself;
-                               oldself = self;
-                               self = ent;
-                               assault_new_round();
-                               self = oldself;
+                               WITH(entity, self, ent, assault_new_round());
                        }
                }
        }
@@ -1741,85 +1713,6 @@ float WinningCondition_Assault()
        return status;
 }
 
-// LMS winning condition: game terminates if and only if there's at most one
-// one player who's living lives. Top two scores being equal cancels the time
-// limit.
-float WinningCondition_LMS()
-{
-       entity head, head2;
-       float have_player;
-       float have_players;
-       float l;
-
-       have_player = false;
-       have_players = false;
-       l = LMS_NewPlayerLives();
-
-       head = find(world, classname, "player");
-       if(head)
-               have_player = true;
-       head2 = find(head, classname, "player");
-       if(head2)
-               have_players = true;
-
-       if(have_player)
-       {
-               // we have at least one player
-               if(have_players)
-               {
-                       // two or more active players - continue with the game
-               }
-               else
-               {
-                       // exactly one player?
-
-                       ClearWinners();
-                       SetWinners(winning, 0); // NOTE: exactly one player is still "player", so this works out
-
-                       if(l)
-                       {
-                               // game still running (that is, nobody got removed from the game by a frag yet)? then continue
-                               return WINNING_NO;
-                       }
-                       else
-                       {
-                               // a winner!
-                               // and assign him his first place
-                               PlayerScore_Add(head, SP_LMS_RANK, 1);
-                               return WINNING_YES;
-                       }
-               }
-       }
-       else
-       {
-               // nobody is playing at all...
-               if(l)
-               {
-                       // wait for players...
-               }
-               else
-               {
-                       // SNAFU (maybe a draw game?)
-                       ClearWinners();
-                       dprint("No players, ending game.\n");
-                       return WINNING_YES;
-               }
-       }
-
-       // When we get here, we have at least two players who are actually LIVING,
-       // now check if the top two players have equal score.
-       WinningConditionHelper();
-
-       ClearWinners();
-       if(WinningConditionHelper_winner)
-               WinningConditionHelper_winner.winning = true;
-       if(WinningConditionHelper_topscore == WinningConditionHelper_secondscore)
-               return WINNING_NEVER;
-
-       // Top two have different scores? Way to go for our beloved TIMELIMIT!
-       return WINNING_NO;
-}
-
 void ShuffleMaplist()
 {
        cvar_set("g_maplist", shufflewords(autocvar_g_maplist));
@@ -1857,7 +1750,7 @@ float WinningCondition_Scores(float limit, float leadlimit)
        if(WinningConditionHelper_zeroisworst)
                leadlimit = 0; // not supported in this mode
 
-       if(g_dm || g_tdm || g_ca || g_freezetag || (g_race && !g_race_qualifying) || g_nexball)
+       if(MUTATOR_CALLHOOK(Scores_CountFragsRemaining))
        // these modes always score in increments of 1, thus this makes sense
        {
                if(leaderfrags != WinningConditionHelper_topscore)
@@ -2121,35 +2014,13 @@ void CheckRules_World()
                return;
        }
 
-       float checkrules_status;
-       checkrules_status = WinningCondition_RanOutOfSpawns();
+       int checkrules_status = WinningCondition_RanOutOfSpawns();
        if(checkrules_status == WINNING_YES)
-       {
                bprint("Hey! Someone ran out of spawns!\n");
-       }
-       else if(g_race && !g_race_qualifying && timelimit >= 0)
-       {
-               checkrules_status = WinningCondition_Race(fraglimit);
-               //print("WC_RACE yields ", ftos(checkrules_status), "\n");
-       }
-       else if(g_race && g_race_qualifying == 2 && timelimit >= 0)
-       {
-               checkrules_status = WinningCondition_QualifyingThenRace(fraglimit);
-               //print("WC_QUALIFYING_THEN_RACE yields ", ftos(checkrules_status), "\n");
-       }
-       else if(g_assault)
-       {
-               checkrules_status = WinningCondition_Assault(); // TODO remove this?
-       }
-       else if(g_lms)
-       {
-               checkrules_status = WinningCondition_LMS();
-       }
+       else if(MUTATOR_CALLHOOK(CheckRules_World, checkrules_status, timelimit, fraglimit))
+               checkrules_status = ret_float;
        else
-       {
                checkrules_status = WinningCondition_Scores(fraglimit, leadlimit);
-               //print("WC_SCORES yields ", ftos(checkrules_status), "\n");
-       }
 
        if(checkrules_status == WINNING_STARTSUDDENDEATHOVERTIME)
        {
@@ -2204,19 +2075,20 @@ string GotoMap(string m)
 
 
 void EndFrame()
-{
+{SELFPARAM();
        anticheat_endframe();
 
        float altime;
-       FOR_EACH_REALCLIENT(self)
+       entity e_;
+       FOR_EACH_REALCLIENT(e_)
        {
-               entity e = IS_SPEC(self) ? self.enemy : self;
+               entity e = IS_SPEC(e_) ? e_.enemy : e_;
                if(e.typehitsound)
-                       self.typehit_time = time;
+                       e_.typehit_time = time;
                else if(e.damage_dealt)
                {
-                       self.hit_time = time;
-                       self.damage_dealt_total += ceil(e.damage_dealt);
+                       e_.hit_time = time;
+                       e_.damage_dealt_total += ceil(e.damage_dealt);
                }
        }
        altime = time + frametime * (1 + autocvar_g_antilag_nudge);
@@ -2225,14 +2097,18 @@ void EndFrame()
        // add another frametime because client shows everything with
        // 1 frame of lag (cl_nolerp 0). The last +1 however should not be
        // needed!
-       FOR_EACH_CLIENT(self)
+       FOR_EACH_CLIENT(e_)
        {
-               self.typehitsound = false;
-               self.damage_dealt = 0;
-               antilag_record(self, altime);
+               e_.typehitsound = false;
+               e_.damage_dealt = 0;
+               setself(e_);
+               antilag_record(e_, altime);
+       }
+       FOR_EACH_MONSTER(e_)
+       {
+               setself(e_);
+               antilag_record(e_, altime);
        }
-       FOR_EACH_MONSTER(self)
-               antilag_record(self, altime);
 }
 
 
@@ -2243,7 +2119,7 @@ void EndFrame()
 float redirection_timeout;
 float redirection_nextthink;
 float RedirectionThink()
-{
+{SELFPARAM();
        float clients_found;
 
        if(redirection_target == "")
@@ -2265,10 +2141,12 @@ float RedirectionThink()
        redirection_nextthink = time + 1;
 
        clients_found = 0;
-       FOR_EACH_REALCLIENT(self)
+       entity e;
+       FOR_EACH_REALCLIENT(e)
        {
+               setself(e);
                // TODO add timer
-               print("Redirecting: sending connect command to ", self.netname, "\n");
+               LOG_INFO("Redirecting: sending connect command to ", self.netname, "\n");
                if(redirection_target == "self")
                        stuffcmd(self, "\ndisconnect; defer ", ftos(autocvar_quit_and_redirect_timer), " reconnect\n");
                else
@@ -2276,7 +2154,7 @@ float RedirectionThink()
                ++clients_found;
        }
 
-       print("Redirecting: ", ftos(clients_found), " clients left.\n");
+       LOG_INFO("Redirecting: ", ftos(clients_found), " clients left.\n");
 
        if(time > redirection_timeout || clients_found == 0)
                localcmd("\nwait; wait; wait; quit\n");
@@ -2309,7 +2187,7 @@ void Shutdown()
        if(world_initialized > 0)
        {
                world_initialized = 0;
-               print("Saving persistent data...\n");
+               LOG_INFO("Saving persistent data...\n");
                Ban_SaveBans();
 
                // playerstats with unfinished match
@@ -2332,7 +2210,7 @@ void Shutdown()
                CheatShutdown(); // must be after cheatcount check
                db_close(ServerProgsDB);
                db_close(TemporaryDB);
-               print("done!\n");
+               LOG_INFO("done!\n");
                // tell the bot system the game is ending now
                bot_endgame();
 
@@ -2341,6 +2219,6 @@ void Shutdown()
        }
        else if(world_initialized == 0)
        {
-               print("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\n");
        }
 }