]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/w_common.qc
Merge branch 'master' into mario/mutator_minstagib
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_common.qc
index 3343fa7c3f5f24d9977e41b05e4da32a498bc0ac..d755f68dfc7dbb182b52f7e8c970b3e84eb896f4 100644 (file)
@@ -1,5 +1,5 @@
 
-void W_GiveWeapon (entity e, float wep, string name)
+void W_GiveWeapon (entity e, float wep)
 {
        entity oldself;
 
@@ -11,13 +11,8 @@ void W_GiveWeapon (entity e, float wep, string name)
        oldself = self;
        self = e;
 
-       if not(g_minstagib)
-       if (other.classname == "player")
-       {
-               sprint (other, "You got the ^2");
-               sprint (other, name);
-               sprint (other, "\n");
-       }
+       if(other.classname == "player")
+               { Send_Notification(NOTIF_ONE, other, MSG_MULTI, ITEM_WEAPON_GOT, wep); }
 
        self = oldself;
 }
@@ -38,6 +33,8 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f
        entity pseudoprojectile;
        float f, ffs;
 
+       pseudoprojectile = world;
+
        railgun_start = start;
        railgun_end = end;
 
@@ -165,7 +162,6 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f
        trace_dphitq3surfaceflags = endq3surfaceflags;
 }
 
-.float dmg_edge;
 .float dmg_force;
 .float dmg_radius;
 .float dmg_total;
@@ -183,24 +179,14 @@ void W_BallisticBullet_Hit (void)
        {
                endzcurveparticles();
 
-               headshot = 0;
                yoda = 0;
-               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.realowner, other);
                Damage(other, self, self.realowner, self.dmg * f, self.projectiledeathtype, self.origin, self.dmg_force * normalize(self.velocity) * f);
-               damage_headshotbonus = 0;
 
-               if(headshot)
-                       f *= q;
-               if(self.dmg_edge > 0)
-               {
-                       if(headshot)
-                               AnnounceTo(self.realowner, "headshot");
-                       if(yoda)
-                               AnnounceTo(self.realowner, "awesome");
-               }
+               if(yoda)
+                       AnnounceTo(self.realowner, "awesome");
 
                // calculate hits for ballistic weapons
                if(g)
@@ -227,7 +213,7 @@ void W_BallisticBullet_LeaveSolid_think()
 
        self.think = self.W_BallisticBullet_LeaveSolid_think_save;
        self.nextthink = max(time, self.W_BallisticBullet_LeaveSolid_nextthink_save);
-       self.W_BallisticBullet_LeaveSolid_think_save = SUB_Null;
+       self.W_BallisticBullet_LeaveSolid_think_save = func_null;
 
        self.flags &~= FL_ONGROUND;
 
@@ -241,31 +227,58 @@ void W_BallisticBullet_LeaveSolid_think()
        UpdateCSQCProjectile(self);
 }
 
-float W_BallisticBullet_LeaveSolid(entity e, vector vel, float constant)
+float W_BallisticBullet_LeaveSolid(float eff)
 {
        // move the entity along its velocity until it's out of solid, then let it resume
-
+       vector vel = self.velocity;
        float dt, dst, velfactor, v0, vs;
        float maxdist;
        float E0_m, Es_m;
+       float constant = self.dmg_radius * (other.ballistics_density ? other.ballistics_density : 1);
 
        // outside the world? forget it
        if(self.origin_x > world.maxs_x || self.origin_y > world.maxs_y || self.origin_z > world.maxs_z || self.origin_x < world.mins_x || self.origin_y < world.mins_y || self.origin_z < world.mins_z)
                return 0;
 
+       // special case for zero density and zero bullet constant: 
+
+       if(self.dmg_radius == 0)
+       {
+               if(other.ballistics_density < 0)
+                       constant = 0; // infinite travel distance
+               else
+                       return 0; // no penetration
+       }
+       else
+       {
+               if(other.ballistics_density < 0)
+                       constant = 0; // infinite travel distance
+               else if(other.ballistics_density == 0)
+                       constant = self.dmg_radius;
+               else
+                       constant = self.dmg_radius * other.ballistics_density;
+       }
+
        // E(s) = E0 - constant * s, constant = area of bullet circle * material constant / mass
        v0 = vlen(vel);
 
        E0_m = 0.5 * v0 * v0;
-       maxdist = E0_m / constant;
-       // maxdist = 0.5 * v0 * v0 / constant
-       // dprint("max dist = ", ftos(maxdist), "\n");
 
-       if(maxdist <= autocvar_g_ballistics_mindistance)
-               return 0;
+       if(constant)
+       {
+               maxdist = E0_m / constant;
+               // maxdist = 0.5 * v0 * v0 / constant
+               // dprint("max dist = ", ftos(maxdist), "\n");
 
-       traceline_inverted (self.origin, self.origin + normalize(vel) * maxdist, MOVE_NORMAL, self);
+               if(maxdist <= autocvar_g_ballistics_mindistance)
+                       return 0;
+       }
+       else
+       {
+               maxdist = vlen(other.maxs - other.mins) + 1; // any distance, as long as we leave the entity
+       }
 
+       traceline_inverted (self.origin, self.origin + normalize(vel) * maxdist, MOVE_NORMAL, self, TRUE);
        if(trace_fraction == 1) // 1: we never got out of solid
                return 0;
 
@@ -298,12 +311,19 @@ float W_BallisticBullet_LeaveSolid(entity e, vector vel, float constant)
        self.flags |= FL_ONGROUND; // prevent moving
        self.W_BallisticBullet_LeaveSolid_velocity = vel;
 
+       if(eff >= 0)
+               if(vlen(trace_endpos - self.origin) > 4)
+               {
+                       endzcurveparticles();
+                       trailparticles(self, eff, self.origin, trace_endpos);
+               }
+
        return 1;
 }
 
 void W_BallisticBullet_Touch (void)
 {
-       float density;
+       //float density;
 
        if(self.think == W_BallisticBullet_LeaveSolid_think) // skip this!
                return;
@@ -311,6 +331,12 @@ void W_BallisticBullet_Touch (void)
        PROJECTILE_TOUCH;
        W_BallisticBullet_Hit ();
 
+       if(self.dmg_radius < 0) // these NEVER penetrate solid
+       {
+               remove(self);
+               return;
+       }
+
        // if we hit "weapclip", bail out
        //
        // rationale of this check:
@@ -331,12 +357,8 @@ void W_BallisticBullet_Touch (void)
                return;
        }
 
-       density = other.ballistics_density;
-       if(density == 0)
-               density = 1;
-
        // go through solid!
-       if(!W_BallisticBullet_LeaveSolid(self, self.velocity, self.dmg_radius * density))
+       if(!W_BallisticBullet_LeaveSolid(-1))
        {
                remove(self);
                return;
@@ -360,9 +382,9 @@ void fireBallisticBullet_trace_callback(vector start, vector hit, vector end)
        self.owner = world;
 }
 
-void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, float lifetime, float damage, float headshotbonus, float force, float dtype, float tracereffects, float gravityfactor, float bulletconstant)
+void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, float lifetime, float damage, float force, float dtype, float tracereffects, float gravityfactor, float bulletconstant)
 {
-       float lag, dt, savetime, density;
+       float lag, dt, savetime; //, density;
        entity pl, oldself;
        float antilagging;
 
@@ -384,14 +406,18 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
        proj.nextthink = time + lifetime; // min(pLifetime, vlen(world.maxs - world.mins) / pSpeed);
        W_SetupProjectileVelocityEx(proj, dir, v_up, pSpeed, 0, 0, spread, antilagging);
        proj.angles = vectoangles(proj.velocity);
-       proj.dmg_radius = autocvar_g_ballistics_materialconstant / bulletconstant;
+       if(bulletconstant > 0)
+               proj.dmg_radius = autocvar_g_ballistics_materialconstant / bulletconstant;
+       else if(bulletconstant == 0)
+               proj.dmg_radius = 0;
+       else
+               proj.dmg_radius = -1;
        // so: bulletconstant = bullet mass / area of bullet circle
        setorigin(proj, start);
        proj.flags = FL_PROJECTILE;
 
        proj.touch = W_BallisticBullet_Touch;
        proj.dmg = damage;
-       proj.dmg_edge = headshotbonus;
        proj.dmg_force = force;
        proj.projectiledeathtype = dtype;
 
@@ -468,6 +494,9 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
                                W_BallisticBullet_Hit();
                        }
 
+                       if(proj.dmg_radius < 0) // these NEVER penetrate solid
+                               break;
+
                        // if we hit "weapclip", bail out
                        //
                        // rationale of this check:
@@ -485,15 +514,13 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f
                        if not(trace_dphitcontents & DPCONTENTS_OPAQUE)
                                break;
 
-                       density = other.ballistics_density;
-                       if(density == 0)
-                               density = 1;
-
                        // go through solid!
-                       if(!W_BallisticBullet_LeaveSolid(self, self.velocity, self.dmg_radius * density))
+                       if(!W_BallisticBullet_LeaveSolid((other && (other.solid != SOLID_BSP)) ? eff : -1))
                                break;
 
                        W_BallisticBullet_LeaveSolid_think();
+
+                       self.projectiledeathtype |= HITTYPE_BOUNCE;
                }
                frametime = savetime;
                self = oldself;
@@ -584,10 +611,14 @@ float W_CheckProjectileDamage(entity inflictor, entity projowner, float deathtyp
 void W_PrepareExplosionByDamage(entity attacker, void() explode)
 {
        self.takedamage = DAMAGE_NO;
-       self.event_damage = SUB_Null;
-       self.owner = attacker;
-       self.realowner = attacker;
-
+       self.event_damage = func_null;
+       
+       if((attacker.flags & FL_CLIENT) && !autocvar_g_projectiles_keep_owner)
+       {
+               self.owner = attacker;
+               self.realowner = attacker;
+       }
+       
        // do not explode NOW but in the NEXT FRAME!
        // because recursive calls to RadiusDamage are not allowed
        self.nextthink = time;