]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/cl_weaponsystem.qc
More documentation and some minor changes for drag code
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / cl_weaponsystem.qc
index 3d7a33278d15201ce89b789f1a03f9441e0d0be8..4acb8da891fa4fa4158b5ef01b7026a176cced5e 100644 (file)
@@ -34,10 +34,6 @@ float W_WeaponRateFactor()
 
 void W_SwitchWeapon_Force(entity e, float w)
 {
-       // don't switch to another weapon if we're not allowed to
-       if(e.weapon_forbidchange)
-               return;
-
        e.cnt = e.switchweapon;
        e.switchweapon = w;
        e.selectweapon = w;
@@ -131,15 +127,28 @@ vector w_shotorg;
 vector w_shotdir;
 vector w_shotend;
 
+.float prevstrengthsound;
+.float prevstrengthsoundattempt;
+void W_PlayStrengthSound(entity player) // void W_PlayStrengthSound
+{
+               if((!g_minstagib)
+                       && (player.items & IT_STRENGTH)
+                       && ((time > player.prevstrengthsound + autocvar_sv_strengthsound_antispam_time) // prevent insane sound spam
+                       || (time > player.prevstrengthsoundattempt + autocvar_sv_strengthsound_antispam_refire_threshold)))
+               {
+                       sound(player, CH_TRIGGER, "weapons/strength_fire.wav", VOL_BASE, ATTN_NORM);
+                       player.prevstrengthsound = time;
+               }
+               player.prevstrengthsoundattempt = time;
+}
+
 // this function calculates w_shotorg and w_shotdir based on the weapon model
 // offset, trueaim and antilag, and won't put w_shotorg inside a wall.
 // make sure you call makevectors first (FIXME?)
-.float prevstrengthsound;
-.float prevstrengthsoundattempt;
 void W_SetupShot_Dir_ProjectileSize_Range(entity ent, vector s_forward, vector mi, vector ma, float antilag, float recoil, string snd, float chan, float maxdamage, float range)
 {
        float nudge = 1; // added to traceline target and subtracted from result
-       local float oldsolid;
+       float oldsolid;
        vector vecs, dv;
        oldsolid = ent.dphitcontentsmask;
        if(ent.weapon == WEP_RIFLE)
@@ -245,24 +254,14 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, vector s_forward, vector m
                ent.punchangle_x = recoil * -1;
 
        if (snd != "")
-               sound (ent, chan, snd, VOL_BASE, ATTN_NORM);
-
-       if(ent.items & IT_STRENGTH)
-       if(!g_minstagib)
-       if(
-               (time > ent.prevstrengthsound + autocvar_sv_strengthsound_antispam_time)
-               ||
-               (time > ent.prevstrengthsoundattempt + autocvar_sv_strengthsound_antispam_refire_threshold)
-       ) // prevent insane sound spam
        {
-               sound(ent, CH_TRIGGER, "weapons/strength_fire.wav", VOL_BASE, ATTN_NORM);
-               ent.prevstrengthsound = time;
+               sound (ent, chan, snd, VOL_BASE, ATTN_NORM);
+               W_PlayStrengthSound(ent);
        }
-       ent.prevstrengthsoundattempt = time;
 
        // nudge w_shotend so a trace to w_shotend hits
        w_shotend = w_shotend + normalize(w_shotend - w_shotorg) * nudge;
-};
+}
 
 #define W_SetupShot_Dir_ProjectileSize(ent,s_forward,mi,ma,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize_Range(ent, s_forward, mi, ma, antilag, recoil, snd, chan, maxdamage, MAX_SHOT_DISTANCE)
 #define W_SetupShot_ProjectileSize(ent,mi,ma,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize(ent, v_forward, mi, ma, antilag, recoil, snd, chan, maxdamage)
@@ -279,27 +278,6 @@ float CL_Weaponentity_CustomizeEntityForClient()
        return TRUE;
 }
 
-float qcweaponanimation;
-vector weapon_offset = '0 -10 0';
-vector weapon_adjust = '10 0 -15';
-.vector weapon_morph0origin;
-.vector weapon_morph0angles;
-.float  weapon_morph0time;
-.vector weapon_morph1origin;
-.vector weapon_morph1angles;
-.float  weapon_morph1time;
-.vector weapon_morph2origin;
-.vector weapon_morph2angles;
-.float  weapon_morph2time;
-.vector weapon_morph3origin;
-.vector weapon_morph3angles;
-.float  weapon_morph3time;
-.vector weapon_morph4origin;
-.vector weapon_morph4angles;
-.float  weapon_morph4time;
-.string weaponname;
-#define QCWEAPONANIMATION_ORIGIN(e) ((weapon_offset_x + e.view_ofs_x) * v_forward - (weapon_offset_y + e.view_ofs_y) * v_right + (weapon_offset_z + e.view_ofs_z) * v_up + weapon_adjust)
-
 /*
  * supported formats:
  *
@@ -353,8 +331,6 @@ vector weapon_adjust = '10 0 -15';
 //   remove the ent
 void CL_WeaponEntity_SetModel(string name)
 {
-       string animfilename;
-       float animfile;
        float v_shot_idx;
        if (name != "")
        {
@@ -366,140 +342,115 @@ void CL_WeaponEntity_SetModel(string name)
                if(!v_shot_idx)
                        v_shot_idx = gettagindex(self, "tag_shot");
 
-               if(qcweaponanimation)
+               setmodel(self, strcat("models/weapons/h_", name, ".iqm")); // precision set below
+               // preset some defaults that work great for renamed zym files (which don't need an animinfo)
+               self.anim_fire1  = animfixfps(self, '0 1 0.01');
+               self.anim_fire2  = animfixfps(self, '1 1 0.01');
+               self.anim_idle   = animfixfps(self, '2 1 0.01');
+               self.anim_reload = animfixfps(self, '3 1 0.01');
+
+               // if we have a "weapon" tag, let's attach the v_ model to it ("invisible hand" style model)
+               // if we don't, this is a "real" animated model
+               if(gettagindex(self, "weapon"))
+               {
+                       if (!self.weaponentity)
+                               self.weaponentity = spawn();
+                       setmodel(self.weaponentity, strcat("models/weapons/v_", name, ".md3")); // precision does not matter
+                       setattachment(self.weaponentity, self, "weapon");
+               }
+               else if(gettagindex(self, "tag_weapon"))
                {
-                       self.angles = '0 0 0';
-                       makevectors(self.angles_x * '-1 0 0' + self.angles_y * '0 1 0' + self.angles_z * '0 0 1');
-                       self.movedir = weapon_offset_x * v_forward - weapon_offset_y * v_right + weapon_offset_z * v_up + weapon_adjust;
-                       self.movedir_x += 32;
-                       self.spawnorigin = self.movedir;
-                       // oldorigin - not calculated here
+                       if (!self.weaponentity)
+                               self.weaponentity = spawn();
+                       setmodel(self.weaponentity, strcat("models/weapons/v_", name, ".md3")); // precision does not matter
+                       setattachment(self.weaponentity, self, "tag_weapon");
                }
                else
                {
-                       setmodel(self, strcat("models/weapons/h_", name, ".iqm")); // precision set below
-                       animfilename = strcat("models/weapons/h_", name, ".iqm.animinfo");
-                       animfile = fopen(animfilename, FILE_READ);
-                       // preset some defaults that work great for renamed zym files (which don't need an animinfo)
-                       self.anim_fire1  = '0 1 0.01';
-                       self.anim_fire2  = '1 1 0.01';
-                       self.anim_idle   = '2 1 0.01';
-                       self.anim_reload = '3 1 0.01';
-                       if (animfile >= 0)
-                       {
-                               animparseerror = FALSE;
-                               self.anim_fire1  = animparseline(animfile);
-                               self.anim_fire2  = animparseline(animfile);
-                               self.anim_idle   = animparseline(animfile);
-                               self.anim_reload = animparseline(animfile);
-                               fclose(animfile);
-                               if (animparseerror)
-                                       print("Parse error in ", animfilename, ", some player animations are broken\n");
-                       }
-
-                       // if we have a "weapon" tag, let's attach the v_ model to it ("invisible hand" style model)
-                       // if we don't, this is a "real" animated model
-                       if(gettagindex(self, "weapon"))
-                       {
-                               if (!self.weaponentity)
-                                       self.weaponentity = spawn();
-                               setmodel(self.weaponentity, strcat("models/weapons/v_", name, ".md3")); // precision does not matter
-                               setattachment(self.weaponentity, self, "weapon");
-                       }
-                       else if(gettagindex(self, "tag_weapon"))
-                       {
-                               if (!self.weaponentity)
-                                       self.weaponentity = spawn();
-                               setmodel(self.weaponentity, strcat("models/weapons/v_", name, ".md3")); // precision does not matter
-                               setattachment(self.weaponentity, self, "tag_weapon");
-                       }
-                       else
-                       {
-                               if(self.weaponentity)
-                                       remove(self.weaponentity);
-                               self.weaponentity = world;
-                       }
+                       if(self.weaponentity)
+                               remove(self.weaponentity);
+                       self.weaponentity = world;
+               }
 
-                       setorigin(self,'0 0 0');
-                       self.angles = '0 0 0';
-                       self.frame = 0;
-                       self.viewmodelforclient = world;
+               setorigin(self,'0 0 0');
+               self.angles = '0 0 0';
+               self.frame = 0;
+               self.viewmodelforclient = world;
 
-                       float idx;
+               float idx;
 
-                       if(v_shot_idx) // v_ model attached to invisible h_ model
+               if(v_shot_idx) // v_ model attached to invisible h_ model
+               {
+                       self.movedir = gettaginfo(self.weaponentity, v_shot_idx);
+               }
+               else
+               {
+                       idx = gettagindex(self, "shot");
+                       if(!idx)
+                               idx = gettagindex(self, "tag_shot");
+                       if(idx)
+                               self.movedir = gettaginfo(self, idx);
+                       else
                        {
-                               self.movedir = gettaginfo(self.weaponentity, v_shot_idx);
+                               print("WARNING: weapon model ", self.model, " does not support the 'shot' tag, will display shots TOTALLY wrong\n");
+                               self.movedir = '0 0 0';
                        }
+               }
+
+               if(self.weaponentity) // v_ model attached to invisible h_ model
+               {
+                       idx = gettagindex(self.weaponentity, "shell");
+                       if(!idx)
+                               idx = gettagindex(self.weaponentity, "tag_shell");
+                       if(idx)
+                               self.spawnorigin = gettaginfo(self.weaponentity, idx);
+               }
+               else
+                       idx = 0;
+               if(!idx)
+               {
+                       idx = gettagindex(self, "shell");
+                       if(!idx)
+                               idx = gettagindex(self, "tag_shell");
+                       if(idx)
+                               self.spawnorigin = gettaginfo(self, idx);
                        else
                        {
-                               idx = gettagindex(self, "shot");
-                               if(!idx)
-                                       idx = gettagindex(self, "tag_shot");
-                               if(idx)
-                                       self.movedir = gettaginfo(self, idx);
-                               else
-                               {
-                                       print("WARNING: weapon model ", self.model, " does not support the 'shot' tag, will display shots TOTALLY wrong\n");
-                                       self.movedir = '0 0 0';
-                               }
+                               print("WARNING: weapon model ", self.model, " does not support the 'shell' tag, will display casings wrong\n");
+                               self.spawnorigin = self.movedir;
                        }
+               }
 
-                       if(self.weaponentity) // v_ model attached to invisible h_ model
+               if(v_shot_idx)
+               {
+                       self.oldorigin = '0 0 0'; // use regular attachment
+               }
+               else
+               {
+                       if(self.weaponentity)
                        {
-                               idx = gettagindex(self.weaponentity, "shell");
+                               idx = gettagindex(self, "weapon");
                                if(!idx)
-                                       idx = gettagindex(self.weaponentity, "tag_shell");
-                               if(idx)
-                                       self.spawnorigin = gettaginfo(self.weaponentity, idx);
+                                       idx = gettagindex(self, "tag_weapon");
                        }
                        else
-                               idx = 0;
-                       if(!idx)
                        {
-                               idx = gettagindex(self, "shell");
+                               idx = gettagindex(self, "handle");
                                if(!idx)
-                                       idx = gettagindex(self, "tag_shell");
-                               if(idx)
-                                       self.spawnorigin = gettaginfo(self, idx);
-                               else
-                               {
-                                       print("WARNING: weapon model ", self.model, " does not support the 'shell' tag, will display casings wrong\n");
-                                       self.spawnorigin = self.movedir;
-                               }
+                                       idx = gettagindex(self, "tag_handle");
                        }
-
-                       if(v_shot_idx)
+                       if(idx)
                        {
-                               self.oldorigin = '0 0 0'; // use regular attachment
+                               self.oldorigin = self.movedir - gettaginfo(self, idx);
                        }
                        else
                        {
-                               if(self.weaponentity)
-                               {
-                                       idx = gettagindex(self, "weapon");
-                                       if(!idx)
-                                               idx = gettagindex(self, "tag_weapon");
-                               }
-                               else
-                               {
-                                       idx = gettagindex(self, "handle");
-                                       if(!idx)
-                                               idx = gettagindex(self, "tag_handle");
-                               }
-                               if(idx)
-                               {
-                                       self.oldorigin = self.movedir - gettaginfo(self, idx);
-                               }
-                               else
-                               {
-                                       print("WARNING: weapon model ", self.model, " does not support the 'handle' tag and neither does the v_ model support the 'shot' tag, will display muzzle flashes TOTALLY wrong\n");
-                                       self.oldorigin = '0 0 0'; // there is no way to recover from this
-                               }
+                               print("WARNING: weapon model ", self.model, " does not support the 'handle' tag and neither does the v_ model support the 'shot' tag, will display muzzle flashes TOTALLY wrong\n");
+                               self.oldorigin = '0 0 0'; // there is no way to recover from this
                        }
-
-                       self.viewmodelforclient = self.owner;
                }
+
+               self.viewmodelforclient = self.owner;
        }
        else
        {
@@ -531,24 +482,9 @@ void CL_WeaponEntity_SetModel(string name)
        self.spawnorigin += self.view_ofs; // offset the casings origin by the same amount
 
        // check if an instant weapon switch occurred
-       if (qcweaponanimation)
-       {
-               if (self.state == WS_READY)
-               {
-                       self.angles = '0 0 0';
-                       makevectors(self.angles_x * '-1 0 0' + self.angles_y * '0 1 0' + self.angles_z * '0 0 1');
-                       setorigin(self, QCWEAPONANIMATION_ORIGIN(self));
-               }
-       }
-       else
-               setorigin(self, self.view_ofs);
+       setorigin(self, self.view_ofs);
        // reset animstate now
        self.wframe = WFRAME_IDLE;
-       self.weapon_morph0time = 0;
-       self.weapon_morph1time = 0;
-       self.weapon_morph2time = 0;
-       self.weapon_morph3time = 0;
-       self.weapon_morph4time = 0;
        setanim(self, self.anim_idle, TRUE, FALSE, TRUE);
 }
 
@@ -587,9 +523,9 @@ void CL_Weaponentity_Think()
                        self.weaponentity.model = "";
                return;
        }
-       if (self.cnt != self.owner.weapon || self.dmg != self.owner.modelindex || self.deadflag != self.owner.deadflag)
+       if (self.weaponname != self.owner.weaponname || self.dmg != self.owner.modelindex || self.deadflag != self.owner.deadflag)
        {
-               self.cnt = self.owner.weapon;
+               self.weaponname = self.owner.weaponname;
                self.dmg = self.owner.modelindex;
                self.deadflag = self.owner.deadflag;
 
@@ -622,161 +558,24 @@ void CL_Weaponentity_Think()
        }
 
        self.angles = '0 0 0';
-       local float f;
+       float f;
        f = 0;
        if (self.state == WS_RAISE && !intermission_running)
        {
                f = (self.owner.weapon_nextthink - time) * g_weaponratefactor / autocvar_g_balance_weaponswitchdelay;
                self.angles_x = -90 * f * f;
-               if (qcweaponanimation)
-               {
-                       makevectors(self.angles_x * '-1 0 0' + self.angles_y * '0 1 0' + self.angles_z * '0 0 1');
-                       setorigin(self, QCWEAPONANIMATION_ORIGIN(self));
-               }
        }
        else if (self.state == WS_DROP && !intermission_running)
        {
                f = 1 - (self.owner.weapon_nextthink - time) * g_weaponratefactor / autocvar_g_balance_weaponswitchdelay;
                self.angles_x = -90 * f * f;
-               if (qcweaponanimation)
-               {
-                       makevectors(self.angles_x * '-1 0 0' + self.angles_y * '0 1 0' + self.angles_z * '0 0 1');
-                       setorigin(self, QCWEAPONANIMATION_ORIGIN(self));
-               }
        }
        else if (self.state == WS_CLEAR)
        {
                f = 1;
                self.angles_x = -90 * f * f;
-               if (qcweaponanimation)
-               {
-                       makevectors(self.angles_x * '-1 0 0' + self.angles_y * '0 1 0' + self.angles_z * '0 0 1');
-                       setorigin(self, QCWEAPONANIMATION_ORIGIN(self));
-               }
-       }
-       else if (qcweaponanimation && time < self.owner.weapon_morph1time)
-       {
-               f = (time - self.owner.weapon_morph0time) / (self.owner.weapon_morph1time - self.owner.weapon_morph0time);
-               f = 1 - pow(1 - f, 3);
-               self.angles = self.owner.weapon_morph0angles * (1 - f) + self.owner.weapon_morph1angles * f;
-               setorigin(self, self.owner.weapon_morph0origin * (1 - f) + self.owner.weapon_morph1origin * f);
-       }
-       else if (qcweaponanimation && time < self.owner.weapon_morph2time)
-       {
-               f = (time - self.owner.weapon_morph1time) / (self.owner.weapon_morph2time - self.owner.weapon_morph1time);
-               f = 1 - pow(1 - f, 3);
-               self.angles = self.owner.weapon_morph1angles * (1 - f) + self.owner.weapon_morph2angles * f;
-               setorigin(self, self.owner.weapon_morph1origin * (1 - f) + self.owner.weapon_morph2origin * f);
-       }
-       else if (qcweaponanimation && time < self.owner.weapon_morph3time)
-       {
-               f = (time - self.owner.weapon_morph2time) / (self.owner.weapon_morph3time - self.owner.weapon_morph2time);
-               f = 1 - pow(1 - f, 3);
-               self.angles = self.owner.weapon_morph2angles * (1 - f) + self.owner.weapon_morph3angles * f;
-               setorigin(self, self.owner.weapon_morph2origin * (1 - f) + self.owner.weapon_morph3origin * f);
        }
-       else if (qcweaponanimation && time < self.owner.weapon_morph4time)
-       {
-               f = (time - self.owner.weapon_morph3time) / (self.owner.weapon_morph4time - self.owner.weapon_morph3time);
-               f = 1 - pow(1 - f, 3);
-               self.angles = self.owner.weapon_morph3angles * (1 - f) + self.owner.weapon_morph4angles * f;
-               setorigin(self, self.owner.weapon_morph3origin * (1 - f) + self.owner.weapon_morph4origin * f);
-       }
-       else if (qcweaponanimation)
-       {
-               // begin a new idle morph
-               self.owner.weapon_morph0time   = time;
-               self.owner.weapon_morph0angles = self.angles;
-               self.owner.weapon_morph0origin = self.origin;
-
-               float r;
-               float t;
-
-               r = random();
-               if (r < 0.1)
-               {
-                       // turn gun to the left to look at it
-                       t = 2;
-                       self.owner.weapon_morph1time   = time + t * 0.2;
-                       self.owner.weapon_morph1angles = randomvec() * 3 + '-5 30 0';
-                       makevectors(self.owner.weapon_morph1angles_x * '-1 0 0' + self.owner.weapon_morph1angles_y * '0 1 0' + self.owner.weapon_morph1angles_z * '0 0 1');
-                       self.owner.weapon_morph1origin = QCWEAPONANIMATION_ORIGIN(self);
-
-                       self.owner.weapon_morph2time   = time + t * 0.6;
-                       self.owner.weapon_morph2angles = randomvec() * 3 + '-5 30 0';
-                       makevectors(self.owner.weapon_morph2angles_x * '-1 0 0' + self.owner.weapon_morph2angles_y * '0 1 0' + self.owner.weapon_morph2angles_z * '0 0 1');
-                       self.owner.weapon_morph2origin = QCWEAPONANIMATION_ORIGIN(self);
-
-                       self.owner.weapon_morph3time   = time + t;
-                       self.owner.weapon_morph3angles = '0 0 0';
-                       makevectors(self.owner.weapon_morph3angles_x * '-1 0 0' + self.owner.weapon_morph3angles_y * '0 1 0' + self.owner.weapon_morph3angles_z * '0 0 1');
-                       self.owner.weapon_morph3origin = QCWEAPONANIMATION_ORIGIN(self);
-               }
-               else if (r < 0.2)
-               {
-                       // raise the gun a bit
-                       t = 2;
-                       self.owner.weapon_morph1time   = time + t * 0.2;
-                       self.owner.weapon_morph1angles = randomvec() * 3 + '30 -10 0';
-                       makevectors(self.owner.weapon_morph1angles_x * '-1 0 0' + self.owner.weapon_morph1angles_y * '0 1 0' + self.owner.weapon_morph1angles_z * '0 0 1');
-                       self.owner.weapon_morph1origin = QCWEAPONANIMATION_ORIGIN(self);
-
-                       self.owner.weapon_morph2time   = time + t * 0.5;
-                       self.owner.weapon_morph2angles = randomvec() * 3 + '30 -10 5';
-                       makevectors(self.owner.weapon_morph2angles_x * '-1 0 0' + self.owner.weapon_morph2angles_y * '0 1 0' + self.owner.weapon_morph2angles_z * '0 0 1');
-                       self.owner.weapon_morph2origin = QCWEAPONANIMATION_ORIGIN(self);
-
-                       self.owner.weapon_morph3time   = time + t;
-                       self.owner.weapon_morph3angles = '0 0 0';
-                       makevectors(self.owner.weapon_morph3angles_x * '-1 0 0' + self.owner.weapon_morph3angles_y * '0 1 0' + self.owner.weapon_morph3angles_z * '0 0 1');
-                       self.owner.weapon_morph3origin = QCWEAPONANIMATION_ORIGIN(self);
-               }
-               else if (r < 0.3)
-               {
-                       // tweak it a bit
-                       t = 5;
-                       self.owner.weapon_morph1time   = time + t * 0.3;
-                       self.owner.weapon_morph1angles = randomvec() * 6;
-                       makevectors(self.owner.weapon_morph1angles_x * '-1 0 0' + self.owner.weapon_morph1angles_y * '0 1 0' + self.owner.weapon_morph1angles_z * '0 0 1');
-                       self.owner.weapon_morph1origin = QCWEAPONANIMATION_ORIGIN(self);
-
-                       self.owner.weapon_morph2time   = time + t * 0.7;
-                       self.owner.weapon_morph2angles = randomvec() * 6;
-                       makevectors(self.owner.weapon_morph2angles_x * '-1 0 0' + self.owner.weapon_morph2angles_y * '0 1 0' + self.owner.weapon_morph2angles_z * '0 0 1');
-                       self.owner.weapon_morph2origin = QCWEAPONANIMATION_ORIGIN(self);
-
-                       self.owner.weapon_morph3time   = time + t;
-                       self.owner.weapon_morph3angles = '0 0 0';
-                       makevectors(self.owner.weapon_morph3angles_x * '-1 0 0' + self.owner.weapon_morph3angles_y * '0 1 0' + self.owner.weapon_morph3angles_z * '0 0 1');
-                       self.owner.weapon_morph3origin = QCWEAPONANIMATION_ORIGIN(self);
-               }
-               else
-               {
-                       // hold it mostly steady
-                       t = random() * 6 + 4;
-                       self.owner.weapon_morph1time   = time + t * 0.2;
-                       self.owner.weapon_morph1angles = randomvec() * 1;
-                       makevectors(self.owner.weapon_morph1angles_x * '-1 0 0' + self.owner.weapon_morph1angles_y * '0 1 0' + self.owner.weapon_morph1angles_z * '0 0 1');
-                       self.owner.weapon_morph1origin = QCWEAPONANIMATION_ORIGIN(self);
-
-                       self.owner.weapon_morph2time   = time + t * 0.5;
-                       self.owner.weapon_morph2angles = randomvec() * 1;
-                       makevectors(self.owner.weapon_morph2angles_x * '-1 0 0' + self.owner.weapon_morph2angles_y * '0 1 0' + self.owner.weapon_morph2angles_z * '0 0 1');
-                       self.owner.weapon_morph2origin = QCWEAPONANIMATION_ORIGIN(self);
-
-                       self.owner.weapon_morph3time   = time + t * 0.7;
-                       self.owner.weapon_morph3angles = randomvec() * 1;
-                       makevectors(self.owner.weapon_morph3angles_x * '-1 0 0' + self.owner.weapon_morph3angles_y * '0 1 0' + self.owner.weapon_morph3angles_z * '0 0 1');
-                       self.owner.weapon_morph3origin = QCWEAPONANIMATION_ORIGIN(self);
-               }
-
-               self.owner.weapon_morph4time   = time + t;
-               self.owner.weapon_morph4angles = '0 0 0';
-               makevectors(self.owner.weapon_morph4angles_x * '-1 0 0' + self.owner.weapon_morph4angles_y * '0 1 0' + self.owner.weapon_morph4angles_z * '0 0 1');
-               self.owner.weapon_morph4origin = QCWEAPONANIMATION_ORIGIN(self);
-
-       }
-};
+}
 
 void CL_ExteriorWeaponentity_Think()
 {
@@ -793,9 +592,9 @@ void CL_ExteriorWeaponentity_Think()
                self.model = "";
                return;
        }
-       if (self.cnt != self.owner.weapon || self.dmg != self.owner.modelindex || self.deadflag != self.owner.deadflag)
+       if (self.weaponname != self.owner.weaponname || self.dmg != self.owner.modelindex || self.deadflag != self.owner.deadflag)
        {
-               self.cnt = self.owner.weapon;
+               self.weaponname = self.owner.weaponname;
                self.dmg = self.owner.modelindex;
                self.deadflag = self.owner.deadflag;
                if (self.owner.weaponname != "")
@@ -858,11 +657,31 @@ void CL_ExteriorWeaponentity_Think()
                        ang_x = -/* don't ask */ang_x;
                        self.angles = ang;
                }
+
+               if(autocvar_g_loituma)
+               {
+                       vector modangles;
+                       float t;
+
+                       t = time * autocvar_g_loituma;
+
+                       modangles_x = t * 360;
+                       modangles_y = 90;
+                       modangles_z = 0;
+
+                       self.angles =
+                               AnglesTransform_ToAngles(
+                                       AnglesTransform_Multiply(
+                                               AnglesTransform_FromAngles(self.angles),
+                                               AnglesTransform_FromAngles(modangles)
+                                       )
+                               );
+               }
        }
 
        self.glowmod = self.owner.weaponentity_glowmod;
        self.colormap = self.owner.colormap;
-};
+}
 
 // spawning weaponentity for client
 void CL_SpawnWeaponentity()
@@ -889,7 +708,7 @@ void CL_SpawnWeaponentity()
        self.exteriorweaponentity.angles = '0 0 0';
        self.exteriorweaponentity.think = CL_ExteriorWeaponentity_Think;
        self.exteriorweaponentity.nextthink = time;
-};
+}
 
 void Send_WeaponComplain (entity e, float wpn, string wpnname, float type)
 {
@@ -905,8 +724,8 @@ void Send_WeaponComplain (entity e, float wpn, string wpnname, float type)
 
 float client_hasweapon(entity cl, float wpn, float andammo, float complain)
 {
-       local float weaponbit, f;
-       local entity oldself;
+       float weaponbit, f;
+       entity oldself;
 
        if(time < self.hasweapon_complain_spam)
                complain = 0;
@@ -936,7 +755,7 @@ float client_hasweapon(entity cl, float wpn, float andammo, float complain)
                                f = f + weapon_action(wpn, WR_CHECKAMMO2);
 
                                // always allow selecting the Mine Layer if we placed mines, so that we can detonate them
-                               local entity mine;
+                               entity mine;
                                if(wpn == WEP_MINE_LAYER)
                                for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self)
                                        f = 1;
@@ -1001,41 +820,44 @@ float client_hasweapon(entity cl, float wpn, float andammo, float complain)
                play2(cl, "weapons/unavailable.wav");
        }
        return FALSE;
-};
+}
 
 // Weapon subs
 void w_clear()
 {
        if (self.weapon != -1)
+       {
                self.weapon = 0;
+               self.switchingweapon = 0;
+       }
        if (self.weaponentity)
        {
                self.weaponentity.state = WS_CLEAR;
                self.weaponentity.effects = 0;
        }
-};
+}
 
 void w_ready()
 {
        if (self.weaponentity)
                self.weaponentity.state = WS_READY;
        weapon_thinkf(WFRAME_IDLE, 1000000, w_ready);
-};
+}
 
 // Setup weapon for client (after this raise frame will be launched)
 void weapon_setup(float windex)
 {
        entity e;
-       qcweaponanimation = autocvar_sv_qcweaponanimation;
        e = get_weaponinfo(windex);
        self.items &~= IT_AMMO;
        self.items = self.items | e.items;
 
        // the two weapon entities will notice this has changed and update their models
        self.weapon = windex;
+       self.switchingweapon = windex; // to make sure
        self.weaponname = e.mdl;
        self.bulletcounter = 0;
-};
+}
 
 // perform weapon to attack (weaponstate and attack_finished check is here)
 void W_SwitchToOtherWeapon(entity pl)
@@ -1056,7 +878,7 @@ float weapon_prepareattack_checkammo(float secondary)
        if (!weapon_action(self.weapon, WR_CHECKAMMO1 + secondary))
        {
                // always keep the Mine Layer if we placed mines, so that we can detonate them
-               local entity mine;
+               entity mine;
                if(self.weapon == WEP_MINE_LAYER)
                for(mine = world; (mine = find(mine, classname, "mine")); ) if(mine.owner == self)
                        return FALSE;
@@ -1157,82 +979,16 @@ void weapon_thinkf(float fr, float t, void() func)
        if (self.weaponentity)
        {
                self.weaponentity.wframe = fr;
-               if (qcweaponanimation)
-               {
-                       if (fr != WFRAME_IDLE)
-                       {
-                               self.weapon_morph0time = time;
-                               self.weapon_morph0angles = self.weaponentity.angles;
-                               self.weapon_morph0origin = self.weaponentity.origin;
-
-                               self.weapon_morph1angles = '0 0 0';
-                               self.weapon_morph1time = time + t;
-                               makevectors(self.weapon_morph1angles_x * '-1 0 0' + self.weapon_morph1angles_y * '0 1 0' + self.weapon_morph1angles_z * '0 0 1');
-                               self.weapon_morph1origin = QCWEAPONANIMATION_ORIGIN(self.weaponentity);
-
-                               self.weapon_morph2angles = '0 0 0';
-                               self.weapon_morph2time = time + t;
-                               makevectors(self.weapon_morph2angles_x * '-1 0 0' + self.weapon_morph2angles_y * '0 1 0' + self.weapon_morph2angles_z * '0 0 1');
-                               self.weapon_morph2origin = QCWEAPONANIMATION_ORIGIN(self.weaponentity);
-
-                               self.weapon_morph3angles = '0 0 0';
-                               self.weapon_morph3time = time + t;
-                               makevectors(self.weapon_morph3angles_x * '-1 0 0' + self.weapon_morph3angles_y * '0 1 0' + self.weapon_morph3angles_z * '0 0 1');
-                               self.weapon_morph3origin = QCWEAPONANIMATION_ORIGIN(self.weaponentity);
-
-                               self.weapon_morph4angles = '0 0 0';
-                               self.weapon_morph4time = time + t;
-                               makevectors(self.weapon_morph4angles_x * '-1 0 0' + self.weapon_morph4angles_y * '0 1 0' + self.weapon_morph4angles_z * '0 0 1');
-                               self.weapon_morph4origin = QCWEAPONANIMATION_ORIGIN(self.weaponentity);
-
-                               if (fr == WFRAME_FIRE1)
-                               {
-                                       self.weapon_morph1angles = '5 0 0';
-                                       self.weapon_morph1time = time + t * 0.1;
-                                       makevectors(self.weapon_morph1angles_x * '-1 0 0' + self.weapon_morph1angles_y * '0 1 0' + self.weapon_morph1angles_z * '0 0 1');
-                                       self.weapon_morph1origin = QCWEAPONANIMATION_ORIGIN(self.weaponentity);
-                                       self.weapon_morph4time = time + t + 1; // delay idle effect
-                               }
-                               else if (fr == WFRAME_FIRE2)
-                               {
-                                       self.weapon_morph1angles = '10 0 0';
-                                       self.weapon_morph1time = time + t * 0.1;
-                                       makevectors(self.weapon_morph1angles_x * '-1 0 0' + self.weapon_morph1angles_y * '0 1 0' + self.weapon_morph1angles_z * '0 0 1');
-                                       self.weapon_morph1origin = QCWEAPONANIMATION_ORIGIN(self.weaponentity);
-                                       self.weapon_morph4time = time + t + 1; // delay idle effect
-                               }
-                               else if (fr == WFRAME_RELOAD)
-                               {
-                                       self.weapon_morph1time = time + t * 0.05;
-                                       self.weapon_morph1angles = '-10 40 0';
-                                       makevectors(self.weapon_morph1angles_x * '-1 0 0' + self.weapon_morph1angles_y * '0 1 0' + self.weapon_morph1angles_z * '0 0 1');
-                                       self.weapon_morph1origin = QCWEAPONANIMATION_ORIGIN(self.weaponentity);
-
-                                       self.weapon_morph2time = time + t * 0.15;
-                                       self.weapon_morph2angles = '-10 40 5';
-                                       makevectors(self.weapon_morph2angles_x * '-1 0 0' + self.weapon_morph2angles_y * '0 1 0' + self.weapon_morph2angles_z * '0 0 1');
-                                       self.weapon_morph2origin = QCWEAPONANIMATION_ORIGIN(self.weaponentity);
-
-                                       self.weapon_morph3time = time + t * 0.25;
-                                       self.weapon_morph3angles = '-10 40 0';
-                                       makevectors(self.weapon_morph3angles_x * '-1 0 0' + self.weapon_morph3angles_y * '0 1 0' + self.weapon_morph3angles_z * '0 0 1');
-                                       self.weapon_morph3origin = QCWEAPONANIMATION_ORIGIN(self.weaponentity);
-                               }
-                       }
-               }
-               else
-               {
-                       if (fr == WFRAME_IDLE)
-                               a = self.weaponentity.anim_idle;
-                       else if (fr == WFRAME_FIRE1)
-                               a = self.weaponentity.anim_fire1;
-                       else if (fr == WFRAME_FIRE2)
-                               a = self.weaponentity.anim_fire2;
-                       else if (fr == WFRAME_RELOAD)
-                               a = self.weaponentity.anim_reload;
-                       a_z *= g_weaponratefactor;
-                       setanim(self.weaponentity, a, restartanim == FALSE, restartanim, restartanim);
-               }
+               if (fr == WFRAME_IDLE)
+                       a = self.weaponentity.anim_idle;
+               else if (fr == WFRAME_FIRE1)
+                       a = self.weaponentity.anim_fire1;
+               else if (fr == WFRAME_FIRE2)
+                       a = self.weaponentity.anim_fire2;
+               else if (fr == WFRAME_RELOAD)
+                       a = self.weaponentity.anim_reload;
+               a_z *= g_weaponratefactor;
+               setanim(self.weaponentity, a, restartanim == FALSE, restartanim, restartanim);
        }
 
        v_forward = of;
@@ -1274,13 +1030,19 @@ void weapon_thinkf(float fr, float t, void() func)
                        anim_z = anim_y / (t + sys_frametime);
                        setanim(self, anim, FALSE, TRUE, TRUE);
                }
+               else if (self.animstate_startframe == self.anim_idle_x) // only allow shoot anim to override idle animation until we have animation blending
+               {
+                       anim = self.anim_shoot;
+                       anim_z = anim_y / (t + sys_frametime);
+                       setanim(self, anim, FALSE, TRUE, TRUE);
+               }
        }
-};
+}
 
 void weapon_boblayer1(float spd, vector org)
 {
        // VorteX: haste can be added here
-};
+}
 
 vector W_CalculateProjectileVelocity(vector pvelocity, vector mvelocity, float forceAbsolute)
 {
@@ -1359,38 +1121,30 @@ void W_AttachToShotorg(entity flash, vector offset)
        entity xflash;
        flash.owner = self;
        flash.angles_z = random() * 360;
-       if(qcweaponanimation)
-       {
-               setorigin(flash, w_shotorg + w_shotdir * 50);
-               flash.angles = vectoangles(w_shotdir);
-               flash.angles_z = random() * 360;
-       }
+
+       if(gettagindex(self.weaponentity, "shot"))
+               setattachment(flash, self.weaponentity, "shot");
        else
-       {
-               if(gettagindex(self.weaponentity, "shot"))
-                       setattachment(flash, self.weaponentity, "shot");
-               else
-                       setattachment(flash, self.weaponentity, "tag_shot");
-               setorigin(flash, offset);
+               setattachment(flash, self.weaponentity, "tag_shot");
+       setorigin(flash, offset);
 
-               xflash = spawn();
-               copyentity(flash, xflash);
+       xflash = spawn();
+       copyentity(flash, xflash);
 
-               flash.viewmodelforclient = self;
+       flash.viewmodelforclient = self;
 
-               if(self.weaponentity.oldorigin_x > 0)
-               {
-                       setattachment(xflash, self.exteriorweaponentity, "");
-                       setorigin(xflash, self.weaponentity.oldorigin + offset);
-               }
+       if(self.weaponentity.oldorigin_x > 0)
+       {
+               setattachment(xflash, self.exteriorweaponentity, "");
+               setorigin(xflash, self.weaponentity.oldorigin + offset);
+       }
+       else
+       {
+               if(gettagindex(self.exteriorweaponentity, "shot"))
+                       setattachment(xflash, self.exteriorweaponentity, "shot");
                else
-               {
-                       if(gettagindex(self.exteriorweaponentity, "shot"))
-                               setattachment(xflash, self.exteriorweaponentity, "shot");
-                       else
-                               setattachment(xflash, self.exteriorweaponentity, "tag_shot");
-                       setorigin(xflash, offset);
-               }
+                       setattachment(xflash, self.exteriorweaponentity, "tag_shot");
+               setorigin(xflash, offset);
        }
 }
 
@@ -1634,7 +1388,7 @@ void W_DecreaseAmmo(.float ammo_type, float ammo_use, float ammo_reload)
        if(ammo_reload)
        {
                self.clip_load -= ammo_use;
-               self.weapon_load[self.weapon] = self.clip_load;
+               self.(weapon_load[self.weapon]) = self.clip_load;
        }
        else
                self.(self.current_ammo) -= ammo_use;
@@ -1663,7 +1417,7 @@ void W_ReloadedAndReady()
                        self.(self.current_ammo) -= 1;
                }
        }
-       self.weapon_load[self.weapon] = self.clip_load;
+       self.(weapon_load[self.weapon]) = self.clip_load;
 
        // do not set ATTACK_FINISHED in reload code any more. This causes annoying delays if eg: You start reloading a weapon,
        // then quickly switch to another weapon and back. Reloading is canceled, but the reload delay is still there,
@@ -1746,5 +1500,5 @@ void W_Reload(float sent_ammo_min, float sent_ammo_amount, float sent_time, stri
        if(self.clip_load < 0)
                self.clip_load = 0;
        self.old_clip_load = self.clip_load;
-       self.clip_load = self.weapon_load[self.weapon] = -1;
+       self.clip_load = self.(weapon_load[self.weapon]) = -1;
 }