]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/cl_player.qc
Purge self from the damage/death mutator hooks
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / cl_player.qc
index fe0951e8713f18e7d3c17096fd45a8c310c0c678..3b04a492217d062c5188859dea37909cc8b612f3 100644 (file)
@@ -9,6 +9,7 @@
 #include "teamplay.qh"
 #include "weapons/throwing.qh"
 #include "command/common.qh"
+#include "../common/state.qh"
 #include "../common/anim.qh"
 #include "../common/animdecide.qh"
 #include "../common/csqcmodel_settings.qh"
@@ -19,6 +20,8 @@
 
 #include "../common/minigames/sv_minigames.qh"
 
+#include "../common/physics/player.qh"
+#include "../common/effects/qc/all.qh"
 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
 #include "../common/triggers/include.qh"
 
@@ -34,19 +37,19 @@ void Drop_Special_Items(entity player)
        MUTATOR_CALLHOOK(DropSpecialItems, player);
 }
 
-void CopyBody_Think()
-{SELFPARAM();
-       if(self.CopyBody_nextthink && time > self.CopyBody_nextthink)
+void CopyBody_Think(entity this)
+{
+       if(this.CopyBody_nextthink && time > this.CopyBody_nextthink)
        {
-               self.CopyBody_think();
-               if(wasfreed(self))
+               this.CopyBody_think(this);
+               if(wasfreed(this))
                        return;
-               self.CopyBody_nextthink = self.nextthink;
-               self.CopyBody_think = self.think;
-               self.think = CopyBody_Think;
+               this.CopyBody_nextthink = this.nextthink;
+               this.CopyBody_think = getthink(this);
+               setthink(this, CopyBody_Think);
        }
-       CSQCMODEL_AUTOUPDATE(self);
-       self.nextthink = time;
+       CSQCMODEL_AUTOUPDATE(this);
+       this.nextthink = time;
 }
 void CopyBody(entity this, float keepvelocity)
 {
@@ -92,7 +95,7 @@ void CopyBody(entity this, float keepvelocity)
        clone.solid = this.solid;
        clone.ballistics_density = this.ballistics_density;
        clone.takedamage = this.takedamage;
-       clone.customizeentityforclient = this.customizeentityforclient;
+       setcefc(clone, getcefc(this));
        clone.uncustomizeentityforclient = this.uncustomizeentityforclient;
        clone.uncustomizeentityforclient_set = this.uncustomizeentityforclient_set;
        if (keepvelocity == 1)
@@ -115,9 +118,9 @@ void CopyBody(entity this, float keepvelocity)
 
        CSQCMODEL_AUTOINIT(clone);
        clone.CopyBody_nextthink = this.nextthink;
-       clone.CopyBody_think = this.think;
+       clone.CopyBody_think = getthink(this);
        clone.nextthink = time;
-       clone.think = CopyBody_Think;
+       setthink(clone, CopyBody_Think);
        // "bake" the current animation frame for clones (they don't get clientside animation)
        animdecide_load_if_needed(clone);
        animdecide_setframes(clone, false, frame, frame1time, frame2, frame2time);
@@ -132,8 +135,8 @@ void player_setupanimsformodel()
 
 void player_anim ()
 {SELFPARAM();
-       int deadbits = (self.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
-       if(IS_DEAD(self)) {
+       int deadbits = (this.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
+       if(IS_DEAD(this)) {
                if (!deadbits) {
                        // Decide on which death animation to use.
                        if(random() < 0.5)
@@ -146,14 +149,14 @@ void player_anim ()
                deadbits = 0;
        }
        int animbits = deadbits;
-       if(STAT(FROZEN, self))
+       if(STAT(FROZEN, this))
                animbits |= ANIMSTATE_FROZEN;
-       if(self.movetype == MOVETYPE_FOLLOW)
+       if(this.movetype == MOVETYPE_FOLLOW)
                animbits |= ANIMSTATE_FOLLOW;
-       if(self.crouch)
+       if(this.crouch)
                animbits |= ANIMSTATE_DUCK;
-       animdecide_setstate(self, animbits, false);
-       animdecide_setimplicitstate(self, IS_ONGROUND(self));
+       animdecide_setstate(this, animbits, false);
+       animdecide_setimplicitstate(this, IS_ONGROUND(this));
 }
 
 void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
@@ -361,7 +364,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
        {
                this.pusher = attacker;
                this.pushltime = time + autocvar_g_maxpushtime;
-               this.istypefrag = this.BUTTON_CHAT;
+               this.istypefrag = PHYS_INPUT_BUTTON_CHAT(this);
        }
        else if(time < this.pushltime)
        {
@@ -381,10 +384,9 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                save = v.y;
        }
 
-       frag_damage = damage;
-       MUTATOR_CALLHOOK(PlayerDamage_SplitHealthArmor, inflictor, attacker, this, force, take, save);
-       take = bound(0, damage_take, this.health);
-       save = bound(0, damage_save, this.armorvalue);
+       MUTATOR_CALLHOOK(PlayerDamage_SplitHealthArmor, inflictor, attacker, this, force, take, save, deathtype, damage);
+       take = bound(0, M_ARGV(4, float), this.health);
+       save = bound(0, M_ARGV(5, float), this.armorvalue);
        excess = max(0, damage - take - save);
 
        if(sound_allowed(MSG_BROADCAST, attacker))
@@ -435,7 +437,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                                        {
                                                if(deathtype == DEATH_FALL.m_id)
                                                        PlayerSound(this, playersound_fall, CH_PAIN, VOICETYPE_PLAYERSOUND);
-                                               else if(this.health > 75) // TODO make a "gentle" version?
+                                               else if(this.health > 75)
                                                        PlayerSound(this, playersound_pain100, CH_PAIN, VOICETYPE_PLAYERSOUND);
                                                else if(this.health > 50)
                                                        PlayerSound(this, playersound_pain75, CH_PAIN, VOICETYPE_PLAYERSOUND);
@@ -514,7 +516,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                if(valid_damage_for_weaponstats)
                        WeaponStats_LogKill(awep.m_id, abot, PS(this).m_weapon.m_id, vbot);
 
-               if(autocvar_sv_gentle < 1) // TODO make a "gentle" version?
+               if(autocvar_sv_gentle < 1)
                if(sound_allowed(MSG_BROADCAST, attacker))
                {
                        if(deathtype == DEATH_DROWN.m_id)
@@ -549,11 +551,11 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
        if(accuracy_isgooddamage(attacker, this))
         attacker.accuracy.(accuracy_frags[w.m_id-1]) += 1;
 
-               MUTATOR_CALLHOOK(PlayerDies, inflictor, attacker, this, deathtype);
-               excess = frag_damage;
+               MUTATOR_CALLHOOK(PlayerDies, inflictor, attacker, this, deathtype, excess);
+               excess = M_ARGV(4, float);
 
                Weapon wep = PS(this).m_weapon;
-               WITH(entity, self, this, wep.wr_playerdeath(wep));
+               WITHSELF(this, wep.wr_playerdeath(wep, this));
 
                RemoveGrapplingHook(this);
 
@@ -619,10 +621,10 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                // set up to fade out later
                SUB_SetFade (this, time + 6 + random (), 1);
                // reset body think wrapper broken by SUB_SetFade
-               if(this.classname == "body" && this.think != CopyBody_Think) {
-                       this.CopyBody_think = this.think;
+               if(this.classname == "body" && getthink(this) != CopyBody_Think) {
+                       this.CopyBody_think = getthink(this);
                        this.CopyBody_nextthink = this.nextthink;
-                       this.think = CopyBody_Think;
+                       setthink(this, CopyBody_Think);
                        this.nextthink = time;
                }
 
@@ -634,7 +636,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
 
                // reset fields the weapons may use just in case
                FOREACH(Weapons, it != WEP_Null, LAMBDA(
-                       WITH(entity, self, this, it.wr_resetplayer(it));
+                       WITHSELF(this, it.wr_resetplayer(it, this));
                        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                        {
                                ATTACK_FINISHED_FOR(this, it.m_id, slot) = 0;
@@ -654,6 +656,12 @@ void MoveToTeam(entity client, int team_colour, int type)
        LogTeamchange(client.playerid, client.team, type);
 }
 
+/** print(), but only print if the server is not local */
+void dedicated_print(string input)
+{
+       if (server_is_dedicated) print(input);
+}
+
 /**
  * message "": do not say, just test flood control
  * return value:
@@ -661,20 +669,14 @@ void MoveToTeam(entity client, int team_colour, int type)
  *   0 = reject
  *  -1 = fake accept
  */
-int Say(entity source, float teamsay, entity privatesay, string msgin, bool floodcontrol)
+int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodcontrol)
 {
-       string msgstr, colorstr, cmsgstr, namestr, fullmsgstr, sourcemsgstr, fullcmsgstr, sourcecmsgstr, colorprefix;
-       float flood;
-       var .float flood_field;
-       float ret;
-       string privatemsgprefix = string_null; float privatemsgprefixlen = 0;
-
-       if(!teamsay && !privatesay)
-               if(substring(msgin, 0, 1) == " ")
-                       msgin = substring(msgin, 1, strlen(msgin) - 1); // work around DP say bug (say_team does not have this!)
+       if (!teamsay && !privatesay) if (substring(msgin, 0, 1) == " ")
+        msgin = substring(msgin, 1, -1); // work around DP say bug (say_team does not have this!)
 
-       msgin = formatmessage(msgin);
+       msgin = formatmessage(source, msgin);
 
+    string colorstr;
        if (!IS_PLAYER(source))
                colorstr = "^0"; // black for spectators
        else if(teamplay)
@@ -688,6 +690,11 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo
        if(intermission_running)
                teamsay = false;
 
+    if (!source) {
+               colorstr = "";
+               teamsay = false;
+    }
+
        if(msgin != "")
                msgin = trigger_magicear_processmessage_forallears(source, teamsay, privatesay, msgin);
 
@@ -702,18 +709,18 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo
        }
        */
 
-       if(autocvar_g_chat_teamcolors)
-               namestr = playername(source);
-       else
-               namestr = source.netname;
+    string namestr = "";
+    if (source)
+        namestr = autocvar_g_chat_teamcolors ? playername(source) : source.netname;
 
-       if(strdecolorize(namestr) == namestr)
-               colorprefix = "^3";
-       else
-               colorprefix = "^7";
+    string colorprefix = (strdecolorize(namestr) == namestr) ? "^3" : "^7";
 
-       if(msgin != "")
-       {
+    string msgstr, cmsgstr;
+    string privatemsgprefix = string_null;
+    int privatemsgprefixlen = 0;
+       if (msgin == "") {
+        msgstr = cmsgstr = "";
+       } else {
                if(privatesay)
                {
                        msgstr = strcat("\{1}\{13}* ", colorprefix, namestr, "^3 tells you: ^7");
@@ -747,23 +754,22 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo
                                msgin = strreplace("/me", strcat(colorprefix, namestr), msgin);
                                msgstr = strcat("\{1}^4* ", "^7", msgin);
                        }
-                       else
-                               msgstr = strcat("\{1}", colorprefix, namestr, "^7: ", msgin);
+                       else {
+                msgstr = "\{1}";
+                msgstr = strcat(msgstr, (namestr != "") ? strcat(colorprefix, namestr, "^7: ") : "^7");
+                msgstr = strcat(msgstr, msgin);
+            }
                        cmsgstr = "";
                }
                msgstr = strcat(strreplace("\n", " ", msgstr), "\n"); // newlines only are good for centerprint
        }
-       else
-       {
-               msgstr = cmsgstr = "";
-       }
 
-       fullmsgstr = msgstr;
-       fullcmsgstr = cmsgstr;
+       string fullmsgstr = msgstr;
+       string fullcmsgstr = cmsgstr;
 
        // FLOOD CONTROL
-       flood = 0;
-       flood_field = floodcontrol_chat;
+       int flood = 0;
+       var .float flood_field = floodcontrol_chat;
        if(floodcontrol)
        {
                float flood_spl;
@@ -835,6 +841,7 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo
                        source.(flood_field) = flood = 0;
        }
 
+    string sourcemsgstr, sourcecmsgstr;
        if(flood == 2) // cannot happen for empty msgstr
        {
                if(autocvar_g_chat_flood_notify_flooder)
@@ -855,8 +862,7 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo
                sourcecmsgstr = cmsgstr;
        }
 
-       if(!privatesay)
-       if (!IS_PLAYER(source))
+       if (!privatesay && source && !IS_PLAYER(source))
        {
                if (!intermission_running)
                        if(teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !(warmup_stage || gameover)))
@@ -870,6 +876,7 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo
        if(privatesay)
                sourcemsgstr = strcat(privatemsgprefix, substring(sourcemsgstr, privatemsgprefixlen, -1));
 
+    int ret;
        if(source.muted)
        {
                // always fake the message
@@ -910,7 +917,7 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo
                {
                        sprint(source, sourcemsgstr);
                        dedicated_print(msgstr); // send to server console too
-                       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && it.active_minigame == source.active_minigame, LAMBDA(sprint(it, msgstr)));
+                       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && it.active_minigame == source.active_minigame, sprint(it, msgstr));
                }
                else if(teamsay > 0) // team message, only sent to team mates
                {
@@ -918,26 +925,27 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo
                        dedicated_print(msgstr); // send to server console too
                        if(sourcecmsgstr != "")
                                centerprint(source, sourcecmsgstr);
-                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source && it.team == source.team, LAMBDA(
+                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source && it.team == source.team, {
                                sprint(it, msgstr);
                                if(cmsgstr != "")
                                        centerprint(it, cmsgstr);
-                       ));
+                       });
                }
                else if(teamsay < 0) // spectator message, only sent to spectators
                {
                        sprint(source, sourcemsgstr);
                        dedicated_print(msgstr); // send to server console too
-                       FOREACH_CLIENT(!IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source, LAMBDA(sprint(it, msgstr)));
-               }
-               else if(sourcemsgstr != msgstr) // trimmed/server fixed message, sent to all players
-               {
-                       sprint(source, sourcemsgstr);
-                       dedicated_print(msgstr); // send to server console too
-                       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source, LAMBDA(sprint(it, msgstr)));
+                       FOREACH_CLIENT(!IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source, sprint(it, msgstr));
                }
                else
-                       bprint(msgstr); // entirely normal message, sent to all players -- bprint sends to server console too.
+               {
+            if (source) {
+                sprint(source, sourcemsgstr);
+                dedicated_print(msgstr); // send to server console too
+                MX_Say(strcat(playername(source), "^7: ", msgin));
+            }
+            FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source, sprint(it, msgstr));
+        }
        }
 
        return ret;