]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/client.qc
Merge branch 'master' into Lyberta/StandaloneOverkillWeapons
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / client.qc
index a05999d62987692eca018c02c64c2451c13e7e9e..7ff2f028f0faf330492b3f4dcb41546c72723495 100644 (file)
@@ -56,6 +56,8 @@
 
 #include "../lib/warpzone/server.qh"
 
+#include <common/mutators/mutator/overkill/okvortex.qh>
+
 STATIC_METHOD(Client, Add, void(Client this, int _team))
 {
     ClientConnect(this);
@@ -279,7 +281,7 @@ void PutObserverInServer(entity this)
        if (this.killcount != FRAGS_SPECTATOR)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, this.netname);
-               if(!gameover)
+               if(!game_stopped)
                if(autocvar_g_chat_nospectators == 1 || (!warmup_stage && autocvar_g_chat_nospectators == 2))
                        Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CHAT_NOSPECTATORS);
 
@@ -338,15 +340,12 @@ void PutObserverInServer(entity this)
 
        this.items = 0;
        this.weapons = '0 0 0';
+       this.dual_weapons = '0 0 0';
        this.drawonlytoclient = this;
 
        this.weaponmodel = "";
        for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
        {
-               if(!this.weaponentities[slot])
-                       continue; // first load
-               this.weaponentities[slot].hook_time = 0;
-               this.weaponentities[slot].weaponname = "";
                this.weaponentities[slot] = NULL;
        }
        this.exteriorweaponentity = NULL;
@@ -358,6 +357,15 @@ void PutObserverInServer(entity this)
        this.oldvelocity = this.velocity;
        this.fire_endtime = -1;
        this.event_damage = func_null;
+
+       for(int slot = 0; slot < MAX_AXH; ++slot)
+       {
+               entity axh = this.(AuxiliaryXhair[slot]);
+               this.(AuxiliaryXhair[slot]) = NULL;
+
+               if(axh.owner == this && axh != NULL && !wasfreed(axh))
+                       delete(axh);
+       }
 }
 
 int player_getspecies(entity this)
@@ -378,11 +386,12 @@ void FixPlayermodel(entity player)
        {
                if(teamplay)
                {
-                       string s = Static_Team_ColorName_Lower(player.team);
-                       if (s != "neutral")
+                       switch(player.team)
                        {
-                               defaultmodel = cvar_string(strcat("sv_defaultplayermodel_", s));
-                               defaultskin = cvar(strcat("sv_defaultplayerskin_", s));
+                               case NUM_TEAM_1: defaultmodel = autocvar_sv_defaultplayermodel_red; defaultskin = autocvar_sv_defaultplayerskin_red; break;
+                               case NUM_TEAM_2: defaultmodel = autocvar_sv_defaultplayermodel_blue; defaultskin = autocvar_sv_defaultplayerskin_blue; break;
+                               case NUM_TEAM_3: defaultmodel = autocvar_sv_defaultplayermodel_yellow; defaultskin = autocvar_sv_defaultplayerskin_yellow; break;
+                               case NUM_TEAM_4: defaultmodel = autocvar_sv_defaultplayermodel_pink; defaultskin = autocvar_sv_defaultplayerskin_pink; break;
                        }
                }
 
@@ -413,9 +422,13 @@ void FixPlayermodel(entity player)
        {
                if(teamplay)
                {
-                       string s = Static_Team_ColorName_Lower(player.team);
-                       if (s != "neutral")
-                               defaultskin = cvar(strcat("sv_defaultplayerskin_", s));
+                       switch(player.team)
+                       {
+                               case NUM_TEAM_1: defaultskin = autocvar_sv_defaultplayerskin_red; break;
+                               case NUM_TEAM_2: defaultskin = autocvar_sv_defaultplayerskin_blue; break;
+                               case NUM_TEAM_3: defaultskin = autocvar_sv_defaultplayerskin_yellow; break;
+                               case NUM_TEAM_4: defaultskin = autocvar_sv_defaultplayerskin_pink; break;
+                       }
                }
 
                if(!defaultskin)
@@ -488,9 +501,8 @@ void PutClientInServer(entity this)
                WriteByte(MSG_ONE, SVC_SETVIEW);
                WriteEntity(MSG_ONE, this);
        }
-       if (gameover) {
+       if (game_stopped)
                TRANSMUTE(Observer, this);
-       }
 
        SetSpectatee(this, NULL);
 
@@ -563,6 +575,8 @@ void PutClientInServer(entity this)
                }
                SetSpectatee_status(this, 0);
 
+               this.dual_weapons = '0 0 0';
+
                this.superweapons_finished = (this.weapons & WEPSET_SUPERWEAPONS) ? time + autocvar_g_balance_superweapons_time : 0;
 
                this.items = start_items;
@@ -647,6 +661,7 @@ void PutClientInServer(entity this)
                        IL_PUSH(g_bot_targets, this);
                this.bot_attack = true;
                this.monster_attack = true;
+               navigation_dynamicgoal_init(this, false);
 
                PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_JUMP(this) = PHYS_INPUT_BUTTON_ATCK2(this) = false;
 
@@ -658,7 +673,10 @@ void PutClientInServer(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;
@@ -701,7 +719,7 @@ void PutClientInServer(entity this)
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
                        .entity weaponentity = weaponentities[slot];
-                       if(slot == 0)
+                       if(slot == 0 || autocvar_g_weaponswitch_debug == 1)
                                this.(weaponentity).m_switchweapon = w_getbestweapon(this, weaponentity);
                        else
                                this.(weaponentity).m_switchweapon = WEP_Null;
@@ -711,6 +729,8 @@ void PutClientInServer(entity this)
                        this.(weaponentity).cnt = -1;
                }
 
+               MUTATOR_CALLHOOK(PlayerWeaponSelect, this);
+
                if (!warmup_stage && !this.alivetime)
                        this.alivetime = time;
 
@@ -873,7 +893,7 @@ void ClientKill_Now(entity this)
 }
 void KillIndicator_Think(entity this)
 {
-       if (gameover)
+       if (game_stopped)
        {
                this.owner.killindicator = NULL;
                delete(this);
@@ -917,7 +937,7 @@ void ClientKill_TeamChange (entity this, float targetteam) // 0 = don't change,
        float killtime;
        float starttime;
 
-       if (gameover)
+       if (game_stopped)
                return;
 
        killtime = autocvar_g_balance_kill_delay;
@@ -1009,7 +1029,7 @@ void ClientKill_TeamChange (entity this, float targetteam) // 0 = don't change,
 
 void ClientKill (entity this)
 {
-       if(gameover) return;
+       if(game_stopped) return;
        if(this.player_blocked) return;
        if(STAT(FROZEN, this)) return;
 
@@ -1147,7 +1167,7 @@ void ClientConnect(entity this)
     if (IS_BOT_CLIENT(this)) PlayerStats_GameReport_AddPlayer(this);
 
        if (autocvar_sv_eventlog)
-               GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? this.netaddress : "bot"), ":", this.netname));
+               GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? this.netaddress : "bot"), ":", playername(this, false)));
 
        LogTeamchange(this.playerid, this.team, 1);
 
@@ -1205,7 +1225,7 @@ void ClientConnect(entity this)
                stuffcmd(this, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n"));
 
        if (autocvar_sv_teamnagger && !(autocvar_bot_vs_human && AvailableTeams() == 2))
-               if (!g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts
+               if(!MUTATOR_CALLHOOK(HideTeamNagger, this))
                        send_CSQC_teamnagger();
 
        CSQCMODEL_AUTOINIT(this);
@@ -1216,6 +1236,8 @@ void ClientConnect(entity this)
                sv_notice_join(this);
 
        // update physics stats (players can spawn before physics runs)
+       STAT(MOVEVARS_HIGHSPEED, this) = autocvar_g_movement_highspeed;
+       MUTATOR_CALLHOOK(PlayerPhysics_UpdateStats, this); // do it BEFORE the function so we can modify highspeed!
        Physics_UpdateStats(this, PHYS_HIGHSPEED(this));
 
        IL_EACH(g_initforplayer, it.init_for_player, {
@@ -1256,7 +1278,8 @@ void ClientDisconnect(entity this)
 
        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_DISCONNECT, this.netname);
 
-       SetSpectatee(this, NULL);
+       if(IS_SPEC(this))
+               SetSpectatee(this, NULL);
 
     MUTATOR_CALLHOOK(ClientDisconnect, this);
 
@@ -1391,7 +1414,7 @@ void player_powerups(entity this)
        // add a way to see what the items were BEFORE all of these checks for the mutator hook
        int items_prev = this.items;
 
-       if((this.items & IT_USING_JETPACK) && !IS_DEAD(this) && !gameover)
+       if((this.items & IT_USING_JETPACK) && !IS_DEAD(this) && !game_stopped)
                this.modelflags |= MF_ROCKET;
        else
                this.modelflags &= ~MF_ROCKET;
@@ -1422,7 +1445,8 @@ void player_powerups(entity this)
                        if (time < this.strength_finished)
                        {
                                this.items = this.items | ITEM_Strength.m_itemid;
-                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_STRENGTH, this.netname);
+                               if(!g_cts)
+                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_STRENGTH, this.netname);
                                Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERUP_STRENGTH);
                        }
                }
@@ -1442,7 +1466,8 @@ void player_powerups(entity this)
                        if (time < this.invincible_finished)
                        {
                                this.items = this.items | ITEM_Shield.m_itemid;
-                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_SHIELD, this.netname);
+                               if(!g_cts)
+                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_POWERUP_SHIELD, this.netname);
                                Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_POWERUP_SHIELD);
                        }
                }
@@ -1476,7 +1501,8 @@ void player_powerups(entity this)
                        if (time < this.superweapons_finished || (this.items & IT_UNLIMITED_SUPERWEAPONS))
                        {
                                this.items = this.items | IT_SUPERWEAPON;
-                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_PICKUP, this.netname);
+                               if(!g_cts)
+                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_PICKUP, this.netname);
                                Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_SUPERWEAPON_PICKUP);
                        }
                        else
@@ -1673,10 +1699,14 @@ void SpectateCopy(entity this, entity spectatee)
        this.hit_time = spectatee.hit_time;
        this.strength_finished = spectatee.strength_finished;
        this.invincible_finished = spectatee.invincible_finished;
+       this.superweapons_finished = spectatee.superweapons_finished;
        STAT(PRESSED_KEYS, this) = STAT(PRESSED_KEYS, spectatee);
        this.weapons = spectatee.weapons;
+       this.dual_weapons = spectatee.dual_weapons;
        this.vortex_charge = spectatee.vortex_charge;
        this.vortex_chargepool_ammo = spectatee.vortex_chargepool_ammo;
+       this.okvortex_charge = spectatee.okvortex_charge;
+       this.okvortex_chargepool_ammo = spectatee.okvortex_chargepool_ammo;
        this.hagar_load = spectatee.hagar_load;
        this.arc_heat_percent = spectatee.arc_heat_percent;
        this.minelayer_mines = spectatee.minelayer_mines;
@@ -1703,6 +1733,11 @@ void SpectateCopy(entity this, entity spectatee)
                this.(weaponentity) = spectatee.(weaponentity);
        }
 
+       for(int slot = 0; slot < MAX_AXH; ++slot)
+       {
+               this.(AuxiliaryXhair[slot]) = spectatee.(AuxiliaryXhair[slot]);
+       }
+
     anticheat_spectatecopy(this, spectatee);
        this.hud = spectatee.hud;
        if(spectatee.vehicle)
@@ -1782,6 +1817,9 @@ void SetSpectatee_status(entity this, int spectatee_num)
 
 void SetSpectatee(entity this, entity spectatee)
 {
+       if(IS_BOT_CLIENT(this))
+               return; // bots abuse .enemy, this code is useless to them
+
        entity old_spectatee = this.enemy;
 
        this.enemy = spectatee;
@@ -1922,6 +1960,7 @@ void Join(entity this)
 
        PutClientInServer(this);
 
+       if(IS_PLAYER(this))
        if(teamplay && this.team != -1)
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_JOIN_PLAY_TEAM), this.netname);
        else
@@ -2155,7 +2194,7 @@ void PlayerUseKey(entity this)
 
        if(this.vehicle)
        {
-               if(!gameover)
+               if(!game_stopped)
                {
                        vehicles_exit(this.vehicle, VHEF_NORMAL);
                        return;
@@ -2165,7 +2204,7 @@ void PlayerUseKey(entity this)
        {
                if(!STAT(FROZEN, this))
                if(!IS_DEAD(this))
-               if(!gameover)
+               if(!game_stopped)
                {
                        entity head, closest_target = NULL;
                        head = WarpZone_FindRadius(this.origin, autocvar_g_vehicles_enter_radius, true);
@@ -2238,7 +2277,7 @@ void PlayerPreThink (entity this)
        }
        if (this.netname != this.netname_previous) {
                if (autocvar_sv_eventlog) {
-                       GameLogEcho(strcat(":name:", ftos(this.playerid), ":", this.netname));
+                       GameLogEcho(strcat(":name:", ftos(this.playerid), ":", playername(this, false)));
         }
                if (this.netname_previous) strunzone(this.netname_previous);
                this.netname_previous = strzone(this.netname);
@@ -2296,7 +2335,7 @@ void PlayerPreThink (entity this)
 
        MUTATOR_CALLHOOK(PlayerPreThink, this);
 
-       if(autocvar_g_vehicles_enter && (time > this.last_vehiclecheck) && !gameover && !this.vehicle)
+       if(autocvar_g_vehicles_enter && (time > this.last_vehiclecheck) && !game_stopped && !this.vehicle)
        if(IS_PLAYER(this) && !STAT(FROZEN, this) && !IS_DEAD(this))
        {
                FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_vehicles_enter_radius, IS_VEHICLE(it),
@@ -2331,7 +2370,8 @@ void PlayerPreThink (entity this)
        if (IS_PLAYER(this)) {
                CheckRules_Player(this);
 
-               if (gameover || intermission_running) {
+               if (game_stopped || intermission_running) {
+                       this.modelflags &= ~MF_ROCKET;
                        if(intermission_running)
                                IntermissionThink(this);
                        return;
@@ -2356,6 +2396,13 @@ void PlayerPreThink (entity this)
                                }
                        } else {
                                if (frametime) player_anim(this);
+
+                               if (this.respawn_flags & RESPAWN_DENY)
+                               {
+                                       STAT(RESPAWN_TIME, this) = 0;
+                                       return;
+                               }
+
                                bool button_pressed = (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));
 
                                switch(this.deadflag)
@@ -2489,7 +2536,13 @@ void PlayerPreThink (entity this)
                {
                        .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 (WEP_CVAR(okvortex, charge_rot_rate) && this.(weaponentity).okvortex_charge > WEP_CVAR(okvortex, charge_limit) && this.(weaponentity).okvortex_charge_rottime < time)
+                       {
+                               this.(weaponentity).okvortex_charge = bound(WEP_CVAR(okvortex, charge_limit), this.(weaponentity).okvortex_charge - WEP_CVAR(okvortex, charge_rot_rate) * frametime / W_TICSPERFRAME, 1);
+                       }
                }
 
                if (frametime) player_anim(this);
@@ -2502,7 +2555,7 @@ void PlayerPreThink (entity this)
 
                this.dmg_team = max(0, this.dmg_team - autocvar_g_teamdamage_resetspeed * frametime);
        }
-       else if (gameover || intermission_running) {
+       else if (game_stopped || intermission_running) {
                if(intermission_running)
                        IntermissionThink(this);
                return;
@@ -2654,7 +2707,7 @@ void PlayerPostThink (entity this)
        CheatFrame(this);
 
        //CheckPlayerJump();
-       if (gameover)
+       if (game_stopped)
        {
                this.solid = SOLID_NOT;
                this.takedamage = DAMAGE_NO;
@@ -2666,7 +2719,7 @@ void PlayerPostThink (entity this)
                CheckRules_Player(this);
                UpdateChatBubble(this);
                if (this.impulse) ImpulseCommands(this);
-               if (gameover)
+               if (game_stopped)
                {
                        CSQCMODEL_AUTOUPDATE(this);
                        return;