]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/damage.qc
Transifex autosync
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / damage.qc
index d480c229b9b244024d6efae2e81eccb30657657e..d5a9a20c760d352a7d6631ed2530eba9cf2faad4 100644 (file)
@@ -17,6 +17,7 @@
 #include <common/physics/movetypes/movetypes.qh>
 #include <common/physics/player.qh>
 #include <common/playerstats.qh>
+#include <common/resources/sv_resources.qh>
 #include <common/state.qh>
 #include <common/teams.qh>
 #include <common/util.qh>
@@ -31,7 +32,6 @@
 #include <server/items/items.qh>
 #include <server/main.qh>
 #include <server/mutators/_mod.qh>
-#include <server/resources.qh>
 #include <server/scores.qh>
 #include <server/spawnpoints.qh>
 #include <server/teamplay.qh>
@@ -245,8 +245,10 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
        if (MUTATOR_CALLHOOK(ClientObituary, inflictor, attacker, targ, deathtype, attacker.(weaponentity))) { CS(targ).killcount = 0; return; }
        notif_anonymous = M_ARGV(5, bool);
 
+       // TODO: Replace "???" with a translatable "Anonymous player" string
+       // https://gitlab.com/xonotic/xonotic-data.pk3dir/-/issues/2839
        if(notif_anonymous)
-               attacker_name = "Anonymous player";
+               attacker_name = "???";
 
        #ifdef NOTIFICATIONS_DEBUG
        Debug_Notification(
@@ -531,11 +533,11 @@ void Freeze(entity targ, float revivespeed, int frozen_type, bool show_waypoint)
        FOREACH_CLIENT(IS_PLAYER(it),
        {
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-           {
-               .entity weaponentity = weaponentities[slot];
-               if(it.(weaponentity).hook.aiment == targ)
-                       RemoveHook(it.(weaponentity).hook);
-           }
+               {
+                       .entity weaponentity = weaponentities[slot];
+                       if(it.(weaponentity).hook.aiment == targ)
+                               RemoveHook(it.(weaponentity).hook);
+               }
        });
 
        // add waypoint
@@ -565,11 +567,11 @@ void Unfreeze(entity targ, bool reset_health)
        FOREACH_CLIENT(IS_PLAYER(it),
        {
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-           {
-               .entity weaponentity = weaponentities[slot];
-               if(it.(weaponentity).hook.aiment == targ)
-                       RemoveHook(it.(weaponentity).hook);
-           }
+               {
+                       .entity weaponentity = weaponentities[slot];
+                       if(it.(weaponentity).hook.aiment == targ)
+                               RemoveHook(it.(weaponentity).hook);
+               }
        });
 
        // remove the ice block
@@ -608,7 +610,7 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
 
                // These are ALWAYS lethal
                // No damage modification here
-               // Instead, prepare the victim for his death...
+               // Instead, prepare the victim for their death...
                if(deathtype == DEATH_TEAMCHANGE.m_id || deathtype == DEATH_AUTOTEAMCHANGE.m_id)
                {
                        SetResourceExplicit(targ, RES_ARMOR, 0);
@@ -628,7 +630,10 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
                if(deathtype != DEATH_TELEFRAG.m_id)
                if(IS_PLAYER(attacker))
                {
-                       if(IS_PLAYER(targ) && targ != attacker && (IS_INDEPENDENT_PLAYER(attacker) || IS_INDEPENDENT_PLAYER(targ)))
+                       // avoid dealing damage or force to other independent players
+                       // and avoid dealing damage or force to things owned by other independent players
+                       if((IS_PLAYER(targ) && targ != attacker && (IS_INDEPENDENT_PLAYER(attacker) || IS_INDEPENDENT_PLAYER(targ))) ||
+                               (targ.realowner && IS_INDEPENDENT_PLAYER(targ.realowner) && attacker != targ.realowner))
                        {
                                damage = 0;
                                force = '0 0 0';
@@ -707,11 +712,11 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
                if(IS_PLAYER(targ) && damage > 0 && attacker)
                {
                        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-                   {
-                       .entity went = weaponentities[slot];
-                       if(targ.(went).hook && targ.(went).hook.aiment == attacker)
-                               RemoveHook(targ.(went).hook);
-                   }
+                       {
+                               .entity went = weaponentities[slot];
+                               if(targ.(went).hook && targ.(went).hook.aiment == attacker)
+                                       RemoveHook(targ.(went).hook);
+                       }
                }
 
                if(STAT(FROZEN, targ) && !ITEM_DAMAGE_NEEDKILL(deathtype)
@@ -790,7 +795,7 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
                                                        if(PHYS_INPUT_BUTTON_CHAT(victim))
                                                                attacker.typehitsound += 1;
                                                        else
-                                                               attacker.damage_dealt += damage;
+                                                               attacker.hitsound_damage_dealt += damage;
                                                }
 
                                                impressive_hits += 1;
@@ -881,6 +886,8 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in
                return 0;
        }
 
+       if (rad < 0) rad = 0;
+
        RadiusDamage_running = 1;
 
        tfloordmg = autocvar_g_throughfloor_damage;
@@ -912,42 +919,86 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in
                if (((cantbe != targ) && !mustbe) || (mustbe == targ))
                if (targ.takedamage)
                {
-                       vector nearest;
-                       vector diff;
-                       float power;
-
-                       // LordHavoc: measure distance to nearest point on target (not origin)
-                       // (this guarentees 100% damage on a touch impact)
-                       nearest = targ.WarpZone_findradius_nearest;
-                       diff = targ.WarpZone_findradius_dist;
+                       // calculate distance from nearest point on target to nearest point on inflictor
+                       // instead of origin to ensure full damage on impacts
+
+                       vector nearest = targ.WarpZone_findradius_nearest;
+
+                       // optimize code by getting inflictororigin_wz from WarpZone_FindRadius calculations instead of
+                       //vector inflictororigin_wz = WarpZone_TransformOrigin(targ, inflictororigin);
+
+                       vector inflictororigin_wz = targ.WarpZone_findradius_nearest + targ.WarpZone_findradius_dist;
+                       vector inflictornearest = NearestPointOnBoundingBox(
+                               inflictororigin_wz + inflictor.mins, inflictororigin_wz + inflictor.maxs, nearest);
+                       vector diff = inflictornearest - nearest;
+
                        // round up a little on the damage to ensure full damage on impacts
                        // and turn the distance into a fraction of the radius
-                       power = 1 - ((vlen (diff) - bound(MIN_DAMAGEEXTRARADIUS, targ.damageextraradius, MAX_DAMAGEEXTRARADIUS)) / rad);
-                       //bprint(" ");
-                       //bprint(ftos(power));
-                       //if (targ == attacker)
-                       //      print(ftos(power), "\n");
-                       if (power > 0)
+                       float dist = max(0, vlen(diff) - bound(MIN_DAMAGEEXTRARADIUS, targ.damageextraradius, MAX_DAMAGEEXTRARADIUS));
+                       if (dist <= rad)
                        {
-                               float finaldmg;
-                               if (power > 1)
-                                       power = 1;
-                               finaldmg = coredamage * power + edgedamage * (1 - power);
+                               float f = (rad > 0) ? 1 - (dist / rad) : 1;
+                               // at this point f can't be < 0 or > 1
+                               float finaldmg = coredamage * f + edgedamage * (1 - f);
                                if (finaldmg > 0)
                                {
                                        float a;
                                        float c;
                                        vector hitloc;
-                                       vector myblastorigin;
-                                       vector center;
-
-                                       myblastorigin = WarpZone_TransformOrigin(targ, inflictororigin);
 
                                        // if it's a player, use the view origin as reference
-                                       center = CENTER_OR_VIEWOFS(targ);
+                                       vector center = CENTER_OR_VIEWOFS(targ);
+
+                                       if (autocvar_g_player_damageplayercenter)
+                                       {
+                                               if (targ != attacker)
+                                               {
+                                                       // always use target's bbox centerpoint
+                                                       center = targ.origin + ((targ.mins + targ.maxs) * 0.5);
+                                               }
+                                               else // targ == attacker
+                                               {
+                                               #if 0
+                                                       // code stolen from W_SetupShot_Dir_ProjectileSize_Range()
+                                                       vector md = targ.(weaponentity).movedir;
+                                                       vector dv = v_right * -md.y + v_up * md.z;
+                                                       vector mi = '0 0 0', ma = '0 0 0';
 
-                                       force = normalize(center - myblastorigin);
-                                       force = force * (finaldmg / coredamage) * forceintensity;
+                                                       if(IS_CLIENT(targ)) // no antilag for non-clients!
+                                                       {
+                                                               if(CS(targ).antilag_debug)
+                                                                       tracebox_antilag(targ, center, mi, ma, center + dv, MOVE_NORMAL, targ, CS(targ).antilag_debug);
+                                                               else
+                                                                       tracebox_antilag(targ, center, mi, ma, center + dv, MOVE_NORMAL, targ, ANTILAG_LATENCY(targ));
+                                                       }
+                                                       else
+                                                               tracebox(center, mi, ma, center + dv, MOVE_NORMAL, targ);
+
+                                                       center.z = trace_endpos.z;
+                                               #else
+                                                       // very cheap way but it skips move into solid checks which is fine most of the time for now AFAIK
+                                                       // this should only really be an issue with some rare edge cases where
+                                                       // shot origin was prevented from going into a ceiling but it still explodes at the ceiling
+                                                       // shot origin wasn't raised as high as possible and the shooter gets upwards knockback
+                                                       // TL;DR: no bugs if vertical shot origin is always within player bbox
+                                                       center.z = center.z + targ.(weaponentity).movedir.z;
+                                               #endif
+                                               }
+                                       }
+
+                                       /* debug prints
+                                       print(sprintf("origin  vec %v\n", targ.origin));
+                                       print(sprintf("movedir vec %v\n", targ.(weaponentity).movedir));
+                                       print(sprintf("old def vec %v\n", CENTER_OR_VIEWOFS(targ)));
+                                       print(sprintf("origin+vofs %v\n", targ.origin + targ.view_ofs));
+                                       print(sprintf("bbox center %v\n", (targ.origin + ((targ.mins + targ.maxs) * 0.5))));
+                                       print(sprintf("center  vec %v\n", center));
+                                       print(sprintf("shotorg vec %v\n", w_shotorg));
+                                       print("\n");
+                                       */
+
+                                       force = normalize(center - inflictororigin_wz);
+                                       force = force * (finaldmg / max(coredamage, edgedamage)) * forceintensity;
                                        hitloc = nearest;
 
                                        // apply special scaling along the z axis if set
@@ -1017,14 +1068,15 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in
 
                                                if(autocvar_g_throughfloor_debug)
                                                        LOG_INFOF(" D=%f F=%f", finaldmg, vlen(force));
+
+                                               /*if (targ == attacker)
+                                               {
+                                                       print("hits ", ftos(hits), " / ", ftos(total));
+                                                       print(" finaldmg ", ftos(finaldmg), " force ", ftos(vlen(force)));
+                                                       print(" (", vtos(force), ") (", ftos(a), ")\n");
+                                               }*/
                                        }
 
-                                       //if (targ == attacker)
-                                       //{
-                                       //      print("hits ", ftos(hits), " / ", ftos(total));
-                                       //      print(" finaldmg ", ftos(finaldmg), " force ", vtos(force));
-                                       //      print(" (", ftos(a), ")\n");
-                                       //}
                                        if(finaldmg || force)
                                        {
                                                if(targ.iscreature)
@@ -1049,14 +1101,14 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in
        RadiusDamage_running = 0;
 
        if(!DEATH_ISSPECIAL(deathtype))
-               accuracy_add(attacker, DEATH_WEAPONOF(deathtype), 0, min(coredamage, stat_damagedone));
+               accuracy_add(attacker, DEATH_WEAPONOF(deathtype), 0, min(max(coredamage, edgedamage), stat_damagedone));
 
        return total_damage_to_creatures;
 }
 
 float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity)
 {
-       return RadiusDamageForSource(inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, 
+       return RadiusDamageForSource(inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad,
                                                                        cantbe, mustbe, false, forceintensity, 1, deathtype, weaponentity, directhitentity);
 }
 
@@ -1197,12 +1249,12 @@ void Fire_ApplyDamage(entity e)
        t = min(frametime, fireendtime - time);
        d = e.fire_damagepersec * t;
 
-       hi = e.fire_owner.damage_dealt;
+       hi = e.fire_owner.hitsound_damage_dealt;
        ty = e.fire_owner.typehitsound;
        Damage(e, e, e.fire_owner, d, e.fire_deathtype, DMG_NOWEP, e.origin, '0 0 0');
        if(e.fire_hitsound && e.fire_owner)
        {
-               e.fire_owner.damage_dealt = hi;
+               e.fire_owner.hitsound_damage_dealt = hi;
                e.fire_owner.typehitsound = ty;
        }
        e.fire_hitsound = true;