]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/w_common.qc
add a "weak" rifle trail for secondary
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_common.qc
index 8f2de4e8ce27b777624ea583860d081df599e830..24f434044a9b466b816b8cc0244fcd6d7d88f17f 100644 (file)
@@ -28,6 +28,7 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f
        local vector hitloc, force, endpoint, dir;
        local entity ent, endent;
        local float endq3surfaceflags;
+       float totaldmg;
 
        float length;
        vector beampos;
@@ -35,8 +36,6 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f
        entity pseudoprojectile;
        float f, ffs;
 
-       float hit;
-
        railgun_start = start;
        railgun_end = end;
 
@@ -47,6 +46,8 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f
        // go a little bit into the wall because we need to hit this wall later
        end = end + dir;
 
+       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
@@ -121,18 +122,12 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f
                // get the details we need to call the damage function
                hitloc = ent.railgunhitloc;
 
-               //for stats so that team hit will count as a miss
-               if(ent.flags & FL_CLIENT)
-               if(ent.deadflag == DEAD_NO)
-                       hit = 1;
-
-               if(teams_matter)
-               if(ent.team == self.team)
-                       hit = 0;
-
                f = ExponentialFalloff(mindist, maxdist, halflifedist, ent.railgundistance);
                ffs = ExponentialFalloff(mindist, maxdist, forcehalflifedist, ent.railgundistance);
 
+               if(accuracy_isgooddamage(self.owner, ent))
+                       totaldmg += bdamage * f;
+
                // apply the damage
                if (ent.takedamage)
                        Damage (ent, self, self, bdamage * f, deathtype, hitloc, force * ffs);
@@ -151,16 +146,7 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f
        }
 
        // calculate hits and fired shots for hitscan
-       if not(inWarmupStage)
-       {
-               self.stats_fired[self.weapon - 1] += 1;
-               self.stat_fired = self.weapon + 64 * floor(self.stats_fired[self.weapon - 1]);
-
-               if(hit) {
-                       self.stats_hit[self.weapon - 1] += 1;
-                       self.stat_hit = self.weapon + 64 * floor(self.stats_hit[self.weapon - 1]);
-               }
-       }
+       accuracy_add(self, self.weapon, 0, min(bdamage, totaldmg));
 
        trace_endpos = endpoint;
        trace_ent = endent;
@@ -170,11 +156,13 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f
 .float dmg_edge;
 .float dmg_force;
 .float dmg_radius;
+.float dmg_total;
 void W_BallisticBullet_Hit (void)
 {
-       float f;
+       float f, q, g;
 
        f = pow(bound(0, vlen(self.velocity) / vlen(self.oldvelocity), 1), 2); // energy multiplier
+       q = 1 + self.dmg_edge / self.dmg;
 
        if(other.solid == SOLID_BSP)
                Damage_DamageInfo(self.origin, self.dmg * f, 0, 0, max(1, self.dmg_force) * normalize(self.velocity) * f, self.projectiledeathtype, self);
@@ -185,14 +173,16 @@ void W_BallisticBullet_Hit (void)
 
                headshot = 0;
                yoda = 0;
-               damage_headshotbonus = self.dmg_edge;
+               damage_headshotbonus = self.dmg_edge * f;
                railgun_start = self.origin - 2 * frametime * self.velocity;
                railgun_end = self.origin + 2 * frametime * self.velocity;
-
+               g = accuracy_isgooddamage(self.owner, other);
                Damage(other, self, self.owner, self.dmg * f, self.projectiledeathtype, self.origin, self.dmg_force * normalize(self.velocity) * f);
                damage_headshotbonus = 0;
 
-               if(self.dmg_edge != 0)
+               if(headshot)
+                       f *= q;
+               if(DEATH_WEAPONOF(self.projectiledeathtype) == WEP_CAMPINGRIFLE)
                {
                        if(headshot)
                                AnnounceTo(self.owner, "headshot");
@@ -201,13 +191,12 @@ void W_BallisticBullet_Hit (void)
                }
 
                // calculate hits for ballistic weapons
-               if (other.flags & FL_CLIENT)  // is the player a client
-               if (other.deadflag == DEAD_NO)  // is the victim a corpse
-               if ((!(teamplay)) | (other.team != self.owner.team))  // not teamplay (ctf, kh, tdm etc) or the victim is in the same team
-               if not(inWarmupStage)  // not in warm up stage
+               if(g)
                {
-                       self.owner.stats_hit[self.owner.weapon - 1] += 1;
-                       self.owner.stat_hit = self.owner.weapon + 64 * floor(self.owner.stats_hit[self.owner.weapon - 1]);
+                       // do not exceed 100%
+                       q = min(self.dmg * q, self.dmg_total + f * self.dmg) - self.dmg_total;
+                       self.dmg_total += f * self.dmg;
+                       accuracy_add(self.owner, self.owner.weapon, 0, q);
                }
        }
 
@@ -260,7 +249,7 @@ float W_BallisticBullet_LeaveSolid(entity e, vector vel, float constant)
        // maxdist = 0.5 * v0 * v0 / constant
        // dprint("max dist = ", ftos(maxdist), "\n");
 
-       if(maxdist <= cvar("g_ballistics_mindistance"))
+       if(maxdist <= autocvar_g_ballistics_mindistance)
                return 0;
 
        traceline_inverted (self.origin, self.origin + normalize(vel) * maxdist, MOVE_NORMAL, self);
@@ -270,7 +259,7 @@ float W_BallisticBullet_LeaveSolid(entity e, vector vel, float constant)
 
        self.W_BallisticBullet_LeaveSolid_origin = trace_endpos;
 
-       dst = vlen(trace_endpos - self.origin);
+       dst = max(autocvar_g_ballistics_mindistance, vlen(trace_endpos - self.origin));
        // E(s) = E0 - constant * s, constant = area of bullet circle * material constant / mass
        Es_m = E0_m - constant * dst;
        if(Es_m <= 0)
@@ -310,6 +299,26 @@ void W_BallisticBullet_Touch (void)
        PROJECTILE_TOUCH;
        W_BallisticBullet_Hit ();
 
+       // if we hit "weapclip", bail out
+       //
+       // rationale of this check:
+       //
+       // any shader that is solid, nodraw AND trans is meant to clip weapon
+       // shots and players, but has no other effect!
+       //
+       // if it is not trans, it is caulk and should not have this side effect
+       //
+       // matching shaders:
+       //   common/weapclip (intended)
+       //   common/noimpact (is supposed to eat projectiles, but is erased farther above)
+       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NODRAW)
+       if not(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID)
+       if not(trace_dphitcontents & DPCONTENTS_OPAQUE)
+       {
+               remove(self);
+               return;
+       }
+
        density = other.ballistics_density;
        if(density == 0)
                density = 1;
@@ -341,6 +350,9 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
 {
        float lag, dt, savetime, density;
        entity pl, oldself;
+       float antilagging;
+
+       antilagging = (autocvar_g_antilag_bullets && (pSpeed >= autocvar_g_antilag_bullets));
 
        entity proj;
        proj = spawn();
@@ -356,9 +368,9 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
                proj.movetype = MOVETYPE_FLY;
        proj.think = SUB_Remove;
        proj.nextthink = time + lifetime; // min(pLifetime, vlen(world.maxs - world.mins) / pSpeed);
-       W_SetupProjectileVelocityEx(proj, dir, v_up, pSpeed, 0, 0, spread);
+       W_SetupProjectileVelocityEx(proj, dir, v_up, pSpeed, 0, 0, spread, antilagging);
        proj.angles = vectoangles(proj.velocity);
-       proj.dmg_radius = cvar("g_ballistics_materialconstant") / bulletconstant;
+       proj.dmg_radius = autocvar_g_ballistics_materialconstant / bulletconstant;
        // so: bulletconstant = bullet mass / area of bullet circle
        setorigin(proj, start);
        proj.flags = FL_PROJECTILE;
@@ -371,13 +383,16 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
 
        proj.oldvelocity = proj.velocity;
 
-       if(cvar("g_antilag_bullets"))
-       if(pSpeed >= cvar("g_antilag_bullets"))
+       other = proj; MUTATOR_CALLHOOK(EditProjectile);
+
+       if(antilagging)
        {
                float eff;
 
                if(tracereffects & EF_RED)
                        eff = particleeffectnum("tr_rifle");
+               else if(tracereffects & EF_BLUE)
+                       eff = particleeffectnum("tr_rifle_weak");
                else
                        eff = particleeffectnum("tr_bullet");
 
@@ -387,7 +402,7 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
                        lag = 0;
                if(clienttype(self) != CLIENTTYPE_REAL)
                        lag = 0;
-               if(cvar("g_antilag") == 0 || self.cvar_cl_noantilag)
+               if(autocvar_g_antilag == 0 || self.cvar_cl_noantilag)
                        lag = 0; // only do hitscan, but no antilag
 
                if(lag)
@@ -400,13 +415,6 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
                savetime = frametime;
                frametime = 0.05;
 
-               // update the accuracy stats - increase shots fired by 1
-               if not(inWarmupStage)
-               {
-                       oldself.stats_fired[oldself.weapon - 1] += 1;
-                       oldself.stat_fired = oldself.weapon + 64 * floor(oldself.stats_fired[oldself.weapon - 1]);
-               }
-
                for(;;)
                {
                        // DP tracetoss is stupid and always traces in 0.05s
@@ -445,6 +453,23 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
                                W_BallisticBullet_Hit();
                        }
 
+                       // if we hit "weapclip", bail out
+                       //
+                       // rationale of this check:
+                       //
+                       // any shader that is solid, nodraw AND trans is meant to clip weapon
+                       // shots and players, but has no other effect!
+                       //
+                       // if it is not trans, it is caulk and should not have this side effect
+                       //
+                       // matching shaders:
+                       //   common/weapclip (intended)
+                       //   common/noimpact (is supposed to eat projectiles, but is erased farther above)
+                       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NODRAW)
+                       if not(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NONSOLID)
+                       if not(trace_dphitcontents & DPCONTENTS_OPAQUE)
+                               break;
+
                        density = other.ballistics_density;
                        if(density == 0)
                                density = 1;
@@ -467,13 +492,6 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
                return;
        }
 
-       // update the accuracy stats
-       if not(inWarmupStage)
-       {
-               self.stats_fired[self.weapon - 1] += 1;
-               self.stat_fired = self.weapon + 64 * floor(self.stats_fired[self.weapon - 1]);
-       }
-
        if(tracereffects & EF_RED)
                CSQCProjectile(proj, TRUE, PROJECTILE_BULLET_GLOWING_TRACER, TRUE);
        else if(tracereffects & EF_BLUE)
@@ -511,6 +529,7 @@ void W_PrepareExplosionByDamage(entity attacker, void() explode)
        self.takedamage = DAMAGE_NO;
        self.event_damage = SUB_Null;
        self.owner = attacker;
+       self.realowner = attacker;
 
        // do not explode NOW but in the NEXT FRAME!
        // because recursive calls to RadiusDamage are not allowed