]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into TimePath/csqc_viewmodels
authorTimePath <andrew.hardaker1995@gmail.com>
Fri, 6 Nov 2015 08:55:40 +0000 (19:55 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Fri, 6 Nov 2015 08:59:26 +0000 (19:59 +1100)
# Conflicts:
# qcsrc/common/weapons/all.qc
# qcsrc/common/weapons/weapon/rifle.qc
# qcsrc/server/weapons/weaponsystem.qc

15 files changed:
1  2 
qcsrc/client/progs.inc
qcsrc/client/view.qc
qcsrc/client/weapons/projectile.qc
qcsrc/common/weapons/all.qc
qcsrc/common/weapons/all.qh
qcsrc/common/weapons/weapon/rifle.qc
qcsrc/lib/_all.inc
qcsrc/server/cl_client.qc
qcsrc/server/cl_player.qc
qcsrc/server/defs.qh
qcsrc/server/g_subs.qc
qcsrc/server/g_subs.qh
qcsrc/server/g_world.qc
qcsrc/server/progs.inc
qcsrc/server/weapons/weaponsystem.qc

diff --combined qcsrc/client/progs.inc
index 2b9c22a24f0529510da5dbaca1a1dada9c0d562f,4e127917aa48cb136eeb6b77b2f788f81238d670..12d43b5c4c44eca85fd368f046f6119bed35063c
@@@ -1,25 -1,18 +1,18 @@@
  #include "../lib/_all.inc"
  #include "_all.qh"
  
+ #include "../common/effects/qc/all.qc"
  #include "announcer.qc"
  #include "bgmscript.qc"
- #include "controlpoint.qc"
  #include "csqcmodel_hooks.qc"
- #include "damage.qc"
- #include "effects.qc"
- #include "generator.qc"
- #include "gibs.qc"
  #include "hook.qc"
- #include "hud.qc"
- #include "hud_config.qc"
+ #include "hud/all.qc"
  #include "main.qc"
  #include "mapvoting.qc"
  #include "miscfunctions.qc"
- #include "modeleffects.qc"
  #include "movelib.qc"
- #include "particles.qc"
  #include "player_skeleton.qc"
- #include "rubble.qc"
  #include "scoreboard.qc"
  #include "shownames.qc"
  #include "teamradar.qc"
@@@ -32,7 -25,6 +25,7 @@@
  
  #include "weapons/projectile.qc" // TODO
  
 +#include "../common/anim.qc"
  #include "../common/animdecide.qc"
  #include "../common/effects/effectinfo.qc"
  #include "../common/mapinfo.qc"
  #include "../lib/csqcmodel/cl_player.qc"
  #include "../lib/csqcmodel/interpolate.qc"
  
- // TODO: move to common
- #include "../server/mutators/mutator/mutator_multijump.qc"
- #define IMPLEMENTATION
- #include "../server/mutators/mutator/mutator_multijump.qc"
- #undef IMPLEMENTATION
  #include "../lib/warpzone/anglestransform.qc"
  #include "../lib/warpzone/client.qc"
  #include "../lib/warpzone/common.qc"
diff --combined qcsrc/client/view.qc
index 0e7ec4aa421ceffe18bb181a87e03205e46125d2,6f37f39e346d1a272ca3ada94ac1eecdf80ff19d..f1e107de2f0c8e8faebee4f30acc2443c29a33a9
@@@ -1,8 -1,7 +1,7 @@@
  
  #include "announcer.qh"
  #include "hook.qh"
- #include "hud.qh"
- #include "hud_config.qh"
+ #include "hud/all.qh"
  #include "mapvoting.qh"
  #include "scoreboard.qh"
  #include "shownames.qh"
@@@ -10,8 -9,8 +9,9 @@@
  
  #include "mutators/events.qh"
  
 +#include "../common/anim.qh"
  #include "../common/constants.qh"
+ #include "../common/debug.qh"
  #include "../common/mapinfo.qh"
  #include "../common/gamemodes/all.qh"
  #include "../common/nades/all.qh"
  #include "../lib/warpzone/client.qh"
  #include "../lib/warpzone/common.qh"
  
 +#define EFMASK_CHEAP (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NODRAW | EF_NOSHADOW | EF_SELECTABLE | EF_TELEPORT_BIT)
 +
 +void viewmodel_draw(entity this)
 +{
 +      int mask = (intermission || (getstati(STAT_HEALTH) <= 0) || autocvar_chase_active) ? 0 : MASK_NORMAL;
 +      float a = this.alpha;
 +      int c = stof(getplayerkeyvalue(current_player, "colors"));
 +      vector g = this.glowmod; // TODO: completely clientside: colormapPaletteColor(c & 0x0F, true) * 2;
 +      entity me = CSQCModel_server2csqc(player_localentnum);
 +      int fx = ((me.csqcmodel_effects & EFMASK_CHEAP)
 +              | EF_NODEPTHTEST)
 +              &~ (EF_FULLBRIGHT); // can mask team color, so get rid of it
 +      for (entity e = this; e; e = e.weaponchild)
 +      {
 +              e.drawmask = mask;
 +              e.alpha = a;
 +              e.colormap = c;
 +              e.glowmod = g;
 +              e.csqcmodel_effects = fx;
 +              WITH(entity, self, e, CSQCModel_Effects_Apply());
 +      }
 +      {
 +              static string name_last;
 +              string name = get_weaponinfo(activeweapon).mdl;
 +              if (name != name_last)
 +              {
 +                      name_last = name;
 +                      CL_WeaponEntity_SetModel(this, name);
 +                      updateanim(this);
 +                      if (!this.animstate_override)
 +                              setanim(this, this.anim_idle, true, false, false);
 +              }
 +      }
 +      float eta = (getstatf(STAT_WEAPON_NEXTTHINK) - time); // TODO: / W_WeaponRateFactor();
 +      float f = 0; // 0..1; 0: fully active
 +      switch (this.state)
 +      {
 +              case WS_RAISE:
 +              {
 +                      // entity newwep = Weapons_from(activeweapon);
 +                      float delay = 0.2; // TODO: newwep.switchdelay_raise;
 +                      f = eta / max(eta, delay);
 +                      this.angles_x = -90 * f * f;
 +                      break;
 +              }
 +              case WS_DROP:
 +              {
 +                      // entity oldwep = Weapons_from(activeweapon);
 +                      float delay = 0.2; // TODO: newwep.switchdelay_drop;
 +                      f = 1 - eta / max(eta, delay);
 +                      this.angles_x = -90 * f * f;
 +                      break;
 +              }
 +              case WS_CLEAR:
 +              {
 +                      f = 1;
 +                      break;
 +              }
 +      }
 +      this.angles_x = -90 * f * f;
 +}
 +
 +entity viewmodel;
 +STATIC_INIT(viewmodel) {
 +    viewmodel = new(viewmodel);
 +      viewmodel.draw = viewmodel_draw;
 +}
 +
  entity porto;
  vector polyline[16];
  void Porto_Draw(entity this)
  
  void Porto_Init()
  {
-       porto = spawn();
-       porto.classname = "porto";
+       porto = new(porto);
+       make_pure(porto);
        porto.draw = Porto_Draw;
        porto.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
  }
@@@ -347,11 -278,11 +347,11 @@@ const float SHOTTYPE_HITENEMY = 4
  
  void TrueAim_Init()
  {
-       trueaim = spawn();
-       trueaim.classname = "trueaim";
+       trueaim = new(trueaim);
+       make_pure(trueaim);
        trueaim.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
-       trueaim_rifle = spawn();
-       trueaim_rifle.classname = "trueaim_rifle";
+       trueaim_rifle = new(trueaim_rifle);
+       make_pure(trueaim_rifle);
        trueaim_rifle.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_CORPSE;
  }
  
@@@ -467,7 -398,7 +467,7 @@@ float TrueAimCheck(
        return SHOTTYPE_HITWORLD;
  }
  
- void PostInit(void);
+ void PostInit();
  void CSQC_Demo_Camera();
  float HUD_WouldDrawScoreboard();
  float camera_mode;
@@@ -1585,13 -1516,11 +1585,11 @@@ void CSQC_UpdateView(float w, float h
  
                if(!nightvision_noise)
                {
-                       nightvision_noise = spawn();
-                       nightvision_noise.classname = "nightvision_noise";
+                       nightvision_noise = new(nightvision_noise);
                }
                if(!nightvision_noise2)
                {
-                       nightvision_noise2 = spawn();
-                       nightvision_noise2.classname = "nightvision_noise2";
+                       nightvision_noise2 = new(nightvision_noise2);
                }
  
                // color tint in yellow
        else if(cvar("r_glsl_postprocess") == 2)
                cvar_set("r_glsl_postprocess", "0");
  
-       if(menu_visible)
-               menu_show();
        /*if(gametype == MAPINFO_TYPE_CTF)
          {
          ctf_view();
                WITH(entity, self, e, e.draw2d(e));
        }
        Draw_ShowNames_All();
+       Debug_Draw();
  
        scoreboard_active = HUD_WouldDrawScoreboard();
  
index d220ccbf1576d7cb5a273cf7e40a87b179360c10,04a600cb694ffcfeb1be630e459f56a9a2128ef0..c423032fe963870fe39e3a90290e563e2d1c4408
@@@ -183,11 -183,8 +183,8 @@@ void Ent_RemoveProjectile(
        }
  }
  
void Ent_Projectile()
NET_HANDLE(ENT_CLIENT_PROJECTILE, bool isnew)
  {
-       SELFPARAM();
-       int f;
        // projectile properties:
        //   kind (interpolated, or clientside)
        //
        //
        // projectiles don't send angles, because they always follow the velocity
  
-       f = ReadByte();
+       int f = ReadByte();
        self.count = (f & 0x80);
        self.iflags = (self.iflags & IFLAG_INTERNALMASK) | IFLAG_AUTOANGLES | IFLAG_ANGLES | IFLAG_ORIGIN;
        self.solid = SOLID_TRIGGER;
                self.traileffect = 0;
                switch (self.cnt)
                {
 -                      #define CASE(id) case PROJECTILE_##id: setmodel(self, MDL_PROJECTILE_##id);
 -                      CASE(ELECTRO)            self.traileffect = EFFECT_TR_NEXUIZPLASMA.m_id; break;
 -                      CASE(ROCKET)             self.traileffect = EFFECT_TR_ROCKET.m_id; self.scale = 2; break;
 -                      CASE(CRYLINK)            self.traileffect = EFFECT_TR_CRYLINKPLASMA.m_id; break;
 -                      CASE(CRYLINK_BOUNCING)   self.traileffect = EFFECT_TR_CRYLINKPLASMA.m_id; break;
 -                      CASE(ELECTRO_BEAM)       self.traileffect = EFFECT_TR_NEXUIZPLASMA.m_id; break;
 -                      CASE(GRENADE)            self.traileffect = EFFECT_TR_GRENADE.m_id; break;
 -                      CASE(GRENADE_BOUNCING)   self.traileffect = EFFECT_TR_GRENADE.m_id; break;
 -                      CASE(MINE)               self.traileffect = EFFECT_TR_GRENADE.m_id; break;
 -                      CASE(BLASTER)            self.traileffect = EFFECT_Null.m_id; break;
 -                      CASE(HLAC)               self.traileffect = EFFECT_Null.m_id; break;
 -                      CASE(PORTO_RED)          self.traileffect = EFFECT_TR_WIZSPIKE.m_id; self.scale = 4; break;
 -                      CASE(PORTO_BLUE)         self.traileffect = EFFECT_TR_WIZSPIKE.m_id; self.scale = 4; break;
 -                      CASE(HOOKBOMB)           self.traileffect = EFFECT_TR_KNIGHTSPIKE.m_id; break;
 -                      CASE(HAGAR)              self.traileffect = EFFECT_HAGAR_ROCKET.m_id; self.scale = 0.75; break;
 -                      CASE(HAGAR_BOUNCING)     self.traileffect = EFFECT_HAGAR_ROCKET.m_id; self.scale = 0.75; break;
 -                      CASE(NAPALM_FOUNTAIN)                                                                         // fallthrough // sself.modelindex = 0; self.traileffect = _particleeffectnum("torch_small"); break;
 -                      CASE(FIREBALL)           self.modelindex = 0; self.traileffect = EFFECT_FIREBALL.m_id; break; // particle effect is good enough
 -                      CASE(FIREMINE)           self.modelindex = 0; self.traileffect = EFFECT_FIREMINE.m_id; break; // particle effect is good enough
 -                      CASE(TAG)                self.traileffect = EFFECT_TR_ROCKET.m_id; break;
 -                      CASE(FLAC)               self.scale = 0.4; self.traileffect = EFFECT_FLAC_TRAIL.m_id; break;
 -                      CASE(SEEKER)             self.traileffect = EFFECT_SEEKER_TRAIL.m_id; break;
 -
 -                      CASE(MAGE_SPIKE)         self.traileffect = EFFECT_TR_VORESPIKE.m_id; break;
 -                      CASE(SHAMBLER_LIGHTNING) self.traileffect = EFFECT_TR_NEXUIZPLASMA.m_id; break;
 -
 -                      CASE(RAPTORBOMB)         self.gravity = 1; self.avelocity = '0 0 180'; self.traileffect = EFFECT_Null.m_id; break;
 -                      CASE(RAPTORBOMBLET)      self.gravity = 1; self.avelocity = '0 0 180'; self.traileffect = EFFECT_Null.m_id; break;
 -                      CASE(RAPTORCANNON)       self.traileffect = EFFECT_TR_CRYLINKPLASMA.m_id; break;
 -
 -                      CASE(SPIDERROCKET)       self.traileffect = EFFECT_SPIDERBOT_ROCKET_TRAIL.m_id; break;
 -                      CASE(WAKIROCKET)         self.traileffect = EFFECT_RACER_ROCKET_TRAIL.m_id; break;
 -                      CASE(WAKICANNON)         self.traileffect = EFFECT_Null.m_id; break;
 -
 -                      CASE(BUMBLE_GUN)         self.traileffect = EFFECT_TR_NEXUIZPLASMA.m_id; break;
 -                      CASE(BUMBLE_BEAM)        self.traileffect = EFFECT_TR_NEXUIZPLASMA.m_id; break;
 -
 -                      CASE(RPC)                self.traileffect = EFFECT_TR_ROCKET.m_id; break;
 -
 -                      CASE(ROCKETMINSTA_LASER) self.traileffect = EFFECT_ROCKETMINSTA_LASER(self.team).m_id; break;
 -#undef CASE
 +                      #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(NAPALM_FOUNTAIN)                                                                         // fallthrough // sself.modelindex = 0; self.traileffect = _particleeffectnum("torch_small"); 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))
                                        break;
                setsize(self, self.mins, self.maxs);
        }
  
+       return = true;
        if (self.gravity)
        {
                if (self.move_movetype == MOVETYPE_FLY)
        self.entremove = Ent_RemoveProjectile;
  }
  
void Projectile_Precache()
PRECACHE(Projectiles)
  {
        MUTATOR_CALLHOOK(PrecacheProjectiles);
  }
index b408ee15737e44c105fec28e2d16366086d3c096,b338122139730e150fa773b28e27ded825aca60d..177d12c2d36d54e221be9ef5aec6145c09e2f5ea
        #include "../../lib/csqcmodel/cl_model.qh"
  #elif defined(MENUQC)
  #elif defined(SVQC)
 -    #include "../../lib/warpzone/anglestransform.qh"
 -    #include "../../lib/warpzone/common.qh"
 -    #include "../../lib/warpzone/util_server.qh"
 -    #include "../../lib/warpzone/server.qh"
 -    #include "../constants.qh"
 -    #include "../stats.qh"
 -    #include "../teams.qh"
 -    #include "../util.qh"
 -    #include "../buffs/all.qh"
 -    #include "../monsters/all.qh"
 -    #include "config.qh"
 -    #include "../../server/weapons/csqcprojectile.qh"
 -    #include "../../server/weapons/tracing.qh"
 -    #include "../../server/t_items.qh"
 -    #include "../../server/autocvars.qh"
 -    #include "../../server/constants.qh"
 -    #include "../../server/defs.qh"
 -    #include "../notifications.qh"
 -    #include "../deathtypes/all.qh"
 -    #include "../../server/mutators/all.qh"
 -    #include "../mapinfo.qh"
 -    #include "../../server/command/common.qh"
 -    #include "../../lib/csqcmodel/sv_model.qh"
 -    #include "../../server/portals.qh"
 -    #include "../../server/g_hook.qh"
 +      #include "../../lib/warpzone/anglestransform.qh"
 +      #include "../../lib/warpzone/common.qh"
 +      #include "../../lib/warpzone/util_server.qh"
 +      #include "../../lib/warpzone/server.qh"
 +      #include "../constants.qh"
 +      #include "../stats.qh"
 +      #include "../teams.qh"
 +      #include "../util.qh"
 +      #include "../buffs/all.qh"
 +      #include "../monsters/all.qh"
 +      #include "config.qh"
 +      #include "../../server/weapons/csqcprojectile.qh"
 +      #include "../../server/weapons/tracing.qh"
 +      #include "../../server/t_items.qh"
 +      #include "../../server/autocvars.qh"
 +      #include "../../server/constants.qh"
 +      #include "../../server/defs.qh"
 +      #include "../notifications.qh"
 +      #include "../deathtypes/all.qh"
 +      #include "../../server/mutators/all.qh"
 +      #include "../mapinfo.qh"
 +      #include "../../server/command/common.qh"
 +      #include "../../lib/csqcmodel/sv_model.qh"
 +      #include "../../server/portals.qh"
 +      #include "../../server/g_hook.qh"
  #endif
  #ifndef MENUQC
 -#include "calculations.qc"
 +      #include "calculations.qc"
  #endif
  #define IMPLEMENTATION
  #include "all.inc"
  
  // WEAPON PLUGIN SYSTEM
  
 -WepSet WepSet_FromWeapon(int a) {
 +WepSet WepSet_FromWeapon(int a)
 +{
        a -= WEP_FIRST;
        if (Weapons_MAX > 24)
 -      if (a >= 24) {
 -              a -= 24;
 -              if (Weapons_MAX > 48)
 -              if (a >= 24) {
 +              if (a >= 24)
 +              {
                        a -= 24;
 -                      return '0 0 1' * power2of(a);
 +                      if (Weapons_MAX > 48)
 +                              if (a >= 24)
 +                              {
 +                                      a -= 24;
 +                                      return '0 0 1' * power2of(a);
 +                              }
 +                      return '0 1 0' * power2of(a);
                }
 -              return '0 1 0' * power2of(a);
 -      }
        return '1 0 0' * power2of(a);
  }
  #ifdef SVQC
 -void WepSet_AddStat()
 -{
 -      addstat(STAT_WEAPONS, AS_INT, weapons_x);
 -      if (Weapons_MAX > 24)
 -      addstat(STAT_WEAPONS2, AS_INT, weapons_y);
 -      if (Weapons_MAX > 48)
 -      addstat(STAT_WEAPONS3, AS_INT, weapons_z);
 -}
 -void WepSet_AddStat_InMap()
 -{
 -      addstat(STAT_WEAPONSINMAP, AS_INT, weaponsinmap_x);
 -      if (Weapons_MAX > 24)
 -      addstat(STAT_WEAPONSINMAP2, AS_INT, weaponsinmap_y);
 -      if (Weapons_MAX > 48)
 -      addstat(STAT_WEAPONSINMAP3, AS_INT, weaponsinmap_z);
 -}
 -void WriteWepSet(float dst, WepSet w)
 -{
 -      if (Weapons_MAX > 48)
 -      WriteInt72_t(dst, w);
 -      else if (Weapons_MAX > 24)
 -      WriteInt48_t(dst, w);
 -      else
 -      WriteInt24_t(dst, w.x);
 -}
 +      void WepSet_AddStat()
 +      {
 +              addstat(STAT_WEAPONS, AS_INT, weapons_x);
 +              if (Weapons_MAX > 24) addstat(STAT_WEAPONS2, AS_INT, weapons_y);
 +              if (Weapons_MAX > 48) addstat(STAT_WEAPONS3, AS_INT, weapons_z);
 +      }
 +      void WepSet_AddStat_InMap()
 +      {
 +              addstat(STAT_WEAPONSINMAP, AS_INT, weaponsinmap_x);
 +              if (Weapons_MAX > 24) addstat(STAT_WEAPONSINMAP2, AS_INT, weaponsinmap_y);
 +              if (Weapons_MAX > 48) addstat(STAT_WEAPONSINMAP3, AS_INT, weaponsinmap_z);
 +      }
 +      void WriteWepSet(float dst, WepSet w)
 +      {
 +              if (Weapons_MAX > 48) WriteInt72_t(dst, w);
 +              else if (Weapons_MAX > 24) WriteInt48_t(dst, w);
 +              else WriteInt24_t(dst, w.x);
 +      }
  #endif
  #ifdef CSQC
 -WepSet WepSet_GetFromStat()
 -{
 -      WepSet w = '0 0 0';
 -      w.x = getstati(STAT_WEAPONS);
 -      if (Weapons_MAX > 24)
 -      w.y = getstati(STAT_WEAPONS2);
 -      if (Weapons_MAX > 48)
 -      w.z = getstati(STAT_WEAPONS3);
 -      return w;
 -}
 -WepSet WepSet_GetFromStat_InMap()
 -{
 -      WepSet w = '0 0 0';
 -      w_x = getstati(STAT_WEAPONSINMAP);
 -      if (Weapons_MAX > 24)
 -      w_y = getstati(STAT_WEAPONSINMAP2);
 -      if (Weapons_MAX > 48)
 -      w_z = getstati(STAT_WEAPONSINMAP3);
 -      return w;
 -}
 -WepSet ReadWepSet()
 -{
 -      if (Weapons_MAX > 48)
 -      return ReadInt72_t();
 -      if (Weapons_MAX > 24)
 -      return ReadInt48_t();
 -      return ReadInt24_t() * '1 0 0';
 -}
 +      WepSet WepSet_GetFromStat()
 +      {
 +              WepSet w = '0 0 0';
 +              w.x = getstati(STAT_WEAPONS);
 +              if (Weapons_MAX > 24) w.y = getstati(STAT_WEAPONS2);
 +              if (Weapons_MAX > 48) w.z = getstati(STAT_WEAPONS3);
 +              return w;
 +      }
 +      WepSet WepSet_GetFromStat_InMap()
 +      {
 +              WepSet w = '0 0 0';
 +              w_x = getstati(STAT_WEAPONSINMAP);
 +              if (Weapons_MAX > 24) w_y = getstati(STAT_WEAPONSINMAP2);
 +              if (Weapons_MAX > 48) w_z = getstati(STAT_WEAPONSINMAP3);
 +              return w;
 +      }
 +      WepSet ReadWepSet()
 +      {
 +              if (Weapons_MAX > 48) return ReadInt72_t();
 +              if (Weapons_MAX > 24) return ReadInt48_t();
 +              return ReadInt24_t() * '1 0 0';
 +      }
  #endif
  
  string W_FixWeaponOrder(string order, float complete)
  string W_NameWeaponOrder_MapFunc(string s)
  {
        entity wi;
 -      if(s == "0" || stof(s))
 +      if (s == "0" || stof(s))
        {
                wi = get_weaponinfo(stof(s));
 -              if(wi != WEP_Null)
 -                      return wi.netname;
 +              if (wi != WEP_Null) return wi.netname;
        }
        return s;
  }
  
  string W_UndeprecateName(string s)
  {
 -      switch ( s )
 +      switch (s)
        {
 -              case "nex"            : return "vortex";
 -              case "rocketlauncher" : return "devastator";
 -              case "laser"          : return "blaster";
 -              case "minstanex"      : return "vaporizer";
 +              case "nex": return "vortex";
 +              case "rocketlauncher": return "devastator";
 +              case "laser": return "blaster";
 +              case "minstanex": return "vaporizer";
                case "grenadelauncher": return "mortar";
 -              case "uzi"            : return "machinegun";
 -              default               : return s;
 +              case "uzi": return "machinegun";
 +              default: return s;
        }
  }
  string W_NameWeaponOrder(string order)
  string W_NumberWeaponOrder_MapFunc(string s)
  {
        int i;
 -      if(s == "0" || stof(s))
 -              return s;
 +      if (s == "0" || stof(s)) return s;
        s = W_UndeprecateName(s);
 -      for(i = WEP_FIRST; i <= WEP_LAST; ++i)
 -              if(s == get_weaponinfo(i).netname)
 -                      return ftos(i);
 +      for (i = WEP_FIRST; i <= WEP_LAST; ++i)
 +              if (s == get_weaponinfo(i).netname) return ftos(i);
        return s;
  }
  string W_NumberWeaponOrder(string order)
@@@ -179,24 -192,23 +179,24 @@@ float W_FixWeaponOrder_BuildImpulseList
        e1 = get_weaponinfo(W_FixWeaponOrder_BuildImpulseList_buf[i]);
        e2 = get_weaponinfo(W_FixWeaponOrder_BuildImpulseList_buf[j]);
        d = (e1.impulse + 9) % 10 - (e2.impulse + 9) % 10;
 -      if(d != 0)
 -              return -d; // high impulse first!
 -      return
 -              strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[i]), 0)
 -              -
 -              strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "), sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[j]), 0)
 -              ; // low char index first!
 +      if (d != 0) return -d;  // high impulse first!
 +      return strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "),
 +              sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[i]), 0)
 +             -
 +             strstrofs(strcat(" ", W_FixWeaponOrder_BuildImpulseList_order, " "),
 +              sprintf(" %d ", W_FixWeaponOrder_BuildImpulseList_buf[j]), 0)
 +       // low char index first!
  }
  string W_FixWeaponOrder_BuildImpulseList(string o)
  {
        int i;
        W_FixWeaponOrder_BuildImpulseList_order = o;
 -      for(i = WEP_FIRST; i <= WEP_LAST; ++i)
 +      for (i = WEP_FIRST; i <= WEP_LAST; ++i)
                W_FixWeaponOrder_BuildImpulseList_buf[i - WEP_FIRST] = i;
 -      heapsort(WEP_LAST - WEP_FIRST + 1, W_FixWeaponOrder_BuildImpulseList_swap, W_FixWeaponOrder_BuildImpulseList_cmp, world);
 +      heapsort(WEP_LAST - WEP_FIRST + 1, W_FixWeaponOrder_BuildImpulseList_swap, W_FixWeaponOrder_BuildImpulseList_cmp,
 +              world);
        o = "";
 -      for(i = WEP_FIRST; i <= WEP_LAST; ++i)
 +      for (i = WEP_FIRST; i <= WEP_LAST; ++i)
                o = strcat(o, " ", ftos(W_FixWeaponOrder_BuildImpulseList_buf[i - WEP_FIRST]));
        W_FixWeaponOrder_BuildImpulseList_order = string_null;
        return substring(o, 1, -1);
@@@ -209,7 -221,8 +209,7 @@@ string W_FixWeaponOrder_AllowIncomplete
  
  string W_FixWeaponOrder_ForceComplete(string order)
  {
 -      if(order == "")
 -              order = W_NumberWeaponOrder(cvar_defstring("cl_weaponpriority"));
 +      if (order == "") order = W_NumberWeaponOrder(cvar_defstring("cl_weaponpriority"));
        return W_FixWeaponOrder(order, 1);
  }
  
@@@ -220,11 -233,12 +220,11 @@@ void W_RandomWeapons(entity e, float n
        WepSet result;
        remaining = e.weapons;
        result = '0 0 0';
 -      for(i = 0; i < n; ++i)
 +      for (i = 0; i < n; ++i)
        {
                RandomSelection_Init();
 -              for(j = WEP_FIRST; j <= WEP_LAST; ++j)
 -                      if(remaining & WepSet_FromWeapon(j))
 -                              RandomSelection_Add(world, j, string_null, 1, 1);
 +              for (j = WEP_FIRST; j <= WEP_LAST; ++j)
 +                      if (remaining & WepSet_FromWeapon(j)) RandomSelection_Add(world, j, string_null, 1, 1);
                result |= WepSet_FromWeapon(RandomSelection_chosen_float);
                remaining &= ~WepSet_FromWeapon(RandomSelection_chosen_float);
        }
@@@ -241,59 -255,48 +241,48 @@@ string GetAmmoPicture(.int ammotype
                case ammo_cells:   return ITEM_Cells.m_icon;
                case ammo_plasma:  return ITEM_Plasma.m_icon;
                case ammo_fuel:    return ITEM_JetpackFuel.m_icon;
 -              default: return ""; // wtf, no ammo type?
 +              default: return "";  // wtf, no ammo type?
        }
  }
  
  #ifdef CSQC
 -.int GetAmmoFieldFromNum(int i)
 -{
 -      switch(i)
 +      .int GetAmmoFieldFromNum(int i)
        {
 -              case 0: return ammo_shells;
 -              case 1: return ammo_nails;
 -              case 2: return ammo_rockets;
 -              case 3: return ammo_cells;
 -              case 4: return ammo_plasma;
 -              case 5: return ammo_fuel;
 -              default: return ammo_none;
 +              switch (i)
 +              {
 +                      case 0: return ammo_shells;
 +                      case 1: return ammo_nails;
 +                      case 2: return ammo_rockets;
 +                      case 3: return ammo_cells;
 +                      case 4: return ammo_plasma;
 +                      case 5: return ammo_fuel;
 +                      default: return ammo_none;
 +              }
        }
 -}
  
 -int GetAmmoStat(.int ammotype)
 -{
 -      switch(ammotype)
 +      int GetAmmoStat(.int ammotype)
        {
 -              case ammo_shells: return STAT_SHELLS;
 -              case ammo_nails: return STAT_NAILS;
 -              case ammo_rockets: return STAT_ROCKETS;
 -              case ammo_cells: return STAT_CELLS;
 -              case ammo_plasma: return STAT_PLASMA;
 -              case ammo_fuel: return STAT_FUEL;
 -              default: return -1;
 +              switch (ammotype)
 +              {
 +                      case ammo_shells: return STAT_SHELLS;
 +                      case ammo_nails: return STAT_NAILS;
 +                      case ammo_rockets: return STAT_ROCKETS;
 +                      case ammo_cells: return STAT_CELLS;
 +                      case ammo_plasma: return STAT_PLASMA;
 +                      case ammo_fuel: return STAT_FUEL;
 +                      default: return -1;
 +              }
        }
 -}
  #endif
  
  string W_Sound(string w_snd)
  {
-       #define extensions(X) X(wav) X(ogg)
-       #define tryext(ext) { if (fexists(strcat("sound/", output = strcat("weapons/", w_snd, "." #ext)))) break; }
-       string output;
-       do
-       {
-               extensions(tryext);
- #undef tryext
- #undef extensions
-               output = strcat("weapons/", w_snd);
-       }
-       while (0);
+       string output = strcat("weapons/", w_snd);
  #ifdef SVQC
 -      MUTATOR_CALLHOOK(WeaponSound, w_snd, output);
 -      return weapon_sound_output;
 +              MUTATOR_CALLHOOK(WeaponSound, w_snd, output);
 +              return weapon_sound_output;
  #else
 -      return output;
 +              return output;
  #endif
  }
  
@@@ -301,341 -304,11 +290,345 @@@ string W_Model(string w_mdl
  {
        string output = strcat("models/weapons/", w_mdl);
  #ifdef SVQC
 -      MUTATOR_CALLHOOK(WeaponModel, w_mdl, output);
 -      return weapon_model_output;
 +              MUTATOR_CALLHOOK(WeaponModel, w_mdl, output);
 +              return weapon_model_output;
 +#else
 +              return output;
 +#endif
 +}
 +
 +#ifndef MENUQC
 +vector shotorg_adjustfromclient(vector vecs, float y_is_right, float algn)
 +{
 +      switch (algn)
 +      {
 +              default:
 +              case 3:
 +                      // right alignment
 +                      break;
 +              case 4:
 +                      // left
 +                      vecs.y = -vecs.y;
 +                      break;
 +              case 1:
 +              case 2:
 +                      // center
 +                      vecs.y = 0;
 +                      vecs.z -= 2;
 +                      break;
 +      }
 +      return vecs;
 +}
 +
 +vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn)
 +{
 +#ifdef SVQC
 +      string s;
 +#endif
 +      if (visual)
 +      {
 +              vecs = shotorg_adjustfromclient(vecs, y_is_right, algn);
 +      }
 +#ifdef SVQC
 +      else if (autocvar_g_shootfromeye)
 +      {
 +              vecs.y = vecs.z = 0;
 +      }
 +      else if (autocvar_g_shootfromcenter)
 +      {
 +              vecs.y = 0;
 +              vecs.z -= 2;
 +      }
 +      else if ((s = autocvar_g_shootfromfixedorigin) != "")
 +      {
 +              vector v = stov(s);
 +              if (y_is_right) v.y = -v.y;
 +              if (v.x != 0) vecs.x = v.x;
 +              vecs.y = v.y;
 +              vecs.z = v.z;
 +      }
 +#endif
 +      else  // just do the same as top
 +      {
 +              vecs = shotorg_adjustfromclient(vecs, y_is_right, algn);
 +      }
 +
 +      return vecs;
 +}
 +
 +#define shotorg_adjust shotorg_adjust_values
 +
 +/**
 + * supported formats:
 + *
 + * 1. simple animated model, muzzle flash handling on h_ model:
 + *    h_tuba.dpm, h_tuba.dpm.framegroups - invisible model controlling the animation
 + *      tags:
 + *        shot = muzzle end (shot origin, also used for muzzle flashes)
 + *        shell = casings ejection point (must be on the right hand side of the gun)
 + *        weapon = attachment for v_tuba.md3
 + *    v_tuba.md3 - first and third person model
 + *    g_tuba.md3 - pickup model
 + *
 + * 2. simple animated model, muzzle flash handling on v_ model:
 + *    h_tuba.dpm, h_tuba.dpm.framegroups - invisible model controlling the animation
 + *      tags:
 + *        weapon = attachment for v_tuba.md3
 + *    v_tuba.md3 - first and third person model
 + *      tags:
 + *        shot = muzzle end (shot origin, also used for muzzle flashes)
 + *        shell = casings ejection point (must be on the right hand side of the gun)
 + *    g_tuba.md3 - pickup model
 + *
 + * 3. fully animated model, muzzle flash handling on h_ model:
 + *    h_tuba.dpm, h_tuba.dpm.framegroups - animated first person model
 + *      tags:
 + *        shot = muzzle end (shot origin, also used for muzzle flashes)
 + *        shell = casings ejection point (must be on the right hand side of the gun)
 + *        handle = corresponding to the origin of v_tuba.md3 (used for muzzle flashes)
 + *    v_tuba.md3 - third person model
 + *    g_tuba.md3 - pickup model
 + *
 + * 4. fully animated model, muzzle flash handling on v_ model:
 + *    h_tuba.dpm, h_tuba.dpm.framegroups - animated first person model
 + *      tags:
 + *        shot = muzzle end (shot origin)
 + *        shell = casings ejection point (must be on the right hand side of the gun)
 + *    v_tuba.md3 - third person model
 + *      tags:
 + *        shot = muzzle end (for muzzle flashes)
 + *    g_tuba.md3 - pickup model
 + *
 + * writes:
 + *   this.origin, this.angles
 + *   this.weaponchild
 + *   this.movedir, this.view_ofs
 + *   attachment stuff
 + *   anim stuff
 + * to free:
 + *   call again with ""
 + *   remove the ent
 + */
 +void CL_WeaponEntity_SetModel(entity this, string name)
 +{
 +      if (name == "")
 +      {
 +              this.model = "";
 +              if (this.weaponchild) remove(this.weaponchild);
 +              this.weaponchild = NULL;
 +              this.movedir = '0 0 0';
 +              this.spawnorigin = '0 0 0';
 +              this.oldorigin = '0 0 0';
 +              this.anim_fire1  = '0 1 0.01';
 +              this.anim_fire2  = '0 1 0.01';
 +              this.anim_idle   = '0 1 0.01';
 +              this.anim_reload = '0 1 0.01';
 +      }
 +      else
 +      {
 +              // if there is a child entity, hide it until we're sure we use it
 +              if (this.weaponchild) this.weaponchild.model = "";
 +              _setmodel(this, W_Model(strcat("v_", name, ".md3")));
 +              int v_shot_idx;  // used later
 +              (v_shot_idx = gettagindex(this, "shot")) || (v_shot_idx = gettagindex(this, "tag_shot"));
 +
 +              _setmodel(this, W_Model(strcat("h_", name, ".iqm")));
 +              // preset some defaults that work great for renamed zym files (which don't need an animinfo)
 +              this.anim_fire1  = animfixfps(this, '0 1 0.01', '0 0 0');
 +              this.anim_fire2  = animfixfps(this, '1 1 0.01', '0 0 0');
 +              this.anim_idle   = animfixfps(this, '2 1 0.01', '0 0 0');
 +              this.anim_reload = animfixfps(this, '3 1 0.01', '0 0 0');
 +
 +              // 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
 +              string t;
 +              if ((t = "weapon", gettagindex(this, t)) || (t = "tag_weapon", gettagindex(this, t)))
 +              {
 +                      if (!this.weaponchild)
 +                      {
 +                              this.weaponchild = new(weaponchild);
 +#ifdef CSQC
 +                              this.weaponchild.drawmask = MASK_NORMAL;
 +#endif
 +                      }
 +                      _setmodel(this.weaponchild, W_Model(strcat("v_", name, ".md3")));
 +                      setattachment(this.weaponchild, this, t);
 +              }
 +              else
 +              {
 +                      if (this.weaponchild) remove(this.weaponchild);
 +                      this.weaponchild = NULL;
 +              }
 +
 +              setorigin(this, '0 0 0');
 +              this.angles = '0 0 0';
 +              this.frame = 0;
 +#ifdef SVQC
 +              this.viewmodelforclient = NULL;
  #else
 -      return output;
 +              this.renderflags &= ~RF_VIEWMODEL;
  #endif
 +              if (v_shot_idx)  // v_ model attached to invisible h_ model
 +              {
 +                      this.movedir = gettaginfo(this.weaponchild, v_shot_idx);
 +              }
 +              else
 +              {
 +                      int idx;
 +                      if ((idx = gettagindex(this, "shot")) || (idx = gettagindex(this, "tag_shot")))
 +                      {
 +                              this.movedir = gettaginfo(this, idx);
 +                      }
 +                      else
 +                      {
 +                              LOG_WARNINGF("weapon model %s does not support the 'shot' tag, will display shots TOTALLY wrong\n",
 +                                      this.model);
 +                              this.movedir = '0 0 0';
 +                      }
 +              }
 +              {
 +                      int idx = 0;
 +                      // v_ model attached to invisible h_ model
 +                      if (this.weaponchild
 +                          && ((idx = gettagindex(this.weaponchild, "shell")) || (idx = gettagindex(this.weaponchild, "tag_shell"))))
 +                      {
 +                              this.spawnorigin = gettaginfo(this.weaponchild, idx);
 +                      }
 +                      else if ((idx = gettagindex(this, "shell")) || (idx = gettagindex(this, "tag_shell")))
 +                      {
 +                              this.spawnorigin = gettaginfo(this, idx);
 +                      }
 +                      else
 +                      {
 +                              LOG_WARNINGF("weapon model %s does not support the 'shell' tag, will display casings wrong\n",
 +                                      this.model);
 +                              this.spawnorigin = this.movedir;
 +                      }
 +              }
 +              if (v_shot_idx)
 +              {
 +                      this.oldorigin = '0 0 0';  // use regular attachment
 +              }
 +              else
 +              {
 +                      int idx;
 +                      if (this.weaponchild)
 +                              (idx = gettagindex(this, "weapon")) || (idx = gettagindex(this, "tag_weapon"));
 +                      else
 +                              (idx = gettagindex(this, "handle")) || (idx = gettagindex(this, "tag_handle"));
 +                      if (idx)
 +                      {
 +                              this.oldorigin = this.movedir - gettaginfo(this, idx);
 +                      }
 +                      else
 +                      {
 +                              LOG_WARNINGF(
 +                                      "weapon model %s does not support the 'handle' tag "
 +                                      "and neither does the v_ model support the 'shot' tag, "
 +                                      "will display muzzle flashes TOTALLY wrong\n",
 +                                      this.model);
 +                              this.oldorigin = '0 0 0';  // there is no way to recover from this
 +                      }
 +              }
 +
 +#ifdef SVQC
 +              this.viewmodelforclient = this.owner;
 +#else
 +              this.renderflags |= RF_VIEWMODEL;
 +#endif
 +      }
 +
 +      this.view_ofs = '0 0 0';
 +
 +      if (this.movedir.x >= 0)
 +      {
 +#ifdef SVQC
 +              int algn = this.owner.cvar_cl_gunalign;
 +#else
 +              int algn = autocvar_cl_gunalign;
 +#endif
 +              vector v = this.movedir;
 +              this.movedir = shotorg_adjust(v, false, false, algn);
 +              this.view_ofs = shotorg_adjust(v, false, true, algn) - v;
 +      }
 +      int compressed_shotorg = compressShotOrigin(this.movedir);
 +      // make them match perfectly
 +#ifdef SVQC
 +      this.movedir = decompressShotOrigin(this.owner.stat_shotorg = compressed_shotorg);
 +#else
 +      this.movedir = decompressShotOrigin(compressed_shotorg);
 +#endif
 +
 +      this.spawnorigin += this.view_ofs;  // offset the casings origin by the same amount
 +
 +      // check if an instant weapon switch occurred
 +      setorigin(this, this.view_ofs);
 +      // reset animstate now
 +      this.wframe = WFRAME_IDLE;
 +      setanim(this, this.anim_idle, true, false, true);
  }
- REGISTER_NET_TEMP(wframe, bool isNew)
 +#endif
 +
 +#ifndef MENUQC
 +
- REGISTER_NET_TEMP(wglow, bool isNew)
++REGISTER_NET_TEMP(wframe)
 +#ifdef CSQC
++NET_HANDLE(wframe, bool isNew)
 +{
 +      vector a;
 +      a.x = ReadCoord();
 +    a.y = ReadCoord();
 +    a.z = ReadCoord();
 +      bool restartanim = ReadByte();
 +      setanim(viewmodel, a, restartanim == false, restartanim, restartanim);
 +      viewmodel.state = ReadByte();
 +      viewmodel.alpha = ReadByte() / 255;
++      return true;
 +}
 +#endif
 +
 +#ifdef SVQC
 +void wframe_send(entity actor, entity weaponentity, vector a, bool restartanim)
 +{
 +      if (!IS_REAL_CLIENT(actor)) return;
 +      int channel = MSG_ONE;
 +      msg_entity = actor;
 +      WriteHeader(channel, wframe);
 +      WriteCoord(channel, a.x);
 +      WriteCoord(channel, a.y);
 +      WriteCoord(channel, a.z);
 +      WriteByte(channel, restartanim);
 +      WriteByte(channel, weaponentity.state);
 +      WriteByte(channel, weaponentity.alpha * 255);
 +}
 +#endif
 +
++REGISTER_NET_TEMP(wglow)
 +#ifdef CSQC
++NET_HANDLE(wglow, bool isNew)
 +{
 +      vector g = '0 0 0';
 +      g.x = ReadCoord();
 +      g.y = ReadCoord();
 +      g.z = ReadCoord();
 +      viewmodel.glowmod = g;
++      return true;
 +}
 +#endif
 +
 +#ifdef SVQC
 +void wglow_send(entity actor, vector g)
 +{
 +      if (!IS_REAL_CLIENT(actor)) return;
 +      int channel = MSG_ONE;
 +      msg_entity = actor;
 +      WriteHeader(channel, wglow);
 +      WriteCoord(channel, g.x);
 +      WriteCoord(channel, g.y);
 +      WriteCoord(channel, g.z);
 +}
 +#endif
 +
 +#endif
  
  #endif
index 9959b64dfe813ec9f4e600a07a1abac5ffde0fff,10e804b479be2c3ab761b7c839258d705a1e1eb3..76d536b4a604719db1bd665bf2be92cc46f4b38d
@@@ -133,13 -133,14 +133,14 @@@ REGISTER_WEAPON(Null, NEW(Weapon))
  #include "all.inc"
  
  // TODO: remove after 0.8.2. Retains impulse number compatibility because 0.8.1 clients don't reload the weapons.cfg
- #define WEP_HARDCODED_IMPULSES 22
+ #define WEP_HARDCODED_IMPULSES 20
  
  // TODO: invert after 0.8.2. Will require moving 'best weapon' impulses
  #define WEP_IMPULSE_BEGIN 230
  #define WEP_IMPULSE_END bound(WEP_IMPULSE_BEGIN, WEP_IMPULSE_BEGIN + (Weapons_COUNT - 1) - 1, 253)
  
- REGISTRY_SORT(Weapons, netname, WEP_HARDCODED_IMPULSES + 1)
+ REGISTRY_SORT(Weapons, WEP_HARDCODED_IMPULSES + 1)
+ REGISTRY_CHECK(Weapons)
  
  STATIC_INIT(register_weapons_done)
  {
      weaponorder_byid = strzone(substring(weaponorder_byid, 1, strlen(weaponorder_byid) - 1));
  }
  
 +#ifndef MENUQC
 +
 +.entity weaponchild;
 +.entity exteriorweaponentity;
 +.vector weaponentity_glowmod;
 +
 +//.int weapon; // current weapon
 +.int switchweapon; // weapon requested to switch to
 +.int switchingweapon; // weapon currently being switched to (is copied from switchweapon once switch is possible)
 +.string weaponname; // name of .weapon
 +
 +.vector spawnorigin; // for casings
 +
 +// weapon animation vectors:
 +.vector anim_fire1;
 +.vector anim_fire2;
 +.vector anim_idle;
 +.vector anim_reload;
 +
 +// static frame globals
 +
 +ENUMCLASS(WFRAME)
 +CASE(WFRAME, DONTCHANGE)
 +CASE(WFRAME, FIRE1)
 +CASE(WFRAME, FIRE2)
 +CASE(WFRAME, IDLE)
 +CASE(WFRAME, RELOAD)
 +ENUMCLASS_END(WFRAME)
 +
 +.WFRAME wframe;
 +
 +vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn);
 +void CL_WeaponEntity_SetModel(entity this, string name);
 +#endif
 +
  #endif
index a48765364ec187e1c3416cd80a9651945b0044b4,e7cd2606c1c4a5abbeb8ab5589a53708dc274dbb..be9788fcc7414649398387b3be54be5685c4a990
@@@ -76,18 -76,18 +76,18 @@@ void W_Rifle_FireBullet(Weapon thiswep
                SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, self);
  }
  
- void W_Rifle_Attack(void)
+ void W_Rifle_Attack()
  {
        W_Rifle_FireBullet(WEP_RIFLE, WEP_CVAR_PRI(rifle, spread), WEP_CVAR_PRI(rifle, damage), WEP_CVAR_PRI(rifle, force), WEP_CVAR_PRI(rifle, solidpenetration), WEP_CVAR_PRI(rifle, ammo), WEP_RIFLE.m_id, WEP_CVAR_PRI(rifle, tracer), WEP_CVAR_PRI(rifle, shots), SND(CAMPINGRIFLE_FIRE));
  }
  
- void W_Rifle_Attack2(void)
+ void W_Rifle_Attack2()
  {
        W_Rifle_FireBullet(WEP_RIFLE, WEP_CVAR_SEC(rifle, spread), WEP_CVAR_SEC(rifle, damage), WEP_CVAR_SEC(rifle, force), WEP_CVAR_SEC(rifle, solidpenetration), WEP_CVAR_SEC(rifle, ammo), WEP_RIFLE.m_id | HITTYPE_SECONDARY, WEP_CVAR_SEC(rifle, tracer), WEP_CVAR_SEC(rifle, shots), SND(CAMPINGRIFLE_FIRE2));
  }
  
- .void(void) rifle_bullethail_attackfunc;
+ .void() rifle_bullethail_attackfunc;
 -.float rifle_bullethail_frame;
 +.WFRAME rifle_bullethail_frame;
  .float rifle_bullethail_animtime;
  .float rifle_bullethail_refire;
  void W_Rifle_BulletHail_Continue(Weapon thiswep, entity actor, .entity weaponentity, int fire)
@@@ -99,7 -99,6 +99,6 @@@
        af = ATTACK_FINISHED(actor, slot);
        actor.switchweapon = actor.weapon;
        ATTACK_FINISHED(actor, slot) = time;
-       LOG_INFO(ftos(actor.WEP_AMMO(RIFLE)), "\n");
        r = weapon_prepareattack(thiswep, actor, weaponentity, actor.rifle_bullethail_frame == WFRAME_FIRE2, actor.rifle_bullethail_refire);
        if(actor.switchweapon == actor.weapon)
                actor.switchweapon = sw;
        {
                actor.rifle_bullethail_attackfunc();
                weapon_thinkf(actor, weaponentity, actor.rifle_bullethail_frame, actor.rifle_bullethail_animtime, W_Rifle_BulletHail_Continue);
-               LOG_INFO("thinkf set\n");
        }
        else
        {
                ATTACK_FINISHED(actor, slot) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
-               LOG_INFO("out of ammo... ", ftos(actor.(weaponentity).state), "\n");
        }
  }
  
- void W_Rifle_BulletHail(.entity weaponentity, float mode, void(void) AttackFunc, WFRAME fr, float animtime, float refire)
 -void W_Rifle_BulletHail(.entity weaponentity, float mode, void() AttackFunc, float fr, float animtime, float refire)
++void W_Rifle_BulletHail(.entity weaponentity, float mode, void() AttackFunc, WFRAME fr, float animtime, float refire)
  {SELFPARAM();
        // if we get here, we have at least one bullet to fire
        AttackFunc();
                        pointparticles(EFFECT_RIFLE_IMPACT, org2, w_backoff * 1000, 1);
                        if(!w_issilent)
                        {
-                               if(w_random < 0.2)
-                                       sound(self, CH_SHOTS, SND_RIC1, VOL_BASE, ATTN_NORM);
-                               else if(w_random < 0.4)
-                                       sound(self, CH_SHOTS, SND_RIC2, VOL_BASE, ATTN_NORM);
-                               else if(w_random < 0.5)
-                                       sound(self, CH_SHOTS, SND_RIC3, VOL_BASE, ATTN_NORM);
+                               sound(self, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTN_NORM);
                        }
                }
                METHOD(Rifle, wr_init, void(entity thiswep))
diff --combined qcsrc/lib/_all.inc
index 8a31df602cc0ffae24df86410502e3a1c3ce8f4b,cffa8f7223112bd286813b5a8d98b926b81ddcd6..a752898b43edbf86a7bc7816e06087f1bdcc3f9c
@@@ -35,7 -35,6 +35,7 @@@
  #include "cvar.qh"
  #include "defer.qh"
  #include "draw.qh"
 +#include "enumclass.qh"
  #include "file.qh"
  #include "functional.qh"
  #include "i18n.qh"
@@@ -44,6 -43,7 +44,7 @@@
  #include "lazy.qh"
  #include "linkedlist.qh"
  #include "log.qh"
+ #include "map.qc"
  #include "math.qh"
  #include "misc.qh"
  #include "net.qh"
@@@ -55,6 -55,7 +56,7 @@@
  #include "progname.qh"
  #include "random.qc"
  #include "registry.qh"
+ #include "registry_net.qh"
  #include "replicate.qh"
  #include "self.qh"
  #include "sortlist.qc"
index fdfdedfe732c9490df3fe0572e36b68039b71b58,4994c193652cd65b8266ae53c6262768bf669773..9cd8da807ee9905600faba3fd31ef394c717bf19
@@@ -50,8 -50,7 +50,7 @@@
  
  
  void send_CSQC_teamnagger() {
-       WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-       WriteByte(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
+       WriteHeader(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
  }
  
  bool ClientData_Send(entity this, entity to, int sf)
@@@ -79,7 -78,7 +78,7 @@@
        if(e.porto_v_angle_held)
                sf |= 8; // angles held
  
-       WriteByte(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
        WriteByte(MSG_ENTITY, sf);
  
        if(sf & 2)
  
  void ClientData_Attach()
  {SELFPARAM();
-       Net_LinkEntity(self.clientdata = spawn(), false, 0, ClientData_Send);
-       self.clientdata.drawonlytoclient = self;
-       self.clientdata.owner = self;
+       Net_LinkEntity(this.clientdata = new(clientdata), false, 0, ClientData_Send);
+       make_pure(this.clientdata);
+       self.clientdata.drawonlytoclient = this;
+       self.clientdata.owner = this;
  }
  
  void ClientData_Detach()
@@@ -535,7 -535,8 +535,8 @@@ void PutClientInServer(
                this.revival_time = 0;
                this.air_finished = time + 12;
  
-               entity spawnevent = spawn();
+               entity spawnevent = new(spawnevent);
+               make_pure(spawnevent);
                spawnevent.owner = this;
                Net_LinkEntity(spawnevent, false, 0.5, SpawnEvent_Send);
  
  // changes and just have a console command to update this?
  bool ClientInit_SendEntity(entity this, entity to, int sf)
  {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_INIT);
-       WriteByte(MSG_ENTITY, g_nexball_meter_period * 32);
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[0]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[1]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[2]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(hook_shotorigin[3]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[0]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[1]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[2]));
-       WriteInt24_t(MSG_ENTITY, compressShotOrigin(arc_shotorigin[3]));
+       WriteHeader(MSG_ENTITY, _ENT_CLIENT_INIT);
+       return = true;
+       msg_entity = to;
+       Registry_send_all();
+       int channel = MSG_ONE;
+       WriteHeader(channel, ENT_CLIENT_INIT);
+       WriteByte(channel, g_nexball_meter_period * 32);
+       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[0]));
+       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[1]));
+       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[2]));
+       WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[3]));
+       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[0]));
+       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[1]));
+       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[2]));
+       WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[3]));
  
        if(sv_foginterval && world.fog != "")
-               WriteString(MSG_ENTITY, world.fog);
+               WriteString(channel, world.fog);
        else
-               WriteString(MSG_ENTITY, "");
-       WriteByte(MSG_ENTITY, self.count * 255.0); // g_balance_armor_blockpercent
-       WriteCoord(MSG_ENTITY, self.bouncefactor); // g_balance_mortar_bouncefactor // WEAPONTODO
-       WriteCoord(MSG_ENTITY, self.bouncestop); // g_balance_mortar_bouncestop
-       WriteCoord(MSG_ENTITY, self.ebouncefactor); // g_balance_mortar_bouncefactor
-       WriteCoord(MSG_ENTITY, self.ebouncestop); // g_balance_mortar_bouncestop
-       WriteByte(MSG_ENTITY, WEP_CVAR(vortex, secondary)); // client has to know if it should zoom or not // WEAPONTODO
-       WriteByte(MSG_ENTITY, WEP_CVAR(rifle, secondary)); // client has to know if it should zoom or not // WEAPONTODO
-       WriteByte(MSG_ENTITY, serverflags); // client has to know if it should zoom or not
-       WriteByte(MSG_ENTITY, WEP_CVAR(minelayer, limit)); // minelayer max mines // WEAPONTODO
-       WriteByte(MSG_ENTITY, WEP_CVAR_SEC(hagar, load_max)); // hagar max loadable rockets // WEAPONTODO
-       WriteCoord(MSG_ENTITY, autocvar_g_trueaim_minrange);
-       WriteByte(MSG_ENTITY, WEP_CVAR(porto, secondary)); // WEAPONTODO
+               WriteString(channel, "");
+       WriteByte(channel, self.count * 255.0); // g_balance_armor_blockpercent
+       WriteCoord(channel, self.bouncefactor); // g_balance_mortar_bouncefactor // WEAPONTODO
+       WriteCoord(channel, self.bouncestop); // g_balance_mortar_bouncestop
+       WriteCoord(channel, self.ebouncefactor); // g_balance_mortar_bouncefactor
+       WriteCoord(channel, self.ebouncestop); // g_balance_mortar_bouncestop
+       WriteByte(channel, WEP_CVAR(vortex, secondary)); // client has to know if it should zoom or not // WEAPONTODO
+       WriteByte(channel, WEP_CVAR(rifle, secondary)); // client has to know if it should zoom or not // WEAPONTODO
+       WriteByte(channel, serverflags); // client has to know if it should zoom or not
+       WriteByte(channel, WEP_CVAR(minelayer, limit)); // minelayer max mines // WEAPONTODO
+       WriteByte(channel, WEP_CVAR_SEC(hagar, load_max)); // hagar max loadable rockets // WEAPONTODO
+       WriteCoord(channel, autocvar_g_trueaim_minrange);
+       WriteByte(channel, WEP_CVAR(porto, secondary)); // WEAPONTODO
  
        MUTATOR_CALLHOOK(Ent_Init);
-       return true;
  }
  
  void ClientInit_CheckUpdate()
  
  void ClientInit_Spawn()
  {SELFPARAM();
-       entity e = spawn();
-       e.classname = "clientinit";
+       entity e = new(clientinit);
+       make_pure(e);
        e.think = ClientInit_CheckUpdate;
        Net_LinkEntity(e, false, 0, ClientInit_SendEntity);
  
  SetNewParms
  =============
  */
- void SetNewParms (void)
+ void SetNewParms ()
  {
        // initialize parms for a new player
        parm1 = -(86400 * 366);
  SetChangeParms
  =============
  */
- void SetChangeParms (void)
+ void SetChangeParms ()
  {SELFPARAM();
        // save parms for level change
        parm1 = self.parm_idlesince - time;
  DecodeLevelParms
  =============
  */
- void DecodeLevelParms (void)
+ void DecodeLevelParms ()
  {SELFPARAM();
        // load parms
        self.parm_idlesince = parm1;
@@@ -935,7 -941,7 +941,7 @@@ void ClientKill_TeamChange (float targe
  
  }
  
- void ClientKill (void)
+ void ClientKill ()
  {SELFPARAM();
        if(gameover) return;
        if(self.player_blocked) return;
@@@ -983,7 -989,7 +989,7 @@@ ClientPreConnec
  Called once (not at each match start) when a client begins a connection to the server
  =============
  */
- void ClientPreConnect (void)
+ void ClientPreConnect ()
  {SELFPARAM();
        if(autocvar_sv_eventlog)
        {
@@@ -1003,8 -1009,8 +1009,8 @@@ ClientConnec
  Called when a client connects to the server
  =============
  */
- void DecodeLevelParms (void);
- void ClientConnect (void)
+ void DecodeLevelParms ();
+ void ClientConnect ()
  {SELFPARAM();
        float t;
  
@@@ -1222,7 -1228,7 +1228,7 @@@ Called when a client disconnects from t
  */
  .entity chatbubbleentity;
  void ReadyCount();
- void ClientDisconnect (void)
+ void ClientDisconnect ()
  {SELFPARAM();
        if(self.vehicle)
            vehicles_exit(VHEF_RELEASE);
@@@ -1338,7 -1344,7 +1344,7 @@@ void UpdateChatBubble(
        // spawn a chatbubble entity if needed
        if (!self.chatbubbleentity)
        {
-               self.chatbubbleentity = spawn();
+               self.chatbubbleentity = new(chatbubbleentity);
                self.chatbubbleentity.owner = self;
                self.chatbubbleentity.exteriormodeltoclient = self;
                self.chatbubbleentity.think = ChatBubbleThink;
        else self.colormod = '1 1 1';
  }*/
  
- void respawn(void)
+ void respawn()
  {SELFPARAM();
        if(self.alpha >= 0 && autocvar_g_respawn_ghosts)
        {
@@@ -1399,7 -1405,7 +1405,7 @@@ void play_countdown(float finished, str
                                _sound (self, CH_INFO, samp, VOL_BASE, ATTEN_NORM);
  }
  
- void player_powerups (void)
+ void player_powerups ()
  {SELFPARAM();
        // add a way to see what the items were BEFORE all of these checks for the mutator hook
        int items_prev = self.items;
@@@ -1562,7 -1568,7 +1568,7 @@@ float CalcRotRegen(float current, floa
        return current;
  }
  
- void player_regen (void)
+ void player_regen ()
  {SELFPARAM();
        float max_mod, regen_mod, rot_mod, limit_mod;
        max_mod = regen_mod = rot_mod = limit_mod = 1;
@@@ -1633,19 -1639,20 +1639,20 @@@ void SetZoomState(float z
  }
  
  void GetPressedKeys()
- {SELFPARAM();
+ {
+       SELFPARAM();
        MUTATOR_CALLHOOK(GetPressedKeys);
-       #define X(var,bit,flag) (flag ? var |= bit : var &= ~bit)
-       X(self.pressedkeys, KEY_FORWARD,        self.movement_x > 0);
-       X(self.pressedkeys, KEY_BACKWARD,       self.movement_x < 0);
-       X(self.pressedkeys, KEY_RIGHT,          self.movement_y > 0);
-       X(self.pressedkeys, KEY_LEFT,           self.movement_y < 0);
-       X(self.pressedkeys, KEY_JUMP,           PHYS_INPUT_BUTTON_JUMP(self));
-       X(self.pressedkeys, KEY_CROUCH,         PHYS_INPUT_BUTTON_CROUCH(self));
-       X(self.pressedkeys, KEY_ATCK,           PHYS_INPUT_BUTTON_ATCK(self));
-       X(self.pressedkeys, KEY_ATCK2,          PHYS_INPUT_BUTTON_ATCK2(self));
-       #undef X
+       int keys = this.pressedkeys;
+       keys = BITSET(keys, KEY_FORWARD,        this.movement.x > 0);
+       keys = BITSET(keys, KEY_BACKWARD,       this.movement.x < 0);
+       keys = BITSET(keys, KEY_RIGHT,          this.movement.y > 0);
+       keys = BITSET(keys, KEY_LEFT,           this.movement.y < 0);
+       keys = BITSET(keys, KEY_JUMP,           PHYS_INPUT_BUTTON_JUMP(this));
+       keys = BITSET(keys, KEY_CROUCH,         PHYS_INPUT_BUTTON_CROUCH(this));
+       keys = BITSET(keys, KEY_ATCK,           PHYS_INPUT_BUTTON_ATCK(this));
+       keys = BITSET(keys, KEY_ATCK2,          PHYS_INPUT_BUTTON_ATCK2(this));
+       this.pressedkeys = keys;
  }
  
  /*
@@@ -1680,7 -1687,6 +1687,7 @@@ void SpectateCopy(entity spectatee
        self.switchweapon = spectatee.switchweapon;
        self.switchingweapon = spectatee.switchingweapon;
        self.weapon = spectatee.weapon;
 +      self.weapon_nextthink = spectatee.weapon_nextthink;
        self.vortex_charge = spectatee.vortex_charge;
        self.vortex_chargepool_ammo = spectatee.vortex_chargepool_ammo;
        self.hagar_load = spectatee.hagar_load;
@@@ -1870,7 -1876,6 +1877,6 @@@ void LeaveSpectatorMode(
                if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0)
                {
                        self.classname = STR_PLAYER;
-                       nades_RemoveBonus(self);
  
                        if(autocvar_g_campaign || autocvar_g_balance_teams)
                                { JoinBestTeam(self, false, true); }
@@@ -2138,35 -2143,7 +2144,9 @@@ void PlayerUseKey(
        MUTATOR_CALLHOOK(PlayerUseKey);
  }
  
- float isInvisibleString(string s)
- {
-       float i, n, c;
-       s = strdecolorize(s);
-       for((i = 0), (n = strlen(s)); i < n; ++i)
-       {
-               c = str2chr(s, i);
-               switch(c)
-               {
-                       case 0:
-                       case 32: // space
-                               break;
-                       case 192: // charmap space
-                               if (!autocvar_utf8_enable)
-                                       break;
-                               return false;
-                       case 160: // space in unicode fonts
-                       case 0xE000 + 192: // utf8 charmap space
-                               if (autocvar_utf8_enable)
-                                       break;
-                       default:
-                               return false;
-               }
-       }
-       return true;
- }
  
 +void wglow_send(entity actor, vector g);
 +
  /*
  =============
  PlayerPreThink
@@@ -2178,7 -2155,7 +2158,7 @@@ Called every frame for each client befo
  void() nexball_setstatus;
  .float last_vehiclecheck;
  .int items_added;
- void PlayerPreThink (void)
+ void PlayerPreThink ()
  {SELFPARAM();
        WarpZone_PlayerPhysics_FixVAngle();
  
  
                if(frametime)
                {
 -                      if(self.weapon == WEP_VORTEX.m_id && WEP_CVAR(vortex, charge))
 +                      vector g;
 +                      if (IS_SPEC(self))
 +                      {
 +                              g = self.enemy.weaponentity_glowmod;
 +                      }
 +                      else if(self.weapon == WEP_VORTEX.m_id && WEP_CVAR(vortex, charge))
                        {
 -                              self.weaponentity_glowmod_x = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_half * min(1, self.vortex_charge / WEP_CVAR(vortex, charge_animlimit));
 -                              self.weaponentity_glowmod_y = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_half * min(1, self.vortex_charge / WEP_CVAR(vortex, charge_animlimit));
 -                              self.weaponentity_glowmod_z = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_half * min(1, self.vortex_charge / WEP_CVAR(vortex, charge_animlimit));
 +                              g.x = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_half * min(1, self.vortex_charge / WEP_CVAR(vortex, charge_animlimit));
 +                              g.y = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_half * min(1, self.vortex_charge / WEP_CVAR(vortex, charge_animlimit));
 +                              g.z = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_half * min(1, self.vortex_charge / WEP_CVAR(vortex, charge_animlimit));
  
                                if(self.vortex_charge > WEP_CVAR(vortex, charge_animlimit))
                                {
 -                                      self.weaponentity_glowmod_x = self.weaponentity_glowmod.x + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_full * (self.vortex_charge - WEP_CVAR(vortex, charge_animlimit)) / (1 - WEP_CVAR(vortex, charge_animlimit));
 -                                      self.weaponentity_glowmod_y = self.weaponentity_glowmod.y + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_full * (self.vortex_charge - WEP_CVAR(vortex, charge_animlimit)) / (1 - WEP_CVAR(vortex, charge_animlimit));
 -                                      self.weaponentity_glowmod_z = self.weaponentity_glowmod.z + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_full * (self.vortex_charge - WEP_CVAR(vortex, charge_animlimit)) / (1 - WEP_CVAR(vortex, charge_animlimit));
 +                                      g.x += autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_full * (self.vortex_charge - WEP_CVAR(vortex, charge_animlimit)) / (1 - WEP_CVAR(vortex, charge_animlimit));
 +                                      g.y += autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_full * (self.vortex_charge - WEP_CVAR(vortex, charge_animlimit)) / (1 - WEP_CVAR(vortex, charge_animlimit));
 +                                      g.z += autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_full * (self.vortex_charge - WEP_CVAR(vortex, charge_animlimit)) / (1 - WEP_CVAR(vortex, charge_animlimit));
                                }
                        }
                        else
 -                              self.weaponentity_glowmod = colormapPaletteColor(self.clientcolors & 0x0F, true) * 2;
 -
 +                              g = colormapPaletteColor(self.clientcolors & 0x0F, true) * 2;
 +                      if (g != self.weaponentity_glowmod)
 +                              wglow_send(self, self.weaponentity_glowmod = g);
                        player_powerups();
                }
  
                // WEAPONTODO: THIS SHIT NEEDS TO GO EVENTUALLY
                // It cannot be predicted by the engine!
                .entity weaponentity = weaponentities[0]; // TODO: unhardcode
-               if((self.weapon == WEP_SHOCKWAVE.m_id || self.weapon == WEP_SHOTGUN.m_id) && self.(weaponentity).wframe == WFRAME_FIRE2 && time < self.weapon_nextthink)
+               if((self.weapon == WEP_SHOCKWAVE.m_id || self.weapon == WEP_SHOTGUN.m_id) && self.(weaponentity).wframe == WFRAME_FIRE2 && time < self.(weaponentity).weapon_nextthink)
                        do_crouch = 0;
  
                if (do_crouch)
@@@ -2573,7 -2544,7 +2553,7 @@@ Called every frame for each client afte
  =============
  */
  .float idlekick_lasttimeleft;
- void PlayerPostThink (void)
+ void PlayerPostThink ()
  {SELFPARAM();
        if(sv_maxidle > 0 && frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
        if(IS_REAL_CLIENT(self))
index cb99c022b90339497849a80691e3704fe0753f5b,84e905e85fea28e858763e3932a21bc2c09ad2d7..bacb6bcb9e4c5c95cb044333a4056bcbc8e5d22f
@@@ -4,13 -4,11 +4,12 @@@
  #include "cheats.qh"
  #include "g_damage.qh"
  #include "g_subs.qh"
- #include "g_violence.qh"
  #include "miscfunctions.qh"
  #include "portals.qh"
  #include "teamplay.qh"
  #include "weapons/throwing.qh"
  #include "command/common.qh"
 +#include "../common/anim.qh"
  #include "../common/animdecide.qh"
  #include "../common/csqcmodel_settings.qh"
  #include "../common/deathtypes/all.qh"
@@@ -35,7 -33,7 +34,7 @@@ void Drop_Special_Items(entity player
        MUTATOR_CALLHOOK(DropSpecialItems, player);
  }
  
- void CopyBody_Think(void)
+ void CopyBody_Think()
  {SELFPARAM();
        if(self.CopyBody_nextthink && time > self.CopyBody_nextthink)
        {
@@@ -53,7 -51,7 +52,7 @@@ void CopyBody(float keepvelocity
  {SELFPARAM();
        if (self.effects & EF_NODRAW)
                return;
-       setself(spawn());
+       setself(new(body));
        self.enemy = this;
        self.lip = this.lip;
        self.colormap = this.colormap;
@@@ -63,7 -61,6 +62,6 @@@
        self.angles = this.angles;
        self.v_angle = this.v_angle;
        self.avelocity = this.avelocity;
-       self.classname = "body";
        self.damageforcescale = this.damageforcescale;
        self.effects = this.effects;
        self.glowmod = this.glowmod;
@@@ -144,7 -141,7 +142,7 @@@ void player_setupanimsformodel(
        animdecide_setstate(self, 0, false);
  }
  
- void player_anim (void)
+ void player_anim ()
  {SELFPARAM();
        int deadbits = (self.anim_state & (ANIMSTATE_DEAD1 | ANIMSTATE_DEAD2));
        if(self.deadflag) {
                animbits |= ANIMSTATE_DUCK;
        animdecide_setstate(self, animbits, false);
        animdecide_setimplicitstate(self, (self.flags & FL_ONGROUND));
 -
 -      .entity weaponentity = weaponentities[0]; // TODO: unhardcode
 -      {
 -              if (self.(weaponentity))
 -              {
 -                      updateanim(self.(weaponentity));
 -                      if (!self.(weaponentity).animstate_override)
 -                              setanim(self.(weaponentity), self.(weaponentity).anim_idle, true, false, false);
 -              }
 -      }
  }
  
  void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
diff --combined qcsrc/server/defs.qh
index 4e8188dfd017deab11e20ab4f5b5a5f074568c65,2027b70f172f5f23cf5607258af86b12cb4d8a02..0fc8381ace8e73b6c054df6fd60f156179101667
@@@ -20,7 -20,7 +20,7 @@@
  
  // Globals
  
- float g_cloaked, g_footsteps, g_grappling_hook, g_instagib;
+ float g_footsteps, g_grappling_hook, g_instagib;
  float g_warmup_limit;
  float g_warmup_allguns;
  float g_warmup_allow_timeout;
@@@ -92,7 -92,14 +92,7 @@@ float server_is_dedicated
  .float fade_time;
  .float fade_rate;
  
 -// weapon animation vectors:
 -.vector anim_fire1;
 -.vector anim_fire2;
 -.vector anim_idle;
 -.vector anim_reload;
 -
  void() player_setupanimsformodel;
 -void setanim(entity e, vector anim, float looping, float override, float restart);
  
  .string mdl;
  
@@@ -143,6 -150,16 +143,6 @@@ const float MAX_DAMAGEEXTRARADIUS = 16
  .entity item_pickupsound_ent;
  .entity item_model_ent;
  
 -// definitions for weaponsystem
 -// more WEAPONTODO: move these to their proper files
 -.entity exteriorweaponentity;
 -.vector weaponentity_glowmod;
 -
 -//.int weapon; // current weapon
 -.int switchweapon; // weapon requested to switch to
 -.int switchingweapon; // weapon currently being switched to (is copied from switchweapon once switch is possible)
 -.string weaponname; // name of .weapon
 -
  // WEAPONTODO
  .float autoswitch;
  float client_hasweapon(entity cl, float wpn, float andammo, float complain);
@@@ -153,6 -170,13 +153,6 @@@ void w_ready(Weapon thiswep, entity act
  .void(Weapon thiswep, entity actor, .entity weaponentity, int fire) weapon_think;
  
  
 -// weapon states (self.weaponentity.state)
 -const int WS_CLEAR                    = 0; // no weapon selected
 -const int WS_RAISE                    = 1; // raise frame
 -const int WS_DROP                             = 2; // deselecting frame
 -const int WS_INUSE                    = 3; // fire state
 -const int WS_READY                    = 4; // idle frame
 -
  // there is 2 weapon tics that can run in one server frame
  const int W_TICSPERFRAME = 2;
  
@@@ -189,6 -213,8 +189,6 @@@ float nJoinAllowed(entity ignore)
  float playerid_last;
  .float noalign;               // if set to 1, the item or spawnpoint won't be dropped to the floor
  
 -.vector spawnorigin;
 -
  .vector death_origin;
  .vector killer_origin;
  
diff --combined qcsrc/server/g_subs.qc
index f3e8d4b1f855fca94c842781205121c67858323d,f2e3da898645ddfb755f0bd852e7a077988efa94..f7dcf3073a114b4dbf7078bc9e71cd7f0853c925
@@@ -11,6 -11,50 +11,6 @@@ spawnfunc(info_null
        // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
  }
  
 -void setanim(entity e, vector anim, float looping, float override, float restart)
 -{
 -      if (!anim)
 -              return; // no animation was given to us! We can't use this.
 -
 -      if (anim.x == e.animstate_startframe)
 -      if (anim.y == e.animstate_numframes)
 -      if (anim.z == e.animstate_framerate)
 -      {
 -              if(restart)
 -              {
 -                      if(restart > 0)
 -                      if(anim.y == 1) // ZYM animation
 -                              BITXOR_ASSIGN(e.effects, EF_RESTARTANIM_BIT);
 -              }
 -              else
 -                      return;
 -      }
 -      e.animstate_startframe = anim.x;
 -      e.animstate_numframes = anim.y;
 -      e.animstate_framerate = anim.z;
 -      e.animstate_starttime = servertime - 0.1 * serverframetime; // shift it a little bit into the past to prevent float inaccuracy hiccups
 -      e.animstate_endtime = e.animstate_starttime + e.animstate_numframes / e.animstate_framerate;
 -      e.animstate_looping = looping;
 -      e.animstate_override = override;
 -      e.frame = e.animstate_startframe;
 -      e.frame1time = servertime;
 -}
 -
 -void updateanim(entity e)
 -{
 -      if (time >= e.animstate_endtime)
 -      {
 -              if (e.animstate_looping)
 -              {
 -                      e.animstate_starttime = e.animstate_endtime;
 -                      e.animstate_endtime = e.animstate_starttime + e.animstate_numframes / e.animstate_framerate;
 -              }
 -              e.animstate_override = false;
 -      }
 -      e.frame = e.animstate_startframe + bound(0, (time - e.animstate_starttime) * e.animstate_framerate, e.animstate_numframes - 1);
 -      //print(ftos(time), " -> ", ftos(e.frame), "\n");
 -}
 -
  /*
  ==================
  main
@@@ -18,7 -62,7 +18,7 @@@
  unused but required by the engine
  ==================
  */
- void main (void)
+ void main ()
  {
  
  }
diff --combined qcsrc/server/g_subs.qh
index 3b9447c3e70134f3a2997cd2ffe71b310270dbd1,a50885a7fe45f34208b8c7eea2f57d3382cfa10e..24cbe917e4ac428b3cf54bf7e7ef29e2e663578d
@@@ -1,7 -1,7 +1,7 @@@
  #ifndef G_SUBS_H
  #define G_SUBS_H
  
- void SUB_NullThink(void);
+ void SUB_NullThink();
  
  void()  SUB_CalcMoveDone;
  void() SUB_CalcAngleMoveDone;
@@@ -10,6 -10,10 +10,6 @@@ void() SUB_Remove
  
  spawnfunc(info_null);
  
 -void setanim(entity e, vector anim, float looping, float override, float restart);
 -
 -void updateanim(entity e);
 -
  /*
  ==================
  SUB_Remove
@@@ -17,7 -21,7 +17,7 @@@
  Remove self
  ==================
  */
- void SUB_Remove (void);
+ void SUB_Remove ();
  
  /*
  ==================
@@@ -27,7 -31,7 +27,7 @@@ Applies some friction to sel
  ==================
  */
  .float friction;
- void SUB_Friction (void);
+ void SUB_Friction ();
  
  /*
  ==================
@@@ -38,7 -42,7 +38,7 @@@ Makes client invisible or removes non-c
  */
  void SUB_VanishOrRemove (entity ent);
  
- void SUB_SetFade_Think (void);
+ void SUB_SetFade_Think ();
  
  /*
  ==================
@@@ -57,10 -61,10 +57,10 @@@ calculate self.velocity and self.nextth
  self.origin traveling at speed
  ===============
  */
- void SUB_CalcMoveDone (void);
+ void SUB_CalcMoveDone ();
  
  .float platmovetype_turn;
- void SUB_CalcMove_controller_think (void);
+ void SUB_CalcMove_controller_think ();
  
  void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector dest);
  
@@@ -82,7 -86,7 +82,7 @@@ self.angles rotatin
  The calling function should make sure self.think is valid
  ===============
  */
- void SUB_CalcAngleMoveDone (void);
+ void SUB_CalcAngleMoveDone ();
  
  // FIXME: I fixed this function only for rotation around the main axes
  void SUB_CalcAngleMove (vector destangle, float tspeedtype, float tspeed, void() func);
@@@ -96,7 -100,7 +96,7 @@@ mai
  unused but required by the engine
  ==================
  */
- void main (void);
+ void main ();
  
  // Misc
  
diff --combined qcsrc/server/g_world.qc
index 79afb490df58c1bad588548f5866e566cd125511,aea8b4876a94eedef66e8c580a8cdb47525716c9..f8c1e15256c3cada6d91cdd0c42bc3dd92cce79e
@@@ -54,8 -54,7 +54,7 @@@ void PingPLReport_Think(
        e = edict_num(self.cnt + 1);
        if(IS_REAL_CLIENT(e))
        {
-               WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-               WriteByte(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
+               WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
                WriteByte(MSG_BROADCAST, self.cnt);
                WriteShort(MSG_BROADCAST, max(1, e.ping));
                WriteByte(MSG_BROADCAST, ceil(e.ping_packetloss * 255));
@@@ -72,8 -71,7 +71,7 @@@
        }
        else
        {
-               WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-               WriteByte(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
+               WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
                WriteByte(MSG_BROADCAST, self.cnt);
                WriteShort(MSG_BROADCAST, 0);
                WriteByte(MSG_BROADCAST, 0);
@@@ -83,8 -81,8 +81,8 @@@
  }
  void PingPLReport_Spawn()
  {
-       pingplreport = spawn();
-       pingplreport.classname = "pingplreport";
+       pingplreport = new(pingplreport);
+       make_pure(pingplreport);
        pingplreport.think = PingPLReport_Think;
        pingplreport.nextthink = time;
  }
@@@ -98,17 -96,7 +96,7 @@@ void ShuffleMaplist()
  
  void SetDefaultAlpha()
  {
-       if(autocvar_g_running_guns)
-       {
-               default_player_alpha = -1;
-               default_weapon_alpha = +1;
-       }
-       else if(g_cloaked)
-       {
-               default_player_alpha = autocvar_g_balance_cloaked_alpha;
-               default_weapon_alpha = default_player_alpha;
-       }
-       else
+       if (!MUTATOR_CALLHOOK(SetDefaultAlpha))
        {
                default_player_alpha = autocvar_g_player_alpha;
                if(default_player_alpha == 0)
@@@ -515,7 -503,7 +503,7 @@@ void detect_maptype(
  entity randomseed;
  bool RandomSeed_Send(entity this, entity to, int sf)
  {
-       WriteByte(MSG_ENTITY, ENT_CLIENT_RANDOMSEED);
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_RANDOMSEED);
        WriteShort(MSG_ENTITY, self.cnt);
        return true;
  }
@@@ -528,7 -516,8 +516,8 @@@ void RandomSeed_Think(
  }
  void RandomSeed_Spawn()
  {SELFPARAM();
-       randomseed = spawn();
+       randomseed = new(randomseed);
+       make_pure(randomseed);
        randomseed.think = RandomSeed_Think;
        Net_LinkEntity(randomseed, false, 0, RandomSeed_Send);
  
@@@ -546,13 -535,11 +535,11 @@@ spawnfunc(__init_dedicated_server
  
        remove = remove_unsafely;
  
-       entity e;
-       e = spawn();
+       entity e = spawn();
        e.think = GotoFirstMap;
        e.nextthink = time; // this is usually 1 at this point
  
-       e = spawn();
-       e.classname = "info_player_deathmatch"; // safeguard against player joining
+       e = new(info_player_deathmatch);  // safeguard against player joining
  
        self.classname = "worldspawn"; // safeguard against various stuff ;)
  
@@@ -772,7 -759,6 +759,7 @@@ spawnfunc(worldspawn
        WepSet_AddStat_InMap();
        addstat(STAT_SWITCHWEAPON, AS_INT, switchweapon);
        addstat(STAT_SWITCHINGWEAPON, AS_INT, switchingweapon);
 +      addstat(STAT_WEAPON_NEXTTHINK, AS_FLOAT, weapon_nextthink);
        addstat(STAT_GAMESTARTTIME, AS_FLOAT, stat_game_starttime);
        addstat(STAT_ROUNDSTARTTIME, AS_FLOAT, stat_round_starttime);
        addstat(STAT_ALLOW_OLDVORTEXBEAM, AS_INT, stat_allow_oldvortexbeam);
@@@ -1494,8 -1480,8 +1481,8 @@@ void FixIntermissionClient(entity e
                        if(e.(weaponentity))
                        {
                                e.(weaponentity).effects = EF_NODRAW;
 -                              if (e.(weaponentity).(weaponentity))
 -                                      e.(weaponentity).(weaponentity).effects = EF_NODRAW;
 +                              if (e.(weaponentity).weaponchild)
 +                                      e.(weaponentity).weaponchild.effects = EF_NODRAW;
                        }
                }
                if(IS_REAL_CLIENT(e))
@@@ -1664,7 -1650,7 +1651,7 @@@ void AddWinners(.float field, float val
  }
  
  // clear the .winning flags
- void ClearWinners(void)
+ void ClearWinners()
  {
        entity head;
        FOR_EACH_PLAYER(head)
diff --combined qcsrc/server/progs.inc
index 6ff405fabf2eed8d9908656225223229a82183e1,6ab895f21f9cd7936f78869e630d70b8b1a9f3b9..d83234e906252eadb70ab9eb26b4f3afb0203639
@@@ -1,6 -1,8 +1,8 @@@
  #include "../lib/_all.inc"
  #include "_all.qh"
  
+ #include "../common/effects/qc/all.qc"
  #include "anticheat.qc"
  #include "antilag.qc"
  #include "campaign.qc"
  #include "cl_client.qc"
  #include "cl_impulse.qc"
  #include "cl_player.qc"
- #include "controlpoint.qc"
- #include "csqceffects.qc"
  #include "ent_cs.qc"
  #include "g_damage.qc"
  #include "g_hook.qc"
  // #include "g_lights.qc" // TODO: was never used
  #include "g_models.qc"
  #include "g_subs.qc"
- #include "g_violence.qc"
  #include "g_world.qc"
- #include "generator.qc"
  #include "ipban.qc"
  #include "item_key.qc"
  #include "mapvoting.qc"
@@@ -43,8 -41,6 +41,6 @@@
  
  #include "command/all.qc"
  
- #include "mutators/all.qc"
  #include "pathlib/_all.inc"
  
  #include "weapons/accuracy.qc"
  #include "weapons/weaponstats.qc"
  #include "weapons/weaponsystem.qc"
  
 +#include "../common/anim.qc"
  #include "../common/animdecide.qc"
  #include "../common/campaign_file.qc"
  #include "../common/campaign_setup.qc"
  #include "../common/effects/effectinfo.qc"
  #include "../common/mapinfo.qc"
- #include "../common/monsters/spawn.qc"
- #include "../common/monsters/sv_monsters.qc"
  #include "../common/minigames/minigames.qc"
  #include "../common/minigames/sv_minigames.qc"
+ #include "../common/monsters/spawn.qc"
+ #include "../common/monsters/sv_monsters.qc"
  #include "../common/movetypes/include.qc"
  #include "../common/net_notice.qc"
  #include "../common/notifications.qc"
  #include "../common/physics.qc"
  #include "../common/playerstats.qc"
- #include "../common/viewloc.qc"
  #include "../common/triggers/include.qc"
  #include "../common/util.qc"
+ #include "../common/viewloc.qc"
  
  #include "../common/deathtypes/all.qc"
  #include "../common/buffs/all.qc"
  #include "../common/gamemodes/all.qc"
  #include "../common/items/all.qc"
  #include "../common/monsters/all.qc"
- #include "../common/mutators/all.qc"
  #include "../common/nades/all.qc"
  #include "../common/turrets/all.qc"
  #include "../common/vehicles/all.qc"
  #include "../common/weapons/all.qc"
+ #include "../common/mutators/all.qc"
+ #include "mutators/all.qc"
  
  #include "../common/turrets/sv_turrets.qc"
  #include "../common/turrets/config.qc"
index 9c09025074a0a60189587d4078308ea67924a1f6,3ea45ad46814ca7dfcc306288048b41cded229fb..930bb9065cff943e92ea5749c41f6d86594bcae4
  #include "../../common/weapons/all.qh"
  #include "../../lib/csqcmodel/sv_model.qh"
  
 -vector shotorg_adjustfromclient(vector vecs, float y_is_right, float algn)
 -{
 -      switch (algn)
 -      {
 -              default: case 3: break; // right alignment
 -              case 4: vecs.y = -vecs.y;
 -                      break;              // left
 -              case 1: case 2: vecs.y = 0;
 -                      vecs.z -= 2;
 -                      break;              // center
 -      }
 -
 -      return vecs;
 -}
 -
 -vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn)
 -{
 -      string s;
 -
 -      if (visual)
 -      {
 -              vecs = shotorg_adjustfromclient(vecs, y_is_right, algn);
 -      }
 -      else if (autocvar_g_shootfromeye)
 -      {
 -              vecs.y = vecs.z = 0;
 -      }
 -      else if (autocvar_g_shootfromcenter)
 -      {
 -              vecs.y = 0;
 -              vecs.z -= 2;
 -      }
 -      else if ((s = autocvar_g_shootfromfixedorigin) != "")
 -      {
 -              vector v = stov(s);
 -              if (y_is_right) v.y = -v.y;
 -              if (v.x != 0) vecs.x = v.x;
 -              vecs.y = v.y;
 -              vecs.z = v.z;
 -      }
 -      else  // just do the same as top
 -      {
 -              vecs = shotorg_adjustfromclient(vecs, y_is_right, algn);
 -      }
 -
 -      return vecs;
 -}
 -
 -vector shotorg_adjust(vector vecs, bool y_is_right, bool visual, int algn)
 -{
 -      return shotorg_adjust_values(vecs, y_is_right, visual, algn);
 -}
 -
  .int state;
  
  .float weapon_frametime;
@@@ -39,6 -92,9 +39,6 @@@ float W_WeaponSpeedFactor(
  }
  
  
 -void weapon_thinkf(entity actor, .entity weaponentity, float fr, float t, void(Weapon thiswep, entity actor,
 -    .entity weaponentity, int fire) func);
 -
  bool CL_Weaponentity_CustomizeEntityForClient()
  {
        SELFPARAM();
        return true;
  }
  
 -/*
 - * supported formats:
 - *
 - * 1. simple animated model, muzzle flash handling on h_ model:
 - *    h_tuba.dpm, h_tuba.dpm.framegroups - invisible model controlling the animation
 - *      tags:
 - *        shot = muzzle end (shot origin, also used for muzzle flashes)
 - *        shell = casings ejection point (must be on the right hand side of the gun)
 - *        weapon = attachment for v_tuba.md3
 - *    v_tuba.md3 - first and third person model
 - *    g_tuba.md3 - pickup model
 - *
 - * 2. simple animated model, muzzle flash handling on v_ model:
 - *    h_tuba.dpm, h_tuba.dpm.framegroups - invisible model controlling the animation
 - *      tags:
 - *        weapon = attachment for v_tuba.md3
 - *    v_tuba.md3 - first and third person model
 - *      tags:
 - *        shot = muzzle end (shot origin, also used for muzzle flashes)
 - *        shell = casings ejection point (must be on the right hand side of the gun)
 - *    g_tuba.md3 - pickup model
 - *
 - * 3. fully animated model, muzzle flash handling on h_ model:
 - *    h_tuba.dpm, h_tuba.dpm.framegroups - animated first person model
 - *      tags:
 - *        shot = muzzle end (shot origin, also used for muzzle flashes)
 - *        shell = casings ejection point (must be on the right hand side of the gun)
 - *        handle = corresponding to the origin of v_tuba.md3 (used for muzzle flashes)
 - *    v_tuba.md3 - third person model
 - *    g_tuba.md3 - pickup model
 - *
 - * 4. fully animated model, muzzle flash handling on v_ model:
 - *    h_tuba.dpm, h_tuba.dpm.framegroups - animated first person model
 - *      tags:
 - *        shot = muzzle end (shot origin)
 - *        shell = casings ejection point (must be on the right hand side of the gun)
 - *    v_tuba.md3 - third person model
 - *      tags:
 - *        shot = muzzle end (for muzzle flashes)
 - *    g_tuba.md3 - pickup model
 - */
 -
 -// writes:
 -//   this.origin, this.angles
 -//   this.weaponentity
 -//   this.movedir, this.view_ofs
 -//   attachment stuff
 -//   anim stuff
 -// to free:
 -//   call again with ""
 -//   remove the ent
 -void CL_WeaponEntity_SetModel(entity this, .entity weaponentity, string name)
 -{
 -      if (name != "")
 -      {
 -              // if there is a child entity, hide it until we're sure we use it
 -              if (this.(weaponentity)) this.(weaponentity).model = "";
 -              _setmodel(this, W_Model(strcat("v_", name, ".md3")));
 -              int v_shot_idx = gettagindex(this, "shot");  // used later
 -              if (!v_shot_idx) v_shot_idx = gettagindex(this, "tag_shot");
 -
 -              _setmodel(this, W_Model(strcat("h_", name, ".iqm")));
 -              // preset some defaults that work great for renamed zym files (which don't need an animinfo)
 -              this.anim_fire1  = animfixfps(this, '0 1 0.01', '0 0 0');
 -              this.anim_fire2  = animfixfps(this, '1 1 0.01', '0 0 0');
 -              this.anim_idle   = animfixfps(this, '2 1 0.01', '0 0 0');
 -              this.anim_reload = animfixfps(this, '3 1 0.01', '0 0 0');
 -
 -              // 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(this, "weapon"))
 -              {
 -                      if (!this.(weaponentity)) this.(weaponentity) = new(weaponentity);
 -                      _setmodel(this.(weaponentity), W_Model(strcat("v_", name, ".md3")));
 -                      setattachment(this.(weaponentity), this, "weapon");
 -              }
 -              else if (gettagindex(this, "tag_weapon"))
 -              {
 -                      if (!this.(weaponentity)) this.(weaponentity) = new(weaponentity);
 -                      _setmodel(this.(weaponentity), W_Model(strcat("v_", name, ".md3")));
 -                      setattachment(this.(weaponentity), this, "tag_weapon");
 -              }
 -              else
 -              {
 -                      if (this.(weaponentity)) remove(this.(weaponentity));
 -                      this.(weaponentity) = NULL;
 -              }
 -
 -              setorigin(this, '0 0 0');
 -              this.angles = '0 0 0';
 -              this.frame = 0;
 -              this.viewmodelforclient = NULL;
 -
 -              float idx;
 -
 -              if (v_shot_idx)  // v_ model attached to invisible h_ model
 -              {
 -                      this.movedir = gettaginfo(this.(weaponentity), v_shot_idx);
 -              }
 -              else
 -              {
 -                      idx = gettagindex(this, "shot");
 -                      if (!idx) idx = gettagindex(this, "tag_shot");
 -                      if (idx)
 -                      {
 -                              this.movedir = gettaginfo(this, idx);
 -                      }
 -                      else
 -                      {
 -                              LOG_INFO("WARNING: weapon model ", this.model,
 -                                      " does not support the 'shot' tag, will display shots TOTALLY wrong\n");
 -                              this.movedir = '0 0 0';
 -                      }
 -              }
 -
 -              if (this.(weaponentity))  // v_ model attached to invisible h_ model
 -              {
 -                      idx = gettagindex(this.(weaponentity), "shell");
 -                      if (!idx) idx = gettagindex(this.(weaponentity), "tag_shell");
 -                      if (idx) this.spawnorigin = gettaginfo(this.(weaponentity), idx);
 -              }
 -              else
 -              {
 -                      idx = 0;
 -              }
 -              if (!idx)
 -              {
 -                      idx = gettagindex(this, "shell");
 -                      if (!idx) idx = gettagindex(this, "tag_shell");
 -                      if (idx)
 -                      {
 -                              this.spawnorigin = gettaginfo(this, idx);
 -                      }
 -                      else
 -                      {
 -                              LOG_INFO("WARNING: weapon model ", this.model,
 -                                      " does not support the 'shell' tag, will display casings wrong\n");
 -                              this.spawnorigin = this.movedir;
 -                      }
 -              }
 -
 -              if (v_shot_idx)
 -              {
 -                      this.oldorigin = '0 0 0';  // use regular attachment
 -              }
 -              else
 -              {
 -                      if (this.(weaponentity))
 -                      {
 -                              idx = gettagindex(this, "weapon");
 -                              if (!idx) idx = gettagindex(this, "tag_weapon");
 -                      }
 -                      else
 -                      {
 -                              idx = gettagindex(this, "handle");
 -                              if (!idx) idx = gettagindex(this, "tag_handle");
 -                      }
 -                      if (idx)
 -                      {
 -                              this.oldorigin = this.movedir - gettaginfo(this, idx);
 -                      }
 -                      else
 -                      {
 -                              LOG_INFO("WARNING: weapon model ", this.model,
 -                                      " does not support the 'handle' tag and neither does the v_ model support the 'shot' tag, will display muzzle flashes TOTALLY wrong\n");
 -                              this.oldorigin = '0 0 0';  // there is no way to recover from this
 -                      }
 -              }
 -
 -              this.viewmodelforclient = this.owner;
 -      }
 -      else
 -      {
 -              this.model = "";
 -              if (this.(weaponentity)) remove(this.(weaponentity));
 -              this.(weaponentity) = NULL;
 -              this.movedir = '0 0 0';
 -              this.spawnorigin = '0 0 0';
 -              this.oldorigin = '0 0 0';
 -              this.anim_fire1  = '0 1 0.01';
 -              this.anim_fire2  = '0 1 0.01';
 -              this.anim_idle   = '0 1 0.01';
 -              this.anim_reload = '0 1 0.01';
 -      }
 -
 -      this.view_ofs = '0 0 0';
 -
 -      if (this.movedir.x >= 0)
 -      {
 -              vector v0 = this.movedir;
 -              this.movedir = shotorg_adjust(v0, false, false, this.owner.cvar_cl_gunalign);
 -              this.view_ofs = shotorg_adjust(v0, false, true, this.owner.cvar_cl_gunalign) - v0;
 -      }
 -      this.owner.stat_shotorg = compressShotOrigin(this.movedir);
 -      this.movedir = decompressShotOrigin(this.owner.stat_shotorg); // make them match perfectly
 -
 -      this.spawnorigin += this.view_ofs;                            // offset the casings origin by the same amount
 -
 -      // check if an instant weapon switch occurred
 -      setorigin(this, this.view_ofs);
 -      // reset animstate now
 -      this.wframe = WFRAME_IDLE;
 -      setanim(this, this.anim_idle, true, false, true);
 -}
 -
 -vector CL_Weapon_GetShotOrg(float wpn)
 +vector CL_Weapon_GetShotOrg(int wpn)
  {
        entity wi = Weapons_from(wpn);
        entity e = spawn();
 -      .entity weaponentity = weaponentities[0];
 -      CL_WeaponEntity_SetModel(e, weaponentity, wi.mdl);
 +      CL_WeaponEntity_SetModel(e, wi.mdl);
        vector ret = e.movedir;
 -      CL_WeaponEntity_SetModel(e, weaponentity, "");
 +      CL_WeaponEntity_SetModel(e, "");
        remove(e);
        return ret;
  }
  
+ ..entity weaponentity_fld;
  void CL_Weaponentity_Think()
  {
        SELFPARAM();
        this.nextthink = time;
        if (intermission_running) this.frame = this.anim_idle.x;
-       .entity weaponentity = weaponentities[0];  // TODO: unhardcode
+       .entity weaponentity = this.weaponentity_fld;
        if (this.owner.(weaponentity) != this)
        {
 -              if (this.(weaponentity)) remove(this.(weaponentity));
 +              // owner has new gun; remove self
 +              if (this.weaponchild) remove(this.weaponchild);
                remove(this);
                return;
        }
        if (this.owner.deadflag != DEAD_NO)
        {
 +              // owner died; disappear
                this.model = "";
 -              if (this.(weaponentity)) this.(weaponentity).model = "";
 +              if (this.weaponchild) this.weaponchild.model = "";
                return;
        }
 -      if (this.weaponname != this.owner.weaponname || this.dmg != this.owner.modelindex
 +      if (this.weaponname != this.owner.weaponname
 +          || this.dmg != this.owner.modelindex
            || this.deadflag != this.owner.deadflag)
        {
 +              // owner changed weapons; update appearance
                this.weaponname = this.owner.weaponname;
                this.dmg = this.owner.modelindex;
                this.deadflag = this.owner.deadflag;
  
 -              CL_WeaponEntity_SetModel(this, weaponentity, this.owner.weaponname);
 +              CL_WeaponEntity_SetModel(this, this.owner.weaponname);
        }
  
 -      int tb = (this.effects & (EF_TELEPORT_BIT | EF_RESTARTANIM_BIT));
 -      this.effects = this.owner.effects & EFMASK_CHEAP;
 -      this.effects &= ~EF_LOWPRECISION;
 -      this.effects &= ~EF_FULLBRIGHT;  // can mask team color, so get rid of it
 -      this.effects &= ~EF_TELEPORT_BIT;
 -      this.effects &= ~EF_RESTARTANIM_BIT;
 -      this.effects |= tb;
 -      if (weaponentity != weaponentities[0]) this.effects |= EF_NODRAW;
 +      this.effects = EF_NODRAW; // TODO: don't render this entity at all
  
        if (this.owner.alpha == default_player_alpha) this.alpha = default_weapon_alpha;
        else if (this.owner.alpha != 0) this.alpha = this.owner.alpha;
        else this.alpha = 1;
  
 -      this.glowmod = this.owner.weaponentity_glowmod;
 -      this.colormap = this.owner.colormap;
 -      if (this.(weaponentity))
 -      {
 -              this.(weaponentity).effects = this.effects;
 -              this.(weaponentity).alpha = this.alpha;
 -              this.(weaponentity).colormap = this.colormap;
 -              this.(weaponentity).glowmod = this.glowmod;
 -      }
 -
 -      this.angles = '0 0 0';
 -
 -      float f = this.weapon_nextthink - time;
 -      if (this.state == WS_RAISE && !intermission_running)
 -      {
 -              entity newwep = Weapons_from(this.owner.switchweapon);
 -              f = f * g_weaponratefactor / max(f, newwep.switchdelay_raise);
 -              this.angles_x = -90 * f * f;
 -      }
 -      else if (this.state == WS_DROP && !intermission_running)
 -      {
 -              entity oldwep = Weapons_from(this.owner.weapon);
 -              f = 1 - f * g_weaponratefactor / max(f, oldwep.switchdelay_drop);
 -              this.angles_x = -90 * f * f;
 -      }
 -      else if (this.state == WS_CLEAR)
 +      if (this.weaponchild)
        {
 -              f = 1;
 -              this.angles_x = -90 * f * f;
 +              this.weaponchild.effects = this.effects;
        }
  }
  
@@@ -150,24 -443,31 +152,27 @@@ void CL_ExteriorWeaponentity_Think(
  }
  
  // spawning weaponentity for client
 -void CL_SpawnWeaponentity(entity e, .entity weaponentity)
 +void CL_SpawnWeaponentity(entity actor, .entity weaponentity)
  {
 -      entity view = e.(weaponentity) = new(weaponentity);
 +      entity view = actor.(weaponentity) = new(weaponentity);
+       make_pure(view);
        view.solid = SOLID_NOT;
 -      view.owner = e;
 +      view.owner = actor;
        setmodel(view, MDL_Null);  // precision set when changed
        setorigin(view, '0 0 0');
 -      view.angles = '0 0 0';
 -      view.viewmodelforclient = e;
 -      view.flags = 0;
+       view.weaponentity_fld = weaponentity;
        view.think = CL_Weaponentity_Think;
 -      view.customizeentityforclient = CL_Weaponentity_CustomizeEntityForClient;
        view.nextthink = time;
 +      view.viewmodelforclient = actor;
 +      view.customizeentityforclient = CL_Weaponentity_CustomizeEntityForClient;
  
        if (weaponentity == weaponentities[0])
        {
 -              entity exterior = e.exteriorweaponentity = new(exteriorweaponentity);
 +              entity exterior = actor.exteriorweaponentity = new(exteriorweaponentity);
+               make_pure(exterior);
                exterior.solid = SOLID_NOT;
 -              exterior.exteriorweaponentity = exterior;
 -              exterior.owner = e;
 +              exterior.owner = actor;
                setorigin(exterior, '0 0 0');
 -              exterior.angles = '0 0 0';
                exterior.think = CL_ExteriorWeaponentity_Think;
                exterior.nextthink = time;
  
@@@ -183,16 -483,18 +188,18 @@@ void w_clear(Weapon thiswep, entity act
                actor.weapon = 0;
                actor.switchingweapon = 0;
        }
-       if (actor.(weaponentity))
+       entity this = actor.(weaponentity);
+       if (this)
        {
-               actor.(weaponentity).state = WS_CLEAR;
-               actor.(weaponentity).effects = 0;
+               this.state = WS_CLEAR;
+               this.effects = 0;
        }
  }
  
  void w_ready(Weapon thiswep, entity actor, .entity weaponentity, int fire)
  {
-       if (actor.(weaponentity)) actor.(weaponentity).state = WS_READY;
+       entity this = actor.(weaponentity);
+       if (this) this.state = WS_READY;
        weapon_thinkf(actor, weaponentity, WFRAME_IDLE, 1000000, w_ready);
  }
  
@@@ -267,15 -569,17 +274,17 @@@ bool weapon_prepareattack_check(Weapon 
                int slot = weaponslot(weaponentity);
                // don't fire if previous attack is not finished
                if (ATTACK_FINISHED(actor, slot) > time + actor.weapon_frametime * 0.5) return false;
+               entity this = actor.(weaponentity);
                // don't fire while changing weapon
-               if (actor.(weaponentity).state != WS_READY) return false;
+               if (this.state != WS_READY) return false;
        }
        return true;
  }
  
  void weapon_prepareattack_do(entity actor, .entity weaponentity, bool secondary, float attacktime)
  {
-       actor.(weaponentity).state = WS_INUSE;
+       entity this = actor.(weaponentity);
+       this.state = WS_INUSE;
  
        actor.spawnshieldtime = min(actor.spawnshieldtime, time);  // kill spawn shield when you fire
  
@@@ -304,9 -608,7 +313,9 @@@ bool weapon_prepareattack(Weapon thiswe
        return false;
  }
  
 -void weapon_thinkf(entity actor, .entity weaponentity, float fr, float t, void(Weapon thiswep, entity actor,
 +void wframe_send(entity actor, entity weaponentity, vector a, bool restartanim);
 +
 +void weapon_thinkf(entity actor, .entity weaponentity, WFRAME fr, float t, void(Weapon thiswep, entity actor,
        .entity weaponentity, int fire) func)
  {
        entity this = actor.(weaponentity);
                else  // if (fr == WFRAME_RELOAD)
                        a = this.anim_reload;
                a.z *= g_weaponratefactor;
 -              setanim(this, a, restartanim == false, restartanim, restartanim);
 +              entity e; FOR_EACH_CLIENT(e) if (e == actor || (IS_SPEC(e) && e.enemy == actor)) {
 +                      wframe_send(e, this, a, restartanim);
 +              }
        }
  
        v_forward = of;
        v_right = or;
        v_up = ou;
  
-       if (actor.weapon_think == w_ready && func != w_ready && this.state == WS_RAISE) backtrace(
+       if (this.weapon_think == w_ready && func != w_ready && this.state == WS_RAISE) backtrace(
                        "Tried to override initial weapon think function - should this really happen?");
  
        t *= W_WeaponRateFactor();
  
        // VorteX: haste can be added here
-       if (actor.weapon_think == w_ready)
+       if (this.weapon_think == w_ready)
        {
-               actor.weapon_nextthink = time;
+               this.weapon_nextthink = time;
                // dprint("started firing at ", ftos(time), "\n");
        }
-       if (actor.weapon_nextthink < time - actor.weapon_frametime * 1.5
-           || actor.weapon_nextthink > time + actor.weapon_frametime * 1.5)
+       if (this.weapon_nextthink < time - actor.weapon_frametime * 1.5
+           || this.weapon_nextthink > time + actor.weapon_frametime * 1.5)
        {
-               actor.weapon_nextthink = time;
+               this.weapon_nextthink = time;
                // dprint("reset weapon animation timer at ", ftos(time), "\n");
        }
-       actor.weapon_nextthink += t;
-       actor.weapon_think = func;
-       // dprint("next ", ftos(actor.weapon_nextthink), "\n");
 -      this.weapon_nextthink = this.weapon_nextthink + t;
++      this.weapon_nextthink += t;
++      if (weaponentity == weaponentities[0]) actor.weapon_nextthink = this.weapon_nextthink;
+       this.weapon_think = func;
+       // dprint("next ", ftos(this.weapon_nextthink), "\n");
  
        if ((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t)
        {
@@@ -396,10 -696,12 +406,12 @@@ bool forbidWeaponUse(entity player
  
  void W_WeaponFrame(entity actor)
  {
-       .entity weaponentity = weaponentities[0];              // TODO: unhardcode
+       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
+       entity this = actor.(weaponentity);
        if (frametime) actor.weapon_frametime = frametime;
  
-       if (!actor.(weaponentity) || actor.health < 1) return; // Dead player can't use weapons and injure impulse commands
+       if (!this || actor.health < 1) return; // Dead player can't use weapons and injure impulse commands
  
        if (forbidWeaponUse(actor))
        {
        {
                actor.weapon = 0;
                actor.switchingweapon = 0;
-               actor.(weaponentity).state = WS_CLEAR;
+               this.state = WS_CLEAR;
                actor.weaponname = "";
                // actor.items &= ~IT_AMMO;
                return;
        // Change weapon
        if (actor.weapon != actor.switchweapon)
        {
-               switch (actor.(weaponentity).state)
+               switch (this.state)
                {
                        default:
-                               LOG_WARNINGF("unhandled weaponentity (%i) state for player (%i): %d\n", actor.(weaponentity), actor, actor.(weaponentity).state);
+                               LOG_WARNINGF("unhandled weaponentity (%i) state for player (%i): %d\n", this, actor, this.state);
                                break;
                        case WS_INUSE:
                        case WS_RAISE:
                                actor.bulletcounter = 0;
                                actor.ammo_field = newwep.ammo_field;
                                newwep.wr_setup(newwep);
-                               actor.(weaponentity).state = WS_RAISE;
+                               this.state = WS_RAISE;
  
                                // set our clip load to the load of the weapon we switched to, if it's reloadable
                                if ((newwep.spawnflags & WEP_FLAG_RELOADABLE) && newwep.reloading_ammo)  // prevent accessing undefined cvars
                                   )
                                {
                                        sound(actor, CH_WEAPON_SINGLE, SND_WEAPON_SWITCH, VOL_BASE, ATTN_NORM);
-                                       actor.(weaponentity).state = WS_DROP;
+                                       this.state = WS_DROP;
                                        weapon_thinkf(actor, weaponentity, WFRAME_DONTCHANGE, oldwep.switchdelay_drop, w_clear);
                                }
                                break;
  
        // LordHavoc: network timing test code
        // if (actor.button0)
-       //      print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(actor, slot)), " >= ", ftos(actor.weapon_nextthink), "\n");
+       //      print(ftos(frametime), " ", ftos(time), " >= ", ftos(ATTACK_FINISHED(actor, slot)), " >= ", ftos(this.weapon_nextthink), "\n");
  
        int w = actor.weapon;
  
        // call the think code which may fire the weapon
        // and do so multiple times to resolve framerate dependency issues if the
        // server framerate is very low and the weapon fire rate very high
-       int c = 0;
-       while (c < W_TICSPERFRAME)
+       for (int c = 0; c < W_TICSPERFRAME; ++c)
        {
-               c += 1;
                if (w && !(actor.weapons & WepSet_FromWeapon(w)))
                {
                        if (actor.weapon == actor.switchweapon) W_SwitchWeapon_Force(actor, w_getbestweapon(actor));
                        }
                }
  
-               if (time + actor.weapon_frametime * 0.5 >= actor.weapon_nextthink)
+               if (time + actor.weapon_frametime * 0.5 >= this.weapon_nextthink)
                {
-                       if (actor.weapon_think)
+                       if (this.weapon_think)
                        {
                                v_forward = fo;
                                v_right = ri;
                                v_up = up;
                                Weapon wpn = Weapons_from(actor.weapon);
-                               actor.weapon_think(wpn, actor, weaponentity,
+                               this.weapon_think(wpn, actor, weaponentity,
                                        (actor.BUTTON_ATCK ? 1 : 0) | (actor.BUTTON_ATCK2 ? 2 : 0));
                        }
                        else
@@@ -580,11 -880,9 +590,11 @@@ void W_AttachToShotorg(entity actor, en
        flash.owner = actor;
        flash.angles_z = random() * 360;
  
 -      entity this = actor.(weaponentity);
 -      if (gettagindex(this, "shot")) setattachment(flash, this, "shot");
 -      else setattachment(flash, this, "tag_shot");
 +      entity view = actor.(weaponentity);
 +      entity exterior = actor.exteriorweaponentity;
 +
 +      if (gettagindex(view, "shot")) setattachment(flash, view, "shot");
 +      else setattachment(flash, view, "tag_shot");
        setorigin(flash, offset);
  
        entity xflash = spawn();
  
        flash.viewmodelforclient = actor;
  
 -      if (this.oldorigin.x > 0)
 +      if (view.oldorigin.x > 0)
        {
 -              setattachment(xflash, actor.exteriorweaponentity, "");
 -              setorigin(xflash, this.oldorigin + offset);
 +              setattachment(xflash, exterior, "");
 +              setorigin(xflash, view.oldorigin + offset);
        }
        else
        {
 -              if (gettagindex(actor.exteriorweaponentity, "shot")) setattachment(xflash, actor.exteriorweaponentity, "shot");
 -              else setattachment(xflash, actor.exteriorweaponentity, "tag_shot");
 +              if (gettagindex(exterior, "shot")) setattachment(xflash, exterior, "shot");
 +              else setattachment(xflash, exterior, "tag_shot");
                setorigin(xflash, offset);
        }
  }
  
  void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use)
  {
-       if (cvar("g_overkill"))
-       {
-               if (actor.ok_use_ammocharge)
-               {
-                       ok_DecreaseCharge(actor, actor.weapon);
-                       return;  // TODO
-               }
-       }
+       if (MUTATOR_CALLHOOK(W_DecreaseAmmo, actor)) return;
  
        if ((actor.items & IT_UNLIMITED_WEAPON_AMMO) && !wep.reloading_ammo) return;
  
@@@ -684,9 -975,7 +687,7 @@@ void W_Reload(entity actor, float sent_
        // set global values to work with
        entity e = Weapons_from(actor.weapon);
  
-       if (cvar("g_overkill"))
-               if (actor.ok_use_ammocharge) return;
-       // TODO
+       if (MUTATOR_CALLHOOK(W_Reload, actor)) return;
  
        actor.reload_ammo_min = sent_ammo_min;
        actor.reload_ammo_amount = e.reloading_ammo;
                }
        }
  
-       if (actor.(weaponentity))
+       entity this = actor.(weaponentity);
+       if (this)
        {
-               if (actor.(weaponentity).wframe == WFRAME_RELOAD) return;
+               if (this.wframe == WFRAME_RELOAD) return;
  
                // allow switching away while reloading, but this will cause a new reload!
-               actor.(weaponentity).state = WS_READY;
+               this.state = WS_READY;
        }
  
        // now begin the reloading process