Merge branch 'master' into TimePath/csqc_viewmodels
authorTimePath <andrew.hardaker1995@gmail.com>
Sun, 29 Nov 2015 22:59:11 +0000 (09:59 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Sun, 29 Nov 2015 23:32:37 +0000 (10:32 +1100)
# Conflicts:
# qcsrc/client/weapons/projectile.qc
# qcsrc/common/stats.qh
# qcsrc/common/weapons/all.qc
# qcsrc/common/weapons/weapon.qh
# qcsrc/server/defs.qh
# qcsrc/server/g_subs.qh
# qcsrc/server/g_world.qc

17 files changed:
1  2 
qcsrc/client/progs.inc
qcsrc/client/view.qc
qcsrc/client/weapons/projectile.qc
qcsrc/common/stats.qh
qcsrc/common/triggers/subs.qh
qcsrc/common/weapons/all.qc
qcsrc/common/weapons/all.qh
qcsrc/common/weapons/weapon.qh
qcsrc/common/weapons/weapon/arc.qc
qcsrc/lib/_all.inc
qcsrc/lib/vector.qh
qcsrc/server/cl_client.qc
qcsrc/server/cl_player.qc
qcsrc/server/defs.qh
qcsrc/server/g_subs.qh
qcsrc/server/g_world.qc
qcsrc/server/progs.inc

  
  #include "weapons/projectile.qc" // TODO
  
 +#include "../common/anim.qc"
  #include "../common/animdecide.qc"
  #include "../common/effects/effectinfo.qc"
+ #include "../common/ent_cs.qc"
  #include "../common/mapinfo.qc"
  #include "../common/movetypes/include.qc"
  #include "../common/net_notice.qc"
  #include "../lib/warpzone/client.qh"
  #include "../lib/warpzone/common.qh"
  
-       float frametime = (time - prevtime) * getstatf(STAT_MOVEVARS_TIMESCALE);
 +#define EFMASK_CHEAP (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NODRAW | EF_NOSHADOW | EF_SELECTABLE | EF_TELEPORT_BIT)
 +
 +float autocvar_cl_viewmodel_scale;
 +
 +bool autocvar_cl_bobmodel;
 +float autocvar_cl_bobmodel_speed;
 +float autocvar_cl_bobmodel_side;
 +float autocvar_cl_bobmodel_up;
 +
 +float autocvar_cl_followmodel;
 +float autocvar_cl_followmodel_side_speed;
 +float autocvar_cl_followmodel_side_highpass;
 +float autocvar_cl_followmodel_side_highpass1;
 +float autocvar_cl_followmodel_side_limit;
 +float autocvar_cl_followmodel_side_lowpass;
 +float autocvar_cl_followmodel_up_speed;
 +float autocvar_cl_followmodel_up_highpass;
 +float autocvar_cl_followmodel_up_highpass1;
 +float autocvar_cl_followmodel_up_limit;
 +float autocvar_cl_followmodel_up_lowpass;
 +
 +float autocvar_cl_leanmodel;
 +float autocvar_cl_leanmodel_side_speed;
 +float autocvar_cl_leanmodel_side_highpass;
 +float autocvar_cl_leanmodel_side_highpass1;
 +float autocvar_cl_leanmodel_side_lowpass;
 +float autocvar_cl_leanmodel_side_limit;
 +float autocvar_cl_leanmodel_up_speed;
 +float autocvar_cl_leanmodel_up_highpass;
 +float autocvar_cl_leanmodel_up_highpass1;
 +float autocvar_cl_leanmodel_up_lowpass;
 +float autocvar_cl_leanmodel_up_limit;
 +
 +#define lowpass(value, frac, ref_store, ret) do \
 +{ \
 +      float __frac = bound(0, frac, 1); \
 +      ret = ref_store = ref_store * (1 - __frac) + (value) * __frac; \
 +} while (0)
 +
 +#define lowpass_limited(value, frac, limit, ref_store, ret) do \
 +{ \
 +      float __ignore; lowpass(value, frac, ref_store, __ignore); \
 +      ret = ref_store = bound((value) - (limit), ref_store, (value) + (limit)); \
 +} while (0)
 +
 +#define highpass(value, frac, ref_store, ret) do \
 +{ \
 +      float __f; lowpass(value, frac, ref_store, __f); \
 +      ret = (value) - __f; \
 +} while (0)
 +
 +#define highpass_limited(value, frac, limit, ref_store, ret) do \
 +{ \
 +      float __f; lowpass_limited(value, frac, limit, ref_store, __f); \
 +      ret = (value) - __f; \
 +} while (0)
 +
 +#define lowpass3(value, fracx, fracy, fracz, ref_store, ref_out) do \
 +{ \
 +      lowpass(value.x, fracx, ref_store.x, ref_out.x); \
 +      lowpass(value.y, fracy, ref_store.y, ref_out.y); \
 +      lowpass(value.z, fracz, ref_store.z, ref_out.z); \
 +} while (0)
 +
 +#define highpass3(value, fracx, fracy, fracz, ref_store, ref_out) do \
 +{ \
 +      highpass(value.x, fracx, ref_store.x, ref_out.x); \
 +      highpass(value.y, fracy, ref_store.y, ref_out.y); \
 +      highpass(value.z, fracz, ref_store.z, ref_out.z); \
 +} while (0)
 +
 +#define highpass3_limited(value, fracx, limitx, fracy, limity, fracz, limitz, ref_store, ref_out) do \
 +{ \
 +      highpass_limited(value.x, fracx, limitx, ref_store.x, ref_out.x); \
 +      highpass_limited(value.y, fracy, limity, ref_store.y, ref_out.y); \
 +      highpass_limited(value.z, fracz, limitz, ref_store.z, ref_out.z); \
 +} while (0)
 +
 +void viewmodel_animate(entity this)
 +{
 +      static float prevtime;
-       entity view = CSQCModel_server2csqc(player_localentnum);
++      float frametime = (time - prevtime) * STAT(MOVEVARS_TIMESCALE);
 +      prevtime = time;
 +
 +      if (autocvar_chase_active) return;
 +      if (getstati(STAT_HEALTH) <= 0) return;
 +
-       entity me = CSQCModel_server2csqc(player_localentnum);
++      entity view = CSQCModel_server2csqc(player_localentnum - 1);
 +
 +      bool clonground = !(view.anim_implicit_state & ANIMIMPLICITSTATE_INAIR);
 +      static bool oldonground;
 +      static float hitgroundtime;
 +      static float lastongroundtime;
 +      if (clonground)
 +      {
 +              float f = time; // cl.movecmd[0].time
 +              if (!oldonground)
 +                      hitgroundtime = f;
 +              lastongroundtime = f;
 +      }
 +      oldonground = clonground;
 +
 +      vector gunorg = '0 0 0', gunangles = '0 0 0';
 +      static vector gunorg_prev = '0 0 0', gunangles_prev = '0 0 0';
 +
 +      bool teleported = view.csqcmodel_teleported;
 +
 +      // 1. if we teleported, clear the frametime... the lowpass will recover the previous value then
 +      if (teleported)
 +      {
 +              // try to fix the first highpass; result is NOT
 +              // perfect! TODO find a better fix
 +              gunangles_prev = view_angles;
 +              gunorg_prev = view_origin;
 +      }
 +
 +      static vector gunorg_highpass = '0 0 0';
 +
 +      // 2. for the gun origin, only keep the high frequency (non-DC) parts, which is "somewhat like velocity"
 +      gunorg_highpass += gunorg_prev;
 +      highpass3_limited(view_origin,
 +              frametime * autocvar_cl_followmodel_side_highpass1, autocvar_cl_followmodel_side_limit,
 +              frametime * autocvar_cl_followmodel_side_highpass1, autocvar_cl_followmodel_side_limit,
 +              frametime * autocvar_cl_followmodel_up_highpass1, autocvar_cl_followmodel_up_limit,
 +              gunorg_highpass, gunorg);
 +      gunorg_prev = view_origin;
 +      gunorg_highpass -= gunorg_prev;
 +
 +      static vector gunangles_highpass = '0 0 0';
 +
 +      // in the highpass, we _store_ the DIFFERENCE to the actual view angles...
 +      gunangles_highpass += gunangles_prev;
 +      PITCH(gunangles_highpass) += 360 * floor((PITCH(view_angles) - PITCH(gunangles_highpass)) / 360 + 0.5);
 +      YAW(gunangles_highpass) += 360 * floor((YAW(view_angles) - YAW(gunangles_highpass)) / 360 + 0.5);
 +      ROLL(gunangles_highpass) += 360 * floor((ROLL(view_angles) - ROLL(gunangles_highpass)) / 360 + 0.5);
 +      highpass3_limited(view_angles,
 +              frametime * autocvar_cl_leanmodel_up_highpass1, autocvar_cl_leanmodel_up_limit,
 +              frametime * autocvar_cl_leanmodel_side_highpass1, autocvar_cl_leanmodel_side_limit,
 +              0, 0,
 +              gunangles_highpass, gunangles);
 +      gunangles_prev = view_angles;
 +      gunangles_highpass -= gunangles_prev;
 +
 +      // 3. calculate the RAW adjustment vectors
 +      gunorg.x *= (autocvar_cl_followmodel ? -autocvar_cl_followmodel_side_speed : 0);
 +      gunorg.y *= (autocvar_cl_followmodel ? -autocvar_cl_followmodel_side_speed : 0);
 +      gunorg.z *= (autocvar_cl_followmodel ? -autocvar_cl_followmodel_up_speed : 0);
 +
 +      PITCH(gunangles) *= (autocvar_cl_leanmodel ? -autocvar_cl_leanmodel_up_speed : 0);
 +      YAW(gunangles) *= (autocvar_cl_leanmodel ? -autocvar_cl_leanmodel_side_speed : 0);
 +      ROLL(gunangles) = 0;
 +
 +      static vector gunorg_adjustment_highpass;
 +      static vector gunorg_adjustment_lowpass;
 +      static vector gunangles_adjustment_highpass;
 +      static vector gunangles_adjustment_lowpass;
 +
 +      // 4. perform highpass/lowpass on the adjustment vectors (turning velocity into acceleration!)
 +      //    trick: we must do the lowpass LAST, so the lowpass vector IS the final vector!
 +      highpass3(gunorg,
 +              frametime * autocvar_cl_followmodel_side_highpass,
 +              frametime * autocvar_cl_followmodel_side_highpass,
 +              frametime * autocvar_cl_followmodel_up_highpass,
 +              gunorg_adjustment_highpass, gunorg);
 +      lowpass3(gunorg,
 +              frametime * autocvar_cl_followmodel_side_lowpass,
 +              frametime * autocvar_cl_followmodel_side_lowpass,
 +              frametime * autocvar_cl_followmodel_up_lowpass,
 +              gunorg_adjustment_lowpass, gunorg);
 +      // we assume here: PITCH = 0, YAW = 1, ROLL = 2
 +      highpass3(gunangles,
 +              frametime * autocvar_cl_leanmodel_up_highpass,
 +              frametime * autocvar_cl_leanmodel_side_highpass,
 +              0,
 +              gunangles_adjustment_highpass, gunangles);
 +      lowpass3(gunangles,
 +              frametime * autocvar_cl_leanmodel_up_lowpass,
 +              frametime * autocvar_cl_leanmodel_side_lowpass,
 +              0,
 +              gunangles_adjustment_lowpass, gunangles);
 +      float xyspeed = bound(0, vlen(vec2(view.velocity)), 400);
 +
 +      // vertical view bobbing code
 +      // TODO: cl_bob
 +
 +      // horizontal view bobbing code
 +      // TODO: cl_bob2
 +
 +      // fall bobbing code
 +      // causes the view to swing down and back up when touching the ground
 +      // TODO: cl_bobfall
 +
 +      // gun model bobbing code
 +      if (autocvar_cl_bobmodel)
 +      {
 +              // calculate for swinging gun model
 +              // the gun bobs when running on the ground, but doesn't bob when you're in the air.
 +              // Sajt: I tried to smooth out the transitions between bob and no bob, which works
 +              // for the most part, but for some reason when you go through a message trigger or
 +              // pick up an item or anything like that it will momentarily jolt the gun.
 +              vector forward, right, up;
 +              float bspeed;
 +              float t = 1;
 +              float s = time * autocvar_cl_bobmodel_speed;
 +              if (clonground)
 +              {
 +                      if (time - hitgroundtime < 0.2)
 +                      {
 +                              // just hit the ground, speed the bob back up over the next 0.2 seconds
 +                              t = time - hitgroundtime;
 +                              t = bound(0, t, 0.2);
 +                              t *= 5;
 +                      }
 +              }
 +              else
 +              {
 +                      // recently left the ground, slow the bob down over the next 0.2 seconds
 +                      t = time - lastongroundtime;
 +                      t = 0.2 - bound(0, t, 0.2);
 +                      t *= 5;
 +              }
 +              bspeed = xyspeed * 0.01;
 +              MAKEVECTORS(makevectors, gunangles, forward, right, up);
 +              float bobr = bspeed * autocvar_cl_bobmodel_side * autocvar_cl_viewmodel_scale * sin(s) * t;
 +              gunorg += bobr * right;
 +              float bobu = bspeed * autocvar_cl_bobmodel_up * autocvar_cl_viewmodel_scale * cos(s * 2) * t;
 +              gunorg += bobu * up;
 +      }
 +      this.origin += view_forward * gunorg.x + view_right * gunorg.y + view_up * gunorg.z;
 +      gunangles.x = -gunangles.x; // pitch was inverted, now that actually matters
 +      this.angles += gunangles;
 +}
 +
 +.vector viewmodel_origin, viewmodel_angles;
 +
 +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;
-       float eta = (getstatf(STAT_WEAPON_NEXTTHINK) - time); // TODO: / W_WeaponRateFactor();
++      entity me = CSQCModel_server2csqc(player_localentnum - 1);
 +      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 = Weapons_from(activeweapon).mdl;
 +              if (name != name_last)
 +              {
 +                      name_last = name;
 +                      CL_WeaponEntity_SetModel(this, name);
 +                      this.viewmodel_origin = this.origin;
 +                      this.viewmodel_angles = this.angles;
 +              }
 +              anim_update(this);
 +              if (!this.animstate_override)
 +                      anim_set(this, this.anim_idle, true, false, false);
 +      }
++      float eta = (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);
 +                      break;
 +              }
 +              case WS_DROP:
 +              {
 +                      // entity oldwep = Weapons_from(activeweapon);
 +                      float delay = 0.2; // TODO: newwep.switchdelay_drop;
 +                      f = 1 - eta / max(eta, delay);
 +                      break;
 +              }
 +              case WS_CLEAR:
 +              {
 +                      f = 1;
 +                      break;
 +              }
 +      }
 +      this.origin = this.viewmodel_origin;
 +      this.angles = this.viewmodel_angles;
 +      this.angles_x = (-90 * f * f);
 +      viewmodel_animate(this);
 +      setorigin(this, this.origin);
 +}
 +
 +entity viewmodel;
 +STATIC_INIT(viewmodel) {
 +    viewmodel = new(viewmodel);
 +      viewmodel.draw = viewmodel_draw;
 +}
 +
  entity porto;
  vector polyline[16];
  void Porto_Draw(entity this)
@@@ -279,47 -280,46 +280,46 @@@ NET_HANDLE(ENT_CLIENT_PROJECTILE, bool 
                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(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;
  // Full list of all stat constants, included in a single location for easy reference
  // 255 is the current limit (MAX_CL_STATS - 1), engine will need to be modified if you wish to add more stats
  
- const int MAX_CL_STATS                = 256;
- // -Wdouble-declaration
- // const int STAT_HEALTH                 = 0;
- // 1 empty?
- const int STAT_WEAPON                 = 2;
- // -Wdouble-declaration
- // const int STAT_AMMO                   = 3;
- // -Wdouble-declaration
- // const int STAT_ARMOR                  = 4;
- // -Wdouble-declaration
- // const int STAT_WEAPONFRAME            = 5;
- // -Wdouble-declaration
- // const int STAT_SHELLS                 = 6;
- // -Wdouble-declaration
- // const int STAT_NAILS                  = 7;
- // -Wdouble-declaration
- // const int STAT_ROCKETS                = 8;
- // -Wdouble-declaration
- // const int STAT_CELLS                  = 9;
- // -Wdouble-declaration
- // const int STAT_ACTIVEWEAPON           = 10;
- // -Wdouble-declaration
- // const int STAT_TOTALSECRETS           = 11;
- // -Wdouble-declaration
- // const int STAT_TOTALMONSTERS          = 12;
- // -Wdouble-declaration
- // const int STAT_SECRETS                = 13;
- // -Wdouble-declaration
- // const int STAT_MONSTERS               = 14;
- // -Wdouble-declaration
- // const int STAT_ITEMS                  = 15;
- // -Wdouble-declaration
- // const int STAT_VIEWHEIGHT             = 16;
- // 17 empty?
- // 18 empty?
- // 19 empty?
- // 20 empty?
- const int STAT_VIEWZOOM               = 21;
- // 22 empty?
- // 23 empty?
- // 24 empty?
- // 25 empty?
- // 26 empty?
- // 27 empty?
- // 28 empty?
- // 29 empty?
- // 30 empty?
- // 31 empty?
- const int STAT_KH_KEYS                = 32;
- const int STAT_CTF_STATE              = 33;
- // 34 empty?
- const int STAT_WEAPONS                = 35;
- const int STAT_SWITCHWEAPON           = 36;
- const int STAT_GAMESTARTTIME          = 37;
- const int STAT_STRENGTH_FINISHED      = 38;
- const int STAT_INVINCIBLE_FINISHED    = 39;
- // 40 empty?
- const int STAT_ARC_HEAT               = 41;
- const int STAT_PRESSED_KEYS           = 42;
- const int STAT_ALLOW_OLDVORTEXBEAM    = 43; // this stat could later contain some other bits of info, like, more server-side particle config
- const int STAT_FUEL                   = 44;
- const int STAT_NB_METERSTART          = 45;
- const int STAT_SHOTORG                = 46; // compressShotOrigin
- const int STAT_LEADLIMIT              = 47;
- const int STAT_WEAPON_CLIPLOAD        = 48;
- const int STAT_WEAPON_CLIPSIZE        = 49;
- const int STAT_VORTEX_CHARGE          = 50;
- const int STAT_LAST_PICKUP            = 51;
- const int STAT_HUD                    = 52;
- const int STAT_VORTEX_CHARGEPOOL      = 53;
- const int STAT_HIT_TIME               = 54;
- const int STAT_DAMAGE_DEALT_TOTAL     = 55;
- const int STAT_TYPEHIT_TIME           = 56;
- const int STAT_LAYED_MINES            = 57;
- const int STAT_HAGAR_LOAD             = 58;
- const int STAT_SWITCHINGWEAPON        = 59;
- const int STAT_SUPERWEAPONS_FINISHED  = 60;
- const int STAT_VEHICLESTAT_HEALTH     = 61;
- const int STAT_VEHICLESTAT_SHIELD     = 62;
- const int STAT_VEHICLESTAT_ENERGY     = 63;
- const int STAT_VEHICLESTAT_AMMO1      = 64;
- const int STAT_VEHICLESTAT_RELOAD1    = 65;
- const int STAT_VEHICLESTAT_AMMO2      = 66;
- const int STAT_VEHICLESTAT_RELOAD2    = 67;
- const int STAT_VEHICLESTAT_W2MODE     = 68;
- const int STAT_NADE_TIMER             = 69;
- const int STAT_SECRETS_TOTAL          = 70;
- const int STAT_SECRETS_FOUND          = 71;
- const int STAT_RESPAWN_TIME           = 72;
- const int STAT_ROUNDSTARTTIME         = 73;
- const int STAT_WEAPONS2               = 74;
- const int STAT_WEAPONS3               = 75;
- const int STAT_MONSTERS_TOTAL         = 76;
- const int STAT_MONSTERS_KILLED        = 77;
- const int STAT_BUFFS                  = 78;
- const int STAT_NADE_BONUS             = 79;
- const int STAT_NADE_BONUS_TYPE        = 80;
- const int STAT_NADE_BONUS_SCORE       = 81;
- const int STAT_HEALING_ORB            = 82;
- const int STAT_HEALING_ORB_ALPHA      = 83;
- const int STAT_PLASMA                 = 84;
- const int STAT_OK_AMMO_CHARGE         = 85;
- const int STAT_OK_AMMO_CHARGEPOOL     = 86;
- const int STAT_FROZEN                 = 87;
- const int STAT_REVIVE_PROGRESS        = 88;
- const int STAT_WEAPON_NEXTTHINK       = 89;
- // 90 empty?
- // 91 empty?
- // 92 empty?
- // 93 empty?
- // 94 empty?
- // 95 empty?
- // 96 empty?
- // 97 empty?
- // 98 empty?
- const int STAT_ROUNDLOST              = 99;
+ const int MAX_CL_STATS = 256;
+ #ifndef CSQC
+ const int STAT_HEALTH = 0; // .health
+ const int STAT_ARMOR = 4; // .armorvalue
+ const int STAT_SHELLS = 6; // .ammo_shells
+ const int STAT_NAILS = 7; // .ammo_nails
+ const int STAT_ROCKETS = 8; // .ammo_rockets
+ const int STAT_CELLS = 9; // .ammo_cells
+ const int STAT_ACTIVEWEAPON = 10; // .weapon
+ const int STAT_ITEMS = 15; // .items | .items2 << 23 | serverflags << 28
+ const int STAT_VIEWHEIGHT = 16; // .view_ofs_z
+ #endif
+ REGISTER_STAT(WEAPONS, vectori)
+ REGISTER_STAT(WEAPONSINMAP, vectori)
+ REGISTER_STAT(PL_VIEW_OFS, vector, autocvar_sv_player_viewoffset)
+ REGISTER_STAT(PL_CROUCH_VIEW_OFS, vector, autocvar_sv_player_crouch_viewoffset)
+ REGISTER_STAT(PL_MIN, vector, autocvar_sv_player_mins)
+ REGISTER_STAT(PL_CROUCH_MIN, vector, autocvar_sv_player_crouch_mins)
+ REGISTER_STAT(PL_MAX, vector, autocvar_sv_player_maxs)
+ REGISTER_STAT(PL_CROUCH_MAX, vector, autocvar_sv_player_crouch_maxs)
+ REGISTER_STAT(KH_KEYS, int)
++
+ /** weapon requested to switch to; next WANTED weapon (for HUD) */
+ REGISTER_STAT(SWITCHWEAPON, int)
++/** weapon currently being switched to (is copied from switchweapon once switch is possible) */
++REGISTER_STAT(SWITCHINGWEAPON, int)
++REGISTER_STAT(WEAPON_NEXTTHINK, float)
++
+ REGISTER_STAT(GAMESTARTTIME, float)
+ REGISTER_STAT(STRENGTH_FINISHED, float)
+ REGISTER_STAT(INVINCIBLE_FINISHED, float)
+ /** arc heat in [0,1] */
+ REGISTER_STAT(ARC_HEAT, float)
+ REGISTER_STAT(PRESSED_KEYS, int)
+ /** this stat could later contain some other bits of info, like, more server-side particle config */
+ REGISTER_STAT(ALLOW_OLDVORTEXBEAM, bool)
+ REGISTER_STAT(FUEL, int)
+ REGISTER_STAT(NB_METERSTART, float)
+ /** compressShotOrigin */
+ REGISTER_STAT(SHOTORG, int)
+ REGISTER_STAT(LEADLIMIT, float)
+ REGISTER_STAT(WEAPON_CLIPLOAD, int)
+ REGISTER_STAT(WEAPON_CLIPSIZE, int)
+ REGISTER_STAT(VORTEX_CHARGE, float)
+ REGISTER_STAT(LAST_PICKUP, float)
+ REGISTER_STAT(HUD, int)
+ REGISTER_STAT(VORTEX_CHARGEPOOL, float)
+ REGISTER_STAT(HIT_TIME, float)
+ REGISTER_STAT(DAMAGE_DEALT_TOTAL, int)
+ REGISTER_STAT(TYPEHIT_TIME, float)
+ REGISTER_STAT(LAYED_MINES, int)
+ REGISTER_STAT(HAGAR_LOAD, int)
 -REGISTER_STAT(SWITCHINGWEAPON, int)
+ REGISTER_STAT(SUPERWEAPONS_FINISHED, float)
+ REGISTER_STAT(VEHICLESTAT_HEALTH, int)
+ REGISTER_STAT(VEHICLESTAT_SHIELD, int)
+ REGISTER_STAT(VEHICLESTAT_ENERGY, int)
+ REGISTER_STAT(VEHICLESTAT_AMMO1, int)
+ REGISTER_STAT(VEHICLESTAT_RELOAD1, int)
+ REGISTER_STAT(VEHICLESTAT_AMMO2, int)
+ REGISTER_STAT(VEHICLESTAT_RELOAD2, int)
+ REGISTER_STAT(VEHICLESTAT_W2MODE, int)
+ REGISTER_STAT(NADE_TIMER, float)
+ REGISTER_STAT(SECRETS_TOTAL, float)
+ REGISTER_STAT(SECRETS_FOUND, float)
+ REGISTER_STAT(RESPAWN_TIME, float)
+ REGISTER_STAT(ROUNDSTARTTIME, float)
+ REGISTER_STAT(MONSTERS_TOTAL, int)
+ REGISTER_STAT(MONSTERS_KILLED, int)
+ REGISTER_STAT(BUFFS, int)
+ REGISTER_STAT(NADE_BONUS, float)
+ REGISTER_STAT(NADE_BONUS_TYPE, int)
+ REGISTER_STAT(NADE_BONUS_SCORE, float)
+ REGISTER_STAT(HEALING_ORB, float)
+ REGISTER_STAT(HEALING_ORB_ALPHA, float)
+ REGISTER_STAT(PLASMA, int)
+ REGISTER_STAT(OK_AMMO_CHARGE, float)
+ REGISTER_STAT(OK_AMMO_CHARGEPOOL, float)
+ REGISTER_STAT(FROZEN, int)
+ REGISTER_STAT(REVIVE_PROGRESS, float)
+ REGISTER_STAT(ROUNDLOST, int)
+ REGISTER_STAT(BUFF_TIME, float)
+ REGISTER_STAT(CTF_FLAGSTATUS, int)
+ #ifdef SVQC
+ int autocvar_g_multijump;
+ float autocvar_g_multijump_add;
+ float autocvar_g_multijump_speed;
+ float autocvar_g_multijump_maxspeed;
+ float autocvar_g_multijump_dodging = 1;
+ #endif
+ REGISTER_STAT(MULTIJUMP_DODGING, int, autocvar_g_multijump_dodging)
+ REGISTER_STAT(MULTIJUMP_MAXSPEED, float, autocvar_g_multijump_maxspeed)
+ REGISTER_STAT(MULTIJUMP_ADD, int, autocvar_g_multijump_add)
+ REGISTER_STAT(MULTIJUMP_SPEED, float, autocvar_g_multijump_speed)
+ .int multijump_count;
+ REGISTER_STAT(MULTIJUMP_COUNT, int, this.multijump_count)
+ REGISTER_STAT(MULTIJUMP, int, autocvar_g_multijump)
+ REGISTER_STAT(DOUBLEJUMP, int, autocvar_sv_doublejump)
+ #ifdef SVQC
+ bool g_bugrigs;
+ bool g_bugrigs_planar_movement;
+ bool g_bugrigs_planar_movement_car_jumping;
+ float g_bugrigs_reverse_spinning;
+ float g_bugrigs_reverse_speeding;
+ float g_bugrigs_reverse_stopping;
+ float g_bugrigs_air_steering;
+ float g_bugrigs_angle_smoothing;
+ float g_bugrigs_friction_floor;
+ float g_bugrigs_friction_brake;
+ float g_bugrigs_friction_air;
+ float g_bugrigs_accel;
+ float g_bugrigs_speed_ref;
+ float g_bugrigs_speed_pow;
+ float g_bugrigs_steer;
+ #endif
+ REGISTER_STAT(BUGRIGS, int, g_bugrigs)
+ REGISTER_STAT(BUGRIGS_ACCEL, float, g_bugrigs_accel)
+ REGISTER_STAT(BUGRIGS_AIR_STEERING, int, g_bugrigs_air_steering)
+ REGISTER_STAT(BUGRIGS_ANGLE_SMOOTHING, int, g_bugrigs_angle_smoothing)
+ REGISTER_STAT(BUGRIGS_CAR_JUMPING, int, g_bugrigs_planar_movement_car_jumping)
+ REGISTER_STAT(BUGRIGS_FRICTION_AIR, float, g_bugrigs_friction_air)
+ REGISTER_STAT(BUGRIGS_FRICTION_BRAKE, float, g_bugrigs_friction_brake)
+ REGISTER_STAT(BUGRIGS_FRICTION_FLOOR, float, g_bugrigs_friction_floor)
+ REGISTER_STAT(BUGRIGS_PLANAR_MOVEMENT, int, g_bugrigs_planar_movement)
+ REGISTER_STAT(BUGRIGS_REVERSE_SPEEDING, int, g_bugrigs_reverse_speeding)
+ REGISTER_STAT(BUGRIGS_REVERSE_SPINNING, int, g_bugrigs_reverse_spinning)
+ REGISTER_STAT(BUGRIGS_REVERSE_STOPPING, int, g_bugrigs_reverse_stopping)
+ REGISTER_STAT(BUGRIGS_SPEED_POW, float, g_bugrigs_speed_pow)
+ REGISTER_STAT(BUGRIGS_SPEED_REF, float, g_bugrigs_speed_ref)
+ REGISTER_STAT(BUGRIGS_STEER, float, g_bugrigs_steer)
+ REGISTER_STAT(GAMEPLAYFIX_DOWNTRACEONGROUND, int, cvar("sv_gameplayfix_downtracesupportsongroundflag"))
+ REGISTER_STAT(GAMEPLAYFIX_EASIERWATERJUMP, int, cvar("sv_gameplayfix_easierwaterjump"))
+ REGISTER_STAT(GAMEPLAYFIX_STEPDOWN, int, cvar("sv_gameplayfix_stepdown"))
+ REGISTER_STAT(GAMEPLAYFIX_STEPMULTIPLETIMES, int, cvar("sv_gameplayfix_stepmultipletimes"))
+ REGISTER_STAT(GAMEPLAYFIX_UNSTICKPLAYERS, int, cvar("sv_gameplayfix_unstickplayers"))
+ REGISTER_STAT(GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND, int, autocvar_sv_gameplayfix_upwardvelocityclearsongroundflag)
+ REGISTER_STAT(MOVEVARS_JUMPSTEP, int, cvar("sv_jumpstep"))
+ REGISTER_STAT(NOSTEP, int, cvar("sv_nostep"))
+ REGISTER_STAT(MOVEVARS_FRICTION, float)
+ REGISTER_STAT(MOVEVARS_FRICTION_SLICK, float, autocvar_sv_friction_slick)
+ REGISTER_STAT(MOVEVARS_FRICTION_ONLAND, float, autocvar_sv_friction_on_land)
+ REGISTER_STAT(MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS, int, autocvar_sv_jumpspeedcap_max_disable_on_ramps)
+ REGISTER_STAT(MOVEVARS_TRACK_CANJUMP, int)
+ /** cvar loopback */
+ REGISTER_STAT(MOVEVARS_CL_TRACK_CANJUMP, int)
+ #ifdef SVQC
+ int g_dodging;
+ float autocvar_sv_dodging_delay;
+ float autocvar_sv_dodging_wall_distance_threshold;
+ bool autocvar_sv_dodging_frozen;
+ bool autocvar_sv_dodging_frozen_doubletap;
+ float autocvar_sv_dodging_height_threshold;
+ float autocvar_sv_dodging_horiz_speed;
+ float autocvar_sv_dodging_horiz_speed_frozen;
+ float autocvar_sv_dodging_ramp_time;
+ float autocvar_sv_dodging_up_speed;
+ bool autocvar_sv_dodging_wall_dodging;
+ #endif
+ REGISTER_STAT(DODGING, int, g_dodging)
+ REGISTER_STAT(DODGING_DELAY, float, autocvar_sv_dodging_delay)
+ REGISTER_STAT(DODGING_DISTANCE_THRESHOLD, float, autocvar_sv_dodging_wall_distance_threshold)
+ REGISTER_STAT(DODGING_FROZEN, int, autocvar_sv_dodging_frozen)
+ REGISTER_STAT(DODGING_FROZEN_NO_DOUBLETAP, int, autocvar_sv_dodging_frozen_doubletap)
+ REGISTER_STAT(DODGING_HEIGHT_THRESHOLD, float, autocvar_sv_dodging_height_threshold)
+ REGISTER_STAT(DODGING_HORIZ_SPEED, float, autocvar_sv_dodging_horiz_speed)
+ REGISTER_STAT(DODGING_HORIZ_SPEED_FROZEN, float, autocvar_sv_dodging_horiz_speed_frozen)
+ REGISTER_STAT(DODGING_RAMP_TIME, float, autocvar_sv_dodging_ramp_time)
+ /** cvar loopback */
+ REGISTER_STAT(DODGING_TIMEOUT, float)
+ REGISTER_STAT(DODGING_UP_SPEED, float, autocvar_sv_dodging_up_speed)
+ REGISTER_STAT(DODGING_WALL, int, autocvar_sv_dodging_wall_dodging)
+ REGISTER_STAT(JETPACK_ACCEL_SIDE, float, autocvar_g_jetpack_acceleration_side)
+ REGISTER_STAT(JETPACK_ACCEL_UP, float, autocvar_g_jetpack_acceleration_up)
+ REGISTER_STAT(JETPACK_ANTIGRAVITY, float, autocvar_g_jetpack_antigravity)
+ REGISTER_STAT(JETPACK_FUEL, float, autocvar_g_jetpack_fuel)
+ REGISTER_STAT(JETPACK_MAXSPEED_SIDE, float, autocvar_g_jetpack_maxspeed_side)
+ REGISTER_STAT(JETPACK_MAXSPEED_UP, float, autocvar_g_jetpack_maxspeed_up)
  
- /* The following stats change depending on the gamemode, so can share the same ID */
- // IDs 100 to 104 reserved for gamemodes
+ REGISTER_STAT(MOVEVARS_HIGHSPEED, float, autocvar_g_movement_highspeed)
  
- // freeze tag, clan arena, jailbreak
- const int STAT_REDALIVE               = 100;
- const int STAT_BLUEALIVE              = 101;
- const int STAT_YELLOWALIVE            = 102;
- const int STAT_PINKALIVE              = 103;
+ // freeze tag, clan arena
+ REGISTER_STAT(REDALIVE, int)
+ REGISTER_STAT(BLUEALIVE, int)
+ REGISTER_STAT(YELLOWALIVE, int)
+ REGISTER_STAT(PINKALIVE, int)
  
  // domination
- const int STAT_DOM_TOTAL_PPS          = 100;
- const int STAT_DOM_PPS_RED            = 101;
- const int STAT_DOM_PPS_BLUE           = 102;
- const int STAT_DOM_PPS_YELLOW         = 103;
- const int STAT_DOM_PPS_PINK           = 104;
+ REGISTER_STAT(DOM_TOTAL_PPS, float)
+ REGISTER_STAT(DOM_PPS_RED, float)
+ REGISTER_STAT(DOM_PPS_BLUE, float)
+ REGISTER_STAT(DOM_PPS_YELLOW, float)
+ REGISTER_STAT(DOM_PPS_PINK, float)
  
- // vip
- const int STAT_VIP                    = 100;
- const int STAT_VIP_RED                = 101;
- const int STAT_VIP_BLUE               = 102;
- const int STAT_VIP_YELLOW             = 103;
- const int STAT_VIP_PINK               = 104;
+ REGISTER_STAT(TELEPORT_MAXSPEED, float, autocvar_g_teleport_maxspeed)
+ REGISTER_STAT(TELEPORT_TELEFRAG_AVOID, int, autocvar_g_telefrags_avoid)
  
- // key hunt
- const int STAT_KH_REDKEY_TEAM         = 100;
- const int STAT_KH_BLUEKEY_TEAM        = 101;
- const int STAT_KH_YELLOWKEY_TEAM      = 102;
- const int STAT_KH_PINKKEY_TEAM        = 103;
+ #ifdef SVQC
+ #include "movetypes/movetypes.qh"
+ #endif
+ REGISTER_STAT(MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, float)
+ REGISTER_STAT(MOVEVARS_AIRCONTROL_PENALTY, float)
+ REGISTER_STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW, float)
+ REGISTER_STAT(MOVEVARS_AIRSTRAFEACCEL_QW, float)
+ REGISTER_STAT(MOVEVARS_AIRCONTROL_POWER, float)
+ noref bool autocvar_sv_gameplayfix_nogravityonground;
+ REGISTER_STAT(MOVEFLAGS, int, MOVEFLAG_VALID
+                               | (autocvar_sv_gameplayfix_q2airaccelerate ? MOVEFLAG_Q2AIRACCELERATE : 0)
+                               | (autocvar_sv_gameplayfix_nogravityonground ? MOVEFLAG_NOGRAVITYONGROUND : 0)
+                               | (autocvar_sv_gameplayfix_gravityunaffectedbyticrate ? MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE : 0))
  
- /* Gamemode-specific stats end here */
+ REGISTER_STAT(MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL, float)
+ REGISTER_STAT(MOVEVARS_WARSOWBUNNY_ACCEL, float)
+ REGISTER_STAT(MOVEVARS_WARSOWBUNNY_TOPSPEED, float)
+ REGISTER_STAT(MOVEVARS_WARSOWBUNNY_TURNACCEL, float)
+ REGISTER_STAT(MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO, float)
  
- const int STAT_PL_VIEW_OFS1           = 105;
- const int STAT_PL_VIEW_OFS2           = 106;
- const int STAT_PL_VIEW_OFS3           = 107;
- const int STAT_PL_MIN1                = 108;
- const int STAT_PL_MIN2                = 109;
- const int STAT_PL_MIN3                = 110;
- const int STAT_PL_MAX1                = 111;
- const int STAT_PL_MAX2                = 112;
- const int STAT_PL_MAX3                = 113;
- const int STAT_PL_CROUCH_MIN1         = 114;
- const int STAT_PL_CROUCH_MIN2         = 115;
- const int STAT_PL_CROUCH_MIN3         = 116;
- const int STAT_PL_CROUCH_MAX1         = 117;
- const int STAT_PL_CROUCH_MAX2         = 118;
- const int STAT_PL_CROUCH_MAX3         = 119;
- const int STAT_PL_CROUCH_VIEW_OFS1    = 117;
- const int STAT_PL_CROUCH_VIEW_OFS2    = 118;
- const int STAT_PL_CROUCH_VIEW_OFS3    = 119;
- const int STAT_WEAPONSINMAP           = 120;
- const int STAT_WEAPONSINMAP2          = 121;
- const int STAT_WEAPONSINMAP3          = 122;
- const int STAT_BUFF_TIME              = 123;
- const int STAT_CTF_FLAGSTATUS         = 124;
- // 125 empty?
- // 126 empty?
- // 127 empty?
- // 128 empty?
- // 129 empty?
- // 130 empty?
- // 131 empty?
- // 132 empty?
- // 133 empty?
- // 134 empty?
- // 135 empty?
- // 136 empty?
- // 137 empty?
- // 138 empty?
- // 139 empty?
- // 140 reserved
- // 141 reserved
- // 142 reserved
- // 143 reserved
- // 144 reserved
- // 145 reserved
- // 146 reserved
- // 147 reserved
- // 148 reserved
- // 149 reserved
- // 150 reserved
- // 151 reserved
- // 152 reserved
- // 153 reserved
- // 154 reserved
- // 155 reserved
- // 156 empty?
- // 157 empty?
- // 158 empty?
- // 159 empty?
- // 160 empty?
- // 161 empty?
- // 162 empty?
- // 162 empty?
- // 163 empty?
- // 164 empty?
- // 165 empty?
- const int STAT_MULTIJUMP_DODGING                      = 166;
- const int STAT_MULTIJUMP_MAXSPEED                     = 167;
- const int STAT_GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND   = 168;
- const int STAT_BUGRIGS_REVERSE_STOPPING               = 169;
- const int STAT_BUGRIGS_REVERSE_SPINNING               = 170;
- const int STAT_BUGRIGS_CAR_JUMPING                    = 171;
- const int STAT_BUGRIGS_FRICTION_AIR                   = 172;
- const int STAT_BUGRIGS_STEER                          = 173;
- const int STAT_BUGRIGS_SPEED_POW                      = 174;
- const int STAT_BUGRIGS_SPEED_REF                      = 175;
- const int STAT_BUGRIGS_ACCEL                          = 176;
- const int STAT_BUGRIGS_FRICTION_BRAKE                 = 177;
- const int STAT_BUGRIGS_AIR_STEERING                   = 178;
- const int STAT_BUGRIGS_FRICTION_FLOOR                 = 179;
- const int STAT_BUGRIGS_REVERSE_SPEEDING               = 180;
- const int STAT_BUGRIGS_PLANAR_MOVEMENT                = 181;
- const int STAT_BUGRIGS_ANGLE_SMOOTHING                = 182;
- const int STAT_BUGRIGS                                = 183;
- const int STAT_GAMEPLAYFIX_STEPDOWN                   = 184;
- const int STAT_MOVEVARS_JUMPSTEP                      = 185;
- const int STAT_NOSTEP                                 = 186;
- const int STAT_GAMEPLAYFIX_UNSTICKPLAYERS             = 187;
- const int STAT_GAMEPLAYFIX_STEPMULTIPLETIMES          = 188;
- const int STAT_GAMEPLAYFIX_DOWNTRACEONGROUND          = 189;
- const int STAT_GAMEPLAYFIX_EASIERWATERJUMP            = 190;
- const int STAT_MOVEVARS_FRICTION_SLICK                = 191;
- const int STAT_MOVEVARS_FRICTION_ONLAND               = 192;
- const int STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS  = 193;
- const int STAT_MOVEVARS_TRACK_CANJUMP                 = 194;
- // 195 empty?
- const int STAT_DOUBLEJUMP                             = 196;
- const int STAT_MOVEVARS_CL_TRACK_CANJUMP              = 197;
- const int STAT_MULTIJUMP_ADD                          = 198;
- const int STAT_MULTIJUMP_SPEED                        = 199;
- const int STAT_MULTIJUMP                              = 200;
- const int STAT_DODGING_TIMEOUT                        = 201;
- const int STAT_DODGING_WALL                           = 202;
- const int STAT_DODGING_UP_SPEED                       = 203;
- const int STAT_DODGING_RAMP_TIME                      = 204;
- const int STAT_DODGING_HEIGHT_THRESHOLD               = 205;
- const int STAT_DODGING_DISTANCE_THRESHOLD             = 206;
- const int STAT_DODGING_HORIZ_SPEED                    = 207;
- const int STAT_DODGING_DELAY                          = 208;
- const int STAT_DODGING_FROZEN_NO_DOUBLETAP            = 209;
- const int STAT_DODGING_HORIZ_SPEED_FROZEN             = 210;
- const int STAT_DODGING                                = 211;
- const int STAT_DODGING_FROZEN                         = 212;
- const int STAT_JETPACK_MAXSPEED_UP                    = 213;
- const int STAT_JETPACK_MAXSPEED_SIDE                  = 214;
- const int STAT_JETPACK_FUEL                           = 215;
- const int STAT_JETPACK_ANTIGRAVITY                    = 216;
- const int STAT_JETPACK_ACCEL_SIDE                     = 217;
- const int STAT_JETPACK_ACCEL_UP                       = 218;
- const int STAT_MOVEVARS_HIGHSPEED                     = 219;
- const int STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR     = 220;
- const int STAT_MOVEVARS_AIRCONTROL_PENALTY            = 221;
- const int STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW           = 222;
- const int STAT_MOVEVARS_AIRSTRAFEACCEL_QW             = 223;
- const int STAT_MOVEVARS_AIRCONTROL_POWER              = 224;
- const int STAT_MOVEFLAGS                              = 225;
- const int STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL   = 226;
- const int STAT_MOVEVARS_WARSOWBUNNY_ACCEL             = 227;
- const int STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED          = 228;
- const int STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL         = 229;
- const int STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO   = 230;
- const int STAT_MOVEVARS_AIRSTOPACCELERATE             = 231;
- const int STAT_MOVEVARS_AIRSTRAFEACCELERATE           = 232;
- const int STAT_MOVEVARS_MAXAIRSTRAFESPEED             = 233;
- const int STAT_MOVEVARS_AIRCONTROL                    = 234;
- // -Wdouble-declaration
- // const int STAT_FRAGLIMIT                              = 235;
- // -Wdouble-declaration
- // const int STAT_TIMELIMIT                              = 236;
- const int STAT_MOVEVARS_WALLFRICTION                  = 237;
- const int STAT_MOVEVARS_FRICTION                      = 238;
- const int STAT_MOVEVARS_WATERFRICTION                 = 239;
- // -Wdouble-declaration
- // const int STAT_MOVEVARS_TICRATE                       = 240;
- // -Wdouble-declaration
- // const int STAT_MOVEVARS_TIMESCALE                     = 241;
- // -Wdouble-declaration
- // const int STAT_MOVEVARS_GRAVITY                       = 242;
- const int STAT_MOVEVARS_STOPSPEED                     = 243;
- const int STAT_MOVEVARS_MAXSPEED                      = 244;
- const int STAT_MOVEVARS_SPECTATORMAXSPEED             = 245;
- const int STAT_MOVEVARS_ACCELERATE                    = 246;
- const int STAT_MOVEVARS_AIRACCELERATE                 = 247;
- const int STAT_MOVEVARS_WATERACCELERATE               = 248;
- const int STAT_MOVEVARS_ENTGRAVITY                    = 249;
- const int STAT_MOVEVARS_JUMPVELOCITY                  = 250;
- const int STAT_MOVEVARS_EDGEFRICTION                  = 251;
- const int STAT_MOVEVARS_MAXAIRSPEED                   = 252;
- const int STAT_MOVEVARS_STEPHEIGHT                    = 253;
- const int STAT_MOVEVARS_AIRACCEL_QW                   = 254;
- const int STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION    = 255;
+ REGISTER_STAT(MOVEVARS_AIRSTOPACCELERATE, float)
+ REGISTER_STAT(MOVEVARS_AIRSTRAFEACCELERATE, float)
+ REGISTER_STAT(MOVEVARS_MAXAIRSTRAFESPEED, float)
+ REGISTER_STAT(MOVEVARS_AIRCONTROL, float)
+ REGISTER_STAT(FRAGLIMIT, float, autocvar_fraglimit)
+ REGISTER_STAT(TIMELIMIT, float, autocvar_timelimit)
+ #ifdef SVQC
+ float autocvar_sv_wallfriction;
+ #endif
+ REGISTER_STAT(MOVEVARS_WALLFRICTION, int, autocvar_sv_wallfriction)
+ REGISTER_STAT(MOVEVARS_TICRATE, float, autocvar_sys_ticrate)
+ REGISTER_STAT(MOVEVARS_TIMESCALE, float, autocvar_slowmo)
+ REGISTER_STAT(MOVEVARS_GRAVITY, float, autocvar_sv_gravity)
+ REGISTER_STAT(MOVEVARS_STOPSPEED, float)
+ REGISTER_STAT(MOVEVARS_MAXSPEED, float)
+ REGISTER_STAT(MOVEVARS_ACCELERATE, float)
+ REGISTER_STAT(MOVEVARS_AIRACCELERATE, float)
+ .float gravity;
+ // FIXME: Was 0 on server, 1 on client. Still want that?
+ REGISTER_STAT(MOVEVARS_ENTGRAVITY, float, (this.gravity) ? this.gravity : 1)
+ REGISTER_STAT(MOVEVARS_JUMPVELOCITY, float)
+ REGISTER_STAT(MOVEVARS_MAXAIRSPEED, float)
+ REGISTER_STAT(MOVEVARS_STEPHEIGHT, float, autocvar_sv_stepheight)
+ REGISTER_STAT(MOVEVARS_AIRACCEL_QW, float)
+ REGISTER_STAT(MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, float)
  #endif
Simple merge
        #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 "../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) {
++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 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()
 -{
 -      return STAT(WEAPONS);
 -}
 -WepSet WepSet_GetFromStat_InMap()
 -{
 -      return STAT(WEAPONSINMAP);
 -}
 -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;
++              return STAT(WEAPONS);
 +      }
 +      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;
++              return STAT(WEAPONSINMAP);
 +      }
 +      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)
@@@ -246,33 -230,33 +224,33 @@@ string GetAmmoPicture(.int ammotype
  }
  
  #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.m_id;
 -              case ammo_fuel: return STAT_FUEL.m_id;
 -              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;
++                      case ammo_plasma: return STAT_PLASMA.m_id;
++                      case ammo_fuel: return STAT_FUEL.m_id;
 +                      default: return -1;
 +              }
        }
 -}
  #endif
  
  string W_Sound(string w_snd)
@@@ -167,39 -172,4 +172,41 @@@ STATIC_INIT(register_weapons_done
      weaponorder_byid = strzone(substring(weaponorder_byid, 1, strlen(weaponorder_byid) - 1));
  }
  
- .int switchweapon; // weapon requested to switch to
- .int switchingweapon; // weapon currently being switched to (is copied from switchweapon once switch is possible)
 +#ifndef MENUQC
 +
 +.entity weaponchild;
 +.entity exteriorweaponentity;
 +.vector weaponentity_glowmod;
 +
 +//.int weapon; // current weapon
++#ifdef SVQC
++.int switchweapon = _STAT(SWITCHWEAPON);
++.int switchingweapon = _STAT(SWITCHINGWEAPON);
++#endif
 +.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
@@@ -17,18 -18,15 +18,27 @@@ int weaponslot(.entity weaponentity
        return 0;
  }
  
 +// weapon states (actor.(weaponentity).state)
 +/** no weapon selected */
 +const int WS_CLEAR  = 0;
 +/** raise frame */
 +const int WS_RAISE  = 1;
 +/** deselecting frame */
 +const int WS_DROP   = 2;
 +/** fire state */
 +const int WS_INUSE  = 3;
 +/** idle frame */
 +const int WS_READY  = 4;
 +
+ #ifdef SVQC
+ .int ammo_shells;
+ .int ammo_nails;
+ .int ammo_rockets;
+ .int ammo_cells;
+ .int ammo_plasma = _STAT(PLASMA);
+ .int ammo_fuel = _STAT(FUEL);
+ .int ammo_none;
+ #else
  .int ammo_shells;
  .int ammo_nails;
  .int ammo_rockets;
Simple merge
Simple merge
@@@ -47,31 -67,12 +67,22 @@@ float boxesoverlap(vector m1, vector m2
  /** requires the same as boxesoverlap, but is a stronger condition */
  float boxinsidebox(vector smins, vector smaxs, vector bmins, vector bmaxs) { return smins.x >= bmins.x && smaxs.x <= bmaxs.x && smins.y >= bmins.y && smaxs.y <= bmaxs.y && smins.z >= bmins.z && smaxs.z <= bmaxs.z; }
  
 +#define PITCH(v) (v).x
 +#define YAW(v) (v).y
 +#define ROLL(v) (v).z
 +
 +#define MAKEVECTORS(f, angles, forward, right, up) do { \
 +      f(angles); \
 +      forward = v_forward; \
 +      right = v_right; \
 +      up = v_up; \
 +} while (0)
  
- vector vec2(vector v)
- {
-       v.z = 0;
-       return v;
- }
+ noref vector _vec2;
+ #define vec2(v) (_vec2 = (v), _vec2.z = 0, _vec2)
  
- vector vec3(float x, float y, float z)
- {
-       vector v;
-       v.x = x;
-       v.y = y;
-       v.z = z;
-       return v;
- }
+ noref vector _vec3;
+ #define vec3(x, y, z) (_vec3_x = (x), _vec3_y = (y), _vec3_z = (z), _vec3)
  
  vector rotate(vector v, float a)
  {
Simple merge
Simple merge
@@@ -149,7 -165,7 +148,7 @@@ float client_hasweapon(entity cl, floa
  void w_clear(Weapon thiswep, entity actor, .entity weaponentity, int fire);
  void w_ready(Weapon thiswep, entity actor, .entity weaponentity, int fire);
  // VorteX: standalone think for weapons, so normal think on weaponentity can be reserved by weaponflashes (which needs update even player dies)
--.float weapon_nextthink;
++.float weapon_nextthink = _STAT(WEAPON_NEXTTHINK);
  .void(Weapon thiswep, entity actor, .entity weaponentity, int fire) weapon_think;
  
  
@@@ -9,18 -9,14 +9,8 @@@ void() SUB_CalcAngleMoveDone
  
  spawnfunc(info_null);
  
 -void setanim(entity e, vector anim, float looping, float override, float restart);
 -
 -void updateanim(entity e);
 -
 -
 -
  /*
  ==================
- SUB_Remove
- Remove self
- ==================
- */
- void SUB_Remove ();
- /*
- ==================
  SUB_Friction
  
  Applies some friction to self
Simple merge
Simple merge