]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/weapons/tracing.qc
Make map weapons glow the color of their waypoint instead of white
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / weapons / tracing.qc
index eace8ce0c79b086d8107488b274890e198bd3960..b37e1578e2878ed0011c4fe22d59cf42eee168ad 100644 (file)
 #include "../antilag.qh"
 
 #include <common/constants.qh>
+#include <common/net_linked.qh>
 #include <common/util.qh>
 
-#include <common/weapons/all.qh>
+#include <common/weapons/_all.qh>
 #include <common/state.qh>
 
 #include <lib/warpzone/common.qh>
@@ -27,7 +28,7 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect
        float oldsolid;
        vector vecs, dv;
        oldsolid = ent.dphitcontentsmask;
-       if (IS_PLAYER(ent) && PS(ent).m_weapon == WEP_RIFLE)
+       if (IS_PLAYER(ent) && ent.(weaponentity).m_weapon == WEP_RIFLE)
                ent.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_CORPSE;
        else
                ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
@@ -53,10 +54,10 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect
 
        // track max damage
        if (IS_PLAYER(ent) && accuracy_canbegooddamage(ent))
-               accuracy_add(ent, PS(ent).m_weapon.m_id, maxdamage, 0);
+               accuracy_add(ent, ent.(weaponentity).m_weapon.m_id, maxdamage, 0);
 
        if(IS_PLAYER(ent))
-               W_HitPlotAnalysis(ent, v_forward, v_right, v_up);
+               W_HitPlotAnalysis(ent, weaponentity, v_forward, v_right, v_up);
 
        vector md = ent.(weaponentity).movedir;
        if(md.x > 0)
@@ -196,35 +197,23 @@ void W_SetupProjVelocity_Explicit(entity proj, vector dir, vector upDir, float p
 //  Ballistics Tracing
 // ====================
 
-void FireRailgunBullet (entity this, vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype)
+void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype)
 {
-       vector hitloc, force, endpoint, dir;
-       entity ent, endent;
-       float endq3surfaceflags;
-       float totaldmg;
-       entity o;
+       entity pseudoprojectile = NULL;
 
-       float length;
-       vector beampos;
-       string snd;
-       entity pseudoprojectile;
-       float f, ffs;
-
-       pseudoprojectile = NULL;
-
-       dir = normalize(end - start);
-       length = vlen(end - start);
-       force = dir * bforce;
+       vector dir = normalize(end - start);
+       float length = vlen(end - start);
+       vector force = dir * bforce;
 
        // go a little bit into the wall because we need to hit this wall later
        end = end + dir;
 
-       totaldmg = 0;
+       float totaldmg = 0;
 
        // trace multiple times until we hit a wall, each obstacle will be made
        // non-solid so we can hit the next, while doing this we spawn effects and
        // note down which entities were hit so we can damage them later
-       o = this;
+       entity o = this;
        while (1)
        {
                if(CS(this).antilag_debug)
@@ -259,18 +248,15 @@ void FireRailgunBullet (entity this, vector start, vector end, float bdamage, fl
                trace_ent.solid = SOLID_NOT;
        }
 
-       endpoint = trace_endpos;
-       endent = trace_ent;
-       endq3surfaceflags = trace_dphitq3surfaceflags;
+       vector endpoint = trace_endpos;
+       entity endent = trace_ent;
+       float endq3surfaceflags = trace_dphitq3surfaceflags;
 
        // find all the entities the railgun hit and restore their solid state
-       ent = findfloat(NULL, railgunhit, true);
-       while (ent)
+       FOREACH_ENTITY_FLOAT(railgunhit, true,
        {
-               // restore their solid type
-               ent.solid = ent.railgunhitsolidbackup;
-               ent = findfloat(ent, railgunhit, true);
-       }
+               it.solid = it.railgunhitsolidbackup;
+       });
 
        // spawn a temporary explosion entity for RadiusDamage calls
        //explosion = spawn();
@@ -284,17 +270,15 @@ void FireRailgunBullet (entity this, vector start, vector end, float bdamage, fl
                        {
                                msg_entity = it;
                                // nearest point on the beam
-                               beampos = start + dir * bound(0, (msg_entity.origin - start) * dir, length);
+                               vector beampos = start + dir * bound(0, (msg_entity.origin - start) * dir, length);
 
-                               f = bound(0, 1 - vlen(beampos - msg_entity.origin) / 512, 1);
+                               float f = bound(0, 1 - vlen(beampos - msg_entity.origin) / 512, 1);
                                if(f <= 0)
                                        continue;
 
-                               snd = SND(NEXWHOOSH_RANDOM());
-
                                if(!pseudoprojectile)
                                        pseudoprojectile = spawn(); // we need this so the sound uses the "entchannel4" volume
-                               soundtoat(MSG_ONE, pseudoprojectile, beampos, CH_SHOTS, snd, VOL_BASE * f, ATTEN_NONE);
+                               soundtoat(MSG_ONE, pseudoprojectile, beampos, CH_SHOTS, SND(NEXWHOOSH_RANDOM()), VOL_BASE * f, ATTEN_NONE);
                        }
                ));
 
@@ -303,37 +287,33 @@ void FireRailgunBullet (entity this, vector start, vector end, float bdamage, fl
        }
 
        // find all the entities the railgun hit and hurt them
-       ent = findfloat(NULL, railgunhit, true);
-       while (ent)
+       FOREACH_ENTITY_FLOAT(railgunhit, true,
        {
                // get the details we need to call the damage function
-               hitloc = ent.railgunhitloc;
+               vector hitloc = it.railgunhitloc;
 
-               f = ExponentialFalloff(mindist, maxdist, halflifedist, ent.railgundistance);
-               ffs = ExponentialFalloff(mindist, maxdist, forcehalflifedist, ent.railgundistance);
+               float foff = ExponentialFalloff(mindist, maxdist, halflifedist, it.railgundistance);
+               float ffs = ExponentialFalloff(mindist, maxdist, forcehalflifedist, it.railgundistance);
 
-               if(accuracy_isgooddamage(this, ent))
-                       totaldmg += bdamage * f;
+               if(accuracy_isgooddamage(this, it))
+                       totaldmg += bdamage * foff;
 
                // apply the damage
-               if (ent.takedamage)
-                       Damage (ent, this, this, bdamage * f, deathtype, hitloc, ent.railgunforce * ffs);
+               if (it.takedamage)
+                       Damage (it, this, this, bdamage * foff, deathtype, hitloc, it.railgunforce * ffs);
 
                // create a small explosion to throw gibs around (if applicable)
                //setorigin(explosion, hitloc);
                //RadiusDamage (explosion, this, 10, 0, 50, NULL, NULL, 300, deathtype);
 
-               ent.railgunhitloc = '0 0 0';
-               ent.railgunhitsolidbackup = SOLID_NOT;
-               ent.railgunhit = false;
-               ent.railgundistance = 0;
-
-               // advance to the next entity
-               ent = findfloat(ent, railgunhit, true);
-       }
+               it.railgunhitloc = '0 0 0';
+               it.railgunhitsolidbackup = SOLID_NOT;
+               it.railgunhit = false;
+               it.railgundistance = 0;
+       });
 
        // calculate hits and fired shots for hitscan
-       accuracy_add(this, PS(this).m_weapon.m_id, 0, min(bdamage, totaldmg));
+       accuracy_add(this, this.(weaponentity).m_weapon.m_id, 0, min(bdamage, totaldmg));
 
        trace_endpos = endpoint;
        trace_ent = endent;
@@ -348,12 +328,12 @@ void fireBullet_trace_callback(vector start, vector hit, vector end)
        fireBullet_last_hit = NULL;
 }
 
-void fireBullet(entity this, vector start, vector dir, float spread, float max_solid_penetration, float damage, float force, float dtype, int tracereffects)
+void fireBullet(entity this, .entity weaponentity, vector start, vector dir, float spread, float max_solid_penetration, float damage, float force, float dtype, int tracereffects)
 {
        vector  end;
 
        dir = normalize(dir + randomvec() * spread);
-       end = start + dir * MAX_SHOT_DISTANCE;
+       end = start + dir * max_shot_distance;
 
        fireBullet_last_hit = NULL;
        float solid_penetration_left = 1;
@@ -398,8 +378,12 @@ void fireBullet(entity this, vector start, vector dir, float spread, float max_s
                start = trace_endpos;
                entity hit = trace_ent;
 
+               // traced up to max_shot_distance and didn't hit anything at all
+               if (trace_fraction == 1.0)
+                       break;
+
                // When hitting sky, stop.
-               if (pointcontents(start) == CONTENT_SKY)
+               if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
                        break;
 
                // can't use noimpact, as we need to pass through walls
@@ -431,7 +415,7 @@ void fireBullet(entity this, vector start, vector dir, float spread, float max_s
                {
                        fireBullet_last_hit = hit;
                        yoda = 0;
-                       MUTATOR_CALLHOOK(FireBullet_Hit, this, hit, start, end, damage);
+                       MUTATOR_CALLHOOK(FireBullet_Hit, this, hit, start, end, damage, this.(weaponentity));
                        damage = M_ARGV(4, float);
                        float g = accuracy_isgooddamage(this, hit);
                        Damage(hit, this, this, damage * solid_penetration_left, dtype, start, force * dir * solid_penetration_left);
@@ -441,11 +425,11 @@ void fireBullet(entity this, vector start, vector dir, float spread, float max_s
                                // do not exceed 100%
                                float added_damage = min(damage - total_damage, damage * solid_penetration_left);
                                total_damage += damage * solid_penetration_left;
-                               accuracy_add(this, PS(this).m_weapon.m_id, 0, added_damage);
+                               accuracy_add(this, this.(weaponentity).m_weapon.m_id, 0, added_damage);
                        }
                }
 
-               if (is_weapclip)
+               if (is_weapclip && !autocvar_g_ballistics_penetrate_clips)
                        break;
 
                // go through solid!
@@ -475,7 +459,9 @@ void fireBullet(entity this, vector start, vector dir, float spread, float max_s
                        break;
 
                float dist_taken = max(autocvar_g_ballistics_mindistance, vlen(trace_endpos - start));
-               solid_penetration_left -= (dist_taken / maxdist);
+               // fraction_used_of_what_is_left = dist_taken / maxdist
+               // solid_penetration_left = solid_penetration_left - solid_penetration_left * fraction_used_of_what_is_left
+               solid_penetration_left *= 1 - dist_taken / maxdist;
                solid_penetration_left = max(solid_penetration_left, 0);
 
                // Only show effect when going through a player (invisible otherwise)