]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/player.qc
Properly support team field on trigger_multiple
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / player.qc
index faba40f3fc92de55833f334e72590c47ac2d2bac..26fc9e659204d7bf6305a5d2483bf1b2b4ba9819 100644 (file)
@@ -1,8 +1,10 @@
 #include "player.qh"
 
+#include <common/effects/all.qh>
 #include "bot/api.qh"
 #include "cheats.qh"
 #include "g_damage.qh"
+#include "handicap.qh"
 #include "g_subs.qh"
 #include "miscfunctions.qh"
 #include "portals.qh"
@@ -21,7 +23,7 @@
 #include "../common/minigames/sv_minigames.qh"
 
 #include "../common/physics/player.qh"
-#include "../common/effects/qc/all.qh"
+#include "../common/effects/qc/_mod.qh"
 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
 #include "../common/triggers/include.qh"
 #include "../common/wepent.qh"
@@ -97,7 +99,6 @@ void CopyBody(entity this, float keepvelocity)
        clone.move_qcphysics = false; // don't run gamecode logic on clones, too many
        set_movetype(clone, this.move_movetype);
        clone.solid = this.solid;
-       clone.ballistics_density = this.ballistics_density;
        clone.takedamage = this.takedamage;
        setcefc(clone, getcefc(this));
        clone.uncustomizeentityforclient = this.uncustomizeentityforclient;
@@ -111,7 +112,6 @@ void CopyBody(entity this, float keepvelocity)
        //clone.weapon = this.weapon;
        setorigin(clone, this.origin);
        setsize(clone, this.mins, this.maxs);
-       clone.prevorigin = this.origin;
        clone.reset = SUB_Remove;
        clone._ps = this._ps;
 
@@ -237,10 +237,10 @@ void calculate_player_respawn_time(entity this)
        float pcount = 1;  // Include myself whether or not team is already set right and I'm a "player".
        if (teamplay)
        {
-               FOREACH_CLIENT(IS_PLAYER(it) && it != this, LAMBDA(
+               FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
                        if(it.team == this.team)
                                ++pcount;
-               ));
+               });
                if (sdelay_small_count == 0)
                        sdelay_small_count = 1;
                if (sdelay_large_count == 0)
@@ -248,9 +248,9 @@ void calculate_player_respawn_time(entity this)
        }
        else
        {
-               FOREACH_CLIENT(IS_PLAYER(it) && it != this, LAMBDA(
+               FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
                        ++pcount;
-               ));
+               });
                if (sdelay_small_count == 0)
                {
                        if (IS_INDEPENDENT_PLAYER(this))
@@ -318,9 +318,11 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
 
        if(!DEATH_ISSPECIAL(deathtype))
        {
-               damage *= bound(1.0, this.cvar_cl_handicap, 10.0);
-               if(this != attacker)
-                       damage /= bound(1.0, attacker.cvar_cl_handicap, 10.0);
+               damage *= Handicap_GetTotalHandicap(this);
+               if (this != attacker && IS_PLAYER(attacker))
+               {
+                       damage /= Handicap_GetTotalHandicap(attacker);
+               }
        }
 
        if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1)
@@ -473,10 +475,10 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
        if (this != attacker) {
                float realdmg = damage - excess;
                if (IS_PLAYER(attacker)) {
-                       PlayerScore_Add(attacker, SP_DMG, realdmg);
+                       GameRules_scoring_add(attacker, DMG, realdmg);
                }
                if (IS_PLAYER(this)) {
-                       PlayerScore_Add(this, SP_DMGTAKEN, realdmg);
+                       GameRules_scoring_add(this, DMGTAKEN, realdmg);
                }
        }
 
@@ -515,7 +517,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
 
                if(this.alivetime)
                {
-                       PS_GR_P_ADDVAL(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
+                       PlayerStats_GameReport_Event_Player(this, PLAYERSTATS_ALIVETIME, time - this.alivetime);
                        this.alivetime = 0;
                }
 
@@ -554,10 +556,12 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
         // increment frag counter for used weapon type
         Weapon w = DEATH_WEAPONOF(deathtype);
                if(w != WEP_Null && accuracy_isgooddamage(attacker, this))
-                       attacker.accuracy.(accuracy_frags[w.m_id-1]) += 1;
+                       CS(attacker).accuracy.(accuracy_frags[w.m_id-1]) += 1;
 
+               this.respawn_time = 0;
                MUTATOR_CALLHOOK(PlayerDies, inflictor, attacker, this, deathtype, damage);
-               excess = M_ARGV(4, float);
+               damage = M_ARGV(4, float);
+               excess = max(0, damage - take - save);
 
                //Weapon wep = this.(weaponentity).m_weapon;
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
@@ -583,6 +587,9 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                if(this.health >= 1 || !(IS_PLAYER(this) || this.classname == "body"))
                        return;
 
+               if (!this.respawn_time) // can be set in the mutator hook PlayerDies
+                       calculate_player_respawn_time(this);
+
                // when we get here, player actually dies
 
                Unfreeze(this); // remove any icy remains
@@ -610,14 +617,13 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                set_movetype(this, MOVETYPE_TOSS);
                // shootable corpse
                this.solid = SOLID_CORPSE;
-               this.ballistics_density = autocvar_g_ballistics_density_corpse;
+               PS(this).ballistics_density = autocvar_g_ballistics_density_corpse;
                // don't stick to the floor
                UNSET_ONGROUND(this);
                // dying animation
                this.deadflag = DEAD_DYING;
 
-               // when to allow respawn
-               calculate_player_respawn_time(this);
+               STAT(MOVEVARS_SPECIALCOMMAND, this) = false; // sweet release
 
                this.death_time = time;
                if (random() < 0.5)
@@ -666,15 +672,19 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
        }
 }
 
-void MoveToTeam(entity client, int team_colour, int type)
+bool MoveToTeam(entity client, int team_colour, int type)
 {
        int lockteams_backup = lockteams;  // backup any team lock
        lockteams = 0;  // disable locked teams
        TeamchangeFrags(client);  // move the players frags
-       SetPlayerColors(client, team_colour - 1);  // set the players colour
+       if (!SetPlayerTeamSimple(client, team_colour))
+       {
+               return false;
+       }
        Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE.m_id, client.origin, '0 0 0');  // kill the player
        lockteams = lockteams_backup;  // restore the team lock
        LogTeamchange(client.playerid, client.team, type);
+       return true;
 }
 
 /** print(), but only print if the server is not local */
@@ -743,7 +753,8 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
        if (!teamsay && !privatesay && substring(msgin, 0, 1) == " ")
         msgin = substring(msgin, 1, -1); // work around DP say bug (say_team does not have this!)
 
-       msgin = formatmessage(source, msgin);
+    if(source)
+               msgin = formatmessage(source, msgin);
 
     string colorstr;
        if (!IS_PLAYER(source))
@@ -836,7 +847,7 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
        // FLOOD CONTROL
        int flood = 0;
        var .float flood_field = floodcontrol_chat;
-       if(floodcontrol)
+       if(floodcontrol && source)
        {
                float flood_spl;
                float flood_burst;
@@ -936,14 +947,14 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
        }
 
        if(flood)
-               LOG_INFO("NOTE: ", playername(source, true), "^7 is flooding.\n");
+               LOG_INFO("NOTE: ", playername(source, true), "^7 is flooding.");
 
        // build sourcemsgstr by cutting off a prefix and replacing it by the other one
        if(privatesay)
                sourcemsgstr = strcat(privatemsgprefix, substring(sourcemsgstr, privatemsgprefixlen, -1));
 
     int ret;
-       if(source.muted)
+       if(source && CS(source).muted)
        {
                // always fake the message
                ret = -1;
@@ -992,11 +1003,11 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
                                        centerprint(privatesay, cmsgstr);
                        }
                }
-               else if ( teamsay && source.active_minigame )
+               else if ( teamsay && CS(source).active_minigame )
                {
                        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 && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), sprint(it, msgstr));
+                       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && CS(it).active_minigame == CS(source).active_minigame && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), sprint(it, msgstr));
                }
                else if(teamsay > 0) // team message, only sent to team mates
                {