]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/g_world.qc
Merge branch 'master' into TimePath/csqc_viewmodels
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / g_world.qc
index b5a2806d76d7a5756ad55a656c29951f8dd23514..9587d3cd1e2e4d103109bc77c8f3d21019eecea1 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/constants.qh"
-#include "../common/deathtypes.qh"
-#include "../common/effects/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"
@@ -53,8 +53,7 @@ void PingPLReport_Think()
        e = edict_num(self.cnt + 1);
        if(IS_REAL_CLIENT(e))
        {
-               WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-               WriteByte(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
+               WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
                WriteByte(MSG_BROADCAST, self.cnt);
                WriteShort(MSG_BROADCAST, max(1, e.ping));
                WriteByte(MSG_BROADCAST, ceil(e.ping_packetloss * 255));
@@ -71,8 +70,7 @@ void PingPLReport_Think()
        }
        else
        {
-               WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-               WriteByte(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
+               WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
                WriteByte(MSG_BROADCAST, self.cnt);
                WriteShort(MSG_BROADCAST, 0);
                WriteByte(MSG_BROADCAST, 0);
@@ -82,8 +80,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;
 }
@@ -97,17 +95,7 @@ void ShuffleMaplist();
 
 void SetDefaultAlpha()
 {
-       if(autocvar_g_running_guns)
-       {
-               default_player_alpha = -1;
-               default_weapon_alpha = +1;
-       }
-       else if(g_cloaked)
-       {
-               default_player_alpha = autocvar_g_balance_cloaked_alpha;
-               default_weapon_alpha = default_player_alpha;
-       }
-       else
+       if (!MUTATOR_CALLHOOK(SetDefaultAlpha))
        {
                default_player_alpha = autocvar_g_player_alpha;
                if(default_player_alpha == 0)
@@ -512,9 +500,9 @@ void detect_maptype()
 }
 
 entity randomseed;
-float RandomSeed_Send(entity to, int sf)
-{SELFPARAM();
-       WriteByte(MSG_ENTITY, ENT_CLIENT_RANDOMSEED);
+bool RandomSeed_Send(entity this, entity to, int sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_RANDOMSEED);
        WriteShort(MSG_ENTITY, self.cnt);
        return true;
 }
@@ -527,15 +515,16 @@ void RandomSeed_Think()
 }
 void RandomSeed_Spawn()
 {SELFPARAM();
-       randomseed = spawn();
+       randomseed = new(randomseed);
+       make_pure(randomseed);
        randomseed.think = RandomSeed_Think;
        Net_LinkEntity(randomseed, false, 0, RandomSeed_Send);
 
        WITH(entity, self, randomseed, randomseed.think()); // sets random seed and nextthink
 }
 
-void spawnfunc___init_dedicated_server(void)
-{SELFPARAM();
+spawnfunc(__init_dedicated_server)
+{
        // handler for _init/_init map (only for dedicated server initialization)
 
        world_initialized = -1; // don't complain
@@ -545,35 +534,35 @@ 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);
+       static_init_late();
+       static_init_precache();
 
        MapInfo_Enumerate();
        MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
 }
 
+void __init_dedicated_server_shutdown() {
+       MapInfo_Shutdown();
+}
+
 void Map_MarkAsRecent(string m);
 float world_already_spawned;
 void Nagger_Init();
 void ClientInit_Spawn();
 void WeaponStats_Init();
 void WeaponStats_Shutdown();
-void Physics_AddStats();
-void spawnfunc_worldspawn (void)
-{SELFPARAM();
+spawnfunc(worldspawn)
+{
        float fd, l, j, n;
        string s;
 
@@ -591,24 +580,16 @@ void spawnfunc_worldspawn (void)
 
        compressShortVector_init();
 
-       entity head;
-       head = nextent(world);
        maxclients = 0;
-       while(head)
+       for (entity head = nextent(world); head; head = nextent(head))
        {
                ++maxclients;
-               head = nextent(head);
        }
 
        server_is_dedicated = (stof(cvar_defstring("is_dedicated")) ? true : false);
 
        // 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);
-
-       initialize_minigames();
 
        ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid));
 
@@ -663,6 +644,8 @@ void spawnfunc_worldspawn (void)
        PlayerStats_GameReport_Init(); // we need this to be initiated before InitGameplayMode
 
        InitGameplayMode();
+       static_init_late();
+       static_init_precache();
        readlevelcvars();
        GrappleHookInit();
 
@@ -692,10 +675,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");
@@ -775,77 +754,8 @@ void spawnfunc_worldspawn (void)
 
        WeaponStats_Init();
 
-       WepSet_AddStat();
-       WepSet_AddStat_InMap();
-       addstat(STAT_SWITCHWEAPON, AS_INT, switchweapon);
-       addstat(STAT_SWITCHINGWEAPON, AS_INT, switchingweapon);
-       addstat(STAT_GAMESTARTTIME, AS_FLOAT, stat_game_starttime);
-       addstat(STAT_ROUNDSTARTTIME, AS_FLOAT, stat_round_starttime);
-       addstat(STAT_ALLOW_OLDVORTEXBEAM, AS_INT, stat_allow_oldvortexbeam);
        Nagger_Init();
 
-       addstat(STAT_STRENGTH_FINISHED, AS_FLOAT, strength_finished);
-       addstat(STAT_INVINCIBLE_FINISHED, AS_FLOAT, invincible_finished);
-       addstat(STAT_SUPERWEAPONS_FINISHED, AS_FLOAT, superweapons_finished);
-       addstat(STAT_PRESSED_KEYS, AS_FLOAT, pressedkeys);
-       addstat(STAT_FUEL, AS_INT, ammo_fuel);
-       addstat(STAT_PLASMA, AS_INT, ammo_plasma);
-       addstat(STAT_SHOTORG, AS_INT, stat_shotorg);
-       addstat(STAT_LEADLIMIT, AS_FLOAT, stat_leadlimit);
-       addstat(STAT_WEAPON_CLIPLOAD, AS_INT, clip_load);
-       addstat(STAT_WEAPON_CLIPSIZE, AS_INT, clip_size);
-       addstat(STAT_LAST_PICKUP, AS_FLOAT, last_pickup);
-       addstat(STAT_HIT_TIME, AS_FLOAT, hit_time);
-       addstat(STAT_DAMAGE_DEALT_TOTAL, AS_INT, damage_dealt_total);
-       addstat(STAT_TYPEHIT_TIME, AS_FLOAT, typehit_time);
-       addstat(STAT_LAYED_MINES, AS_INT, minelayer_mines);
-
-       addstat(STAT_VORTEX_CHARGE, AS_FLOAT, vortex_charge);
-       addstat(STAT_VORTEX_CHARGEPOOL, AS_FLOAT, vortex_chargepool_ammo);
-
-       addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load);
-
-       addstat(STAT_ARC_HEAT, AS_FLOAT, arc_heat_percent);
-
-       // freeze attacks
-       addstat(STAT_FROZEN, AS_INT, frozen);
-       addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, revive_progress);
-
-       // physics
-       Physics_AddStats();
-
-       // new properties
-       addstat(STAT_MOVEVARS_JUMPVELOCITY, AS_FLOAT, stat_sv_jumpvelocity);
-       addstat(STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, AS_FLOAT, stat_sv_airaccel_qw_stretchfactor);
-       addstat(STAT_MOVEVARS_MAXAIRSTRAFESPEED, AS_FLOAT, stat_sv_maxairstrafespeed);
-       addstat(STAT_MOVEVARS_MAXAIRSPEED, AS_FLOAT, stat_sv_maxairspeed);
-       addstat(STAT_MOVEVARS_AIRSTRAFEACCELERATE, AS_FLOAT, stat_sv_airstrafeaccelerate);
-       addstat(STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL, AS_FLOAT, stat_sv_warsowbunny_turnaccel);
-       addstat(STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, AS_FLOAT, stat_sv_airaccel_sideways_friction);
-       addstat(STAT_MOVEVARS_AIRCONTROL, AS_FLOAT, stat_sv_aircontrol);
-       addstat(STAT_MOVEVARS_AIRCONTROL_POWER, AS_FLOAT, stat_sv_aircontrol_power);
-       addstat(STAT_MOVEVARS_AIRCONTROL_PENALTY, AS_FLOAT, stat_sv_aircontrol_penalty);
-       addstat(STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL, AS_FLOAT, stat_sv_warsowbunny_airforwardaccel);
-       addstat(STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED, AS_FLOAT, stat_sv_warsowbunny_topspeed);
-       addstat(STAT_MOVEVARS_WARSOWBUNNY_ACCEL, AS_FLOAT, stat_sv_warsowbunny_accel);
-       addstat(STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO, AS_FLOAT, stat_sv_warsowbunny_backtosideratio);
-       addstat(STAT_MOVEVARS_FRICTION, AS_FLOAT, stat_sv_friction);
-       addstat(STAT_MOVEVARS_ACCELERATE, AS_FLOAT, stat_sv_accelerate);
-       addstat(STAT_MOVEVARS_STOPSPEED, AS_FLOAT, stat_sv_stopspeed);
-       addstat(STAT_MOVEVARS_AIRACCELERATE, AS_FLOAT, stat_sv_airaccelerate);
-       addstat(STAT_MOVEVARS_AIRSTOPACCELERATE, AS_FLOAT, stat_sv_airstopaccelerate);
-
-       // secrets
-       addstat(STAT_SECRETS_TOTAL, AS_FLOAT, stat_secrets_total);
-       addstat(STAT_SECRETS_FOUND, AS_FLOAT, stat_secrets_found);
-
-       // monsters
-       addstat(STAT_MONSTERS_TOTAL, AS_FLOAT, stat_monsters_total);
-       addstat(STAT_MONSTERS_KILLED, AS_FLOAT, stat_monsters_killed);
-
-       // misc
-       addstat(STAT_RESPAWN_TIME, AS_FLOAT, stat_respawn_time);
-
        next_pingtime = time + 5;
 
        detect_maptype();
@@ -920,8 +830,8 @@ void spawnfunc_worldspawn (void)
        world_initialized = 1;
 }
 
-void spawnfunc_light (void)
-{SELFPARAM();
+spawnfunc(light)
+{
        //makestatic (self); // Who the f___ did that?
        remove(self);
 }
@@ -1008,22 +918,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)));
@@ -1451,7 +1345,7 @@ 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:");
@@ -1501,7 +1395,6 @@ void DumpStats(float final)
 
 void FixIntermissionClient(entity e)
 {
-       string s;
        if(!e.autoscreenshot) // initial call
        {
                e.autoscreenshot = time + 0.8;  // used for autoscreenshot
@@ -1510,18 +1403,24 @@ 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;
+                   .entity weaponentity = weaponentities[slot];
+                       if(e.(weaponentity))
+                       {
+                               e.(weaponentity).effects = EF_NODRAW;
+                               if (e.(weaponentity).weaponchild)
+                                       e.(weaponentity).weaponchild.effects = EF_NODRAW;
+                       }
                }
                if(IS_REAL_CLIENT(e))
                {
                        stuffcmd(e, "\nscr_printspeed 1000000\n");
-                       s = autocvar_sv_intermission_cdtrack;
-                       if(s != "")
-                               stuffcmd(e, strcat("\ncd loop ", s, "\n"));
+                       string list = autocvar_sv_intermission_cdtrack;
+                       for(string it; (it = car(list)); list = cdr(list))
+                               RandomSelection_Add(world, 0, it, 1, 1);
+                       if(RandomSelection_chosen_string && RandomSelection_chosen_string != "")
+                               stuffcmd(e, strcat("\ncd loop ", RandomSelection_chosen_string, "\n"));
                        msg_entity = e;
                        WriteByte(MSG_ONE, SVC_INTERMISSION);
                }
@@ -1574,6 +1473,10 @@ void NextLevel()
                        bprint(other.netname, " ^7wins.\n");
        }
 
+       entity oldself = self;
+       target_music_kill();
+       self = oldself;
+
        if(autocvar_g_campaign)
                CampaignPreIntermission();
 
@@ -1678,7 +1581,7 @@ void AddWinners(.float field, float value)
 }
 
 // clear the .winning flags
-void ClearWinners(void)
+void ClearWinners()
 {
        entity head;
        FOR_EACH_PLAYER(head)
@@ -1730,85 +1633,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();
-                       LOG_TRACE("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));
@@ -1886,46 +1710,6 @@ float WinningCondition_Scores(float limit, float leadlimit)
        );
 }
 
-float WinningCondition_Race(float fraglimit)
-{
-       float wc;
-       entity p;
-       float n, c;
-
-       n = 0;
-       c = 0;
-       FOR_EACH_PLAYER(p)
-       {
-               ++n;
-               if(p.race_completed)
-                       ++c;
-       }
-       if(n && (n == c))
-               return WINNING_YES;
-       wc = WinningCondition_Scores(fraglimit, 0);
-
-       // ALWAYS initiate overtime, unless EVERYONE has finished the race!
-       if(wc == WINNING_YES || wc == WINNING_STARTSUDDENDEATHOVERTIME)
-       // do NOT support equality when the laps are all raced!
-               return WINNING_STARTSUDDENDEATHOVERTIME;
-       else
-               return WINNING_NEVER;
-}
-
-float WinningCondition_QualifyingThenRace(float limit)
-{
-       float wc;
-       wc = WinningCondition_Scores(limit, 0);
-
-       // NEVER initiate overtime
-       if(wc == WINNING_YES || wc == WINNING_STARTSUDDENDEATHOVERTIME)
-       {
-               return WINNING_YES;
-       }
-
-       return wc;
-}
-
 float WinningCondition_RanOutOfSpawns()
 {
        entity head;
@@ -2110,35 +1894,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)
        {
@@ -2339,4 +2101,8 @@ void Shutdown()
        {
                LOG_INFO("NOTE: crashed before even initializing the world, not saving persistent data\n");
        }
+       else
+       {
+               __init_dedicated_server_shutdown();
+       }
 }