]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/client.qc
Merge branch 'master' into Mario/qcphysics
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / client.qc
index 39ea13604d9a3730dfe5914b639f974a1f46541d..887e00c5946263b8ddc511ec1a2ca1673cf9f733 100644 (file)
@@ -25,6 +25,7 @@
 #include "campaign.qh"
 #include "command/common.qh"
 #include "scores_rules.qh"
+#include "weapons/common.qh"
 
 #include "bot/api.qh"
 
@@ -40,6 +41,7 @@
 #include "../common/mapobjects/teleporters.qh"
 #include "../common/mapobjects/target/spawnpoint.qh"
 #include <common/mapobjects/trigger/counter.qh>
+#include <common/mapobjects/trigger/swamp.qh>
 
 #include "../common/vehicles/all.qh"
 
@@ -604,12 +606,13 @@ void PutPlayerInServer(entity this)
                this.pauseregen_finished += f;
        }
 
-       this.damageforcescale = 2;
+       this.damageforcescale = autocvar_g_player_damageforcescale;
        this.death_time = 0;
        this.respawn_flags = 0;
        this.respawn_time = 0;
        STAT(RESPAWN_TIME, this) = 0;
-       this.scale = autocvar_sv_player_scale;
+       bool q3dfcompat = autocvar_sv_q3defragcompat && autocvar_sv_q3defragcompat_changehitbox;
+       this.scale = ((q3dfcompat) ? 0.9 : autocvar_sv_player_scale);
        this.fade_time = 0;
        this.pain_frame = 0;
        this.pain_finished = 0;
@@ -640,6 +643,10 @@ void PutPlayerInServer(entity this)
        STAT(REVIVE_PROGRESS, this) = 0;
        this.revival_time = 0;
 
+       // TODO: we can't set these in the PlayerSpawn hook since the target code is called before it!
+       STAT(BUFFS, this) = 0;
+       STAT(BUFF_TIME, this) = 0;
+
        this.air_finished = time + 12;
        this.waterlevel = WATERLEVEL_NONE;
        this.watertype = CONTENT_EMPTY;
@@ -678,6 +685,9 @@ void PutPlayerInServer(entity this)
        if(this.conveyor)
                IL_REMOVE(g_conveyed, this);
        this.conveyor = NULL; // prevent conveyors at the previous location from moving a freshly spawned player
+       if(this.swampslug)
+               delete(this.swampslug);
+       this.in_swamp = false;
        STAT(HUD, this) = HUD_NORMAL;
 
        this.event_damage = PlayerDamage;
@@ -705,10 +715,7 @@ void PutPlayerInServer(entity this)
        for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
        {
                .entity weaponentity = weaponentities[slot];
-               entity oldwep = this.(weaponentity);
                CL_SpawnWeaponentity(this, weaponentity);
-               if(oldwep && oldwep.owner == this)
-                       this.(weaponentity).m_gunalign = oldwep.m_gunalign;
        }
        this.alpha = default_player_alpha;
        this.colormod = '1 1 1' * autocvar_g_player_brightness;
@@ -770,6 +777,7 @@ void PutPlayerInServer(entity this)
 
        if (CS(this).impulse) ImpulseCommands(this);
 
+       W_ResetGunAlign(this, CS(this).cvar_cl_gunalign);
        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
        {
                .entity weaponentity = weaponentities[slot];
@@ -1061,7 +1069,7 @@ string getwelcomemessage(entity this)
        return s;
 }
 
-bool autocvar_sv_qcphysics = false; // TODO this is for testing - remove when qcphysics work
+bool autocvar_sv_qcphysics = true; // TODO this is for testing - remove when qcphysics work
 
 /**
 =============
@@ -1100,7 +1108,7 @@ void ClientConnect(entity this)
                CS(this).allowed_timeouts = autocvar_sv_timeout_number;
 
        if (autocvar_sv_eventlog)
-               GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? this.netaddress : "bot"), ":", playername(this, false)));
+               GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? GameLog_ProcessIP(this.netaddress) : "bot"), ":", playername(this, false)));
 
        CS(this).just_joined = true;  // stop spamming the eventlog with additional lines when the client connects
 
@@ -1331,7 +1339,7 @@ void PrintToChat(entity client, string text)
 ERASEABLE
 void DebugPrintToChat(entity client, string text)
 {
-       if (autocvar_developer)
+       if (autocvar_developer > 0)
        {
                PrintToChat(client, text);
        }
@@ -1347,7 +1355,7 @@ void PrintToChatAll(string text)
 ERASEABLE
 void DebugPrintToChatAll(string text)
 {
-       if (autocvar_developer)
+       if (autocvar_developer > 0)
        {
                PrintToChatAll(text);
        }
@@ -1369,7 +1377,7 @@ void PrintToChatTeam(int team_num, string text)
 ERASEABLE
 void DebugPrintToChatTeam(int team_num, string text)
 {
-       if (autocvar_developer)
+       if (autocvar_developer > 0)
        {
                PrintToChatTeam(team_num, text);
        }
@@ -1609,7 +1617,7 @@ void player_regen(entity this)
                        this.event_damage(this, this, this, 1, DEATH_ROT.m_id, DMG_NOWEP, this.origin, '0 0 0');
        }
 
-       if (!(this.items & IT_UNLIMITED_WEAPON_AMMO))
+       if (!(this.items & IT_UNLIMITED_AMMO))
        {
                float minf, maxf, limitf;
 
@@ -1675,6 +1683,7 @@ void SpectateCopy(entity this, entity spectatee)
        this.effects = spectatee.effects & EFMASK_CHEAP; // eat performance
        SetResourceExplicit(this, RES_HEALTH, GetResource(spectatee, RES_HEALTH));
        CS(this).impulse = 0;
+       this.disableclientprediction = 1; // no need to run prediction on a spectator
        this.items = spectatee.items;
        STAT(LAST_PICKUP, this) = STAT(LAST_PICKUP, spectatee);
        STAT(HIT_TIME, this) = STAT(HIT_TIME, spectatee);
@@ -2044,12 +2053,21 @@ void PrintWelcomeMessage(entity this)
        {
                if(PHYS_INPUT_BUTTON_INFO(this)) // BUTTON_INFO hides initial MOTD
                        CS(this).motd_actived_time = -2; // wait until BUTTON_INFO gets released
-               else if(CS(this).motd_actived_time == -2 || IS_PLAYER(this) || IS_SPEC(this))
+               else if (CS(this).motd_actived_time == -2)
                {
                        // instantly hide MOTD
                        CS(this).motd_actived_time = 0;
                        Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_MOTD);
                }
+               else if (IS_PLAYER(this) || IS_SPEC(this))
+               {
+                       // FIXME occasionally for some reason MOTD never goes away
+                       // delay MOTD removal a little bit in the hope it fixes this bug
+                       if (CS(this).motd_actived_time == -1) // MOTD marked to fade away as soon as client becomes player or spectator
+                               CS(this).motd_actived_time = -(5 + floor(random() * 10)); // add small delay
+                       else //if (CS(this).motd_actived_time < -2)
+                               CS(this).motd_actived_time++;
+               }
        }
 }
 
@@ -2067,6 +2085,7 @@ bool joinAllowed(entity this)
 
 .int items_added;
 .string shootfromfixedorigin;
+.bool dualwielding_prev;
 bool PlayerThink(entity this)
 {
        if (game_stopped || intermission_running) {
@@ -2169,6 +2188,15 @@ bool PlayerThink(entity this)
                stuffcmd(this, sprintf("\ncl_shootfromfixedorigin \"%s\"\n", autocvar_g_shootfromfixedorigin));
        }
 
+       // reset gun alignment when dual wielding status changes
+       // to ensure guns are always aligned right and left
+       bool dualwielding = W_DualWielding(this);
+       if(this.dualwielding_prev != dualwielding)
+       {
+               W_ResetGunAlign(this, CS(this).cvar_cl_gunalign);
+               this.dualwielding_prev = dualwielding;
+       }
+
        // LordHavoc: allow firing on move frames (sub-ticrate), this gives better timing on slow servers
        //if(frametime)
        {
@@ -2177,6 +2205,8 @@ bool PlayerThink(entity this)
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
                        .entity weaponentity = weaponentities[slot];
+                       if(WEP_CVAR(vortex, charge_always))
+                               W_Vortex_Charge(this, weaponentity, frametime);
                        W_WeaponFrame(this, weaponentity);
                }
 
@@ -2187,27 +2217,25 @@ bool PlayerThink(entity this)
                this.items |= this.items_added;
        }
 
-       player_regen(this);
-
-       // WEAPONTODO: Add a weapon request for this
-       // rot vortex charge to the charge limit
-       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+       if (frametime)
        {
-               .entity weaponentity = weaponentities[slot];
-               if (WEP_CVAR(vortex, charge_rot_rate) && this.(weaponentity).vortex_charge > WEP_CVAR(vortex, charge_limit) && this.(weaponentity).vortex_charge_rottime < time)
-                       this.(weaponentity).vortex_charge = bound(WEP_CVAR(vortex, charge_limit), this.(weaponentity).vortex_charge - WEP_CVAR(vortex, charge_rot_rate) * frametime / W_TICSPERFRAME, 1);
-       }
+               // WEAPONTODO: Add a weapon request for this
+               // rot vortex charge to the charge limit
+               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+               {
+                       .entity weaponentity = weaponentities[slot];
+                       if (WEP_CVAR(vortex, charge_rot_rate) && this.(weaponentity).vortex_charge > WEP_CVAR(vortex, charge_limit) && this.(weaponentity).vortex_charge_rottime < time)
+                               this.(weaponentity).vortex_charge = bound(WEP_CVAR(vortex, charge_limit), this.(weaponentity).vortex_charge - WEP_CVAR(vortex, charge_rot_rate) * frametime / W_TICSPERFRAME, 1);
+               }
 
-       if (frametime) player_anim(this);
+               player_regen(this);
+               player_anim(this);
+               this.dmg_team = max(0, this.dmg_team - autocvar_g_teamdamage_resetspeed * frametime);
+       }
 
-       // secret status
        secrets_setstatus(this);
-
-       // monsters status
        monsters_setstatus(this);
 
-       this.dmg_team = max(0, this.dmg_team - autocvar_g_teamdamage_resetspeed * frametime);
-
        return true;
 }
 
@@ -2437,7 +2465,7 @@ void PlayerPreThink (entity this)
                this.max_armorvalue = 0;
        }
 
-       if(IS_PLAYER(this))
+       if (frametime && IS_PLAYER(this))
        {
                if (STAT(FROZEN, this) == FROZEN_TEMP_REVIVING)
                {