]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/client/weapons/projectile.qc
Merge branch 'master' into terencehill/lms_itemtimes_fix
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / weapons / projectile.qc
index 7f13ab5dfe5455c31baa259cfe9a5feb8bd88510..4ebe4afcfb7e8c55c64f6f8f0425c46b0f393976 100644 (file)
@@ -3,56 +3,55 @@
 #include "../autocvars.qh"
 #include "../defs.qh"
 #include "../main.qh"
+#include "../mutators/events.qh"
 
-#include "../../common/constants.qh"
-#include "../../common/nades.qh"
-#include "../../common/movetypes/movetypes.qh"
-#include "../../common/util.qh"
+#include <common/constants.qh>
+#include <common/physics/movetypes/movetypes.qh>
 
-#include "../../csqcmodellib/interpolate.qh"
+#include <lib/csqcmodel/interpolate.qh>
 
-#include "../../warpzonelib/anglestransform.qh"
+#include <lib/warpzone/anglestransform.qh>
 
 .float alpha;
 .float scale;
 .vector colormod;
 
 void SUB_Stop()
-{SELFPARAM();
+{
+       SELFPARAM();
        self.move_velocity = self.move_avelocity = '0 0 0';
        self.move_movetype = MOVETYPE_NONE;
 }
 
-void Projectile_ResetTrail(vector to)
-{SELFPARAM();
-       self.trail_oldorigin = to;
-       self.trail_oldtime = time;
+void Projectile_ResetTrail(entity this, vector to)
+{
+       this.trail_oldorigin = to;
+       this.trail_oldtime = time;
 }
 
-void Projectile_DrawTrail(vector to)
-{SELFPARAM();
-       vector from;
-       float t0;
-
-       from = self.trail_oldorigin;
-       t0 = self.trail_oldtime;
-       self.trail_oldorigin = to;
-       self.trail_oldtime = time;
+void Projectile_DrawTrail(entity this, vector to)
+{
+       vector from = this.trail_oldorigin;
+       // float t0 = this.trail_oldtime;
+       this.trail_oldorigin = to;
+       this.trail_oldtime = time;
 
        // force the effect even for stationary firemine
-       if(self.cnt == PROJECTILE_FIREMINE)
-               if(from == to)
+       if (this.cnt == PROJECTILE_FIREMINE)
+               if (from == to)
                        from.z += 1;
 
-       if (self.traileffect)
+       if (this.traileffect)
        {
-               particles_alphamin = particles_alphamax = particles_fade = sqrt(self.alpha);
-               boxparticles(self.traileffect, self, from, to, self.velocity, self.velocity, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE | PARTICLES_DRAWASTRAIL);
+               particles_alphamin = particles_alphamax = particles_fade = sqrt(this.alpha);
+               boxparticles(particleeffectnum(Effects_from(this.traileffect)), this, from, to, this.velocity, this.velocity, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE | PARTICLES_DRAWASTRAIL);
        }
 }
 
-void Projectile_Draw()
-{SELFPARAM();
+bool Projectile_isnade(int proj); // TODO: remove
+
+void Projectile_Draw(entity this)
+{
        vector rot;
        vector trailorigin;
        int f;
@@ -62,28 +61,28 @@ void Projectile_Draw()
 
        f = self.move_flags;
 
-       if(self.count & 0x80)
+       if (self.count & 0x80)
        {
-               //self.move_flags &= ~FL_ONGROUND;
-               if(self.move_movetype == MOVETYPE_NONE || self.move_movetype == MOVETYPE_FLY)
-                       Movetype_Physics_NoMatchServer();
-                       // the trivial movetypes do not have to match the
-                       // server's ticrate as they are ticrate independent
-                       // NOTE: this assumption is only true if MOVETYPE_FLY
-                       // projectiles detonate on impact. If they continue
-                       // moving, we might still be ticrate dependent.
+               // self.move_flags &= ~FL_ONGROUND;
+               if (self.move_movetype == MOVETYPE_NONE || self.move_movetype == MOVETYPE_FLY)
+                       Movetype_Physics_NoMatchServer(self);
+               // the trivial movetypes do not have to match the
+               // server's ticrate as they are ticrate independent
+               // NOTE: this assumption is only true if MOVETYPE_FLY
+               // projectiles detonate on impact. If they continue
+               // moving, we might still be ticrate dependent.
                else
-                       Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
-               if(!(self.move_flags & FL_ONGROUND))
-                       if(self.velocity != '0 0 0')
+                       Movetype_Physics_MatchServer(self, autocvar_cl_projectiles_sloppy);
+               if (!(self.move_flags & FL_ONGROUND))
+                       if (self.velocity != '0 0 0')
                                self.move_angles = self.angles = vectoangles(self.velocity);
        }
        else
        {
-               InterpolateOrigin_Do();
+               InterpolateOrigin_Do(self);
        }
 
-       if(self.count & 0x80)
+       if (self.count & 0x80)
        {
                drawn = (time >= self.spawntime - 0.02);
                t = max(time, self.spawntime);
@@ -94,27 +93,27 @@ void Projectile_Draw()
                t = time;
        }
 
-       if(!(f & FL_ONGROUND))
+       if (!(f & FL_ONGROUND))
        {
                rot = '0 0 0';
-               switch(self.cnt)
+               switch (self.cnt)
                {
                        /*
                        case PROJECTILE_GRENADE:
-                               rot = '-2000 0 0'; // forward
-                               break;
+                           rot = '-2000 0 0'; // forward
+                           break;
                        */
                        case PROJECTILE_GRENADE_BOUNCING:
                                rot = '0 -1000 0'; // sideways
                                break;
                        case PROJECTILE_HOOKBOMB:
-                               rot = '1000 0 0'; // forward
+                               rot = '1000 0 0';  // forward
                                break;
                        default:
                                break;
                }
 
-               if(Nade_FromProjectile(self.cnt) != NADE_TYPE_NULL)
+               if (Projectile_isnade(self.cnt))
                        rot = self.avelocity;
 
                self.angles = AnglesTransform_ToAngles(AnglesTransform_Multiply(AnglesTransform_FromAngles(self.angles), rot * (t - self.spawntime)));
@@ -127,12 +126,12 @@ void Projectile_Draw()
 
        a = 1 - (time - self.fade_time) * self.fade_rate;
        self.alpha = bound(0, self.alphamod * a, 1);
-       if(self.alpha <= 0)
+       if (self.alpha <= 0)
                drawn = 0;
        self.renderflags = 0;
 
        trailorigin = self.origin;
-       switch(self.cnt)
+       switch (self.cnt)
        {
                case PROJECTILE_GRENADE:
                case PROJECTILE_GRENADE_BOUNCING:
@@ -142,20 +141,20 @@ void Projectile_Draw()
                        break;
        }
 
-       if(Nade_FromProjectile(self.cnt) != NADE_TYPE_NULL)
+       if (Projectile_isnade(self.cnt))
                trailorigin += v_up * 4;
 
-       if(drawn)
-               Projectile_DrawTrail(trailorigin);
+       if (drawn)
+               Projectile_DrawTrail(self, trailorigin);
        else
-               Projectile_ResetTrail(trailorigin);
+               Projectile_ResetTrail(self, trailorigin);
 
        self.drawmask = 0;
 
-       if(!drawn)
+       if (!drawn)
                return;
 
-       switch(self.cnt)
+       switch (self.cnt)
        {
                // Possibly add dlights here.
                default:
@@ -166,27 +165,27 @@ void Projectile_Draw()
 }
 
 void loopsound(entity e, int ch, string samp, float vol, float attn)
-{SELFPARAM();
-       if(self.silent)
+{
+       SELFPARAM();
+       if (self.silent)
                return;
 
-       sound(e, ch, samp, vol, attn);
+       _sound(e, ch, samp, vol, attn);
        e.snd_looping = ch;
 }
 
 void Ent_RemoveProjectile()
-{SELFPARAM();
-       if(self.count & 0x80)
+{
+       SELFPARAM();
+       if (self.count & 0x80)
        {
                tracebox(self.origin, self.mins, self.maxs, self.origin + self.velocity * 0.05, MOVE_NORMAL, self);
-               Projectile_DrawTrail(trace_endpos);
+               Projectile_DrawTrail(self, trace_endpos);
        }
 }
 
-void Ent_Projectile()
-{SELFPARAM();
-       int f;
-
+NET_HANDLE(ENT_CLIENT_PROJECTILE, bool isnew)
+{
        // projectile properties:
        //   kind (interpolated, or clientside)
        //
@@ -201,21 +200,22 @@ void Ent_Projectile()
        //
        // projectiles don't send angles, because they always follow the velocity
 
-       f = ReadByte();
+       int f = ReadByte();
        self.count = (f & 0x80);
+       self.flags |= FL_PROJECTILE;
        self.iflags = (self.iflags & IFLAG_INTERNALMASK) | IFLAG_AUTOANGLES | IFLAG_ANGLES | IFLAG_ORIGIN;
        self.solid = SOLID_TRIGGER;
-       //self.effects = EF_NOMODELFLAGS;
+       // self.effects = EF_NOMODELFLAGS;
 
        // this should make collisions with bmodels more exact, but it leads to
        // projectiles no longer being able to lie on a bmodel
        self.move_nomonsters = MOVE_WORLDONLY;
-       if(f & 0x40)
+       if (f & 0x40)
                self.move_flags |= FL_ONGROUND;
        else
                self.move_flags &= ~FL_ONGROUND;
 
-       if(!self.move_time)
+       if (!self.move_time)
        {
                // for some unknown reason, we don't need to care for
                // sv_gameplayfix_delayprojectiles here.
@@ -223,38 +223,40 @@ void Ent_Projectile()
                self.spawntime = time;
        }
        else
+       {
                self.move_time = max(self.move_time, time);
+       }
 
-       if(!(self.count & 0x80))
-               InterpolateOrigin_Undo();
+       if (!(self.count & 0x80))
+               InterpolateOrigin_Undo(self);
 
-       if(f & 1)
+       if (f & 1)
        {
                self.origin_x = ReadCoord();
                self.origin_y = ReadCoord();
                self.origin_z = ReadCoord();
                setorigin(self, self.origin);
-               if(self.count & 0x80)
+               if (self.count & 0x80)
                {
                        self.velocity_x = ReadCoord();
                        self.velocity_y = ReadCoord();
                        self.velocity_z = ReadCoord();
-                       if(f & 0x10)
+                       if (f & 0x10)
                                self.gravity = ReadCoord();
                        else
-                               self.gravity = 0; // none
+                               self.gravity = 0;  // none
                        self.move_origin = self.origin;
                        self.move_velocity = self.velocity;
                }
 
-               if(time == self.spawntime || (self.count & 0x80) || (f & 0x08))
+               if (time == self.spawntime || (self.count & 0x80) || (f & 0x08))
                {
                        self.trail_oldorigin = self.origin;
-                       if(!(self.count & 0x80))
+                       if (!(self.count & 0x80))
                                InterpolateOrigin_Reset();
                }
 
-               if(f & 0x20)
+               if (f & 0x20)
                {
                        self.fade_time = time + ReadByte() * ticrate;
                        self.fade_rate = 1 / (ReadByte() * ticrate);
@@ -268,11 +270,8 @@ void Ent_Projectile()
                self.team = ReadByte() - 1;
        }
 
-       if(f & 2)
+       if (f & 2)
        {
-               string rm_suffix = strcat("rocketminsta_laser_", Static_Team_ColorName_Lower(self.team));
-               if(_particleeffectnum(rm_suffix) < 0 || Team_TeamToNumber(self.team) == -1) { rm_suffix = "TR_NEXUIZPLASMA"; }
-
                self.cnt = ReadByte();
 
                self.silent = (self.cnt & 0x80);
@@ -280,58 +279,52 @@ void Ent_Projectile()
 
                self.scale = 1;
                self.traileffect = 0;
-               switch(self.cnt)
+               switch (self.cnt)
                {
-                       case PROJECTILE_ELECTRO: setmodel(self, "models/ebomb.mdl");self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
-                       case PROJECTILE_ROCKET: setmodel(self, "models/rocket.md3");self.traileffect = particleeffectnum(EFFECT_TR_ROCKET); self.scale = 2; break;
-                       case PROJECTILE_CRYLINK: setmodel(self, "models/plasmatrail.mdl");self.traileffect = particleeffectnum(EFFECT_TR_CRYLINKPLASMA); break;
-                       case PROJECTILE_CRYLINK_BOUNCING: setmodel(self, "models/plasmatrail.mdl");self.traileffect = particleeffectnum(EFFECT_TR_CRYLINKPLASMA); break;
-                       case PROJECTILE_ELECTRO_BEAM: setmodel(self, "models/elaser.mdl");self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
-                       case PROJECTILE_GRENADE: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum(EFFECT_TR_GRENADE); break;
-                       case PROJECTILE_GRENADE_BOUNCING: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum(EFFECT_TR_GRENADE); break;
-                       case PROJECTILE_MINE: setmodel(self, "models/mine.md3");self.traileffect = particleeffectnum(EFFECT_TR_GRENADE); break;
-                       case PROJECTILE_BLASTER: setmodel(self, "models/laser.mdl");self.traileffect = particleeffectnum(EFFECT_NULL); break;
-                       case PROJECTILE_HLAC: setmodel(self, "models/hlac_bullet.md3");self.traileffect = particleeffectnum(EFFECT_NULL); break;
-                       case PROJECTILE_PORTO_RED: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum(EFFECT_TR_WIZSPIKE); self.scale = 4; break;
-                       case PROJECTILE_PORTO_BLUE: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum(EFFECT_TR_WIZSPIKE); self.scale = 4; break;
-                       case PROJECTILE_HOOKBOMB: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum(EFFECT_TR_KNIGHTSPIKE); break;
-                       case PROJECTILE_HAGAR: setmodel(self, "models/hagarmissile.mdl");self.traileffect = particleeffectnum(EFFECT_HAGAR_ROCKET); self.scale = 0.75; break;
-                       case PROJECTILE_HAGAR_BOUNCING: setmodel(self, "models/hagarmissile.mdl");self.traileffect = particleeffectnum(EFFECT_HAGAR_ROCKET); self.scale = 0.75; break;
-                       case PROJECTILE_NAPALM_FOUNTAIN: //self.model = ""; self.modelindex = 0; self.traileffect = _particleeffectnum("torch_small"); break;
-                       case PROJECTILE_FIREBALL: self.model = ""; self.modelindex = 0; self.traileffect = particleeffectnum(EFFECT_FIREBALL); break; // particle effect is good enough
-                       case PROJECTILE_FIREMINE: self.model = ""; self.modelindex = 0; self.traileffect = particleeffectnum(EFFECT_FIREMINE); break; // particle effect is good enough
-                       case PROJECTILE_TAG: setmodel(self, "models/laser.mdl"); self.traileffect = particleeffectnum(EFFECT_TR_ROCKET); break;
-                       case PROJECTILE_FLAC: setmodel(self, "models/hagarmissile.mdl"); self.scale = 0.4; self.traileffect = particleeffectnum(EFFECT_FLAC_TRAIL); break;
-                       case PROJECTILE_SEEKER: setmodel(self, "models/tagrocket.md3"); self.traileffect = particleeffectnum(EFFECT_SEEKER_TRAIL); break;
-
-                       case PROJECTILE_MAGE_SPIKE: setmodel(self, "models/ebomb.mdl"); self.traileffect = particleeffectnum(EFFECT_TR_VORESPIKE); break;
-                       case PROJECTILE_SHAMBLER_LIGHTNING: setmodel(self, "models/ebomb.mdl"); self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
-
-                       case PROJECTILE_RAPTORBOMB:    setmodel(self, "models/vehicles/clusterbomb.md3"); self.gravity = 1; self.avelocity = '0 0 180'; self.traileffect = particleeffectnum(EFFECT_NULL); break;
-                       case PROJECTILE_RAPTORBOMBLET: setmodel(self, "models/vehicles/bomblet.md3");     self.gravity = 1; self.avelocity = '0 0 180'; self.traileffect = particleeffectnum(EFFECT_NULL); break;
-                       case PROJECTILE_RAPTORCANNON:  setmodel(self, "models/plasmatrail.mdl"); self.traileffect = particleeffectnum(EFFECT_TR_CRYLINKPLASMA); break;
-
-                       case PROJECTILE_SPIDERROCKET: setmodel(self, "models/vehicles/rocket02.md3"); self.traileffect = particleeffectnum(EFFECT_SPIDERBOT_ROCKET_TRAIL); break;
-                       case PROJECTILE_WAKIROCKET:   setmodel(self, "models/vehicles/rocket01.md3");  self.traileffect = particleeffectnum(EFFECT_RACER_ROCKET_TRAIL); break;
-                       case PROJECTILE_WAKICANNON:   setmodel(self, "models/laser.mdl");  self.traileffect = particleeffectnum(EFFECT_NULL); break;
-
-                       case PROJECTILE_BUMBLE_GUN: setmodel(self, "models/elaser.mdl");self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
-                       case PROJECTILE_BUMBLE_BEAM: setmodel(self, "models/elaser.mdl");self.traileffect = particleeffectnum(EFFECT_TR_NEXUIZPLASMA); break;
-
-                       case PROJECTILE_RPC: setmodel(self, W_Model("ok_rocket"));self.traileffect = particleeffectnum(EFFECT_TR_ROCKET); break;
-
-                       case PROJECTILE_ROCKETMINSTA_LASER: setmodel(self, "models/elaser.mdl");self.traileffect = _particleeffectnum(rm_suffix); break;
-
+                       #define HANDLE(id) case PROJECTILE_##id: setmodel(self, MDL_PROJECTILE_##id);
+                       HANDLE(ELECTRO)            self.traileffect = EFFECT_TR_NEXUIZPLASMA.m_id; break;
+                       HANDLE(ROCKET)             self.traileffect = EFFECT_TR_ROCKET.m_id; self.scale = 2; break;
+                       HANDLE(CRYLINK)            self.traileffect = EFFECT_TR_CRYLINKPLASMA.m_id; break;
+                       HANDLE(CRYLINK_BOUNCING)   self.traileffect = EFFECT_TR_CRYLINKPLASMA.m_id; break;
+                       HANDLE(ELECTRO_BEAM)       self.traileffect = EFFECT_TR_NEXUIZPLASMA.m_id; break;
+                       HANDLE(GRENADE)            self.traileffect = EFFECT_TR_GRENADE.m_id; break;
+                       HANDLE(GRENADE_BOUNCING)   self.traileffect = EFFECT_TR_GRENADE.m_id; break;
+                       HANDLE(MINE)               self.traileffect = EFFECT_TR_GRENADE.m_id; break;
+                       HANDLE(BLASTER)            self.traileffect = EFFECT_Null.m_id; break;
+                       HANDLE(HLAC)               self.traileffect = EFFECT_Null.m_id; break;
+                       HANDLE(PORTO_RED)          self.traileffect = EFFECT_TR_WIZSPIKE.m_id; self.scale = 4; break;
+                       HANDLE(PORTO_BLUE)         self.traileffect = EFFECT_TR_WIZSPIKE.m_id; self.scale = 4; break;
+                       HANDLE(HOOKBOMB)           self.traileffect = EFFECT_TR_KNIGHTSPIKE.m_id; break;
+                       HANDLE(HAGAR)              self.traileffect = EFFECT_HAGAR_ROCKET.m_id; self.scale = 0.75; break;
+                       HANDLE(HAGAR_BOUNCING)     self.traileffect = EFFECT_HAGAR_ROCKET.m_id; self.scale = 0.75; break;
+                       HANDLE(FIREBALL)           self.modelindex = 0; self.traileffect = EFFECT_FIREBALL.m_id; break; // particle effect is good enough
+                       HANDLE(FIREMINE)           self.modelindex = 0; self.traileffect = EFFECT_FIREMINE.m_id; break; // particle effect is good enough
+                       HANDLE(TAG)                self.traileffect = EFFECT_TR_ROCKET.m_id; break;
+                       HANDLE(FLAC)               self.scale = 0.4; self.traileffect = EFFECT_FLAC_TRAIL.m_id; break;
+                       HANDLE(SEEKER)             self.traileffect = EFFECT_SEEKER_TRAIL.m_id; break;
+
+                       HANDLE(MAGE_SPIKE)         self.traileffect = EFFECT_TR_VORESPIKE.m_id; break;
+                       HANDLE(SHAMBLER_LIGHTNING) self.traileffect = EFFECT_TR_NEXUIZPLASMA.m_id; break;
+
+                       HANDLE(RAPTORBOMB)         self.gravity = 1; self.avelocity = '0 0 180'; self.traileffect = EFFECT_Null.m_id; break;
+                       HANDLE(RAPTORBOMBLET)      self.gravity = 1; self.avelocity = '0 0 180'; self.traileffect = EFFECT_Null.m_id; break;
+                       HANDLE(RAPTORCANNON)       self.traileffect = EFFECT_TR_CRYLINKPLASMA.m_id; break;
+
+                       HANDLE(SPIDERROCKET)       self.traileffect = EFFECT_SPIDERBOT_ROCKET_TRAIL.m_id; break;
+                       HANDLE(WAKIROCKET)         self.traileffect = EFFECT_RACER_ROCKET_TRAIL.m_id; break;
+                       HANDLE(WAKICANNON)         self.traileffect = EFFECT_Null.m_id; break;
+
+                       HANDLE(BUMBLE_GUN)         self.traileffect = EFFECT_TR_NEXUIZPLASMA.m_id; break;
+                       HANDLE(BUMBLE_BEAM)        self.traileffect = EFFECT_TR_NEXUIZPLASMA.m_id; break;
+
+                       HANDLE(RPC)                self.traileffect = EFFECT_TR_ROCKET.m_id; break;
+
+                       HANDLE(ROCKETMINSTA_LASER) self.traileffect = EFFECT_ROCKETMINSTA_LASER(self.team).m_id; break;
+#undef HANDLE
                        default:
-                               if(MUTATOR_CALLHOOK(Ent_Projectile, self))
+                               if (MUTATOR_CALLHOOK(Ent_Projectile, self))
                                        break;
 
-                               if (Nade_FromProjectile(self.cnt) != NADE_TYPE_NULL)
-                               {
-                                       setmodel(self, W_Model("v_ok_grenade.md3"));
-                                       self.traileffect = _particleeffectnum(Nade_TrailEffect(self.cnt, self.team));
-                                       break;
-                               }
                                error("Received invalid CSQC projectile, can't work with this!");
                                break;
                }
@@ -343,21 +336,21 @@ void Ent_Projectile()
                self.move_movetype = MOVETYPE_TOSS;
                self.alphamod = 1;
 
-               switch(self.cnt)
+               switch (self.cnt)
                {
                        case PROJECTILE_ELECTRO:
                                // only new engines support sound moving with object
-                               loopsound(self, CH_SHOTS_SINGLE, W_Sound("electro_fly"), VOL_BASE, ATTEN_NORM);
+                               loopsound(self, CH_SHOTS_SINGLE, SND(ELECTRO_FLY), VOL_BASE, ATTEN_NORM);
                                self.mins = '0 0 -4';
                                self.maxs = '0 0 -4';
                                self.move_movetype = MOVETYPE_BOUNCE;
                                self.move_touch = func_null;
-                               self.move_bounce_factor = g_balance_electro_secondary_bouncefactor;
-                               self.move_bounce_stopspeed = g_balance_electro_secondary_bouncestop;
+                               self.move_bounce_factor = WEP_CVAR_SEC(electro, bouncefactor);
+                               self.move_bounce_stopspeed = WEP_CVAR_SEC(electro, bouncestop);
                                break;
                        case PROJECTILE_RPC:
                        case PROJECTILE_ROCKET:
-                               loopsound(self, CH_SHOTS_SINGLE, W_Sound("rocket_fly"), VOL_BASE, ATTEN_NORM);
+                               loopsound(self, CH_SHOTS_SINGLE, SND(ROCKET_FLY), VOL_BASE, ATTEN_NORM);
                                self.mins = '-3 -3 -3';
                                self.maxs = '3 3 3';
                                break;
@@ -370,8 +363,8 @@ void Ent_Projectile()
                                self.maxs = '3 3 3';
                                self.move_movetype = MOVETYPE_BOUNCE;
                                self.move_touch = func_null;
-                               self.move_bounce_factor = g_balance_mortar_bouncefactor;
-                               self.move_bounce_stopspeed = g_balance_mortar_bouncestop;
+                               self.move_bounce_factor = WEP_CVAR(mortar, bouncefactor);
+                               self.move_bounce_stopspeed = WEP_CVAR(mortar, bouncestop);
                                break;
                        case PROJECTILE_SHAMBLER_LIGHTNING:
                                self.mins = '-8 -8 -8';
@@ -403,14 +396,13 @@ void Ent_Projectile()
                                self.move_movetype = MOVETYPE_BOUNCE;
                                self.move_touch = func_null;
                                break;
-                       case PROJECTILE_NAPALM_FOUNTAIN:
                        case PROJECTILE_FIREBALL:
-                               loopsound(self, CH_SHOTS_SINGLE, W_Sound("fireball_fly2"), VOL_BASE, ATTEN_NORM);
+                               loopsound(self, CH_SHOTS_SINGLE, SND(FIREBALL_FLY2), VOL_BASE, ATTEN_NORM);
                                self.mins = '-16 -16 -16';
                                self.maxs = '16 16 16';
                                break;
                        case PROJECTILE_FIREMINE:
-                               loopsound(self, CH_SHOTS_SINGLE, W_Sound("fireball_fly"), VOL_BASE, ATTEN_NORM);
+                               loopsound(self, CH_SHOTS_SINGLE, SND(FIREBALL_FLY), VOL_BASE, ATTEN_NORM);
                                self.move_movetype = MOVETYPE_BOUNCE;
                                self.move_touch = func_null;
                                self.mins = '-4 -4 -4';
@@ -425,110 +417,73 @@ void Ent_Projectile()
                                self.maxs = '2 2 2';
                                break;
                        case PROJECTILE_SEEKER:
-                               loopsound(self, CH_SHOTS_SINGLE, W_Sound("tag_rocket_fly"), VOL_BASE, ATTEN_NORM);
+                               loopsound(self, CH_SHOTS_SINGLE, SND(TAG_ROCKET_FLY), VOL_BASE, ATTEN_NORM);
                                self.mins = '-4 -4 -4';
                                self.maxs = '4 4 4';
                                break;
-            case PROJECTILE_RAPTORBOMB:
+                       case PROJECTILE_RAPTORBOMB:
                                self.mins = '-3 -3 -3';
                                self.maxs = '3 3 3';
                                break;
-            case PROJECTILE_RAPTORBOMBLET:
+                       case PROJECTILE_RAPTORBOMBLET:
                                break;
-            case PROJECTILE_RAPTORCANNON:
+                       case PROJECTILE_RAPTORCANNON:
                                break;
-            case PROJECTILE_SPIDERROCKET:
-                loopsound(self, CH_SHOTS_SINGLE, W_Sound("tag_rocket_fly"), VOL_BASE, ATTEN_NORM);
+                       case PROJECTILE_SPIDERROCKET:
+                               loopsound(self, CH_SHOTS_SINGLE, SND(TAG_ROCKET_FLY), VOL_BASE, ATTEN_NORM);
                                break;
-            case PROJECTILE_WAKIROCKET:
-                loopsound(self, CH_SHOTS_SINGLE, W_Sound("tag_rocket_fly"), VOL_BASE, ATTEN_NORM);
-                               break;
-            /*
-            case PROJECTILE_WAKICANNON:
+                       case PROJECTILE_WAKIROCKET:
+                               loopsound(self, CH_SHOTS_SINGLE, SND(TAG_ROCKET_FLY), VOL_BASE, ATTEN_NORM);
                                break;
+                       /*
+                       case PROJECTILE_WAKICANNON:
+                           break;
                        case PROJECTILE_BUMBLE_GUN:
-                               // only new engines support sound moving with object
-                               loopsound(self, CH_SHOTS_SINGLE, W_Sound("electro_fly"), VOL_BASE, ATTEN_NORM);
-                               self.mins = '0 0 -4';
-                               self.maxs = '0 0 -4';
-                               self.move_movetype = MOVETYPE_BOUNCE;
-                               self.move_touch = func_null;
-                               self.move_bounce_factor = g_balance_electro_secondary_bouncefactor;
-                               self.move_bounce_stopspeed = g_balance_electro_secondary_bouncestop;
-                               break;
+                           // only new engines support sound moving with object
+                           loopsound(self, CH_SHOTS_SINGLE, SND(ELECTRO_FLY), VOL_BASE, ATTEN_NORM);
+                           self.mins = '0 0 -4';
+                           self.maxs = '0 0 -4';
+                           self.move_movetype = MOVETYPE_BOUNCE;
+                           self.move_touch = func_null;
+                           self.move_bounce_factor = WEP_CVAR_SEC(electro, bouncefactor);
+                           self.move_bounce_stopspeed = WEP_CVAR_SEC(electro, bouncestop);
+                           break;
                        */
                        default:
                                break;
                }
 
-               if(Nade_FromProjectile(self.cnt) != NADE_TYPE_NULL)
-               {
-                       entity nade_type = Nade_FromProjectile(self.cnt);
-                       self.mins = '-16 -16 -16';
-                       self.maxs = '16 16 16';
-                       self.colormod = nade_type.m_color;
-                       self.move_movetype = MOVETYPE_BOUNCE;
-                       self.move_touch = func_null;
-                       self.scale = 1.5;
-                       self.avelocity = randomvec() * 720;
-
-                       if(nade_type == NADE_TYPE_TRANSLOCATE || nade_type == NADE_TYPE_SPAWN)
-                               self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
-                       else
-                               self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
-               }
-
                MUTATOR_CALLHOOK(EditProjectile, self);
 
                setsize(self, self.mins, self.maxs);
        }
 
-       if(self.gravity)
+       return = true;
+
+       if (self.gravity)
        {
-               if(self.move_movetype == MOVETYPE_FLY)
+               if (self.move_movetype == MOVETYPE_FLY)
                        self.move_movetype = MOVETYPE_TOSS;
-               if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
+               if (self.move_movetype == MOVETYPE_BOUNCEMISSILE)
                        self.move_movetype = MOVETYPE_BOUNCE;
        }
        else
        {
-               if(self.move_movetype == MOVETYPE_TOSS)
+               if (self.move_movetype == MOVETYPE_TOSS)
                        self.move_movetype = MOVETYPE_FLY;
-               if(self.move_movetype == MOVETYPE_BOUNCE)
+               if (self.move_movetype == MOVETYPE_BOUNCE)
                        self.move_movetype = MOVETYPE_BOUNCEMISSILE;
        }
 
-       if(!(self.count & 0x80))
-               InterpolateOrigin_Note();
+       if (!(self.count & 0x80))
+               InterpolateOrigin_Note(this);
 
        self.classname = "csqcprojectile";
        self.draw = Projectile_Draw;
        self.entremove = Ent_RemoveProjectile;
 }
 
-void Projectile_Precache()
+PRECACHE(Projectiles)
 {
-       precache_model("models/ebomb.mdl");
-       precache_model("models/elaser.mdl");
-       precache_model("models/grenademodel.md3");
-       precache_model("models/mine.md3");
-       precache_model("models/hagarmissile.mdl");
-       precache_model("models/hlac_bullet.md3");
-       precache_model("models/laser.mdl");
-       precache_model("models/plasmatrail.mdl");
-       precache_model("models/rocket.md3");
-       precache_model("models/tagrocket.md3");
-       precache_model("models/tracer.mdl");
-       precache_model("models/sphere/sphere.md3");
-
-       precache_model(W_Model("v_ok_grenade.md3"));
-       precache_model(W_Model("ok_rocket.md3"));
-
-       precache_sound(W_Sound("electro_fly"));
-       precache_sound(W_Sound("rocket_fly"));
-       precache_sound(W_Sound("fireball_fly"));
-       precache_sound(W_Sound("fireball_fly2"));
-       precache_sound(W_Sound("tag_rocket_fly"));
-
        MUTATOR_CALLHOOK(PrecacheProjectiles);
 }