Merge master into qc_physics_prehax (blame TimePath if it's completely broken)
authorMario <zacjardine@y7mail.com>
Wed, 8 Jul 2015 14:15:25 +0000 (00:15 +1000)
committerMario <zacjardine@y7mail.com>
Wed, 8 Jul 2015 14:15:25 +0000 (00:15 +1000)
80 files changed:
1  2 
defaultXonotic.cfg
qcsrc/client/bgmscript.qh
qcsrc/client/casings.qc
qcsrc/client/command/cl_cmd.qc
qcsrc/client/csqcmodel_hooks.qc
qcsrc/client/damage.qc
qcsrc/client/effects.qc
qcsrc/client/gibs.qc
qcsrc/client/main.qc
qcsrc/client/miscfunctions.qc
qcsrc/client/miscfunctions.qh
qcsrc/client/particles.qc
qcsrc/client/particles.qh
qcsrc/client/player_skeleton.qc
qcsrc/client/progs.src
qcsrc/client/t_items.qc
qcsrc/client/tturrets.qc
qcsrc/client/vehicles/all.qc
qcsrc/client/vehicles/bumblebee.qc
qcsrc/client/view.qc
qcsrc/client/waypointsprites.qc
qcsrc/client/weapons/projectile.qc
qcsrc/common/constants.qh
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/physics.qc
qcsrc/common/physics.qh
qcsrc/common/stats.qh
qcsrc/common/triggers/func/breakable.qc
qcsrc/common/triggers/func/pointparticles.qc
qcsrc/common/triggers/target/music.qc
qcsrc/common/triggers/target/music.qh
qcsrc/common/triggers/target/spawn.qc
qcsrc/common/triggers/teleporters.qc
qcsrc/common/triggers/trigger/jumppads.qc
qcsrc/common/triggers/trigger/secret.qc
qcsrc/common/triggers/trigger/swamp.qc
qcsrc/common/triggers/triggers.qh
qcsrc/common/util.qc
qcsrc/common/weapons/all.qc
qcsrc/dpdefs/upstream/csprogsdefs.qc
qcsrc/server/bot/havocbot/havocbot.qc
qcsrc/server/bot/navigation.qc
qcsrc/server/bot/waypoints.qc
qcsrc/server/cheats.qc
qcsrc/server/cl_client.qc
qcsrc/server/cl_player.qc
qcsrc/server/command/cmd.qc
qcsrc/server/command/radarmap.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_hook.qc
qcsrc/server/g_models.qc
qcsrc/server/g_subs.qc
qcsrc/server/g_world.qc
qcsrc/server/item_key.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/miscfunctions.qh
qcsrc/server/mutators/gamemode.qh
qcsrc/server/mutators/gamemode_ctf.qc
qcsrc/server/mutators/gamemode_ctf.qh
qcsrc/server/mutators/gamemode_keyhunt.qc
qcsrc/server/mutators/gamemode_nexball.qc
qcsrc/server/mutators/mutator.qh
qcsrc/server/mutators/mutator_dodging.qc
qcsrc/server/mutators/mutator_multijump.qc
qcsrc/server/mutators/mutators_include.qc
qcsrc/server/pathlib.qc
qcsrc/server/portals.qc
qcsrc/server/progs.src
qcsrc/server/spawnpoints.qc
qcsrc/server/t_items.qc
qcsrc/server/t_plats.qc
qcsrc/server/tturrets/units/unit_walker.qc
qcsrc/server/vehicles/racer.qc
qcsrc/server/vehicles/vehicle.qh
qcsrc/server/weapons/hitplot.qc
qcsrc/server/weapons/throwing.qc
qcsrc/warpzonelib/common.qc
qcsrc/warpzonelib/server.qc
qcsrc/warpzonelib/util_server.qc

Simple merge
@@@ -1,8 -1,15 +1,18 @@@
  #ifndef BGMSCRIPT_H
  #define BGMSCRIPT_H
  
- .float just_toggled;
+ entityclass(BGMScript);
+ class(BGMScript) .string bgmscript;
+ class(BGMScript) .float bgmscriptattack;
+ class(BGMScript) .float bgmscriptdecay;
+ class(BGMScript) .float bgmscriptsustain;
+ class(BGMScript) .float bgmscriptrelease;
  
+ class(BGMScript) .float just_toggled;
++#ifdef CSQC
  void BGMScript_InitEntity(entity e);
- float BGMScript(entity e);
+ float doBGMScript(entity e);
+ #endif
++
 +#endif
@@@ -1,17 -1,18 +1,18 @@@
- #if defined(CSQC)
-       #include "../common/movetypes/movetypes.qh"
-       #include "prandom.qh"
-       #include "rubble.qh"
+ #include "casings.qh"
+ #include "_all.qh"
  
-       .float cnt;
-       .float alpha;
-       .int state;
- #elif defined(MENUQC)
- #elif defined(SVQC)
- #endif
 -#include "movetypes.qh"
++#include "../common/movetypes/movetypes.qh"
+ #include "prandom.qh"
+ #include "rubble.qh"
  
+ #include "../common/util.qh"
  
- .bool silent;
+ .float cnt;
+ .float alpha;
+ .int state;
+ entityclass(Casing);
+ class(Casing) .bool silent;
  
  void Casing_Delete()
  {
Simple merge
Simple merge
@@@ -1,18 -1,23 +1,23 @@@
- #if defined(CSQC)
-       #include "../dpdefs/csprogsdefs.qh"
-       #include "defs.qh"
-       #include "../common/constants.qh"
-       #include "../common/util.qh"
-       #include "../common/weapons/weapons.qh"
-       #include "autocvars.qh"
-       #include "../common/deathtypes.qh"
-       #include "damage.qh"
-       #include "../common/movetypes/movetypes.qh"
-       #include "prandom.qh"
-       #include "vehicles/vehicles.qh"
- #elif defined(MENUQC)
- #elif defined(SVQC)
- #endif
+ #include "damage.qh"
+ #include "_all.qh"
+ #include "gibs.qh"
 -#include "movetypes.qh"
+ #include "prandom.qh"
+ #include "vehicles/all.qh"
+ #include "../common/constants.qh"
+ #include "../common/deathtypes.qh"
++#include "../common/movetypes/movetypes.qh"
+ #include "../common/util.qh"
+ #include "../common/weapons/all.qh"
+ .entity tag_entity;
+ .float cnt;
+ .int state;
+ .bool isplayermodel;
  
  void DamageEffect_Think()
  {
Simple merge
@@@ -1,4 -1,17 +1,17 @@@
  #include "gibs.qh"
 -#include "movetypes.qh"
+ #include "_all.qh"
+ #include "prandom.qh"
+ #include "rubble.qh"
+ #include "../common/constants.qh"
++#include "../common/movetypes/movetypes.qh"
+ #include "../common/util.qh"
+ .float scale;
+ .float alpha;
+ .float cnt;
+ .float gravity;
  
  void Gib_Delete()
  {
  #include "mapvoting.qh"
  #include "modeleffects.qh"
  #include "particles.qh"
+ #include "prandom.qh"
  #include "scoreboard.qh"
  #include "shownames.qh"
 -#include "target_music.qh"
+ #include "sortlist.qh"
  #include "tturrets.qh"
  #include "tuba.qh"
+ #include "t_items.qh"
  #include "wall.qh"
  #include "waypointsprites.qh"
  
- #include "vehicles/vehicles.qh"
+ #include "vehicles/bumblebee.qh"
+ #include "vehicles/all.qh"
  
- #include "../server/vehicles/bumblebee.qh"
+ #include "weapons/projectile.qh"
  
+ #include "../common/buffs.qh"
+ #include "../common/deathtypes.qh"
+ #include "../common/mapinfo.qh"
+ #include "../common/monsters/all.qh"
+ #include "../common/nades.qh"
  #include "../common/net_notice.qh"
+ #include "../common/notifications.qh"
+ #include "../common/stats.qh"
+ #include "../common/teams.qh"
  
- #include "../common/monsters/monsters.qh"
+ #include "../common/items/all.qh"
+ #include "../common/weapons/all.qh"
+ #include "../csqcmodellib/cl_model.qh"
+ #include "../csqcmodellib/interpolate.qh"
  
 +#include "../common/triggers/include.qh"
 +
  #include "../warpzonelib/client.qh"
  
  // --------------------------------------------------------------------------
Simple merge
@@@ -5,24 -5,6 +5,15 @@@ entity players
  entity teams;
  float team_count; // real teams
  
- .void(void) initialize_entity;
- .int initialize_entity_order;
- .entity initialize_entity_next;
- entity initialize_entity_first;
- void InitializeEntity(entity e, void(void) func, int order);
- void InitializeEntitiesRun();
 +const int INITPRIO_FIRST                              = 0;
 +const int INITPRIO_GAMETYPE                   = 0;
 +const int INITPRIO_GAMETYPE_FALLBACK  = 1;
 +const int INITPRIO_FINDTARGET                         = 10;
 +const int INITPRIO_DROPTOFLOOR                        = 20;
 +const int INITPRIO_SETLOCATION                        = 90;
 +const int INITPRIO_LINKDOORS                  = 91;
 +const int INITPRIO_LAST                               = 99;
 +
  void AuditLists();
  
  float RegisterPlayer(entity player);
@@@ -1,5 -1,226 +1,11 @@@
  #include "particles.qh"
 -#include "bgmscript.qh"
 -
+ #include "_all.qh"
+ #include "../common/stats.qh"
+ #include "../common/util.qh"
+ #include "../warpzonelib/common.qh"
  
 -void Draw_PointParticles()
 -{
 -      float n, i, fail;
 -      vector p;
 -      vector sz;
 -      vector o;
 -      o = self.origin;
 -      sz = self.maxs - self.mins;
 -      n = doBGMScript(self);
 -      if(self.absolute == 2)
 -      {
 -              if(n >= 0)
 -                      n = self.just_toggled ? self.impulse : 0;
 -              else
 -                      n = self.impulse * drawframetime;
 -      }
 -      else
 -      {
 -              n *= self.impulse * drawframetime;
 -              if(self.just_toggled)
 -                      if(n < 1)
 -                              n = 1;
 -      }
 -      if(n == 0)
 -              return;
 -      fail = 0;
 -      for(i = random(); i <= n && fail <= 64*n; ++i)
 -      {
 -              p = o + self.mins;
 -              p.x += random() * sz.x;
 -              p.y += random() * sz.y;
 -              p.z += random() * sz.z;
 -              if(WarpZoneLib_BoxTouchesBrush(p, p, self, world))
 -              {
 -                      if(self.movedir != '0 0 0')
 -                      {
 -                              traceline(p, p + normalize(self.movedir) * 4096, 0, world);
 -                              p = trace_endpos;
 -                              pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count);
 -                      }
 -                      else
 -                      {
 -                              pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count);
 -                      }
 -                      if(self.noise != "")
 -                      {
 -                              setorigin(self, p);
 -                              sound(self, CH_AMBIENT, self.noise, VOL_BASE * self.volume, self.atten);
 -                      }
 -                      self.just_toggled = 0;
 -              }
 -              else if(self.absolute)
 -              {
 -                      ++fail;
 -                      --i;
 -              }
 -      }
 -      setorigin(self, o);
 -}
 -
 -void Ent_PointParticles_Remove()
 -{
 -      if(self.noise)
 -              strunzone(self.noise);
 -      self.noise = string_null;
 -      if(self.bgmscript)
 -              strunzone(self.bgmscript);
 -      self.bgmscript = string_null;
 -}
 -
 -void Ent_PointParticles()
 -{
 -      float i;
 -      vector v;
 -      int f = ReadByte();
 -      if(f & 2)
 -      {
 -              i = ReadCoord(); // density (<0: point, >0: volume)
 -              if(i && !self.impulse && self.cnt) // self.cnt check is so it only happens if the ent already existed
 -                      self.just_toggled = 1;
 -              self.impulse = i;
 -      }
 -      if(f & 4)
 -      {
 -              self.origin_x = ReadCoord();
 -              self.origin_y = ReadCoord();
 -              self.origin_z = ReadCoord();
 -      }
 -      if(f & 1)
 -      {
 -              self.modelindex = ReadShort();
 -              if(f & 0x80)
 -              {
 -                      if(self.modelindex)
 -                      {
 -                              self.mins_x = ReadCoord();
 -                              self.mins_y = ReadCoord();
 -                              self.mins_z = ReadCoord();
 -                              self.maxs_x = ReadCoord();
 -                              self.maxs_y = ReadCoord();
 -                              self.maxs_z = ReadCoord();
 -                      }
 -                      else
 -                      {
 -                              self.mins    = '0 0 0';
 -                              self.maxs_x = ReadCoord();
 -                              self.maxs_y = ReadCoord();
 -                              self.maxs_z = ReadCoord();
 -                      }
 -              }
 -              else
 -              {
 -                      self.mins = self.maxs = '0 0 0';
 -              }
 -
 -              self.cnt = ReadShort(); // effect number
 -
 -              if(f & 0x20)
 -              {
 -                      self.velocity = decompressShortVector(ReadShort());
 -                      self.movedir = decompressShortVector(ReadShort());
 -              }
 -              else
 -              {
 -                      self.velocity = self.movedir = '0 0 0';
 -              }
 -              if(f & 0x40)
 -              {
 -                      self.waterlevel = ReadShort() / 16.0;
 -                      self.count = ReadByte() / 16.0;
 -              }
 -              else
 -              {
 -                      self.waterlevel = 0;
 -                      self.count = 1;
 -              }
 -              if(self.noise)
 -                      strunzone(self.noise);
 -              if(self.bgmscript)
 -                      strunzone(self.bgmscript);
 -              self.noise = strzone(ReadString());
 -              if(self.noise != "")
 -              {
 -                      self.atten = ReadByte() / 64.0;
 -                      self.volume = ReadByte() / 255.0;
 -              }
 -              self.bgmscript = strzone(ReadString());
 -              if(self.bgmscript != "")
 -              {
 -                      self.bgmscriptattack = ReadByte() / 64.0;
 -                      self.bgmscriptdecay = ReadByte() / 64.0;
 -                      self.bgmscriptsustain = ReadByte() / 255.0;
 -                      self.bgmscriptrelease = ReadByte() / 64.0;
 -              }
 -              BGMScript_InitEntity(self);
 -      }
 -
 -      if(f & 2)
 -      {
 -              self.absolute = (self.impulse >= 0);
 -              if(!self.absolute)
 -              {
 -                      v = self.maxs - self.mins;
 -                      self.impulse *= -v.x * v.y * v.z / 262144; // relative: particles per 64^3 cube
 -              }
 -      }
 -
 -      if(f & 0x10)
 -              self.absolute = 2;
 -
 -      setorigin(self, self.origin);
 -      setsize(self, self.mins, self.maxs);
 -      self.solid = SOLID_NOT;
 -      self.draw = Draw_PointParticles;
 -      self.entremove = Ent_PointParticles_Remove;
 -}
 -
 -void Draw_Rain()
 -{
 -    te_particlerain(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
 -}
 -
 -void Draw_Snow()
 -{
 -    te_particlesnow(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
 -}
 -
 -void Ent_RainOrSnow()
 -{
 -      self.impulse = ReadByte(); // Rain, Snow, or Whatever
 -      self.origin_x = ReadCoord();
 -      self.origin_y = ReadCoord();
 -      self.origin_z = ReadCoord();
 -      self.maxs_x = ReadCoord();
 -      self.maxs_y = ReadCoord();
 -      self.maxs_z = ReadCoord();
 -      self.velocity = decompressShortVector(ReadShort());
 -      self.count = ReadShort() * 10;
 -      self.glow_color = ReadByte(); // color
 -
 -      self.mins    = -0.5 * self.maxs;
 -      self.maxs    =  0.5 * self.maxs;
 -      self.origin  = self.origin - self.mins;
 -
 -      setorigin(self, self.origin);
 -      setsize(self, self.mins, self.maxs);
 -      self.solid = SOLID_NOT;
 -      if(self.impulse)
 -              self.draw = Draw_Rain;
 -      else
 -              self.draw = Draw_Snow;
 -}
 -
  void Net_ReadVortexBeamParticle()
  {
        vector shotorg, endpos;
@@@ -1,19 -1,33 +1,26 @@@
  #ifndef PARTICLES_H
  #define PARTICLES_H
 -
  .int dphitcontentsmask;
  
- .int cnt; // effect number
- .vector velocity; // particle velocity
- .float waterlevel; // direction jitter
- .int count; // count multiplier
- .int impulse; // density
- .string noise; // sound
- .float atten;
- .float volume;
- .float absolute; // 1 = count per second is absolute, 2 = only spawn at toggle
- .vector movedir; // trace direction
+ entityclass(PointParticles);
+ class(PointParticles) .int cnt; // effect number
+ class(PointParticles) .vector velocity; // particle velocity
+ class(PointParticles) .float waterlevel; // direction jitter
+ class(PointParticles) .int count; // count multiplier
+ class(PointParticles) .int impulse; // density
+ class(PointParticles) .string noise; // sound
+ class(PointParticles) .float atten;
+ class(PointParticles) .float volume;
+ class(PointParticles) .float absolute; // 1 = count per second is absolute, 2 = only spawn at toggle
+ class(PointParticles) .vector movedir; // trace direction
  
- .float glow_color; // palette index
+ void Draw_PointParticles();
+ void Ent_PointParticles_Remove();
+ void Ent_PointParticles();
+ class(PointParticles) .float glow_color; // palette index
  
 -void Draw_Rain();
 -
 -void Draw_Snow();
 -
 -void Ent_RainOrSnow();
 -
  void Net_ReadVortexBeamParticle();
  #endif
Simple merge
@@@ -11,12 -11,15 +11,13 @@@ damage.q
  effects.qc
  gibs.qc
  hook.qc
- hud_config.qc
  hud.qc
 -laser.qc
+ hud_config.qc
  main.qc
  mapvoting.qc
  miscfunctions.qc
  modeleffects.qc
 -movetypes.qc
+ movelib.qc
  noise.qc
  particles.qc
  player_skeleton.qc
@@@ -50,28 -55,16 +54,20 @@@ weapons/projectile.qc // TOD
  ../common/urllib.qc
  ../common/util.qc
  
- ../common/command/generic.qc
- ../common/command/markup.qc
- ../common/command/rpn.qc
+ ../common/items/all.qc
  
- ../common/monsters/monsters.qc
+ ../common/monsters/all.qc
  
- ../common/weapons/weapons.qc // TODO
+ ../common/weapons/all.qc // TODO
  
 +../common/triggers/include.qc
 +
  ../csqcmodellib/cl_model.qc
  ../csqcmodellib/cl_player.qc
  ../csqcmodellib/interpolate.qc
  
- ../server/movelib.qc
 +../server/mutators/mutator_multijump.qc
 +
- ../server/vehicles/bumblebee.qc
- ../server/t_items.qc
  ../warpzonelib/anglestransform.qc
  ../warpzonelib/client.qc
  ../warpzonelib/common.qc
index 0000000,ca631fc..3981b29
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,10 +1,10 @@@
 -#include "movetypes.qh"
+ #include "_all.qh"
+ #include "../common/buffs.qh"
++#include "../common/movetypes/movetypes.qh"
+ #include "../common/util.qh"
+ #include "../common/weapons/all.qh"
+ #include "../csqcmodellib/cl_model.qh"
+ #include "../csqcmodellib/common.qh"
+ #include "../server/t_items.qc"
@@@ -1,7 -1,24 +1,25 @@@
  #include "tturrets.qh"
 -#include "movetypes.qh"
+ #include "_all.qh"
+ #include "hud.qh"
+ #include "movelib.qh"
+ #include "prandom.qh"
+ #include "teamradar.qh"
  #include "waypointsprites.qh"
  
- #include "../server/movelib.qh"
+ #include "../common/teams.qh"
++#include "../common/movetypes/movetypes.qh"
++
+ #include "../server/tturrets/include/turrets_early.qh"
+ #include "../warpzonelib/anglestransform.qh"
+ #include "../warpzonelib/mathlib.qh"
+ .vector colormod;
+ .float cnt;
+ .float alpha;
+ .float gravity;
  
  string tid2info_base;
  string tid2info_head;
index 0000000,0af4d4b..ba92d7c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1054 +1,1054 @@@
 -#include "../movetypes.qh"
 -#include "../movetypes.qh"
+ #include "all.qh"
+ #include "../_all.qh"
++#include "../../common/movetypes/movetypes.qh"
+ #include "../prandom.qh"
+ #include "../scoreboard.qh"
+ #include "../t_items.qh"
+ #include "../../common/buffs.qh"
+ #include "../../common/constants.qh"
++#include "../../common/movetypes/movetypes.qh"
+ #include "../../common/stats.qh"
+ #include "../../common/util.qh"
+ #include "../../csqcmodellib/cl_model.qh"
+ .float cnt;
+ const string hud_bg = "gfx/vehicles/frame.tga";
+ const string hud_sh = "gfx/vehicles/vh-shield.tga";
+ const string hud_hp_bar = "gfx/vehicles/bar_up_left.tga";
+ const string hud_hp_ico = "gfx/vehicles/health.tga";
+ const string hud_sh_bar = "gfx/vehicles/bar_dwn_left.tga";
+ const string hud_sh_ico = "gfx/vehicles/shield.tga";
+ const string hud_ammo1_bar = "gfx/vehicles/bar_up_right.tga";
+ const string hud_ammo1_ico = "gfx/vehicles/bullets.tga";
+ const string hud_ammo2_bar = "gfx/vehicles/bar_dwn_right.tga";
+ const string hud_ammo2_ico = "gfx/vehicles/rocket.tga";
+ const string hud_energy = "gfx/vehicles/energy.tga";
+ const int SBRM_FIRST = 1;
+ const int SBRM_VOLLY = 1;
+ const int SBRM_GUIDE = 2;
+ const int SBRM_ARTILLERY = 3;
+ const int SBRM_LAST = 3;
+ const int RSM_FIRST = 1;
+ const int RSM_BOMB = 1;
+ const int RSM_FLARE = 2;
+ const int RSM_LAST = 2;
+ entity dropmark;
+ float autocvar_cl_vehicles_hudscale = 0.5;
+ float autocvar_cl_vehicles_hudalpha = 0.75;
+ const string raptor_ico =  "gfx/vehicles/raptor.tga";
+ const string raptor_gun =  "gfx/vehicles/raptor_guns.tga";
+ const string raptor_bomb = "gfx/vehicles/raptor_bombs.tga";
+ const string raptor_drop = "gfx/vehicles/axh-dropcross.tga";
+ string raptor_xhair;
+ const int MAX_AXH = 4;
+ entity AuxiliaryXhairs[MAX_AXH];
+ entityclass(AuxiliaryXhair);
+ class(AuxiliaryXhair) .string axh_image;
+ class(AuxiliaryXhair) .float  axh_fadetime;
+ class(AuxiliaryXhair) .float  axh_drawflag;
+ class(AuxiliaryXhair) .float  axh_scale;
+ const string bumb_ico =  "gfx/vehicles/bumb.tga";
+ const string bumb_lgun =  "gfx/vehicles/bumb_lgun.tga";
+ const string bumb_rgun =  "gfx/vehicles/bumb_rgun.tga";
+ const string bumb_gun_ico =  "gfx/vehicles/bumb_side.tga";
+ const string bumb_gun_gun =  "gfx/vehicles/bumb_side_gun.tga";
+ const string spider_ico =  "gfx/vehicles/sbot.tga";
+ const string spider_rkt =  "gfx/vehicles/sbot_rpods.tga";
+ const string spider_mgun = "gfx/vehicles/sbot_mguns.tga";
+ string spider_xhair; // = "gfx/vehicles/axh-special1.tga";
+ const string waki_ico = "gfx/vehicles/waki.tga";
+ const string waki_eng = "gfx/vehicles/waki_e.tga";
+ const string waki_gun = "gfx/vehicles/waki_guns.tga";
+ const string waki_rkt = "gfx/vehicles/waki_rockets.tga";
+ const string waki_xhair = "gfx/vehicles/axh-special1.tga";
+ float alarm1time;
+ float alarm2time;
+ int weapon2mode;
+ void AuxiliaryXhair_Draw2D()
+ {
+     vector loc, psize;
+     psize = self.axh_scale * draw_getimagesize(self.axh_image);
+     loc = project_3d_to_2d(self.move_origin) - 0.5 * psize;
+     if (!(loc.z < 0 || loc.x < 0 || loc.y < 0 || loc.x > vid_conwidth || loc.y > vid_conheight))
+     {
+         loc.z = 0;
+         psize.z = 0;
+         drawpic(loc, self.axh_image, psize, self.colormod, self.alpha, self.axh_drawflag);
+     }
+     if(time - self.cnt > self.axh_fadetime)
+         self.draw2d = func_null;
+ }
+ void Net_AuXair2(bool bIsNew)
+ {
+     int axh_id        = bound(0, ReadByte(), MAX_AXH);
+     entity axh                = AuxiliaryXhairs[axh_id];
+     if(axh == world || wasfreed(axh))  // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
+     {
+         axh                                   = spawn();
+               axh.draw2d                      = func_null;
+               axh.drawmask            = MASK_NORMAL;
+               axh.axh_drawflag        = DRAWFLAG_ADDITIVE;
+               axh.axh_fadetime        = 0.1;
+               axh.axh_image           = "gfx/vehicles/axh-ring.tga";
+               axh.axh_scale           = 1;
+         axh.alpha                     = 1;
+               AuxiliaryXhairs[axh_id] = axh;
+     }
+       axh.move_origin_x = ReadCoord();
+       axh.move_origin_y = ReadCoord();
+       axh.move_origin_z = ReadCoord();
+       axh.colormod_x = ReadByte() / 255;
+       axh.colormod_y = ReadByte() / 255;
+       axh.colormod_z = ReadByte() / 255;
+     axh.cnt                   = time;
+     axh.draw2d                        = AuxiliaryXhair_Draw2D;
+ }
+ void Net_VehicleSetup()
+ {
+     int hud_id = ReadByte();
+     // Weapon update?
+     if(hud_id > HUD_VEHICLE_LAST)
+     {
+         weapon2mode = hud_id - HUD_VEHICLE_LAST;
+         return;
+     }
+     // hud_id == 0 means we exited a vehicle, so stop alarm sound/s
+     if(hud_id == 0)
+     {
+         sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+         sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+         return;
+     }
+     hud_id  = bound(HUD_VEHICLE_FIRST, hud_id, HUD_VEHICLE_LAST);
+     // Init auxiliary crosshairs
+     int i;
+     for(i = 0; i < MAX_AXH; ++i)
+     {
+         entity axh = AuxiliaryXhairs[i];
+         if(axh != world && !wasfreed(axh))  // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?)
+             remove(axh);
+         axh                                   = spawn();
+               axh.draw2d                      = func_null;
+               axh.drawmask            = MASK_NORMAL;
+               axh.axh_drawflag        = DRAWFLAG_NORMAL;
+               axh.axh_fadetime        = 0.1;
+               axh.axh_image           = "gfx/vehicles/axh-ring.tga";
+               axh.axh_scale           = 1;
+         axh.alpha                     = 1;
+               AuxiliaryXhairs[i]      = axh;
+     }
+     switch(hud_id)
+     {
+         case HUD_SPIDERBOT:
+             // Minigun1
+             AuxiliaryXhairs[0].axh_image   = "gfx/vehicles/axh-ring.tga";
+             AuxiliaryXhairs[0].axh_scale   = 0.25;
+             // Minigun2
+             AuxiliaryXhairs[1].axh_image   = "gfx/vehicles/axh-ring.tga";
+             AuxiliaryXhairs[1].axh_scale   = 0.25;
+             // Rocket
+             AuxiliaryXhairs[2].axh_image   = "gfx/vehicles/axh-special1.tga";
+             AuxiliaryXhairs[2].axh_scale   = 0.5;
+             break;
+         case HUD_WAKIZASHI:
+             AuxiliaryXhairs[0].axh_image   = "gfx/vehicles/axh-bracket.tga";
+             AuxiliaryXhairs[0].axh_scale   = 0.25;
+             break;
+         case HUD_RAPTOR:
+             AuxiliaryXhairs[0].axh_image   = "gfx/vehicles/axh-special2.tga";
+             AuxiliaryXhairs[0].axh_scale   = 0.5;
+             //AuxiliaryXhair[0].alpha       = 0.5;
+             AuxiliaryXhairs[1].axh_image   = "gfx/vehicles/axh-bracket.tga";
+             AuxiliaryXhairs[1].axh_scale   = 0.25;
+             //AuxiliaryXhair[1].alpha       = 0.75;
+             //AuxiliaryXhair[1].axh_drawflag  = DRAWFLAG_NORMAL;
+             break;
+         case HUD_BUMBLEBEE:
+             // Raygun-locked
+             AuxiliaryXhairs[0].axh_image   = "gfx/vehicles/axh-bracket.tga";
+             AuxiliaryXhairs[0].axh_scale   = 0.5;
+             // Gunner1
+             AuxiliaryXhairs[1].axh_image   = "gfx/vehicles/axh-target.tga";
+             AuxiliaryXhairs[1].axh_scale   = 0.75;
+             // Gunner2
+             AuxiliaryXhairs[2].axh_image   = "gfx/vehicles/axh-target.tga";
+             AuxiliaryXhairs[2].axh_scale   = 0.75;
+             break;
+         case HUD_BUMBLEBEE_GUN:
+             // Plasma cannons
+             AuxiliaryXhairs[0].axh_image   = "gfx/vehicles/axh-bracket.tga";
+             AuxiliaryXhairs[0].axh_scale   = 0.25;
+             // Raygun
+             AuxiliaryXhairs[1].axh_image   = "gfx/vehicles/axh-bracket.tga";
+             AuxiliaryXhairs[1].axh_scale   = 0.25;
+             break;
+     }
+ }
+ #define HUD_GETSTATS \
+     int vh_health       = getstati(STAT_VEHICLESTAT_HEALTH);  \
+       float shield        = getstati(STAT_VEHICLESTAT_SHIELD);  \
+       noref int energy    = getstati(STAT_VEHICLESTAT_ENERGY);  \
+       noref float ammo1   = getstati(STAT_VEHICLESTAT_AMMO1);   \
+       noref float reload1 = getstati(STAT_VEHICLESTAT_RELOAD1); \
+       noref int ammo2     = getstati(STAT_VEHICLESTAT_AMMO2);   \
+       noref int reload2   = getstati(STAT_VEHICLESTAT_RELOAD2);
+ void CSQC_BUMBLE_HUD()
+ {
+ /*
+     drawpic(hudloc, waki_s, picsize, '1 1 1', shield, DRAWFLAG_NORMAL);
+     drawpic(hudloc, waki_b, picsize, '0 1 0' * health + '1 0 0'  * (1 - health), 1, DRAWFLAG_NORMAL);
+     drawpic(hudloc, waki_r, picsize, '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 1, DRAWFLAG_NORMAL);
+     drawpic(hudloc, waki_e, picsize, '1 1 1' * energy + '1 0 0'  * (1 - energy), 1, DRAWFLAG_NORMAL);
+ */
+       if(autocvar_r_letterbox)
+         return;
+     vector picsize, hudloc = '0 0 0', pic2size, picloc;
+     // Fetch health & ammo stats
+       HUD_GETSTATS
+     picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
+     hudloc.y = vid_conheight - picsize.y;
+     hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
+     drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
+     shield  *= 0.01;
+     vh_health  *= 0.01;
+     energy  *= 0.01;
+     reload1 *= 0.01;
+     pic2size = draw_getimagesize(bumb_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
+     picloc = picsize * 0.5 - pic2size * 0.5;
+     if(vh_health < 0.25)
+         drawpic(hudloc + picloc, bumb_ico, pic2size,  '1 0 0' + '0 1 1' * sin(time * 8),  1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, bumb_ico, pic2size,  '1 1 1' * vh_health  + '1 0 0' * (1 - vh_health),  1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, bumb_lgun, pic2size, '1 1 1' * energy   + '1 0 0' * (1 - energy),   1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, bumb_lgun, pic2size, '1 1 1' * energy   + '1 0 0' * (1 - energy),   1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, hud_sh, pic2size,  '1 1 1', shield, DRAWFLAG_NORMAL);
+ // Health bar
+     picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
+     drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
+     picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
+     if(vh_health < 0.25)
+     {
+         if(alarm1time < time)
+         {
+             alarm1time = time + 2;
+             sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
+         }
+         drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     }
+     else
+     {
+         drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+         if(alarm1time)
+         {
+             sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+             alarm1time = 0;
+         }
+     }
+ // Shield bar
+     picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
+     drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
+     picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
+     if(shield < 0.25)
+     {
+         if(alarm2time < time)
+         {
+             alarm2time = time + 1;
+             sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
+         }
+         drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     }
+     else
+     {
+         drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+         if(alarm2time)
+         {
+             sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+             alarm2time = 0;
+         }
+     }
+       ammo1 *= 0.01;
+       ammo2 *= 0.01;
+ // Gunner1 bar
+     picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * ammo1, vid_conheight);
+     drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // Right gunner slot occupied?
+       if(!AuxiliaryXhairs[1].draw2d)
+       {
+               shield = (picsize.x * 0.5) - (0.5 * stringwidth(_("No right gunner!"), false, '1 0 0' * picsize.y + '0 1 0' * picsize.y));
+               drawfill(hudloc + picloc - '0.2 0.2 0', picsize + '0.4 0.4 0', '0.25 0.25 0.25', 0.75, DRAWFLAG_NORMAL);
+               drawstring(hudloc + picloc + '1 0 0' * shield, _("No right gunner!"), '1 0 0' * picsize.y + '0 1 0' * picsize.y, '1 0 0' + '0 1 1' * sin(time * 10), 1, DRAWFLAG_NORMAL);
+       }
+ // ..  and icon
+     picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale;
+     picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
+     if(ammo1 < 0.2)
+         drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ // Gunner2 bar
+     picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '450 140 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * ammo2, vid_conheight);
+     drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // Left gunner slot occupied?
+       if(!AuxiliaryXhairs[2].draw2d)
+       {
+               shield = (picsize.x * 0.5) - (0.5 * stringwidth(_("No left gunner!"), false, '1 0 0' * picsize.y + '0 1 0' * picsize.y));
+               drawfill(hudloc + picloc - '0.2 0.2 0', picsize + '0.4 0.4 0', '0.25 0.25 0.25', 0.75, DRAWFLAG_NORMAL);
+               drawstring(hudloc + picloc + '1 0 0' * shield, _("No left gunner!"), '1 0 0' * picsize.y + '0 1 0' * picsize.y, '1 0 0' + '0 1 1' * sin(time * 10), 1, DRAWFLAG_NORMAL);
+       }
+ // ..  and icon
+     picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale;
+     picloc = '664 130 0' * autocvar_cl_vehicles_hudscale;
+     if(ammo2 < 0.2)
+         drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+       if (scoreboard_showscores)
+               HUD_DrawScoreboard();
+     else
+     {
+         picsize = draw_getimagesize(waki_xhair);
+         picsize.x *= 0.5;
+         picsize.y *= 0.5;
+         drawpic('0.5 0 0' * (vid_conwidth - picsize.x) + '0 0.5 0' * (vid_conheight - picsize.y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     }
+ }
+ void CSQC_BUMBLE_GUN_HUD()
+ {
+       if(autocvar_r_letterbox)
+         return;
+     vector picsize, hudloc = '0 0 0', pic2size, picloc;
+     // Fetch health & ammo stats
+       HUD_GETSTATS
+     picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
+     hudloc.y = vid_conheight - picsize.y;
+     hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
+     drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
+     shield  *= 0.01;
+     vh_health  *= 0.01;
+     energy  *= 0.01;
+     reload1 *= 0.01;
+     pic2size = draw_getimagesize(bumb_gun_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
+     picloc = picsize * 0.5 - pic2size * 0.5;
+     if(vh_health < 0.25)
+         drawpic(hudloc + picloc, bumb_gun_ico, pic2size,  '1 0 0' + '0 1 1' * sin(time * 8),  1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, bumb_gun_ico, pic2size,  '1 1 1' * vh_health  + '1 0 0' * (1 - vh_health),  1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, bumb_gun_gun, pic2size, '1 1 1' * energy   + '1 0 0' * (1 - energy),   1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, hud_sh, pic2size,  '1 1 1', shield, DRAWFLAG_NORMAL);
+ // Health bar
+     picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
+     drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
+     picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
+     if(vh_health < 0.25)
+     {
+         if(alarm1time < time)
+         {
+             alarm1time = time + 2;
+             sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
+         }
+         drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     }
+     else
+     {
+         drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+         if(alarm1time)
+         {
+             sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+             alarm1time = 0;
+         }
+     }
+ // Shield bar
+     picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
+     drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
+     picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
+     if(shield < 0.25)
+     {
+         if(alarm2time < time)
+         {
+             alarm2time = time + 1;
+             sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
+         }
+         drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     }
+     else
+     {
+         drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+         if(alarm2time)
+         {
+             sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+             alarm2time = 0;
+         }
+     }
+ // Gun bar
+     picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * energy, vid_conheight);
+     drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale;
+     picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
+     if(energy < 0.2)
+         drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+       if (scoreboard_showscores)
+               HUD_DrawScoreboard();
+     /*
+     else
+     {
+         picsize = draw_getimagesize(waki_xhair);
+         picsize_x *= 0.5;
+         picsize_y *= 0.5;
+         drawpic('0.5 0 0' * (vid_conwidth - picsize_x) + '0 0.5 0' * (vid_conheight - picsize_y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     }
+     */
+ }
+ void CSQC_SPIDER_HUD()
+ {
+       if(autocvar_r_letterbox)
+         return;
+     vector picsize, hudloc = '0 0 0', pic2size, picloc;
+     int i;
+     // Fetch health & ammo stats
+       HUD_GETSTATS
+     picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
+     hudloc.y = vid_conheight - picsize.y;
+     hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
+     drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
+     ammo1   *= 0.01;
+     shield  *= 0.01;
+     vh_health  *= 0.01;
+     reload2 *= 0.01;
+     pic2size = draw_getimagesize(spider_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
+     picloc = picsize * 0.5 - pic2size * 0.5;
+     if(vh_health < 0.25)
+         drawpic(hudloc + picloc, spider_ico, pic2size,  '1 0 0' + '0 1 1' * sin(time * 8),  1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, spider_ico, pic2size,  '1 1 1' * vh_health  + '1 0 0' * (1 - vh_health),  1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, spider_rkt, pic2size,  '1 1 1' * reload2 + '1 0 0' * (1 - reload2), 1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, spider_mgun, pic2size, '1 1 1' * ammo1   + '1 0 0' * (1 - ammo1),   1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, hud_sh, pic2size,  '1 1 1', shield, DRAWFLAG_NORMAL);
+ // Health bar
+     picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
+     drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
+     picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
+     if(vh_health < 0.25)
+     {
+         if(alarm1time < time)
+         {
+             alarm1time = time + 2;
+             sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
+         }
+         drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     }
+     else
+     {
+         drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+         if(alarm1time)
+         {
+             sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+             alarm1time = 0;
+         }
+     }
+ // Shield bar
+     picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
+     drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
+     picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
+     if(shield < 0.25)
+     {
+         if(alarm2time < time)
+         {
+             alarm2time = time + 1;
+             sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
+         }
+         drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     }
+     else
+     {
+         drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+         if(alarm2time)
+         {
+             sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+             alarm2time = 0;
+         }
+     }
+ // Minigun bar
+     picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * ammo1, vid_conheight);
+     drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picsize = draw_getimagesize(hud_ammo1_ico) * autocvar_cl_vehicles_hudscale;
+     picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
+     if(ammo1 < 0.2)
+         drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ // Rocket ammo bar
+     picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale;
+     ammo1 = picsize.x / 8;
+     picloc = '450 140 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x, hudloc.y + picloc.y, picsize.x * reload2, vid_conheight);
+     drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icons
+     pic2size = 0.35 * draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale;
+     picloc.x -= pic2size.x;
+     picloc.y += pic2size.y * 2.25;
+     if(ammo2 == 9)
+     {
+         for(i = 1; i < 9; ++i)
+         {
+             picloc.x += ammo1;
+             drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, ((8 * reload2 <= i) ? '0 0 0' : '1 1 1'), 0.75, DRAWFLAG_NORMAL);
+         }
+     }
+     else
+     {
+         for(i = 1; i < 9; ++i)
+         {
+             picloc.x += ammo1;
+             drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, ((i >= ammo2) ? '1 1 1' : '0 0 0'), 0.75, DRAWFLAG_NORMAL);
+         }
+     }
+     pic2size = draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale;
+     picloc = '664 130 0' * autocvar_cl_vehicles_hudscale;
+     if(ammo2 == 9)
+         drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 1 1', 1, DRAWFLAG_NORMAL);
+       if (scoreboard_showscores)
+               HUD_DrawScoreboard();
+     else
+     {
+         switch(weapon2mode)
+         {
+             case SBRM_VOLLY:
+                 spider_xhair = "gfx/vehicles/axh-bracket.tga";
+                 break;
+             case SBRM_GUIDE:
+                 spider_xhair = "gfx/vehicles/axh-cross.tga";
+                 break;
+             case SBRM_ARTILLERY:
+                 spider_xhair = "gfx/vehicles/axh-tag.tga";
+                 break;
+             default:
+                 spider_xhair= "gfx/vehicles/axh-tag.tga";
+         }
+         picsize = draw_getimagesize(spider_xhair);
+         picsize.x *= autocvar_cl_vehicle_spiderbot_cross_size;
+         picsize.y *= autocvar_cl_vehicle_spiderbot_cross_size;
+         drawpic('0.5 0 0' * (vid_conwidth - picsize.x) + '0 0.5 0' * (vid_conheight - picsize.y), spider_xhair, picsize, '1 1 1', autocvar_cl_vehicle_spiderbot_cross_alpha, DRAWFLAG_ADDITIVE);
+     }
+ }
+ void CSQC_RAPTOR_HUD()
+ {
+       if(autocvar_r_letterbox)
+         return;
+     vector picsize, hudloc = '0 0 0', pic2size, picloc;
+     // Fetch health & ammo stats
+       HUD_GETSTATS
+     picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
+     hudloc.y = vid_conheight - picsize.y;
+     hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
+     drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
+     ammo1   *= 0.01;
+     ammo2   *= 0.01;
+     shield  *= 0.01;
+     vh_health  *= 0.01;
+     energy  *= 0.01;
+     reload1 = reload2 * 0.01;
+     //reload2 *= 0.01;
+     pic2size = draw_getimagesize(spider_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
+     picloc = picsize * 0.5 - pic2size * 0.5;
+     if(vh_health < 0.25)
+         drawpic(hudloc + picloc, raptor_ico, pic2size,  '1 0 0' + '0 1 1' * sin(time * 8),  1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, raptor_ico, pic2size,  '1 1 1' * vh_health  + '1 0 0' * (1 - vh_health),  1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, raptor_bomb, pic2size,  '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, raptor_gun, pic2size, '1 1 1' * energy   + '1 0 0' * (1 - energy),   1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, hud_sh, pic2size,  '1 1 1', shield, DRAWFLAG_NORMAL);
+ // Health bar
+     picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
+     drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
+     picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
+     if(vh_health < 0.25)
+     {
+         if(alarm1time < time)
+         {
+             alarm1time = time + 2;
+             sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
+         }
+         drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     }
+     else
+     {
+         drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+         if(alarm1time)
+         {
+             sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+             alarm1time = 0;
+         }
+     }
+ // Shield bar
+     picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
+     drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
+     picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
+     if(shield < 0.25)
+     {
+         if(alarm2time < time)
+         {
+             alarm2time = time + 1;
+             sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
+         }
+         drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     }
+     else
+     {
+         drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+         if(alarm2time)
+         {
+             sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+             alarm2time = 0;
+         }
+     }
+ // Gun bar
+     picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * energy, vid_conheight);
+     drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picsize = draw_getimagesize(hud_ammo1_ico) * autocvar_cl_vehicles_hudscale;
+     picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
+     if(energy < 0.2)
+         drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ // Bomb bar
+     picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '450 140 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x, hudloc.y + picloc.y, picsize.x * reload1, vid_conheight);
+     drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     pic2size = draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale;
+     picloc = '664 130 0' * autocvar_cl_vehicles_hudscale;
+     if(reload1 != 1)
+         drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 1 1', 1, DRAWFLAG_NORMAL);
+     if(weapon2mode == RSM_FLARE)
+     {
+         raptor_xhair =  "gfx/vehicles/axh-bracket.tga";
+     }
+     else
+     {
+         raptor_xhair =  "gfx/vehicles/axh-ring.tga";
+         // Bombing crosshair
+         if(!dropmark)
+         {
+             dropmark = spawn();
+             dropmark.owner = self;
+             dropmark.gravity = 1;
+         }
+         if(reload2 == 100)
+         {
+             vector where;
+             setorigin(dropmark, pmove_org);
+             dropmark.velocity = pmove_vel;
+             tracetoss(dropmark, self);
+             where = project_3d_to_2d(trace_endpos);
+             setorigin(dropmark, trace_endpos);
+             picsize = draw_getimagesize(raptor_drop) * 0.2;
+             if (!(where.z < 0 || where.x < 0 || where.y < 0 || where.x > vid_conwidth || where.y > vid_conheight))
+             {
+                 where.x -= picsize.x * 0.5;
+                 where.y -= picsize.y * 0.5;
+                 where.z = 0;
+                 drawpic(where, raptor_drop, picsize, '0 2 0', 1, DRAWFLAG_ADDITIVE);
+             }
+             dropmark.cnt = time + 5;
+         }
+         else
+         {
+             vector where;
+             if(dropmark.cnt > time)
+             {
+                 where = project_3d_to_2d(dropmark.origin);
+                 picsize = draw_getimagesize(raptor_drop) * 0.25;
+                 if (!(where.z < 0 || where.x < 0 || where.y < 0 || where.x > vid_conwidth || where.y > vid_conheight))
+                 {
+                     where.x -= picsize.x * 0.5;
+                     where.y -= picsize.y * 0.5;
+                     where.z = 0;
+                     drawpic(where, raptor_drop, picsize, '2 0 0', 1, DRAWFLAG_ADDITIVE);
+                 }
+             }
+         }
+     }
+       if (scoreboard_showscores)
+               HUD_DrawScoreboard();
+     else
+     {
+         picsize = draw_getimagesize(raptor_xhair);
+         picsize.x *= 0.5;
+         picsize.y *= 0.5;
+         drawpic('0.5 0 0' * (vid_conwidth - picsize.x) + '0 0.5 0' * (vid_conheight - picsize.y), raptor_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     }
+ }
+ void CSQC_WAKIZASHI_HUD()
+ {
+ /*
+     drawpic(hudloc, waki_s, picsize, '1 1 1', shield, DRAWFLAG_NORMAL);
+     drawpic(hudloc, waki_b, picsize, '0 1 0' * health + '1 0 0'  * (1 - health), 1, DRAWFLAG_NORMAL);
+     drawpic(hudloc, waki_r, picsize, '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 1, DRAWFLAG_NORMAL);
+     drawpic(hudloc, waki_e, picsize, '1 1 1' * energy + '1 0 0'  * (1 - energy), 1, DRAWFLAG_NORMAL);
+ */
+       if(autocvar_r_letterbox)
+         return;
+     vector picsize, hudloc = '0 0 0', pic2size, picloc;
+     // Fetch health & ammo stats
+       HUD_GETSTATS
+     picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale;
+     hudloc.y = vid_conheight - picsize.y;
+     hudloc.x = vid_conwidth * 0.5 - picsize.x * 0.5;
+     drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL);
+     shield  *= 0.01;
+     vh_health  *= 0.01;
+     energy  *= 0.01;
+     reload1 *= 0.01;
+     pic2size = draw_getimagesize(spider_ico) * (autocvar_cl_vehicles_hudscale * 0.8);
+     picloc = picsize * 0.5 - pic2size * 0.5;
+     if(vh_health < 0.25)
+         drawpic(hudloc + picloc, waki_ico, pic2size,  '1 0 0' + '0 1 1' * sin(time * 8),  1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, waki_ico, pic2size,  '1 1 1' * vh_health  + '1 0 0' * (1 - vh_health),  1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, waki_eng, pic2size, '1 1 1' * energy   + '1 0 0' * (1 - energy),   1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, waki_gun, pic2size, '1 1 1' * energy   + '1 0 0' * (1 - energy),   1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, waki_rkt, pic2size,  '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 1, DRAWFLAG_NORMAL);
+     drawpic(hudloc + picloc, hud_sh, pic2size,  '1 1 1', shield, DRAWFLAG_NORMAL);
+ // Health bar
+     picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '69 69 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - vh_health)), 0, vid_conwidth, vid_conheight);
+     drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale;
+     picloc = '37 65 0' * autocvar_cl_vehicles_hudscale;
+     if(vh_health < 0.25)
+     {
+         if(alarm1time < time)
+         {
+             alarm1time = time + 2;
+             sound(self, CH_PAIN_SINGLE, "vehicles/alarm.wav", VOL_BASEVOICE, ATTEN_NONE);
+         }
+         drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     }
+     else
+     {
+         drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+         if(alarm1time)
+         {
+             sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+             alarm1time = 0;
+         }
+     }
+ // Shield bar
+     picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '69 140 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x + (picsize.x * (1 - shield)), 0, vid_conwidth, vid_conheight);
+     drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picloc = '40 136 0' * autocvar_cl_vehicles_hudscale;
+     picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale;
+     if(shield < 0.25)
+     {
+         if(alarm2time < time)
+         {
+             alarm2time = time + 1;
+             sound(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav", VOL_BASEVOICE, ATTEN_NONE);
+         }
+         drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     }
+     else
+     {
+         drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+         if(alarm2time)
+         {
+             sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE);
+             alarm2time = 0;
+         }
+     }
+ // Gun bar
+     picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '450 69 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x, picloc.y, picsize.x * energy, vid_conheight);
+     drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     picsize = draw_getimagesize(hud_ammo1_ico) * autocvar_cl_vehicles_hudscale;
+     picloc = '664 60 0' * autocvar_cl_vehicles_hudscale;
+     if(energy < 0.2)
+         drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+ // Bomb bar
+     picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale;
+     picloc = '450 140 0' * autocvar_cl_vehicles_hudscale;
+     drawsetcliparea(hudloc.x + picloc.x, hudloc.y + picloc.y, picsize.x * reload1, vid_conheight);
+     drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     drawresetcliparea();
+ // ..  and icon
+     pic2size = draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale;
+     picloc = '664 130 0' * autocvar_cl_vehicles_hudscale;
+     if(reload1 != 1)
+         drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL);
+     else
+         drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 1 1', 1, DRAWFLAG_NORMAL);
+       if (scoreboard_showscores)
+               HUD_DrawScoreboard();
+     else
+     {
+         picsize = draw_getimagesize(waki_xhair);
+         picsize.x *= 0.5;
+         picsize.y *= 0.5;
+         drawpic('0.5 0 0' * (vid_conwidth - picsize.x) + '0 0.5 0' * (vid_conheight - picsize.y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+     }
+ }
+ void Vehicles_Precache()
+ {
+       precache_model("models/vehicles/bomblet.md3");
+       precache_model("models/vehicles/clusterbomb.md3");
+       precache_model("models/vehicles/clusterbomb_fragment.md3");
+       precache_model("models/vehicles/rocket01.md3");
+       precache_model("models/vehicles/rocket02.md3");
+       precache_sound ("vehicles/alarm.wav");
+       precache_sound ("vehicles/alarm_shield.wav");
+ }
+ void RaptorCBShellfragDraw()
+ {
+       if(wasfreed(self))
+               return;
+       Movetype_Physics_MatchTicrate(autocvar_cl_gibs_ticrate, autocvar_cl_gibs_sloppy);
+       self.move_avelocity += randomvec() * 15;
+       self.renderflags = 0;
+       if(self.cnt < time)
+               self.alpha = bound(0, self.nextthink - time, 1);
+       if(self.alpha < ALPHA_MIN_VISIBLE)
+         remove(self);
+ }
+ void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang)
+ {
+     entity sfrag;
+     sfrag = spawn();
+     setmodel(sfrag, "models/vehicles/clusterbomb_fragment.md3");
+     setorigin(sfrag, _org);
+       sfrag.move_movetype = MOVETYPE_BOUNCE;
+       sfrag.gravity = 0.15;
+       sfrag.solid = SOLID_CORPSE;
+       sfrag.draw = RaptorCBShellfragDraw;
+       sfrag.move_origin = sfrag.origin = _org;
+       sfrag.move_velocity = _vel;
+       sfrag.move_avelocity = prandomvec() * vlen(sfrag.move_velocity);
+       sfrag.angles = self.move_angles = _ang;
+       sfrag.move_time = time;
+       sfrag.damageforcescale = 4;
+       sfrag.nextthink = time + 3;
+       sfrag.cnt = time + 2;
+       sfrag.alpha = 1;
+     sfrag.drawmask = MASK_NORMAL;
+ }
index 0000000,8430668..1304d3a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,11 +1,12 @@@
 -#include "../movetypes.qh"
+ #include "../damage.qh"
+ #include "../defs.qh"
+ #include "../gibs.qh"
+ #include "../hook.qh"
+ #include "../main.qh"
+ #include "../wall.qh"
+ #include "../weapons/projectile.qh"
++#include "../../common/movetypes/movetypes.qh"
++
+ #include "../../server/vehicles/bumblebee.qc"
@@@ -1,25 -1,31 +1,31 @@@
- #if defined(CSQC)
-       #include "../dpdefs/csprogsdefs.qh"
-       #include "defs.qh"
-       #include "../common/constants.qh"
-       #include "../common/stats.qh"
-       #include "../warpzonelib/mathlib.qh"
-       #include "../warpzonelib/common.qh"
-       #include "../warpzonelib/client.qh"
-       #include "../common/teams.qh"
-       #include "../common/util.qh"
-       #include "../common/nades.qh"
-       #include "../common/weapons/weapons.qh"
-       #include "../common/mapinfo.qh"
-       #include "autocvars.qh"
-       #include "hud.qh"
-       #include "scoreboard.qh"
-       #include "noise.qh"
-       #include "main.qh"
-       #include "../csqcmodellib/cl_player.qh"
- #elif defined(MENUQC)
- #elif defined(SVQC)
- #endif
+ #include "_all.qh"
+ #include "announcer.qh"
+ #include "hook.qh"
+ #include "hud.qh"
+ #include "hud_config.qh"
+ #include "mapvoting.qh"
+ #include "noise.qh"
+ #include "scoreboard.qh"
+ #include "shownames.qh"
 -#include "target_music.qh"
+ #include "vehicles/all.qh"
+ #include "waypointsprites.qh"
+ #include "../common/constants.qh"
+ #include "../common/mapinfo.qh"
+ #include "../common/nades.qh"
+ #include "../common/stats.qh"
++#include "../common/triggers/target/music.qh"
+ #include "../common/teams.qh"
+ #include "../common/util.qh"
+ #include "../common/weapons/all.qh"
+ #include "../csqcmodellib/cl_player.qh"
+ #include "../warpzonelib/client.qh"
+ #include "../warpzonelib/common.qh"
+ #include "../warpzonelib/mathlib.qh"
  
  entity porto;
  vector polyline[16];
Simple merge
@@@ -1,5 -1,22 +1,22 @@@
  #include "projectile.qh"
  
 -#include "../movetypes.qh"
+ #include "../autocvars.qh"
+ #include "../defs.qh"
+ #include "../main.qh"
+ #include "../../common/constants.qh"
+ #include "../../common/nades.qh"
++#include "../../common/movetypes/movetypes.qh"
+ #include "../../common/util.qh"
+ #include "../../csqcmodellib/interpolate.qh"
+ #include "../../warpzonelib/anglestransform.qh"
+ .float alpha;
+ .float scale;
+ .vector colormod;
  void SUB_Stop()
  {
        self.move_velocity = self.move_avelocity = '0 0 0';
Simple merge
Simple merge
index 6b7a222,0000000..ea217c5
mode 100644,000000..100644
--- /dev/null
@@@ -1,1844 -1,0 +1,1844 @@@
-       float was_flying = ITEMS(self) & IT_USING_JETPACK;
 +#include "physics.qh"
 +#include "triggers/trigger/swamp.qh"
 +#include "triggers/trigger/jumppads.qh"
 +
 +#ifdef SVQC
 +
 +#include "../server/miscfunctions.qh"
 +
 +void Physics_AddStats()
 +{
 +      // static view offset and hitbox vectors
 +      // networked for all you bandwidth pigs out there
 +      addstat(STAT_PL_VIEW_OFS1, AS_FLOAT, stat_pl_view_ofs_x);
 +      addstat(STAT_PL_VIEW_OFS2, AS_FLOAT, stat_pl_view_ofs_y);
 +      addstat(STAT_PL_VIEW_OFS3, AS_FLOAT, stat_pl_view_ofs_z);
 +      addstat(STAT_PL_CROUCH_VIEW_OFS1, AS_FLOAT, stat_pl_crouch_view_ofs_x);
 +      addstat(STAT_PL_CROUCH_VIEW_OFS2, AS_FLOAT, stat_pl_crouch_view_ofs_y);
 +      addstat(STAT_PL_CROUCH_VIEW_OFS3, AS_FLOAT, stat_pl_crouch_view_ofs_z);
 +
 +      addstat(STAT_PL_MIN1, AS_FLOAT, stat_pl_min_x);
 +      addstat(STAT_PL_MIN2, AS_FLOAT, stat_pl_min_y);
 +      addstat(STAT_PL_MIN3, AS_FLOAT, stat_pl_min_z);
 +      addstat(STAT_PL_MAX1, AS_FLOAT, stat_pl_max_x);
 +      addstat(STAT_PL_MAX2, AS_FLOAT, stat_pl_max_y);
 +      addstat(STAT_PL_MAX3, AS_FLOAT, stat_pl_max_z);
 +      addstat(STAT_PL_CROUCH_MIN1, AS_FLOAT, stat_pl_crouch_min_x);
 +      addstat(STAT_PL_CROUCH_MIN2, AS_FLOAT, stat_pl_crouch_min_y);
 +      addstat(STAT_PL_CROUCH_MIN3, AS_FLOAT, stat_pl_crouch_min_z);
 +      addstat(STAT_PL_CROUCH_MAX1, AS_FLOAT, stat_pl_crouch_max_x);
 +      addstat(STAT_PL_CROUCH_MAX2, AS_FLOAT, stat_pl_crouch_max_y);
 +      addstat(STAT_PL_CROUCH_MAX3, AS_FLOAT, stat_pl_crouch_max_z);
 +
 +      // g_movementspeed hack
 +      addstat(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW, AS_FLOAT, stat_sv_airspeedlimit_nonqw);
 +      addstat(STAT_MOVEVARS_MAXSPEED, AS_FLOAT, stat_sv_maxspeed);
 +      addstat(STAT_MOVEVARS_AIRACCEL_QW, AS_FLOAT, stat_sv_airaccel_qw);
 +      addstat(STAT_MOVEVARS_AIRSTRAFEACCEL_QW, AS_FLOAT, stat_sv_airstrafeaccel_qw);
 +      addstat(STAT_MOVEVARS_HIGHSPEED, AS_FLOAT, stat_movement_highspeed);
 +
 +      // jet pack
 +      addstat(STAT_JETPACK_ACCEL_SIDE, AS_FLOAT, stat_jetpack_accel_side);
 +      addstat(STAT_JETPACK_ACCEL_UP, AS_FLOAT, stat_jetpack_accel_up);
 +      addstat(STAT_JETPACK_ANTIGRAVITY, AS_FLOAT, stat_jetpack_antigravity);
 +      addstat(STAT_JETPACK_FUEL, AS_FLOAT, stat_jetpack_fuel);
 +      addstat(STAT_JETPACK_MAXSPEED_UP, AS_FLOAT, stat_jetpack_maxspeed_up);
 +      addstat(STAT_JETPACK_MAXSPEED_SIDE, AS_FLOAT, stat_jetpack_maxspeed_side);
 +
 +      // hack to fix track_canjump
 +      addstat(STAT_MOVEVARS_TRACK_CANJUMP, AS_INT, cvar_cl_movement_track_canjump);
 +
 +      // double jump
 +      addstat(STAT_DOUBLEJUMP, AS_INT, stat_doublejump);
 +
 +      // jump speed caps
 +      addstat(STAT_MOVEVARS_JUMPSPEEDCAP_MIN, AS_FLOAT, stat_jumpspeedcap_min);
 +      addstat(STAT_MOVEVARS_JUMPSPEEDCAP_MIN, AS_FLOAT, stat_jumpspeedcap_min);
 +      addstat(STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS, AS_INT, stat_jumpspeedcap_disable_onramps);
 +
 +      // hacks
 +      addstat(STAT_MOVEVARS_FRICTION_ONLAND, AS_FLOAT, stat_sv_friction_on_land);
 +      addstat(STAT_MOVEVARS_FRICTION_SLICK, AS_FLOAT, stat_sv_friction_slick);
 +      addstat(STAT_GAMEPLAYFIX_EASIERWATERJUMP, AS_INT, stat_gameplayfix_easierwaterjump);
 +
 +      addstat(STAT_GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND, AS_INT, stat_gameplayfix_upvelocityclearsonground);
 +}
 +
 +void Physics_UpdateStats(float maxspd_mod)
 +{
 +      // blah
 +      self.stat_pl_view_ofs = PL_VIEW_OFS;
 +      self.stat_pl_crouch_view_ofs = PL_CROUCH_VIEW_OFS;
 +
 +      self.stat_pl_min = PL_MIN;
 +      self.stat_pl_max = PL_MAX;
 +      self.stat_pl_crouch_min = PL_CROUCH_MIN;
 +      self.stat_pl_crouch_max = PL_CROUCH_MAX;
 +
 +      self.stat_sv_airaccel_qw = AdjustAirAccelQW(autocvar_sv_airaccel_qw, maxspd_mod);
 +      if (autocvar_sv_airstrafeaccel_qw)
 +              self.stat_sv_airstrafeaccel_qw = AdjustAirAccelQW(autocvar_sv_airstrafeaccel_qw, maxspd_mod);
 +      else
 +              self.stat_sv_airstrafeaccel_qw = 0;
 +      self.stat_sv_airspeedlimit_nonqw = autocvar_sv_airspeedlimit_nonqw * maxspd_mod;
 +      self.stat_sv_maxspeed = autocvar_sv_maxspeed * maxspd_mod; // also slow walking
 +      self.stat_movement_highspeed = PHYS_HIGHSPEED; // TODO: remove this!
 +
 +      self.stat_doublejump = PHYS_DOUBLEJUMP;
 +
 +      self.stat_jetpack_antigravity = PHYS_JETPACK_ANTIGRAVITY;
 +      self.stat_jetpack_accel_up = PHYS_JETPACK_ACCEL_UP;
 +      self.stat_jetpack_accel_side = PHYS_JETPACK_ACCEL_SIDE;
 +      self.stat_jetpack_maxspeed_side = PHYS_JETPACK_MAXSPEED_SIDE;
 +      self.stat_jetpack_maxspeed_up = PHYS_JETPACK_MAXSPEED_UP;
 +      self.stat_jetpack_fuel = PHYS_JETPACK_FUEL;
 +
 +      self.stat_jumpspeedcap_min = PHYS_JUMPSPEEDCAP_MIN;
 +      self.stat_jumpspeedcap_max = PHYS_JUMPSPEEDCAP_MAX;
 +      self.stat_jumpspeedcap_disable_onramps = PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS;
 +
 +      self.stat_sv_friction_on_land = PHYS_FRICTION_ONLAND;
 +      self.stat_sv_friction_slick = PHYS_FRICTION_SLICK;
 +
 +      self.stat_gameplayfix_easierwaterjump = GAMEPLAYFIX_EASIERWATERJUMP;
 +
 +      self.stat_gameplayfix_upvelocityclearsonground = UPWARD_VELOCITY_CLEARS_ONGROUND;
 +}
 +#endif
 +
 +float IsMoveInDirection(vector mv, float ang) // key mix factor
 +{
 +      if (mv_x == 0 && mv_y == 0)
 +              return 0; // avoid division by zero
 +      ang -= RAD2DEG * atan2(mv_y, mv_x);
 +      ang = remainder(ang, 360) / 45;
 +      return ang > 1 ? 0 : ang < -1 ? 0 : 1 - fabs(ang);
 +}
 +
 +float GeomLerp(float a, float lerp, float b)
 +{
 +      return a == 0 ? (lerp < 1 ? 0 : b)
 +              : b == 0 ? (lerp > 0 ? 0 : a)
 +              : a * pow(fabs(b / a), lerp);
 +}
 +
 +noref float pmove_waterjumptime;
 +
 +const float unstick_count = 27;
 +vector unstick_offsets[unstick_count] =
 +{
 +// 1 no nudge (just return the original if this test passes)
 +      '0.000   0.000  0.000',
 +// 6 simple nudges
 +      ' 0.000  0.000  0.125', '0.000  0.000 -0.125',
 +      '-0.125  0.000  0.000', '0.125  0.000  0.000',
 +      ' 0.000 -0.125  0.000', '0.000  0.125  0.000',
 +// 4 diagonal flat nudges
 +      '-0.125 -0.125  0.000', '0.125 -0.125  0.000',
 +      '-0.125  0.125  0.000', '0.125  0.125  0.000',
 +// 8 diagonal upward nudges
 +      '-0.125  0.000  0.125', '0.125  0.000  0.125',
 +      ' 0.000 -0.125  0.125', '0.000  0.125  0.125',
 +      '-0.125 -0.125  0.125', '0.125 -0.125  0.125',
 +      '-0.125  0.125  0.125', '0.125  0.125  0.125',
 +// 8 diagonal downward nudges
 +      '-0.125  0.000 -0.125', '0.125  0.000 -0.125',
 +      ' 0.000 -0.125 -0.125', '0.000  0.125 -0.125',
 +      '-0.125 -0.125 -0.125', '0.125 -0.125 -0.125',
 +      '-0.125  0.125 -0.125', '0.125  0.125 -0.125',
 +};
 +
 +void PM_ClientMovement_Unstick()
 +{
 +      float i;
 +      for (i = 0; i < unstick_count; i++)
 +      {
 +              vector neworigin = unstick_offsets[i] + self.origin;
 +              tracebox(neworigin, PL_CROUCH_MIN, PL_CROUCH_MAX, neworigin, MOVE_NORMAL, self);
 +              if (!trace_startsolid)
 +              {
 +                      setorigin(self, neworigin);
 +                      return;// true;
 +              }
 +      }
 +}
 +
 +void PM_ClientMovement_UpdateStatus(bool ground)
 +{
 +      // make sure player is not stuck
 +      PM_ClientMovement_Unstick();
 +
 +      // set crouched
 +      if (PHYS_INPUT_BUTTON_CROUCH(self))
 +      {
 +              // wants to crouch, this always works..
 +              if (!IS_DUCKED(self))
 +                      SET_DUCKED(self);
 +      }
 +      else
 +      {
 +              // wants to stand, if currently crouching we need to check for a
 +              // low ceiling first
 +              if (IS_DUCKED(self))
 +              {
 +                      tracebox(self.origin, PL_MIN, PL_MAX, self.origin, MOVE_NORMAL, self);
 +                      if (!trace_startsolid)
 +                              UNSET_DUCKED(self);
 +              }
 +      }
 +
 +      // set onground
 +      vector origin1 = self.origin + '0 0 1';
 +      vector origin2 = self.origin - '0 0 1';
 +
 +      if(ground)
 +      {
 +              tracebox(origin1, self.mins, self.maxs, origin2, MOVE_NORMAL, self);
 +              if (trace_fraction < 1.0 && trace_plane_normal_z > 0.7)
 +              {
 +                      SET_ONGROUND(self);
 +
 +                      // this code actually "predicts" an impact; so let's clip velocity first
 +                      float f = self.velocity * trace_plane_normal;
 +                      self.velocity -= f * trace_plane_normal;
 +              }
 +              else
 +                      UNSET_ONGROUND(self);
 +      }
 +
 +      // set watertype/waterlevel
 +      origin1 = self.origin;
 +      origin1_z += self.mins_z + 1;
 +      self.waterlevel = WATERLEVEL_NONE;
 +
 +      int thepoint = pointcontents(origin1);
 +
 +      self.watertype = (thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME);
 +
 +      if(self.watertype)
 +      {
 +              self.waterlevel = WATERLEVEL_WETFEET;
 +              origin1_z = self.origin_z + (self.mins_z + self.maxs_z) * 0.5;
 +              thepoint = pointcontents(origin1);
 +              if(thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME)
 +              {
 +                      self.waterlevel = WATERLEVEL_SWIMMING;
 +                      origin1_z = self.origin_z + 22;
 +                      thepoint = pointcontents(origin1);
 +                      if(thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME)
 +                              self.waterlevel = WATERLEVEL_SUBMERGED;
 +              }
 +      }
 +
 +      if(IS_ONGROUND(self) || self.velocity_z <= 0 || pmove_waterjumptime <= 0)
 +              pmove_waterjumptime = 0;
 +}
 +
 +void PM_ClientMovement_Move()
 +{
 +#ifdef CSQC
 +      int bump;
 +      float t;
 +      float f;
 +      vector neworigin;
 +      vector currentorigin2;
 +      vector neworigin2;
 +      vector primalvelocity;
 +
 +      vector trace1_endpos = '0 0 0';
 +      vector trace2_endpos = '0 0 0';
 +      vector trace3_endpos = '0 0 0';
 +      float trace1_fraction = 0;
 +      float trace2_fraction = 0;
 +      float trace3_fraction = 0;
 +      vector trace1_plane_normal = '0 0 0';
 +      vector trace2_plane_normal = '0 0 0';
 +      vector trace3_plane_normal = '0 0 0';
 +      
 +
 +      PM_ClientMovement_UpdateStatus(false);
 +      primalvelocity = self.velocity;
 +      for(bump = 0, t = PHYS_INPUT_TIMELENGTH; bump < 8 && (self.velocity * self.velocity) > 0; bump++)
 +      {
 +              neworigin = self.origin + t * self.velocity;
 +              tracebox(self.origin, self.mins, self.maxs, neworigin, MOVE_NORMAL, self);
 +              trace1_endpos = trace_endpos;
 +              trace1_fraction = trace_fraction;
 +              trace1_plane_normal = trace_plane_normal;
 +              if(trace1_fraction < 1 && trace1_plane_normal_z == 0)
 +              {
 +                      // may be a step or wall, try stepping up
 +                      // first move forward at a higher level
 +                      currentorigin2 = self.origin;
 +                      currentorigin2_z += PHYS_STEPHEIGHT;
 +                      neworigin2 = neworigin;
 +                      neworigin2_z += PHYS_STEPHEIGHT;
 +                      tracebox(currentorigin2, self.mins, self.maxs, neworigin2, MOVE_NORMAL, self);
 +                      trace2_endpos = trace_endpos;
 +                      trace2_fraction = trace_fraction;
 +                      trace2_plane_normal = trace_plane_normal;
 +                      if(!trace_startsolid)
 +                      {
 +                              // then move down from there
 +                              currentorigin2 = trace2_endpos;
 +                              neworigin2 = trace2_endpos;
 +                              neworigin2_z = self.origin_z;
 +                              tracebox(currentorigin2, self.mins, self.maxs, neworigin2, MOVE_NORMAL, self);
 +                              trace3_endpos = trace_endpos;
 +                              trace3_fraction = trace_fraction;
 +                              trace3_plane_normal = trace_plane_normal;
 +                              // accept the new trace if it made some progress
 +                              if(fabs(trace3_endpos_x - trace1_endpos_x) >= 0.03125 || fabs(trace3_endpos_y - trace1_endpos_y) >= 0.03125)
 +                              {
 +                                      trace1_endpos = trace2_endpos;
 +                                      trace1_fraction = trace2_fraction;
 +                                      trace1_plane_normal = trace2_plane_normal;
 +                                      trace1_endpos = trace3_endpos;
 +                              }
 +                      }
 +              }
 +
 +              // check if it moved at all
 +              if(trace1_fraction >= 0.001)
 +                      setorigin(self, trace1_endpos);
 +
 +              // check if it moved all the way
 +              if(trace1_fraction == 1)
 +                      break;
 +
 +              // this is only really needed for nogravityonground combined with gravityunaffectedbyticrate
 +              // <LordHavoc> I'm pretty sure I commented it out solely because it seemed redundant
 +              // this got commented out in a change that supposedly makes the code match QW better
 +              // so if this is broken, maybe put it in an if(cls.protocol != PROTOCOL_QUAKEWORLD) block
 +              if(trace1_plane_normal_z > 0.7)
 +                      SET_ONGROUND(self);
 +
 +              t -= t * trace1_fraction;
 +
 +              f = (self.velocity * trace1_plane_normal);
 +              self.velocity = self.velocity + -f * trace1_plane_normal;
 +      }
 +      if(pmove_waterjumptime > 0)
 +              self.velocity = primalvelocity;
 +#endif
 +}
 +
 +void CPM_PM_Aircontrol(vector wishdir, float wishspeed)
 +{
 +      float k = 32 * (2 * IsMoveInDirection(self.movement, 0) - 1);
 +      if (k <= 0)
 +              return;
 +
 +      k *= bound(0, wishspeed / PHYS_MAXAIRSPEED, 1);
 +
 +      float zspeed = self.velocity_z;
 +      self.velocity_z = 0;
 +      float xyspeed = vlen(self.velocity);
 +      self.velocity = normalize(self.velocity);
 +
 +      float dot = self.velocity * wishdir;
 +
 +      if (dot > 0) // we can't change direction while slowing down
 +      {
 +              k *= pow(dot, PHYS_AIRCONTROL_POWER) * PHYS_INPUT_TIMELENGTH;
 +              xyspeed = max(0, xyspeed - PHYS_AIRCONTROL_PENALTY * sqrt(max(0, 1 - dot*dot)) * k/32);
 +              k *= PHYS_AIRCONTROL;
 +              self.velocity = normalize(self.velocity * xyspeed + wishdir * k);
 +      }
 +
 +      self.velocity = self.velocity * xyspeed;
 +      self.velocity_z = zspeed;
 +}
 +
 +float AdjustAirAccelQW(float accelqw, float factor)
 +{
 +      return copysign(bound(0.000001, 1 - (1 - fabs(accelqw)) * factor, 1), accelqw);
 +}
 +
 +// example config for alternate speed clamping:
 +//   sv_airaccel_qw 0.8
 +//   sv_airaccel_sideways_friction 0
 +//   prvm_globalset server speedclamp_mode 1
 +//     (or 2)
 +void PM_Accelerate(vector wishdir, float wishspeed, float wishspeed0, float accel, float accelqw, float stretchfactor, float sidefric, float speedlimit)
 +{
 +      float speedclamp = stretchfactor > 0 ? stretchfactor
 +      : accelqw < 0 ? 1 // full clamping, no stretch
 +      : -1; // no clamping
 +
 +      accelqw = fabs(accelqw);
 +
 +      if (GAMEPLAYFIX_Q2AIRACCELERATE)
 +              wishspeed0 = wishspeed; // don't need to emulate this Q1 bug
 +
 +      float vel_straight = self.velocity * wishdir;
 +      float vel_z = self.velocity_z;
 +      vector vel_xy = vec2(self.velocity);
 +      vector vel_perpend = vel_xy - vel_straight * wishdir;
 +
 +      float step = accel * PHYS_INPUT_TIMELENGTH * wishspeed0;
 +
 +      float vel_xy_current  = vlen(vel_xy);
 +      if (speedlimit)
 +              accelqw = AdjustAirAccelQW(accelqw, (speedlimit - bound(wishspeed, vel_xy_current, speedlimit)) / max(1, speedlimit - wishspeed));
 +      float vel_xy_forward =  vel_xy_current  + bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw);
 +      float vel_xy_backward = vel_xy_current  - bound(0, wishspeed + vel_xy_current, step) * accelqw - step * (1 - accelqw);
 +      vel_xy_backward = max(0, vel_xy_backward); // not that it REALLY occurs that this would cause wrong behaviour afterwards
 +      vel_straight =          vel_straight    + bound(0, wishspeed - vel_straight,   step) * accelqw + step * (1 - accelqw);
 +
 +      if (sidefric < 0 && (vel_perpend*vel_perpend))
 +              // negative: only apply so much sideways friction to stay below the speed you could get by "braking"
 +      {
 +              float f = max(0, 1 + PHYS_INPUT_TIMELENGTH * wishspeed * sidefric);
 +              float fmin = (vel_xy_backward * vel_xy_backward - vel_straight * vel_straight) / (vel_perpend * vel_perpend);
 +              // assume: fmin > 1
 +              // vel_xy_backward*vel_xy_backward - vel_straight*vel_straight > vel_perpend*vel_perpend
 +              // vel_xy_backward*vel_xy_backward > vel_straight*vel_straight + vel_perpend*vel_perpend
 +              // vel_xy_backward*vel_xy_backward > vel_xy * vel_xy
 +              // obviously, this cannot be
 +              if (fmin <= 0)
 +                      vel_perpend *= f;
 +              else
 +              {
 +                      fmin = sqrt(fmin);
 +                      vel_perpend *= max(fmin, f);
 +              }
 +      }
 +      else
 +              vel_perpend *= max(0, 1 - PHYS_INPUT_TIMELENGTH * wishspeed * sidefric);
 +
 +      vel_xy = vel_straight * wishdir + vel_perpend;
 +
 +      if (speedclamp >= 0)
 +      {
 +              float vel_xy_preclamp;
 +              vel_xy_preclamp = vlen(vel_xy);
 +              if (vel_xy_preclamp > 0) // prevent division by zero
 +              {
 +                      vel_xy_current += (vel_xy_forward - vel_xy_current) * speedclamp;
 +                      if (vel_xy_current < vel_xy_preclamp)
 +                              vel_xy *= (vel_xy_current / vel_xy_preclamp);
 +              }
 +      }
 +
 +      self.velocity = vel_xy + vel_z * '0 0 1';
 +}
 +
 +void PM_AirAccelerate(vector wishdir, float wishspeed)
 +{
 +      if (wishspeed == 0)
 +              return;
 +
 +      vector curvel = self.velocity;
 +      curvel_z = 0;
 +      float curspeed = vlen(curvel);
 +
 +      if (wishspeed > curspeed * 1.01)
 +              wishspeed = min(wishspeed, curspeed + PHYS_WARSOWBUNNY_AIRFORWARDACCEL * PHYS_MAXSPEED(self) * PHYS_INPUT_TIMELENGTH);
 +      else
 +      {
 +              float f = max(0, (PHYS_WARSOWBUNNY_TOPSPEED - curspeed) / (PHYS_WARSOWBUNNY_TOPSPEED - PHYS_MAXSPEED(self)));
 +              wishspeed = max(curspeed, PHYS_MAXSPEED(self)) + PHYS_WARSOWBUNNY_ACCEL * f * PHYS_MAXSPEED(self) * PHYS_INPUT_TIMELENGTH;
 +      }
 +      vector wishvel = wishdir * wishspeed;
 +      vector acceldir = wishvel - curvel;
 +      float addspeed = vlen(acceldir);
 +      acceldir = normalize(acceldir);
 +
 +      float accelspeed = min(addspeed, PHYS_WARSOWBUNNY_TURNACCEL * PHYS_MAXSPEED(self) * PHYS_INPUT_TIMELENGTH);
 +
 +      if (PHYS_WARSOWBUNNY_BACKTOSIDERATIO < 1)
 +      {
 +              vector curdir = normalize(curvel);
 +              float dot = acceldir * curdir;
 +              if (dot < 0)
 +                      acceldir -= (1 - PHYS_WARSOWBUNNY_BACKTOSIDERATIO) * dot * curdir;
 +      }
 +
 +      self.velocity += accelspeed * acceldir;
 +}
 +
 +
 +/*
 +=============
 +PlayerJump
 +
 +When you press the jump key
 +returns true if handled
 +=============
 +*/
 +bool PlayerJump (void)
 +{
 +      if (PHYS_FROZEN(self))
 +              return true; // no jumping in freezetag when frozen
 +
 +#ifdef SVQC
 +      if (self.player_blocked)
 +              return true; // no jumping while blocked
 +#endif
 +
 +      bool doublejump = false;
 +      float mjumpheight = PHYS_JUMPVELOCITY;
 +
 +      player_multijump = doublejump;
 +      player_jumpheight = mjumpheight;
 +#ifdef SVQC
 +      if (MUTATOR_CALLHOOK(PlayerJump))
 +#elif defined(CSQC)
 +      if(PM_multijump_checkjump())
 +#endif
 +              return true;
 +
 +      doublejump = player_multijump;
 +      mjumpheight = player_jumpheight;
 +
 +      if (PHYS_DOUBLEJUMP)
 +      {
 +              tracebox(self.origin + '0 0 0.01', self.mins, self.maxs, self.origin - '0 0 0.01', MOVE_NORMAL, self);
 +              if (trace_fraction < 1 && trace_plane_normal_z > 0.7)
 +              {
 +                      doublejump = true;
 +
 +                      // we MUST clip velocity here!
 +                      float f;
 +                      f = self.velocity * trace_plane_normal;
 +                      if (f < 0)
 +                              self.velocity -= f * trace_plane_normal;
 +              }
 +      }
 +
 +      if (self.waterlevel >= WATERLEVEL_SWIMMING)
 +      {
 +              self.velocity_z = PHYS_MAXSPEED(self) * 0.7;
 +              return true;
 +      }
 +
 +      if (!doublejump)
 +              if (!IS_ONGROUND(self))
 +                      return IS_JUMP_HELD(self);
 +
 +      if (PHYS_TRACK_CANJUMP(self))
 +              if (IS_JUMP_HELD(self))
 +                      return true;
 +
 +      // sv_jumpspeedcap_min/sv_jumpspeedcap_max act as baseline
 +      // velocity bounds.  Final velocity is bound between (jumpheight *
 +      // min + jumpheight) and (jumpheight * max + jumpheight);
 +
 +      if(PHYS_JUMPSPEEDCAP_MIN)
 +      {
 +              float minjumpspeed = mjumpheight * PHYS_JUMPSPEEDCAP_MIN;
 +
 +              if (self.velocity_z < minjumpspeed)
 +                      mjumpheight += minjumpspeed - self.velocity_z;
 +      }
 +
 +      if(PHYS_JUMPSPEEDCAP_MAX)
 +      {
 +              // don't do jump speedcaps on ramps to preserve old xonotic ramjump style
 +              tracebox(self.origin + '0 0 0.01', self.mins, self.maxs, self.origin - '0 0 0.01', MOVE_NORMAL, self);
 +
 +              if (!(trace_fraction < 1 && trace_plane_normal_z < 0.98 && PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS))
 +              {
 +                      float maxjumpspeed = mjumpheight * PHYS_JUMPSPEEDCAP_MAX;
 +
 +                      if (self.velocity_z > maxjumpspeed)
 +                              mjumpheight -= self.velocity_z - maxjumpspeed;
 +              }
 +      }
 +
 +      if (!WAS_ONGROUND(self))
 +      {
 +#ifdef SVQC
 +              if(autocvar_speedmeter)
 +                      dprint(strcat("landing velocity: ", vtos(self.velocity), " (abs: ", ftos(vlen(self.velocity)), ")\n"));
 +#endif
 +              if(self.lastground < time - 0.3)
 +              {
 +                      self.velocity_x *= (1 - PHYS_FRICTION_ONLAND);
 +                      self.velocity_y *= (1 - PHYS_FRICTION_ONLAND);
 +              }
 +#ifdef SVQC
 +              if(self.jumppadcount > 1)
 +                      dprint(strcat(ftos(self.jumppadcount), "x jumppad combo\n"));
 +              self.jumppadcount = 0;
 +#endif
 +      }
 +
 +      self.velocity_z += mjumpheight;
 +
 +      UNSET_ONGROUND(self);
 +      SET_JUMP_HELD(self);
 +
 +#ifdef SVQC
 +
 +      self.oldvelocity_z = self.velocity_z;
 +
 +      animdecide_setaction(self, ANIMACTION_JUMP, true);
 +
 +      if (autocvar_g_jump_grunt)
 +              PlayerSound(playersound_jump, CH_PLAYER, VOICETYPE_PLAYERSOUND);
 +#endif
 +      return true;
 +}
 +
 +void CheckWaterJump()
 +{
 +// check for a jump-out-of-water
 +      makevectors(self.v_angle);
 +      vector start = self.origin;
 +      start_z += 8;
 +      v_forward_z = 0;
 +      normalize(v_forward);
 +      vector end = start + v_forward*24;
 +      traceline (start, end, true, self);
 +      if (trace_fraction < 1)
 +      {       // solid at waist
 +              start_z = start_z + self.maxs_z - 8;
 +              end = start + v_forward*24;
 +              self.movedir = trace_plane_normal * -50;
 +              traceline(start, end, true, self);
 +              if (trace_fraction == 1)
 +              {       // open at eye level
 +                      self.velocity_z = 225;
 +                      self.flags |= FL_WATERJUMP;
 +                      SET_JUMP_HELD(self);
 +#ifdef SVQC
 +                      self.teleport_time = time + 2;  // safety net
 +#elif defined(CSQC)
 +                      pmove_waterjumptime = time + 2;
 +#endif
 +              }
 +      }
 +}
 +
 +
 +#ifdef SVQC
 +      #define JETPACK_JUMP(s) s.cvar_cl_jetpack_jump
 +#elif defined(CSQC)
 +      float autocvar_cl_jetpack_jump;
 +      #define JETPACK_JUMP(s) autocvar_cl_jetpack_jump
 +#endif
 +.float jetpack_stopped;
 +// Hack: shouldn't need to know about this
 +.float multijump_count;
 +void CheckPlayerJump()
 +{
 +#ifdef SVQC
-               ITEMS(self) &= ~IT_USING_JETPACK;
++      float was_flying = ITEMS_STAT(self) & IT_USING_JETPACK;
 +#endif
 +      if (JETPACK_JUMP(self) < 2)
-               float has_fuel = !PHYS_JETPACK_FUEL || PHYS_AMMO_FUEL(self) || ITEMS(self) & IT_UNLIMITED_WEAPON_AMMO;
++              ITEMS_STAT(self) &= ~IT_USING_JETPACK;
 +
 +      if(PHYS_INPUT_BUTTON_JUMP(self) || PHYS_INPUT_BUTTON_JETPACK(self))
 +      {
 +              float air_jump = !PlayerJump() || self.multijump_count > 0; // PlayerJump() has important side effects
 +              float activate = JETPACK_JUMP(self) && air_jump && PHYS_INPUT_BUTTON_JUMP(self) || PHYS_INPUT_BUTTON_JETPACK(self);
-               if (!(ITEMS(self) & IT_JETPACK)) { }
++              float has_fuel = !PHYS_JETPACK_FUEL || PHYS_AMMO_FUEL(self) || ITEMS_STAT(self) & IT_UNLIMITED_WEAPON_AMMO;
 +
-                       ITEMS(self) &= ~IT_USING_JETPACK;
++              if (!(ITEMS_STAT(self) & IT_JETPACK)) { }
 +              else if (self.jetpack_stopped) { }
 +              else if (!has_fuel)
 +              {
 +#ifdef SVQC
 +                      if (was_flying) // TODO: ran out of fuel message
 +                              Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_JETPACK_NOFUEL);
 +                      else if (activate)
 +                              Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_JETPACK_NOFUEL);
 +#endif
 +                      self.jetpack_stopped = true;
-                       ITEMS(self) |= IT_USING_JETPACK;
++                      ITEMS_STAT(self) &= ~IT_USING_JETPACK;
 +              }
 +              else if (activate && !PHYS_FROZEN(self))
-               ITEMS(self) &= ~IT_USING_JETPACK;
++                      ITEMS_STAT(self) |= IT_USING_JETPACK;
 +      }
 +      else
 +      {
 +              self.jetpack_stopped = false;
-       if (PHYS_JETPACK_FUEL && !(ITEMS(self) & IT_UNLIMITED_WEAPON_AMMO))
++              ITEMS_STAT(self) &= ~IT_USING_JETPACK;
 +      }
 +      if (!PHYS_INPUT_BUTTON_JUMP(self))
 +              UNSET_JUMP_HELD(self);
 +
 +      if (self.waterlevel == WATERLEVEL_SWIMMING)
 +              CheckWaterJump();
 +}
 +
 +float racecar_angle(float forward, float down)
 +{
 +      if (forward < 0)
 +      {
 +              forward = -forward;
 +              down = -down;
 +      }
 +
 +      float ret = vectoyaw('0 1 0' * down + '1 0 0' * forward);
 +
 +      float angle_mult = forward / (800 + forward);
 +
 +      if (ret > 180)
 +              return ret * angle_mult + 360 * (1 - angle_mult);
 +      else
 +              return ret * angle_mult;
 +}
 +
 +void RaceCarPhysics()
 +{
 +#ifdef SVQC
 +      // using this move type for "big rigs"
 +      // the engine does not push the entity!
 +
 +      vector rigvel;
 +
 +      vector angles_save = self.angles;
 +      float accel = bound(-1, self.movement.x / PHYS_MAXSPEED(self), 1);
 +      float steer = bound(-1, self.movement.y / PHYS_MAXSPEED(self), 1);
 +
 +      if (g_bugrigs_reverse_speeding)
 +      {
 +              if (accel < 0)
 +              {
 +                      // back accel is DIGITAL
 +                      // to prevent speedhack
 +                      if (accel < -0.5)
 +                              accel = -1;
 +                      else
 +                              accel = 0;
 +              }
 +      }
 +
 +      self.angles_x = 0;
 +      self.angles_z = 0;
 +      makevectors(self.angles); // new forward direction!
 +
 +      if (IS_ONGROUND(self) || g_bugrigs_air_steering)
 +      {
 +              float myspeed = self.velocity * v_forward;
 +              float upspeed = self.velocity * v_up;
 +
 +              // responsiveness factor for steering and acceleration
 +              float f = 1 / (1 + pow(max(-myspeed, myspeed) / g_bugrigs_speed_ref, g_bugrigs_speed_pow));
 +              //MAXIMA: f(v) := 1 / (1 + (v / g_bugrigs_speed_ref) ^ g_bugrigs_speed_pow);
 +
 +              float steerfactor;
 +              if (myspeed < 0 && g_bugrigs_reverse_spinning)
 +                      steerfactor = -myspeed * g_bugrigs_steer;
 +              else
 +                      steerfactor = -myspeed * f * g_bugrigs_steer;
 +
 +              float accelfactor;
 +              if (myspeed < 0 && g_bugrigs_reverse_speeding)
 +                      accelfactor = g_bugrigs_accel;
 +              else
 +                      accelfactor = f * g_bugrigs_accel;
 +              //MAXIMA: accel(v) := f(v) * g_bugrigs_accel;
 +
 +              if (accel < 0)
 +              {
 +                      if (myspeed > 0)
 +                      {
 +                              myspeed = max(0, myspeed - PHYS_INPUT_TIMELENGTH * (g_bugrigs_friction_floor - g_bugrigs_friction_brake * accel));
 +                      }
 +                      else
 +                      {
 +                              if (!g_bugrigs_reverse_speeding)
 +                                      myspeed = min(0, myspeed + PHYS_INPUT_TIMELENGTH * g_bugrigs_friction_floor);
 +                      }
 +              }
 +              else
 +              {
 +                      if (myspeed >= 0)
 +                      {
 +                              myspeed = max(0, myspeed - PHYS_INPUT_TIMELENGTH * g_bugrigs_friction_floor);
 +                      }
 +                      else
 +                      {
 +                              if (g_bugrigs_reverse_stopping)
 +                                      myspeed = 0;
 +                              else
 +                                      myspeed = min(0, myspeed + PHYS_INPUT_TIMELENGTH * (g_bugrigs_friction_floor + g_bugrigs_friction_brake * accel));
 +                      }
 +              }
 +              // terminal velocity = velocity at which 50 == accelfactor, that is, 1549 units/sec
 +              //MAXIMA: friction(v) := g_bugrigs_friction_floor;
 +
 +              self.angles_y += steer * PHYS_INPUT_TIMELENGTH * steerfactor; // apply steering
 +              makevectors(self.angles); // new forward direction!
 +
 +              myspeed += accel * accelfactor * PHYS_INPUT_TIMELENGTH;
 +
 +              rigvel = myspeed * v_forward + '0 0 1' * upspeed;
 +      }
 +      else
 +      {
 +              float myspeed = vlen(self.velocity);
 +
 +              // responsiveness factor for steering and acceleration
 +              float f = 1 / (1 + pow(max(0, myspeed / g_bugrigs_speed_ref), g_bugrigs_speed_pow));
 +              float steerfactor = -myspeed * f;
 +              self.angles_y += steer * PHYS_INPUT_TIMELENGTH * steerfactor; // apply steering
 +
 +              rigvel = self.velocity;
 +              makevectors(self.angles); // new forward direction!
 +      }
 +
 +      rigvel *= max(0, 1 - vlen(rigvel) * g_bugrigs_friction_air * PHYS_INPUT_TIMELENGTH);
 +      //MAXIMA: airfriction(v) := v * v * g_bugrigs_friction_air;
 +      //MAXIMA: total_acceleration(v) := accel(v) - friction(v) - airfriction(v);
 +      //MAXIMA: solve(total_acceleration(v) = 0, v);
 +
 +      if (g_bugrigs_planar_movement)
 +      {
 +              vector rigvel_xy, neworigin, up;
 +              float mt;
 +
 +              rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY; // 4x gravity plays better
 +              rigvel_xy = vec2(rigvel);
 +
 +              if (g_bugrigs_planar_movement_car_jumping)
 +                      mt = MOVE_NORMAL;
 +              else
 +                      mt = MOVE_NOMONSTERS;
 +
 +              tracebox(self.origin, self.mins, self.maxs, self.origin + '0 0 1024', mt, self);
 +              up = trace_endpos - self.origin;
 +
 +              // BUG RIGS: align the move to the surface instead of doing collision testing
 +              // can we move?
 +              tracebox(trace_endpos, self.mins, self.maxs, trace_endpos + rigvel_xy * PHYS_INPUT_TIMELENGTH, mt, self);
 +
 +              // align to surface
 +              tracebox(trace_endpos, self.mins, self.maxs, trace_endpos - up + '0 0 1' * rigvel_z * PHYS_INPUT_TIMELENGTH, mt, self);
 +
 +              if (trace_fraction < 0.5)
 +              {
 +                      trace_fraction = 1;
 +                      neworigin = self.origin;
 +              }
 +              else
 +                      neworigin = trace_endpos;
 +
 +              if (trace_fraction < 1)
 +              {
 +                      // now set angles_x so that the car points parallel to the surface
 +                      self.angles = vectoangles(
 +                                      '1 0 0' * v_forward_x * trace_plane_normal_z
 +                                      +
 +                                      '0 1 0' * v_forward_y * trace_plane_normal_z
 +                                      +
 +                                      '0 0 1' * -(v_forward_x * trace_plane_normal_x + v_forward_y * trace_plane_normal_y)
 +                                      );
 +                      SET_ONGROUND(self);
 +              }
 +              else
 +              {
 +                      // now set angles_x so that the car points forward, but is tilted in velocity direction
 +                      UNSET_ONGROUND(self);
 +              }
 +
 +              self.velocity = (neworigin - self.origin) * (1.0 / PHYS_INPUT_TIMELENGTH);
 +              self.movetype = MOVETYPE_NOCLIP;
 +      }
 +      else
 +      {
 +              rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY; // 4x gravity plays better
 +              self.velocity = rigvel;
 +              self.movetype = MOVETYPE_FLY;
 +      }
 +
 +      trace_fraction = 1;
 +      tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 4', MOVE_NORMAL, self);
 +      if (trace_fraction != 1)
 +      {
 +              self.angles = vectoangles2(
 +                              '1 0 0' * v_forward_x * trace_plane_normal_z
 +                              +
 +                              '0 1 0' * v_forward_y * trace_plane_normal_z
 +                              +
 +                              '0 0 1' * -(v_forward_x * trace_plane_normal_x + v_forward_y * trace_plane_normal_y),
 +                              trace_plane_normal
 +                              );
 +      }
 +      else
 +      {
 +              vector vel_local;
 +
 +              vel_local_x = v_forward * self.velocity;
 +              vel_local_y = v_right * self.velocity;
 +              vel_local_z = v_up * self.velocity;
 +
 +              self.angles_x = racecar_angle(vel_local_x, vel_local_z);
 +              self.angles_z = racecar_angle(-vel_local_y, vel_local_z);
 +      }
 +
 +      // smooth the angles
 +      vector vf1, vu1, smoothangles;
 +      makevectors(self.angles);
 +      float f = bound(0, PHYS_INPUT_TIMELENGTH * g_bugrigs_angle_smoothing, 1);
 +      if (f == 0)
 +              f = 1;
 +      vf1 = v_forward * f;
 +      vu1 = v_up * f;
 +      makevectors(angles_save);
 +      vf1 = vf1 + v_forward * (1 - f);
 +      vu1 = vu1 + v_up * (1 - f);
 +      smoothangles = vectoangles2(vf1, vu1);
 +      self.angles_x = -smoothangles_x;
 +      self.angles_z =  smoothangles_z;
 +#endif
 +}
 +
 +string specialcommand = "xwxwxsxsxaxdxaxdx1x ";
 +.float specialcommand_pos;
 +void SpecialCommand()
 +{
 +#ifdef SVQC
 +#ifdef TETRIS
 +      TetrisImpulse();
 +#else
 +      if (!CheatImpulse(99))
 +              print("A hollow voice says \"Plugh\".\n");
 +#endif
 +#endif
 +}
 +
 +float PM_check_keepaway(void)
 +{
 +#ifdef SVQC
 +      return (self.ballcarried && g_keepaway) ? autocvar_g_keepaway_ballcarrier_highspeed : 1;
 +#else
 +      return 1;
 +#endif
 +}
 +
 +void PM_check_race_movetime(void)
 +{
 +#ifdef SVQC
 +      self.race_movetime_frac += PHYS_INPUT_TIMELENGTH;
 +      float f = floor(self.race_movetime_frac);
 +      self.race_movetime_frac -= f;
 +      self.race_movetime_count += f;
 +      self.race_movetime = self.race_movetime_frac + self.race_movetime_count;
 +#endif
 +}
 +
 +float PM_check_specialcommand(float buttons)
 +{
 +#ifdef SVQC
 +      string c;
 +      if (!buttons)
 +              c = "x";
 +      else if (buttons == 1)
 +              c = "1";
 +      else if (buttons == 2)
 +              c = " ";
 +      else if (buttons == 128)
 +              c = "s";
 +      else if (buttons == 256)
 +              c = "w";
 +      else if (buttons == 512)
 +              c = "a";
 +      else if (buttons == 1024)
 +              c = "d";
 +      else
 +              c = "?";
 +
 +      if (c == substring(specialcommand, self.specialcommand_pos, 1))
 +      {
 +              self.specialcommand_pos += 1;
 +              if (self.specialcommand_pos >= strlen(specialcommand))
 +              {
 +                      self.specialcommand_pos = 0;
 +                      SpecialCommand();
 +                      return true;
 +              }
 +      }
 +      else if (self.specialcommand_pos && (c != substring(specialcommand, self.specialcommand_pos - 1, 1)))
 +              self.specialcommand_pos = 0;
 +#endif
 +      return false;
 +}
 +
 +void PM_check_nickspam(void)
 +{
 +#ifdef SVQC
 +      if (time >= self.nickspamtime)
 +              return;
 +      if (self.nickspamcount >= autocvar_g_nick_flood_penalty_yellow)
 +      {
 +              // slight annoyance for nick change scripts
 +              self.movement = -1 * self.movement;
 +              self.BUTTON_ATCK = self.BUTTON_JUMP = self.BUTTON_ATCK2 = self.BUTTON_ZOOM = self.BUTTON_CROUCH = self.BUTTON_HOOK = self.BUTTON_USE = 0;
 +
 +              if (self.nickspamcount >= autocvar_g_nick_flood_penalty_red) // if you are persistent and the slight annoyance above does not stop you, I'll show you!
 +              {
 +                      self.v_angle_x = random() * 360;
 +                      self.v_angle_y = random() * 360;
 +                      // at least I'm not forcing retardedview by also assigning to angles_z
 +                      self.fixangle = true;
 +              }
 +      }
 +#endif
 +}
 +
 +void PM_check_punch()
 +{
 +#ifdef SVQC
 +      if (self.punchangle != '0 0 0')
 +      {
 +              float f = vlen(self.punchangle) - 10 * PHYS_INPUT_TIMELENGTH;
 +              if (f > 0)
 +                      self.punchangle = normalize(self.punchangle) * f;
 +              else
 +                      self.punchangle = '0 0 0';
 +      }
 +
 +      if (self.punchvector != '0 0 0')
 +      {
 +              float f = vlen(self.punchvector) - 30 * PHYS_INPUT_TIMELENGTH;
 +              if (f > 0)
 +                      self.punchvector = normalize(self.punchvector) * f;
 +              else
 +                      self.punchvector = '0 0 0';
 +      }
 +#endif
 +}
 +
 +void PM_check_spider(void)
 +{
 +#ifdef SVQC
 +      if (time >= self.spider_slowness)
 +              return;
 +      PHYS_MAXSPEED(self) *= 0.5; // half speed while slow from spider
 +      self.stat_sv_airspeedlimit_nonqw *= 0.5;
 +#endif
 +}
 +
 +// predict frozen movement, as frozen players CAN move in some cases
 +void PM_check_frozen(void)
 +{
 +      if (!PHYS_FROZEN(self))
 +              return;
 +      if (PHYS_DODGING_FROZEN
 +#ifdef SVQC
 +      && IS_REAL_CLIENT(self)
 +#endif
 +      )
 +      {
 +              self.movement_x = bound(-5, self.movement.x, 5);
 +              self.movement_y = bound(-5, self.movement.y, 5);
 +              self.movement_z = bound(-5, self.movement.z, 5);
 +      }
 +      else
 +              self.movement = '0 0 0';
 +
 +      vector midpoint = ((self.absmin + self.absmax) * 0.5);
 +      if (pointcontents(midpoint) == CONTENT_WATER)
 +      {
 +              self.velocity = self.velocity * 0.5;
 +
 +              if (pointcontents(midpoint + '0 0 16') == CONTENT_WATER)
 +                      self.velocity_z = 200;
 +      }
 +}
 +
 +void PM_check_hitground()
 +{
 +#ifdef SVQC
 +      if (IS_ONGROUND(self))
 +      if (IS_PLAYER(self)) // no fall sounds for observers thank you very much
 +      if (self.wasFlying)
 +      {
 +              self.wasFlying = 0;
 +              if (self.waterlevel < WATERLEVEL_SWIMMING)
 +              if (time >= self.ladder_time)
 +              if (!self.hook)
 +              {
 +                      self.nextstep = time + 0.3 + random() * 0.1;
 +                      trace_dphitq3surfaceflags = 0;
 +                      tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 1', MOVE_NOMONSTERS, self);
 +                      if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS))
 +                      {
 +                              if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS)
 +                                      GlobalSound(globalsound_metalfall, CH_PLAYER, VOICETYPE_PLAYERSOUND);
 +                              else
 +                                      GlobalSound(globalsound_fall, CH_PLAYER, VOICETYPE_PLAYERSOUND);
 +                      }
 +              }
 +      }
 +#endif
 +}
 +
 +void PM_check_blocked(void)
 +{
 +#ifdef SVQC
 +      if (!self.player_blocked)
 +              return;
 +      self.movement = '0 0 0';
 +      self.disableclientprediction = 1;
 +#endif
 +}
 +
 +#ifdef SVQC
 +float speedaward_lastsent;
 +float speedaward_lastupdate;
 +#endif
 +void PM_check_race(void)
 +{
 +#ifdef SVQC
 +      if(!(g_cts || g_race))
 +              return;
 +      if (vlen(self.velocity - self.velocity_z * '0 0 1') > speedaward_speed)
 +      {
 +              speedaward_speed = vlen(self.velocity - self.velocity_z * '0 0 1');
 +              speedaward_holder = self.netname;
 +              speedaward_uid = self.crypto_idfp;
 +              speedaward_lastupdate = time;
 +      }
 +      if (speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1)
 +      {
 +              string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
 +              race_send_speedaward(MSG_ALL);
 +              speedaward_lastsent = speedaward_speed;
 +              if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "")
 +              {
 +                      speedaward_alltimebest = speedaward_speed;
 +                      speedaward_alltimebest_holder = speedaward_holder;
 +                      speedaward_alltimebest_uid = speedaward_uid;
 +                      db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed"), ftos(speedaward_alltimebest));
 +                      db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp"), speedaward_alltimebest_uid);
 +                      race_send_speedaward_alltimebest(MSG_ALL);
 +              }
 +      }
 +#endif
 +}
 +
 +void PM_check_vortex(void)
 +{
 +#ifdef SVQC
 +      // WEAPONTODO
 +      float xyspeed = vlen(vec2(self.velocity));
 +      if (self.weapon == WEP_VORTEX && WEP_CVAR(vortex, charge) && WEP_CVAR(vortex, charge_velocity_rate) && xyspeed > WEP_CVAR(vortex, charge_minspeed))
 +      {
 +              // add a maximum of charge_velocity_rate when going fast (f = 1), gradually increasing from minspeed (f = 0) to maxspeed
 +              xyspeed = min(xyspeed, WEP_CVAR(vortex, charge_maxspeed));
 +              float f = (xyspeed - WEP_CVAR(vortex, charge_minspeed)) / (WEP_CVAR(vortex, charge_maxspeed) - WEP_CVAR(vortex, charge_minspeed));
 +              // add the extra charge
 +              self.vortex_charge = min(1, self.vortex_charge + WEP_CVAR(vortex, charge_velocity_rate) * f * PHYS_INPUT_TIMELENGTH);
 +      }
 +#endif
 +}
 +
 +void PM_fly(float maxspd_mod)
 +{
 +      // noclipping or flying
 +      UNSET_ONGROUND(self);
 +
 +      self.velocity = self.velocity * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION);
 +      makevectors(self.v_angle);
 +      //wishvel = v_forward * self.movement.x + v_right * self.movement.y + v_up * self.movement.z;
 +      vector wishvel = v_forward * self.movement.x
 +                                      + v_right * self.movement.y
 +                                      + '0 0 1' * self.movement.z;
 +      // acceleration
 +      vector wishdir = normalize(wishvel);
 +      float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(self) * maxspd_mod);
 +#ifdef SVQC
 +      if (time >= self.teleport_time)
 +#endif
 +              PM_Accelerate(wishdir, wishspeed, wishspeed, PHYS_ACCELERATE * maxspd_mod, 1, 0, 0, 0);
 +      PM_ClientMovement_Move();
 +}
 +
 +void PM_swim(float maxspd_mod)
 +{
 +      // swimming
 +      UNSET_ONGROUND(self);
 +
 +      float jump = PHYS_INPUT_BUTTON_JUMP(self);
 +      // water jump only in certain situations
 +      // this mimics quakeworld code
 +      if (jump && self.waterlevel == WATERLEVEL_SWIMMING && self.velocity_z >= -180)
 +      {
 +              vector yawangles = '0 1 0' * self.v_angle.y;
 +              makevectors(yawangles);
 +              vector forward = v_forward;
 +              vector spot = self.origin + 24 * forward;
 +              spot_z += 8;
 +              traceline(spot, spot, MOVE_NOMONSTERS, self);
 +              if (trace_startsolid)
 +              {
 +                      spot_z += 24;
 +                      traceline(spot, spot, MOVE_NOMONSTERS, self);
 +                      if (!trace_startsolid)
 +                      {
 +                              self.velocity = forward * 50;
 +                              self.velocity_z = 310;
 +                              pmove_waterjumptime = 2;
 +                              UNSET_ONGROUND(self);
 +                              SET_JUMP_HELD(self);
 +                      }
 +              }
 +      }
 +      makevectors(self.v_angle);
 +      //wishvel = v_forward * self.movement.x + v_right * self.movement.y + v_up * self.movement.z;
 +      vector wishvel = v_forward * self.movement.x
 +                                      + v_right * self.movement.y
 +                                      + '0 0 1' * self.movement.z;
 +      if (wishvel == '0 0 0')
 +              wishvel = '0 0 -60'; // drift towards bottom
 +
 +      vector wishdir = normalize(wishvel);
 +      float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(self) * maxspd_mod) * 0.7;
 +
 +      if (IS_DUCKED(self))
 +      wishspeed *= 0.5;
 +
 +//    if (pmove_waterjumptime <= 0) // TODO: use
 +    {
 +              // water friction
 +              float f = 1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION;
 +              f = min(max(0, f), 1);
 +              self.velocity *= f;
 +
 +              f = wishspeed - self.velocity * wishdir;
 +              if (f > 0)
 +              {
 +                      float accelspeed = min(PHYS_ACCELERATE * PHYS_INPUT_TIMELENGTH * wishspeed, f);
 +                      self.velocity += accelspeed * wishdir;
 +              }
 +
 +              // holding jump button swims upward slowly
 +              if (jump)
 +              {
 +#if 0
 +                      if (self.watertype & CONTENT_LAVA)
 +                              self.velocity_z =  50;
 +                      else if (self.watertype & CONTENT_SLIME)
 +                              self.velocity_z =  80;
 +                      else
 +                      {
 +                              if (IS_NEXUIZ_DERIVED(gamemode))
 +#endif
 +                                      self.velocity_z = 200;
 +#if 0
 +                              else
 +                                      self.velocity_z = 100;
 +                      }
 +#endif
 +              }
 +      }
 +      // water acceleration
 +      PM_Accelerate(wishdir, wishspeed, wishspeed, PHYS_ACCELERATE * maxspd_mod, 1, 0, 0, 0);
 +      PM_ClientMovement_Move();
 +}
 +
 +void PM_ladder(float maxspd_mod)
 +{
 +      // on a spawnfunc_func_ladder or swimming in spawnfunc_func_water
 +      UNSET_ONGROUND(self);
 +
 +      float g;
 +      g = PHYS_GRAVITY * PHYS_INPUT_TIMELENGTH;
 +      if (PHYS_ENTGRAVITY(self))
 +              g *= PHYS_ENTGRAVITY(self);
 +      if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
 +      {
 +              g *= 0.5;
 +              self.velocity_z += g;
 +      }
 +
 +      self.velocity = self.velocity * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION);
 +      makevectors(self.v_angle);
 +      //wishvel = v_forward * self.movement.x + v_right * self.movement.y + v_up * self.movement.z;
 +      vector wishvel = v_forward * self.movement_x
 +                                      + v_right * self.movement_y
 +                                      + '0 0 1' * self.movement_z;
 +      self.velocity_z += g;
 +      if (self.ladder_entity.classname == "func_water")
 +      {
 +              float f = vlen(wishvel);
 +              if (f > self.ladder_entity.speed)
 +                      wishvel *= (self.ladder_entity.speed / f);
 +
 +              self.watertype = self.ladder_entity.skin;
 +              f = self.ladder_entity.origin_z + self.ladder_entity.maxs_z;
 +              if ((self.origin_z + self.view_ofs_z) < f)
 +                      self.waterlevel = WATERLEVEL_SUBMERGED;
 +              else if ((self.origin_z + (self.mins_z + self.maxs_z) * 0.5) < f)
 +                      self.waterlevel = WATERLEVEL_SWIMMING;
 +              else if ((self.origin_z + self.mins_z + 1) < f)
 +                      self.waterlevel = WATERLEVEL_WETFEET;
 +              else
 +              {
 +                      self.waterlevel = WATERLEVEL_NONE;
 +                      self.watertype = CONTENT_EMPTY;
 +              }
 +      }
 +      // acceleration
 +      vector wishdir = normalize(wishvel);
 +      float wishspeed = min(vlen(wishvel), PHYS_MAXSPEED(self) * maxspd_mod);
 +#ifdef SVQC
 +      if (time >= self.teleport_time)
 +#endif
 +              // water acceleration
 +              PM_Accelerate(wishdir, wishspeed, wishspeed, PHYS_ACCELERATE*maxspd_mod, 1, 0, 0, 0);
 +      PM_ClientMovement_Move();
 +}
 +
 +void PM_jetpack(float maxspd_mod)
 +{
 +      //makevectors(self.v_angle.y * '0 1 0');
 +      makevectors(self.v_angle);
 +      vector wishvel = v_forward * self.movement_x
 +                                      + v_right * self.movement_y;
 +      // add remaining speed as Z component
 +      float maxairspd = PHYS_MAXAIRSPEED * max(1, maxspd_mod);
 +      // fix speedhacks :P
 +      wishvel = normalize(wishvel) * min(1, vlen(wishvel) / maxairspd);
 +      // add the unused velocity as up component
 +      wishvel_z = 0;
 +
 +      // if (self.BUTTON_JUMP)
 +              wishvel_z = sqrt(max(0, 1 - wishvel * wishvel));
 +
 +      // it is now normalized, so...
 +      float a_side = PHYS_JETPACK_ACCEL_SIDE;
 +      float a_up = PHYS_JETPACK_ACCEL_UP;
 +      float a_add = PHYS_JETPACK_ANTIGRAVITY * PHYS_GRAVITY;
 +
 +      wishvel_x *= a_side;
 +      wishvel_y *= a_side;
 +      wishvel_z *= a_up;
 +      wishvel_z += a_add;
 +
 +      float best = 0;
 +      //////////////////////////////////////////////////////////////////////////////////////
 +      // finding the maximum over all vectors of above form
 +      // with wishvel having an absolute value of 1
 +      //////////////////////////////////////////////////////////////////////////////////////
 +      // we're finding the maximum over
 +      //   f(a_side, a_up, a_add, z) := a_side * (1 - z^2) + (a_add + a_up * z)^2;
 +      // for z in the range from -1 to 1
 +      //////////////////////////////////////////////////////////////////////////////////////
 +      // maximum is EITHER attained at the single extreme point:
 +      float a_diff = a_side * a_side - a_up * a_up;
 +      float f;
 +      if (a_diff != 0)
 +      {
 +              f = a_add * a_up / a_diff; // this is the zero of diff(f(a_side, a_up, a_add, z), z)
 +              if (f > -1 && f < 1) // can it be attained?
 +              {
 +                      best = (a_diff + a_add * a_add) * (a_diff + a_up * a_up) / a_diff;
 +                      //print("middle\n");
 +              }
 +      }
 +      // OR attained at z = 1:
 +      f = (a_up + a_add) * (a_up + a_add);
 +      if (f > best)
 +      {
 +              best = f;
 +              //print("top\n");
 +      }
 +      // OR attained at z = -1:
 +      f = (a_up - a_add) * (a_up - a_add);
 +      if (f > best)
 +      {
 +              best = f;
 +              //print("bottom\n");
 +      }
 +      best = sqrt(best);
 +      //////////////////////////////////////////////////////////////////////////////////////
 +
 +      //print("best possible acceleration: ", ftos(best), "\n");
 +
 +      float fxy, fz;
 +      fxy = bound(0, 1 - (self.velocity * normalize(wishvel_x * '1 0 0' + wishvel_y * '0 1 0')) / PHYS_JETPACK_MAXSPEED_SIDE, 1);
 +      if (wishvel_z - PHYS_GRAVITY > 0)
 +              fz = bound(0, 1 - self.velocity_z / PHYS_JETPACK_MAXSPEED_UP, 1);
 +      else
 +              fz = bound(0, 1 + self.velocity_z / PHYS_JETPACK_MAXSPEED_UP, 1);
 +
 +      float fvel;
 +      fvel = vlen(wishvel);
 +      wishvel_x *= fxy;
 +      wishvel_y *= fxy;
 +      wishvel_z = (wishvel_z - PHYS_GRAVITY) * fz + PHYS_GRAVITY;
 +
 +      fvel = min(1, vlen(wishvel) / best);
-               if (!(ITEMS(self) & IT_UNLIMITED_WEAPON_AMMO))
++      if (PHYS_JETPACK_FUEL && !(ITEMS_STAT(self) & IT_UNLIMITED_WEAPON_AMMO))
 +              f = min(1, PHYS_AMMO_FUEL(self) / (PHYS_JETPACK_FUEL * PHYS_INPUT_TIMELENGTH * fvel));
 +      else
 +              f = 1;
 +
 +      //print("this acceleration: ", ftos(vlen(wishvel) * f), "\n");
 +
 +      if (f > 0 && wishvel != '0 0 0')
 +      {
 +              self.velocity = self.velocity + wishvel * f * PHYS_INPUT_TIMELENGTH;
 +              UNSET_ONGROUND(self);
 +
 +#ifdef SVQC
-               ITEMS(self) |= IT_USING_JETPACK;
++              if (!(ITEMS_STAT(self) & IT_UNLIMITED_WEAPON_AMMO))
 +                      self.ammo_fuel -= PHYS_JETPACK_FUEL * PHYS_INPUT_TIMELENGTH * fvel * f;
 +
-       else if (ITEMS(self) & IT_USING_JETPACK)
++              ITEMS_STAT(self) |= IT_USING_JETPACK;
 +
 +              // jetpack also inhibits health regeneration, but only for 1 second
 +              self.pauseregen_finished = max(self.pauseregen_finished, time + autocvar_g_balance_pause_fuel_regen);
 +#endif
 +      }
 +
 +#ifdef CSQC
 +      float g = PHYS_GRAVITY * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH;
 +      if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
 +              self.velocity_z -= g * 0.5;
 +      else
 +              self.velocity_z -= g;
 +      PM_ClientMovement_Move();
 +      if (!IS_ONGROUND(self) || !(GAMEPLAYFIX_NOGRAVITYONGROUND))
 +              if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
 +                      self.velocity_z -= g * 0.5;
 +#endif
 +}
 +
 +void PM_walk(float buttons_prev, float maxspd_mod)
 +{
 +      if (!WAS_ONGROUND(self))
 +      {
 +#ifdef SVQC
 +              if (autocvar_speedmeter)
 +                      dprint(strcat("landing velocity: ", vtos(self.velocity), " (abs: ", ftos(vlen(self.velocity)), ")\n"));
 +#endif
 +              if (self.lastground < time - 0.3)
 +                      self.velocity *= (1 - PHYS_FRICTION_ONLAND);
 +#ifdef SVQC
 +              if (self.jumppadcount > 1)
 +                      dprint(strcat(ftos(self.jumppadcount), "x jumppad combo\n"));
 +              self.jumppadcount = 0;
 +#endif
 +      }
 +
 +      // walking
 +      makevectors(self.v_angle.y * '0 1 0');
 +      vector wishvel = v_forward * self.movement.x
 +                                      + v_right * self.movement.y;
 +      // acceleration
 +      vector wishdir = normalize(wishvel);
 +      float wishspeed = vlen(wishvel);
 +
 +      wishspeed = min(wishspeed, PHYS_MAXSPEED(self) * maxspd_mod);
 +      if (IS_DUCKED(self))
 +              wishspeed *= 0.5;
 +
 +      // apply edge friction
 +      float f = vlen(vec2(self.velocity));
 +      if (f > 0)
 +      {
 +              float realfriction;
 +              trace_dphitq3surfaceflags = 0;
 +              tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 1', MOVE_NOMONSTERS, self);
 +              // TODO: apply edge friction
 +              // apply ground friction
 +              if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK)
 +                      realfriction = PHYS_FRICTION_SLICK;
 +              else
 +                      realfriction = PHYS_FRICTION;
 +
 +              f = 1 - PHYS_INPUT_TIMELENGTH * realfriction * ((f < PHYS_STOPSPEED) ? (PHYS_STOPSPEED / f) : 1);
 +              f = max(0, f);
 +              self.velocity *= f;
 +              /*
 +                 Mathematical analysis time!
 +
 +                 Our goal is to invert this mess.
 +
 +                 For the two cases we get:
 +                      v = v0 * (1 - PHYS_INPUT_TIMELENGTH * (PHYS_STOPSPEED / v0) * PHYS_FRICTION)
 +                        = v0 - PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED * PHYS_FRICTION
 +                      v0 = v + PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED * PHYS_FRICTION
 +                 and
 +                      v = v0 * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION)
 +                      v0 = v / (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION)
 +
 +                 These cases would be chosen ONLY if:
 +                      v0 < PHYS_STOPSPEED
 +                      v + PHYS_INPUT_TIMELENGTH * PHYS_STOPSPEED * PHYS_FRICTION < PHYS_STOPSPEED
 +                      v < PHYS_STOPSPEED * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION)
 +                 and, respectively:
 +                      v0 >= PHYS_STOPSPEED
 +                      v / (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION) >= PHYS_STOPSPEED
 +                      v >= PHYS_STOPSPEED * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION)
 +               */
 +      }
 +      float addspeed = wishspeed - self.velocity * wishdir;
 +      if (addspeed > 0)
 +      {
 +              float accelspeed = min(PHYS_ACCELERATE * PHYS_INPUT_TIMELENGTH * wishspeed, addspeed);
 +              self.velocity += accelspeed * wishdir;
 +      }
 +      float g = PHYS_GRAVITY * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH;
 +      if (!(GAMEPLAYFIX_NOGRAVITYONGROUND))
 +              self.velocity_z -= g * (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE ? 0.5 : 1);
 +      if (self.velocity * self.velocity)
 +              PM_ClientMovement_Move();
 +      if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
 +              if (!IS_ONGROUND(self) || !GAMEPLAYFIX_NOGRAVITYONGROUND)
 +                      self.velocity_z -= g * 0.5;
 +}
 +
 +void PM_air(float buttons_prev, float maxspd_mod)
 +{
 +      makevectors(self.v_angle.y * '0 1 0');
 +      vector wishvel = v_forward * self.movement.x
 +                                      + v_right * self.movement.y;
 +      // acceleration
 +      vector wishdir = normalize(wishvel);
 +      float wishspeed = vlen(wishvel);
 +
 +#ifdef SVQC
 +      if (time >= self.teleport_time)
 +#else
 +      if (pmove_waterjumptime <= 0)
 +#endif
 +      {
 +              float maxairspd = PHYS_MAXAIRSPEED * min(maxspd_mod, 1);
 +
 +              // apply air speed limit
 +              float airaccelqw = PHYS_AIRACCEL_QW(self);
 +              float wishspeed0 = wishspeed;
 +              wishspeed = min(wishspeed, maxairspd);
 +              if (IS_DUCKED(self))
 +                      wishspeed *= 0.5;
 +              float airaccel = PHYS_AIRACCELERATE * min(maxspd_mod, 1);
 +
 +              float accelerating = (self.velocity * wishdir > 0);
 +              float wishspeed2 = wishspeed;
 +
 +              // CPM: air control
 +              if (PHYS_AIRSTOPACCELERATE)
 +              {
 +                      vector curdir = normalize(vec2(self.velocity));
 +                      airaccel += (PHYS_AIRSTOPACCELERATE*maxspd_mod - airaccel) * max(0, -(curdir * wishdir));
 +              }
 +              // note that for straight forward jumping:
 +              // step = accel * PHYS_INPUT_TIMELENGTH * wishspeed0;
 +              // accel  = bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw);
 +              // -->
 +              // dv/dt = accel * maxspeed (when slow)
 +              // dv/dt = accel * maxspeed * (1 - accelqw) (when fast)
 +              // log dv/dt = logaccel + logmaxspeed (when slow)
 +              // log dv/dt = logaccel + logmaxspeed + log(1 - accelqw) (when fast)
 +              float strafity = IsMoveInDirection(self.movement, -90) + IsMoveInDirection(self.movement, +90); // if one is nonzero, other is always zero
 +              if (PHYS_MAXAIRSTRAFESPEED)
 +                      wishspeed = min(wishspeed, GeomLerp(PHYS_MAXAIRSPEED*maxspd_mod, strafity, PHYS_MAXAIRSTRAFESPEED*maxspd_mod));
 +              if (PHYS_AIRSTRAFEACCELERATE)
 +                      airaccel = GeomLerp(airaccel, strafity, PHYS_AIRSTRAFEACCELERATE*maxspd_mod);
 +              if (PHYS_AIRSTRAFEACCEL_QW(self))
 +                      airaccelqw =
 +              (((strafity > 0.5 ? PHYS_AIRSTRAFEACCEL_QW(self) : PHYS_AIRACCEL_QW(self)) >= 0) ? +1 : -1)
 +              *
 +              (1 - GeomLerp(1 - fabs(PHYS_AIRACCEL_QW(self)), strafity, 1 - fabs(PHYS_AIRSTRAFEACCEL_QW(self))));
 +              // !CPM
 +
 +              if (PHYS_WARSOWBUNNY_TURNACCEL && accelerating && self.movement.y == 0 && self.movement.x != 0)
 +                      PM_AirAccelerate(wishdir, wishspeed2);
 +              else
 +                      PM_Accelerate(wishdir, wishspeed, wishspeed0, airaccel, airaccelqw, PHYS_AIRACCEL_QW_STRETCHFACTOR(self), PHYS_AIRACCEL_SIDEWAYS_FRICTION / maxairspd, PHYS_AIRSPEEDLIMIT_NONQW(self));
 +
 +              if (PHYS_AIRCONTROL)
 +                      CPM_PM_Aircontrol(wishdir, wishspeed2);
 +      }
 +      float g = PHYS_GRAVITY * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH;
 +      if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
 +              self.velocity_z -= g * 0.5;
 +      else
 +              self.velocity_z -= g;
 +      PM_ClientMovement_Move();
 +      if (!IS_ONGROUND(self) || !(GAMEPLAYFIX_NOGRAVITYONGROUND))
 +              if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
 +                      self.velocity_z -= g * 0.5;
 +}
 +
 +// used for calculating airshots
 +bool IsFlying(entity a)
 +{
 +      if(IS_ONGROUND(a))
 +              return false;
 +      if(a.waterlevel >= WATERLEVEL_SWIMMING)
 +              return false;
 +      traceline(a.origin, a.origin - '0 0 48', MOVE_NORMAL, a);
 +      if(trace_fraction < 1)
 +              return false;
 +      return true;
 +}
 +
 +void PM_Main()
 +{
 +      int buttons = PHYS_INPUT_BUTTON_MASK(self);
 +#ifdef CSQC
 +      self.items = getstati(STAT_ITEMS, 0, 24);
 +
 +      self.movement = PHYS_INPUT_MOVEVALUES(self);
 +
 +      vector oldv_angle = self.v_angle;
 +      vector oldangles = self.angles; // we need to save these, as they're abused by other code
 +      self.v_angle = PHYS_INPUT_ANGLES(self);
 +      self.angles = PHYS_WORLD_ANGLES(self);
 +
 +      self.team = myteam + 1; // is this correct?
 +      if (!(PHYS_INPUT_BUTTON_JUMP(self))) // !jump
 +              UNSET_JUMP_HELD(self); // canjump = true
 +      pmove_waterjumptime -= PHYS_INPUT_TIMELENGTH;
 +
 +      PM_ClientMovement_UpdateStatus(true);
 +#endif
 +      
 +
 +#ifdef SVQC
 +      WarpZone_PlayerPhysics_FixVAngle();
 +#endif
 +      float maxspeed_mod = 1;
 +      maxspeed_mod *= PM_check_keepaway();
 +      maxspeed_mod *= PHYS_HIGHSPEED;
 +
 +#ifdef SVQC
 +      Physics_UpdateStats(maxspeed_mod);
 +
 +      if (self.PlayerPhysplug)
 +              if (self.PlayerPhysplug())
 +                      return;
 +#endif
 +
 +      PM_check_race_movetime();
 +#ifdef SVQC
 +      anticheat_physics();
 +#endif
 +
 +      if (PM_check_specialcommand(buttons))
 +              return;
 +#ifdef SVQC
 +      if (sv_maxidle > 0)
 +      {
 +              if (buttons != self.buttons_old || self.movement != self.movement_old || self.v_angle != self.v_angle_old)
 +                      self.parm_idlesince = time;
 +      }
 +#endif
 +      int buttons_prev = self.buttons_old;
 +      self.buttons_old = buttons;
 +      self.movement_old = self.movement;
 +      self.v_angle_old = self.v_angle;
 +
 +      PM_check_nickspam();
 +
 +      PM_check_punch();
 +#ifdef SVQC
 +      if (IS_BOT_CLIENT(self))
 +      {
 +              if (playerdemo_read())
 +                      return;
 +              bot_think();
 +      }
 +
 +      if (IS_PLAYER(self))
 +#endif
 +      {
 +#ifdef SVQC
 +              if (self.race_penalty)
 +                      if (time > self.race_penalty)
 +                              self.race_penalty = 0;
 +#endif
 +
 +              bool not_allowed_to_move = false;
 +#ifdef SVQC
 +              if (self.race_penalty)
 +                      not_allowed_to_move = true;
 +#endif
 +#ifdef SVQC
 +              if (time < game_starttime)
 +                      not_allowed_to_move = true;
 +#endif
 +
 +              if (not_allowed_to_move)
 +              {
 +                      self.velocity = '0 0 0';
 +                      self.movetype = MOVETYPE_NONE;
 +#ifdef SVQC
 +                      self.disableclientprediction = 2;
 +#endif
 +              }
 +#ifdef SVQC
 +              else if (self.disableclientprediction == 2)
 +              {
 +                      if (self.movetype == MOVETYPE_NONE)
 +                              self.movetype = MOVETYPE_WALK;
 +                      self.disableclientprediction = 0;
 +              }
 +#endif
 +      }
 +
 +#ifdef SVQC
 +      if (self.movetype == MOVETYPE_NONE)
 +              return;
 +
 +      // when we get here, disableclientprediction cannot be 2
 +      self.disableclientprediction = 0;
 +#endif
 +
 +      PM_check_spider();
 +
 +      PM_check_frozen();
 +
 +      PM_check_blocked();
 +
 +      maxspeed_mod = 1;
 +
 +      if (self.in_swamp)
 +              maxspeed_mod *= self.swamp_slowdown; //cvar("g_balance_swamp_moverate");
 +
 +      // conveyors: first fix velocity
 +      if (self.conveyor.state)
 +              self.velocity -= self.conveyor.movedir;
 +
 +#ifdef SVQC
 +      MUTATOR_CALLHOOK(PlayerPhysics);
 +#endif
 +#ifdef CSQC
 +      PM_multijump();
 +#endif
 +
 +//    float forcedodge = 1;
 +//    if(forcedodge) {
 +//#ifdef CSQC
 +//            PM_dodging_checkpressedkeys();
 +//#endif
 +//            PM_dodging();
 +//            PM_ClientMovement_Move();
 +//            return;
 +//    }
 +
 +#ifdef SVQC
 +      if (!IS_PLAYER(self))
 +      {
 +              maxspeed_mod = autocvar_sv_spectator_speed_multiplier;
 +              if (!self.spectatorspeed)
 +                      self.spectatorspeed = maxspeed_mod;
 +              if (self.impulse && self.impulse <= 19 || (self.impulse >= 200 && self.impulse <= 209) || (self.impulse >= 220 && self.impulse <= 229))
 +              {
 +                      if (self.lastclassname != "player")
 +                      {
 +                              if (self.impulse == 10 || self.impulse == 15 || self.impulse == 18 || (self.impulse >= 200 && self.impulse <= 209))
 +                                      self.spectatorspeed = bound(1, self.spectatorspeed + 0.5, 5);
 +                              else if (self.impulse == 11)
 +                                      self.spectatorspeed = maxspeed_mod;
 +                              else if (self.impulse == 12 || self.impulse == 16  || self.impulse == 19 || (self.impulse >= 220 && self.impulse <= 229))
 +                                      self.spectatorspeed = bound(1, self.spectatorspeed - 0.5, 5);
 +                              else if (self.impulse >= 1 && self.impulse <= 9)
 +                                      self.spectatorspeed = 1 + 0.5 * (self.impulse - 1);
 +                      } // otherwise just clear
 +                      self.impulse = 0;
 +              }
 +              maxspeed_mod = self.spectatorspeed;
 +      }
 +
 +      float spd = max(PHYS_MAXSPEED(self), PHYS_MAXAIRSPEED) * maxspeed_mod;
 +      if(self.speed != spd)
 +      {
 +              self.speed = spd;
 +              string temps = ftos(spd);
 +              stuffcmd(self, strcat("cl_forwardspeed ", temps, "\n"));
 +              stuffcmd(self, strcat("cl_backspeed ", temps, "\n"));
 +              stuffcmd(self, strcat("cl_sidespeed ", temps, "\n"));
 +              stuffcmd(self, strcat("cl_upspeed ", temps, "\n"));
 +      }
 +#endif
 +
 +      if(PHYS_DEAD(self))
 +              goto end;
 +
 +#ifdef SVQC
 +      if (!self.fixangle && !g_bugrigs)
 +              self.angles = '0 1 0' * self.v_angle.y;
 +#endif
 +
 +      PM_check_hitground();
 +
 +      if(IsFlying(self))
 +              self.wasFlying = 1;
 +
 +      if (IS_PLAYER(self))
 +              CheckPlayerJump();
 +
 +      if (self.flags & FL_WATERJUMP)
 +      {
 +              self.velocity_x = self.movedir_x;
 +              self.velocity_y = self.movedir_y;
 +              if (time > self.teleport_time || self.waterlevel == WATERLEVEL_NONE)
 +              {
 +                      self.flags &= ~FL_WATERJUMP;
 +                      self.teleport_time = 0;
 +              }
 +      }
 +
 +#ifdef SVQC
 +      else if (g_bugrigs && IS_PLAYER(self))
 +              RaceCarPhysics();
 +#endif
 +
 +      else if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY || self.movetype == MOVETYPE_FLY_WORLDONLY || (BUFFS(self) & BUFF_FLIGHT))
 +              PM_fly(maxspeed_mod);
 +
 +      else if (self.waterlevel >= WATERLEVEL_SWIMMING)
 +              PM_swim(maxspeed_mod);
 +
 +      else if (time < self.ladder_time)
 +              PM_ladder(maxspeed_mod);
 +
++      else if (ITEMS_STAT(self) & IT_USING_JETPACK)
 +              PM_jetpack(maxspeed_mod);
 +
 +      else if (IS_ONGROUND(self))
 +              PM_walk(buttons_prev, maxspeed_mod);
 +
 +      else
 +              PM_air(buttons_prev, maxspeed_mod);
 +
 +#ifdef SVQC
 +      if (!IS_OBSERVER(self))
 +              PM_check_race();
 +#endif
 +      PM_check_vortex();
 +
 +:end
 +      if (IS_ONGROUND(self))
 +              self.lastground = time;
 +
 +      // conveyors: then break velocity again
 +      if(self.conveyor.state)
 +              self.velocity += self.conveyor.movedir;
 +
 +      self.lastflags = self.flags;
 +
 +      self.lastclassname = self.classname;
 +
 +#ifdef CSQC
 +      self.v_angle = oldv_angle;
 +      self.angles = oldangles;
 +#endif
 +}
 +
 +#ifdef SVQC
 +void SV_PlayerPhysics(void)
 +#elif defined(CSQC)
 +void CSQC_ClientMovement_PlayerMove_Frame(void)
 +#endif
 +{
 +      PM_Main();
 +
 +#ifdef CSQC
 +      self.pmove_flags = 
 +                      ((self.flags & FL_DUCKED) ? PMF_DUCKED : 0) |
 +                      (!(self.flags & FL_JUMPRELEASED) ? 0 : PMF_JUMP_HELD) |
 +                      ((self.flags & FL_ONGROUND) ? PMF_ONGROUND : 0);
 +#endif
 +}
index c704bc9,0000000..599eee5
mode 100644,000000..100644
--- /dev/null
@@@ -1,349 -1,0 +1,349 @@@
-       #define ITEMS(s)                                                        (s).items
 +#ifndef COMMON_PHYSICS_H
 +#define COMMON_PHYSICS_H
 +
 +// Client/server mappings
 +
 +.entity conveyor;
 +
 +.float race_penalty;
 +
 +.float gravity;
 +.float swamp_slowdown;
 +.float lastflags;
 +.float lastground;
 +.float wasFlying;
 +.float spectatorspeed;
 +
 +.vector movement_old;
 +.float buttons_old;
 +.vector v_angle_old;
 +.string lastclassname;
 +
 +.float() PlayerPhysplug;
 +float AdjustAirAccelQW(float accelqw, float factor);
 +
 +bool IsFlying(entity a);
 +
 +#ifdef CSQC
 +
 +      const int FL_WATERJUMP = 2048;  // player jumping out of water
 +      const int FL_JUMPRELEASED = 4096;       // for jump debouncing
 +
 +      float PM_multijump_checkjump();
 +      void PM_multijump();
 +
 +      .float watertype;
 +      .int items;
 +
 +      .vector movement;
 +      .vector v_angle;
 +
 +// TODO
 +      #define IS_CLIENT(s)                                            (s).isplayermodel
 +      #define IS_PLAYER(s)                                            (s).isplayermodel
 +      #define isPushable(s)                                           (s).isplayermodel
 +
 +      float player_multijump;
 +      float player_jumpheight;
 +
 +      #define PHYS_INPUT_ANGLES(s)                            input_angles
 +// TODO
 +      #define PHYS_WORLD_ANGLES(s)                            input_angles
 +
 +      #define PHYS_INPUT_TIMELENGTH                           input_timelength
 +      #define PHYS_INPUT_FRAMETIME                            serverdeltatime
 +
 +      #define PHYS_INPUT_MOVEVALUES(s)                        input_movevalues
 +
 +      #define PHYS_INPUT_BUTTON_MASK(s)               (input_buttons | 128 * (input_movevalues_x < 0) | 256 * (input_movevalues_x > 0) | 512 * (input_movevalues_y < 0) | 1024 * (input_movevalues_y > 0))
 +      #define PHYS_INPUT_BUTTON_ATCK(s)                       !!(input_buttons & 1)
 +      #define PHYS_INPUT_BUTTON_JUMP(s)                       !!(input_buttons & 2)
 +      #define PHYS_INPUT_BUTTON_ATCK2(s)                      !!(input_buttons & 4)
 +      #define PHYS_INPUT_BUTTON_ZOOM(s)                       !!(input_buttons & 8)
 +      #define PHYS_INPUT_BUTTON_CROUCH(s)                     !!(input_buttons & 16)
 +      #define PHYS_INPUT_BUTTON_HOOK(s)                       !!(input_buttons & 32)
 +      #define PHYS_INPUT_BUTTON_USE(s)                        !!(input_buttons & 64)
 +      #define PHYS_INPUT_BUTTON_BACKWARD(s)           !!(input_buttons & 128)
 +      #define PHYS_INPUT_BUTTON_FORWARD(s)            !!(input_buttons & 256)
 +      #define PHYS_INPUT_BUTTON_LEFT(s)                       !!(input_buttons & 512)
 +      #define PHYS_INPUT_BUTTON_RIGHT(s)                      !!(input_buttons & 1024)
 +      #define PHYS_INPUT_BUTTON_JETPACK(s)            !!(input_buttons & 4096)
 +
 +      #define PHYS_DEAD(s)                                            s.csqcmodel_isdead
 +
 +      #define GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE  !!(moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
 +      #define GAMEPLAYFIX_NOGRAVITYONGROUND                   cvar("sv_gameplayfix_nogravityonground")
 +      #define GAMEPLAYFIX_Q2AIRACCELERATE                             cvar("sv_gameplayfix_q2airaccelerate")
 +      #define GAMEPLAYFIX_EASIERWATERJUMP                     getstati(STAT_GAMEPLAYFIX_EASIERWATERJUMP)
 +      #define GAMEPLAYFIX_DOWNTRACEONGROUND                   getstati(STAT_GAMEPLAYFIX_DOWNTRACEONGROUND)
 +      #define GAMEPLAYFIX_STEPMULTIPLETIMES                   getstati(STAT_GAMEPLAYFIX_STEPMULTIPLETIMES)
 +      #define GAMEPLAYFIX_UNSTICKPLAYERS                              getstati(STAT_GAMEPLAYFIX_UNSTICKPLAYERS)
 +      #define GAMEPLAYFIX_STEPDOWN                                    getstati(STAT_GAMEPLAYFIX_STEPDOWN)
 +
 +      #define IS_DUCKED(s)                                            !!(s.flags & FL_DUCKED)
 +      #define SET_DUCKED(s)                                           s.flags |= FL_DUCKED
 +      #define UNSET_DUCKED(s)                                         s.flags &= ~FL_DUCKED
 +
 +      #define IS_JUMP_HELD(s)                                         !(s.flags & FL_JUMPRELEASED)
 +      #define SET_JUMP_HELD(s)                                        s.flags &= ~FL_JUMPRELEASED
 +      #define UNSET_JUMP_HELD(s)                                      s.flags |= FL_JUMPRELEASED
 +
 +      #define IS_ONGROUND(s)                                          !!(s.flags & FL_ONGROUND)
 +      #define SET_ONGROUND(s)                                         s.flags |= FL_ONGROUND
 +      #define UNSET_ONGROUND(s)                                       s.flags &= ~FL_ONGROUND
 +
 +      #define WAS_ONGROUND(s)                                         !!(s.lastflags & FL_ONGROUND)
 +
-       #define ITEMS(s)                                                        s.items
++      #define ITEMS_STAT(s)                                           (s).items
 +      #define BUFFS(s)                                                        getstati(STAT_BUFFS)
 +
 +      #define PHYS_AMMO_FUEL(s)                                       getstati(STAT_FUEL)
 +
 +      #define PHYS_FROZEN(s)                                          getstati(STAT_FROZEN)
 +
 +      #define PHYS_DOUBLEJUMP                                         getstati(STAT_DOUBLEJUMP)
 +
 +      #define PHYS_BUGRIGS                                            getstati(STAT_BUGRIGS)
 +      #define PHYS_BUGRIGS_ANGLE_SMOOTHING            getstati(STAT_BUGRIGS_ANGLE_SMOOTHING)
 +      #define PHYS_BUGRIGS_PLANAR_MOVEMENT            getstati(STAT_BUGRIGS_PLANAR_MOVEMENT)
 +      #define PHYS_BUGRIGS_REVERSE_SPEEDING           getstati(STAT_BUGRIGS_REVERSE_SPEEDING)
 +      #define PHYS_BUGRIGS_FRICTION_FLOOR             getstatf(STAT_BUGRIGS_FRICTION_FLOOR)
 +      #define PHYS_BUGRIGS_AIR_STEERING                       getstati(STAT_BUGRIGS_AIR_STEERING)
 +      #define PHYS_BUGRIGS_FRICTION_BRAKE             getstatf(STAT_BUGRIGS_FRICTION_BRAKE)
 +      #define PHYS_BUGRIGS_ACCEL                                      getstatf(STAT_BUGRIGS_ACCEL)
 +      #define PHYS_BUGRIGS_SPEED_REF                          getstatf(STAT_BUGRIGS_SPEED_REF)
 +      #define PHYS_BUGRIGS_SPEED_POW                          getstatf(STAT_BUGRIGS_SPEED_POW)
 +      #define PHYS_BUGRIGS_STEER                                      getstatf(STAT_BUGRIGS_STEER)
 +      #define PHYS_BUGRIGS_FRICTION_AIR                       getstatf(STAT_BUGRIGS_FRICTION_AIR)
 +      #define PHYS_BUGRIGS_CAR_JUMPING                        getstatf(STAT_BUGRIGS_CAR_JUMPING)
 +      #define PHYS_BUGRIGS_REVERSE_SPINNING           getstatf(STAT_BUGRIGS_REVERSE_SPINNING)
 +      #define PHYS_BUGRIGS_REVERSE_STOPPING           getstatf(STAT_BUGRIGS_REVERSE_STOPPING)
 +
 +      #define PHYS_JUMPSPEEDCAP_MIN                           getstatf(STAT_MOVEVARS_JUMPSPEEDCAP_MIN)
 +      #define PHYS_JUMPSPEEDCAP_MAX                           getstatf(STAT_MOVEVARS_JUMPSPEEDCAP_MAX)
 +      #define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS       getstati(STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS)
 +
 +      #define PHYS_TRACK_CANJUMP(s)                           getstati(STAT_MOVEVARS_TRACK_CANJUMP)
 +      #define PHYS_ACCELERATE                                         getstatf(STAT_MOVEVARS_ACCELERATE)
 +      #define PHYS_AIRACCEL_QW(s)                                     getstatf(STAT_MOVEVARS_AIRACCEL_QW)
 +      #define PHYS_AIRACCEL_QW_STRETCHFACTOR(s)       getstatf(STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR)
 +      #define PHYS_AIRACCEL_SIDEWAYS_FRICTION         getstatf(STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION)
 +      #define PHYS_AIRACCELERATE                                      getstatf(STAT_MOVEVARS_AIRACCELERATE)
 +      #define PHYS_AIRCONTROL                                         getstatf(STAT_MOVEVARS_AIRCONTROL)
 +      #define PHYS_AIRCONTROL_PENALTY                         getstatf(STAT_MOVEVARS_AIRCONTROL_PENALTY)
 +      #define PHYS_AIRCONTROL_POWER                           getstatf(STAT_MOVEVARS_AIRCONTROL_POWER)
 +      #define PHYS_AIRSPEEDLIMIT_NONQW(s)                     getstatf(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW)
 +      #define PHYS_AIRSTOPACCELERATE                          getstatf(STAT_MOVEVARS_AIRSTOPACCELERATE)
 +      #define PHYS_AIRSTRAFEACCEL_QW(s)                       getstatf(STAT_MOVEVARS_AIRSTRAFEACCEL_QW)
 +      #define PHYS_AIRSTRAFEACCELERATE                        getstatf(STAT_MOVEVARS_AIRSTRAFEACCELERATE)
 +      #define PHYS_ENTGRAVITY(s)                                      getstatf(STAT_MOVEVARS_ENTGRAVITY)
 +      #define PHYS_FRICTION                                           getstatf(STAT_MOVEVARS_FRICTION)
 +      #define PHYS_FRICTION_SLICK                                     getstatf(STAT_MOVEVARS_FRICTION_SLICK)
 +      #define PHYS_FRICTION_ONLAND                            getstatf(STAT_MOVEVARS_FRICTION_ONLAND)
 +      #define PHYS_GRAVITY                                            getstatf(STAT_MOVEVARS_GRAVITY)
 +      #define PHYS_HIGHSPEED                                          getstatf(STAT_MOVEVARS_HIGHSPEED)
 +      #define PHYS_JUMPVELOCITY                                       getstatf(STAT_MOVEVARS_JUMPVELOCITY)
 +      #define PHYS_MAXAIRSPEED                                        getstatf(STAT_MOVEVARS_MAXAIRSPEED)
 +      #define PHYS_MAXAIRSTRAFESPEED                          getstatf(STAT_MOVEVARS_MAXAIRSTRAFESPEED)
 +      #define PHYS_MAXSPEED(s)                                        getstatf(STAT_MOVEVARS_MAXSPEED)
 +      #define PHYS_STEPHEIGHT                                         getstatf(STAT_MOVEVARS_STEPHEIGHT)
 +      #define PHYS_STOPSPEED                                          getstatf(STAT_MOVEVARS_STOPSPEED)
 +      #define PHYS_WARSOWBUNNY_ACCEL                          getstatf(STAT_MOVEVARS_WARSOWBUNNY_ACCEL)
 +      #define PHYS_WARSOWBUNNY_BACKTOSIDERATIO        getstatf(STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO)
 +      #define PHYS_WARSOWBUNNY_AIRFORWARDACCEL        getstatf(STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL)
 +      #define PHYS_WARSOWBUNNY_TOPSPEED                       getstatf(STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED)
 +      #define PHYS_WARSOWBUNNY_TURNACCEL                      getstatf(STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL)
 +
 +      #define PHYS_WALLFRICTION                                       getstati(STAT_MOVEVARS_WALLFRICTION)
 +
 +      #define PHYS_JETPACK_ACCEL_UP                           getstatf(STAT_JETPACK_ACCEL_UP)
 +      #define PHYS_JETPACK_ACCEL_SIDE                         getstatf(STAT_JETPACK_ACCEL_SIDE)
 +      #define PHYS_JETPACK_ANTIGRAVITY                        getstatf(STAT_JETPACK_ANTIGRAVITY)
 +      #define PHYS_JETPACK_FUEL                                       getstatf(STAT_JETPACK_FUEL)
 +      #define PHYS_JETPACK_MAXSPEED_UP                        getstatf(STAT_JETPACK_MAXSPEED_UP)
 +      #define PHYS_JETPACK_MAXSPEED_SIDE                      getstatf(STAT_JETPACK_MAXSPEED_SIDE)
 +
 +      #define PHYS_DODGING_FROZEN                                     getstati(STAT_DODGING_FROZEN)
 +
 +      #define PHYS_NOSTEP                                                     getstati(STAT_NOSTEP)
 +      #define PHYS_JUMPSTEP                                           getstati(STAT_MOVEVARS_JUMPSTEP)
 +
 +#elif defined(SVQC)
 +
 +      .vector stat_pl_view_ofs;
 +      .vector stat_pl_crouch_view_ofs;
 +
 +      .vector stat_pl_min;
 +      .vector stat_pl_max;
 +      .vector stat_pl_crouch_min;
 +      .vector stat_pl_crouch_max;
 +
 +      .float stat_sv_airaccel_qw;
 +      .float stat_sv_airstrafeaccel_qw;
 +      .float stat_sv_airspeedlimit_nonqw;
 +      .float stat_sv_maxspeed;
 +      .float stat_movement_highspeed;
 +
 +      .float stat_sv_friction_on_land;
 +      .float stat_sv_friction_slick;
 +
 +      .float stat_doublejump;
 +
 +      .float stat_jumpspeedcap_min;
 +      .float stat_jumpspeedcap_max;
 +      .float stat_jumpspeedcap_disable_onramps;
 +
 +      .float stat_jetpack_accel_side;
 +      .float stat_jetpack_accel_up;
 +      .float stat_jetpack_antigravity;
 +      .float stat_jetpack_fuel;
 +      .float stat_jetpack_maxspeed_up;
 +      .float stat_jetpack_maxspeed_side;
 +      .float stat_gameplayfix_easierwaterjump;
 +      .float stat_gameplayfix_downtracesupportsongroundflag;
 +      .float stat_gameplayfix_stepmultipletimes;
 +      .float stat_gameplayfix_unstickplayers;
 +      .float stat_gameplayfix_stepdown;
 +
 +      .float stat_bugrigs;
 +      .float stat_bugrigs_angle_smoothing;
 +      .float stat_bugrigs_planar_movement;
 +      .float stat_bugrigs_reverse_speeding;
 +      .float stat_bugrigs_friction_floor;
 +      .float stat_bugrigs_air_steering;
 +      .float stat_bugrigs_friction_brake;
 +      .float stat_bugrigs_accel;
 +      .float stat_bugrigs_speed_ref;
 +      .float stat_bugrigs_speed_pow;
 +      .float stat_bugrigs_steer;
 +      .float stat_bugrigs_friction_air;
 +      .float stat_bugrigs_car_jumping;
 +      .float stat_bugrigs_reverse_spinning;
 +      .float stat_bugrigs_reverse_stopping;
 +
 +      .float stat_nostep;
 +      .float stat_jumpstep;
 +
 +      #define PHYS_INPUT_ANGLES(s)                            s.v_angle
 +      #define PHYS_WORLD_ANGLES(s)                            s.angles
 +
 +      #define PHYS_INPUT_TIMELENGTH                           frametime
 +      #define PHYS_INPUT_FRAMETIME                            sys_frametime
 +
 +      #define PHYS_INPUT_MOVEVALUES(s)                        s.movement
 +      // TODO: cache
 +      #define PHYS_INPUT_BUTTON_MASK(s)               (s.BUTTON_ATCK | 2 * s.BUTTON_JUMP | 4 * s.BUTTON_ATCK2 | 8 * s.BUTTON_ZOOM | 16 * s.BUTTON_CROUCH | 32 * s.BUTTON_HOOK | 64 * s.BUTTON_USE | 128 * (s.movement_x < 0) | 256 * (s.movement_x > 0) | 512 * (s.movement_y < 0) | 1024 * (s.movement_y > 0))
 +      #define PHYS_INPUT_BUTTON_ATCK(s)                       s.BUTTON_ATCK
 +      #define PHYS_INPUT_BUTTON_JUMP(s)                       s.BUTTON_JUMP
 +      #define PHYS_INPUT_BUTTON_ATCK2(s)                      s.BUTTON_ATCK2
 +      #define PHYS_INPUT_BUTTON_ZOOM(s)                       s.BUTTON_ZOOM
 +      #define PHYS_INPUT_BUTTON_CROUCH(s)                     s.BUTTON_CROUCH
 +      #define PHYS_INPUT_BUTTON_HOOK(s)                       s.BUTTON_HOOK
 +      #define PHYS_INPUT_BUTTON_USE(s)                        s.BUTTON_USE
 +      #define PHYS_INPUT_BUTTON_BACKWARD(s)           (s.movement_x < 0)
 +      #define PHYS_INPUT_BUTTON_FORWARD(s)            (s.movement_x > 0)
 +      #define PHYS_INPUT_BUTTON_LEFT(s)                       (s.movement_y < 0)
 +      #define PHYS_INPUT_BUTTON_RIGHT(s)                      (s.movement_y > 0)
 +      #define PHYS_INPUT_BUTTON_JETPACK(s)            s.BUTTON_JETPACK
 +
 +      #define PHYS_DEAD(s)                                            s.deadflag != DEAD_NO
 +
 +      #define GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE  autocvar_sv_gameplayfix_gravityunaffectedbyticrate
 +      #define GAMEPLAYFIX_NOGRAVITYONGROUND                   cvar("sv_gameplayfix_nogravityonground")
 +      #define GAMEPLAYFIX_Q2AIRACCELERATE                             autocvar_sv_gameplayfix_q2airaccelerate
 +      #define GAMEPLAYFIX_EASIERWATERJUMP                             cvar("sv_gameplayfix_easierwaterjump")
 +      #define GAMEPLAYFIX_DOWNTRACEONGROUND                   cvar("sv_gameplayfix_downtracesupportsongroundflag")
 +      #define GAMEPLAYFIX_STEPMULTIPLETIMES                   cvar("sv_gameplayfix_stepmultipletimes")
 +      #define GAMEPLAYFIX_UNSTICKPLAYERS                              cvar("sv_gameplayfix_unstickplayers")
 +      #define GAMEPLAYFIX_STEPDOWN                                    cvar("sv_gameplayfix_stepdown")
 +
 +      #define IS_DUCKED(s)                                            s.crouch
 +      #define SET_DUCKED(s)                                           s.crouch = true
 +      #define UNSET_DUCKED(s)                                         s.crouch = false
 +
 +      #define IS_JUMP_HELD(s)                                         !(s.flags & FL_JUMPRELEASED)
 +      #define SET_JUMP_HELD(s)                                        s.flags &= ~FL_JUMPRELEASED
 +      #define UNSET_JUMP_HELD(s)                                      s.flags |= FL_JUMPRELEASED
 +
 +      #define IS_ONGROUND(s)                                          !!(s.flags & FL_ONGROUND)
 +      #define SET_ONGROUND(s)                                         s.flags |= FL_ONGROUND
 +      #define UNSET_ONGROUND(s)                                       s.flags &= ~FL_ONGROUND
 +
 +      #define WAS_ONGROUND(s)                                         !!((s).lastflags & FL_ONGROUND)
 +
++      #define ITEMS_STAT(s)                                           s.items
 +      #define BUFFS(s)                                                        (s).buffs
 +
 +      #define PHYS_AMMO_FUEL(s)                                       s.ammo_fuel
 +
 +      #define PHYS_FROZEN(s)                                          s.frozen
 +
 +      #define PHYS_DOUBLEJUMP                                         autocvar_sv_doublejump
 +
 +      #define PHYS_BUGRIGS                                            g_bugrigs
 +      #define PHYS_BUGRIGS_ANGLE_SMOOTHING            g_bugrigs_angle_smoothing
 +      #define PHYS_BUGRIGS_PLANAR_MOVEMENT            g_bugrigs_planar_movement
 +      #define PHYS_BUGRIGS_REVERSE_SPEEDING           g_bugrigs_reverse_speeding
 +      #define PHYS_BUGRIGS_FRICTION_FLOOR                     g_bugrigs_friction_floor
 +      #define PHYS_BUGRIGS_AIR_STEERING                       g_bugrigs_air_steering
 +      #define PHYS_BUGRIGS_FRICTION_BRAKE                     g_bugrigs_friction_brake
 +      #define PHYS_BUGRIGS_ACCEL                                      g_bugrigs_accel
 +      #define PHYS_BUGRIGS_SPEED_REF                          g_bugrigs_speed_ref
 +      #define PHYS_BUGRIGS_SPEED_POW                          g_bugrigs_speed_pow
 +      #define PHYS_BUGRIGS_STEER                                      g_bugrigs_steer
 +      #define PHYS_BUGRIGS_FRICTION_AIR                       g_bugrigs_friction_air
 +      #define PHYS_BUGRIGS_CAR_JUMPING                        g_bugrigs_planar_movement_car_jumping
 +      #define PHYS_BUGRIGS_REVERSE_SPINNING           g_bugrigs_reverse_spinning
 +      #define PHYS_BUGRIGS_REVERSE_STOPPING           g_bugrigs_reverse_stopping
 +
 +      #define PHYS_JUMPSPEEDCAP_MIN                           autocvar_sv_jumpspeedcap_min
 +      #define PHYS_JUMPSPEEDCAP_MAX                           autocvar_sv_jumpspeedcap_max
 +      #define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS       autocvar_sv_jumpspeedcap_max_disable_on_ramps
 +
 +      #define PHYS_TRACK_CANJUMP(s)                           s.cvar_cl_movement_track_canjump
 +      #define PHYS_ACCELERATE                                         autocvar_sv_accelerate
 +      #define PHYS_AIRACCEL_QW(s)                                     s.stat_sv_airaccel_qw
 +      #define PHYS_AIRACCEL_QW_STRETCHFACTOR(s)       autocvar_sv_airaccel_qw_stretchfactor
 +      #define PHYS_AIRACCEL_SIDEWAYS_FRICTION         autocvar_sv_airaccel_sideways_friction
 +      #define PHYS_AIRACCELERATE                                      autocvar_sv_airaccelerate
 +      #define PHYS_AIRCONTROL                                         autocvar_sv_aircontrol
 +      #define PHYS_AIRCONTROL_PENALTY                         autocvar_sv_aircontrol_penalty
 +      #define PHYS_AIRCONTROL_POWER                           autocvar_sv_aircontrol_power
 +      #define PHYS_AIRSPEEDLIMIT_NONQW(s)                     s.stat_sv_airspeedlimit_nonqw
 +      #define PHYS_AIRSTOPACCELERATE                          autocvar_sv_airstopaccelerate
 +      #define PHYS_AIRSTRAFEACCEL_QW(s)                       s.stat_sv_airstrafeaccel_qw
 +      #define PHYS_AIRSTRAFEACCELERATE                        autocvar_sv_airstrafeaccelerate
 +      #define PHYS_ENTGRAVITY(s)                                      s.gravity
 +      #define PHYS_FRICTION                                           autocvar_sv_friction
 +      #define PHYS_FRICTION_SLICK                                     autocvar_sv_friction_slick
 +      #define PHYS_FRICTION_ONLAND                            autocvar_sv_friction_on_land
 +      #define PHYS_GRAVITY                                            autocvar_sv_gravity
 +      #define PHYS_HIGHSPEED                                          autocvar_g_movement_highspeed
 +      #define PHYS_JUMPVELOCITY                                       autocvar_sv_jumpvelocity
 +      #define PHYS_MAXAIRSPEED                                        autocvar_sv_maxairspeed
 +      #define PHYS_MAXAIRSTRAFESPEED                          autocvar_sv_maxairstrafespeed
 +      #define PHYS_MAXSPEED(s)                                        s.stat_sv_maxspeed
 +      #define PHYS_STEPHEIGHT                                         autocvar_sv_stepheight
 +      #define PHYS_STOPSPEED                                          autocvar_sv_stopspeed
 +      #define PHYS_WARSOWBUNNY_ACCEL                          autocvar_sv_warsowbunny_accel
 +      #define PHYS_WARSOWBUNNY_BACKTOSIDERATIO        autocvar_sv_warsowbunny_backtosideratio
 +      #define PHYS_WARSOWBUNNY_AIRFORWARDACCEL        autocvar_sv_warsowbunny_airforwardaccel
 +      #define PHYS_WARSOWBUNNY_TOPSPEED                       autocvar_sv_warsowbunny_topspeed
 +      #define PHYS_WARSOWBUNNY_TURNACCEL                      autocvar_sv_warsowbunny_turnaccel
 +
 +      #define PHYS_WALLFRICTION                                       cvar("sv_wallfriction")
 +
 +      #define PHYS_JETPACK_ACCEL_UP                           autocvar_g_jetpack_acceleration_up
 +      #define PHYS_JETPACK_ACCEL_SIDE                         autocvar_g_jetpack_acceleration_side
 +      #define PHYS_JETPACK_ANTIGRAVITY                        autocvar_g_jetpack_antigravity
 +      #define PHYS_JETPACK_FUEL                                       autocvar_g_jetpack_fuel
 +      #define PHYS_JETPACK_MAXSPEED_UP                        autocvar_g_jetpack_maxspeed_up
 +      #define PHYS_JETPACK_MAXSPEED_SIDE                      autocvar_g_jetpack_maxspeed_side
 +
 +      #define PHYS_DODGING_FROZEN                                     autocvar_sv_dodging_frozen
 +
 +      #define PHYS_NOSTEP                                                     cvar("sv_nostep")
 +      #define PHYS_JUMPSTEP                                           cvar("sv_jumpstep")
 +
 +#endif
 +#endif
Simple merge
index 9c371b5,0000000..16bfcd5
mode 100644,000000..100644
--- /dev/null
@@@ -1,315 -1,0 +1,316 @@@
 +#ifdef SVQC
 +#include "../../../server/weapons/common.qh"
++#include "../../../server/_all.qh"
 +
 +.entity sprite;
 +
 +.float dmg;
 +.float dmg_edge;
 +.float dmg_radius;
 +.float dmg_force;
 +.float debrismovetype;
 +.float debrissolid;
 +.vector debrisvelocity;
 +.vector debrisvelocityjitter;
 +.vector debrisavelocityjitter;
 +.float debristime;
 +.float debristimejitter;
 +.float debrisfadetime;
 +.float debrisdamageforcescale;
 +.float debrisskin;
 +
 +.string mdl_dead; // or "" to hide when broken
 +.string debris; // space separated list of debris models
 +// other fields:
 +//   mdl = particle effect name
 +//   count = particle effect multiplier
 +//   targetname = target to trigger to unbreak the model
 +//   target = targets to trigger when broken
 +//   health = amount of damage it can take
 +//   spawnflags:
 +//     1 = start disabled (needs to be triggered to activate)
 +//     2 = indicate damage
 +// notes:
 +//   for mdl_dead to work, origin must be set (using a common/origin brush).
 +//   Otherwise mdl_dead will be displayed at the map origin, and nobody would
 +//   want that!
 +
 +void func_breakable_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
 +
 +//
 +// func_breakable
 +// - basically func_assault_destructible for general gameplay use
 +//
 +void LaunchDebris (string debrisname, vector force)
 +{
 +      entity dbr = spawn();
 +      setorigin(dbr, self.absmin
 +                 + '1 0 0' * random() * (self.absmax.x - self.absmin.x)
 +                 + '0 1 0' * random() * (self.absmax.y - self.absmin.y)
 +                 + '0 0 1' * random() * (self.absmax.z - self.absmin.z));
 +      setmodel (dbr, debrisname );
 +      dbr.skin = self.debrisskin;
 +      dbr.colormap = self.colormap; // inherit team colors
 +      dbr.owner = self; // do not be affected by our own explosion
 +      dbr.movetype = self.debrismovetype;
 +      dbr.solid = self.debrissolid;
 +      if(dbr.solid != SOLID_BSP) // SOLID_BSP has exact collision, MAYBE this works? TODO check this out
 +              setsize(dbr, '0 0 0', '0 0 0'); // needed for performance, until engine can deal better with it
 +      dbr.velocity_x = self.debrisvelocity.x + self.debrisvelocityjitter.x * crandom();
 +      dbr.velocity_y = self.debrisvelocity.y + self.debrisvelocityjitter.y * crandom();
 +      dbr.velocity_z = self.debrisvelocity.z + self.debrisvelocityjitter.z * crandom();
 +      self.velocity = self.velocity + force * self.debrisdamageforcescale;
 +      dbr.avelocity_x = random()*self.debrisavelocityjitter.x;
 +      dbr.avelocity_y = random()*self.debrisavelocityjitter.y;
 +      dbr.avelocity_z = random()*self.debrisavelocityjitter.z;
 +      dbr.damageforcescale = self.debrisdamageforcescale;
 +      if(dbr.damageforcescale)
 +              dbr.takedamage = DAMAGE_YES;
 +      SUB_SetFade(dbr, time + self.debristime + crandom() * self.debristimejitter, self.debrisfadetime);
 +}
 +
 +void func_breakable_colormod()
 +{
 +      float h;
 +      if (!(self.spawnflags & 2))
 +              return;
 +      h = self.health / self.max_health;
 +      if(h < 0.25)
 +              self.colormod = '1 0 0';
 +      else if(h <= 0.75)
 +              self.colormod = '1 0 0' + '0 1 0' * (2 * h - 0.5);
 +      else
 +              self.colormod = '1 1 1';
 +
 +      CSQCMODEL_AUTOUPDATE();
 +}
 +
 +void func_breakable_look_destroyed()
 +{
 +      float floorZ;
 +
 +      if(self.solid == SOLID_BSP) // in case a misc_follow moved me, save the current origin first
 +              self.dropped_origin = self.origin;
 +
 +      if(self.mdl_dead == "")
 +              self.effects |= EF_NODRAW;
 +      else {
 +              if (self.origin == '0 0 0')     {       // probably no origin brush, so don't spawn in the middle of the map..
 +                      floorZ = self.absmin.z;
 +                      setorigin(self,((self.absmax+self.absmin)*.5));
 +                      self.origin_z = floorZ;
 +              }
 +              setmodel(self, self.mdl_dead);
 +              self.effects &= ~EF_NODRAW;
 +      }
 +
 +      CSQCMODEL_AUTOUPDATE();
 +
 +      self.solid = SOLID_NOT;
 +}
 +
 +void func_breakable_look_restore()
 +{
 +      setmodel(self, self.mdl);
 +      self.effects &= ~EF_NODRAW;
 +
 +      if(self.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow
 +              setorigin(self, self.dropped_origin);
 +
 +      CSQCMODEL_AUTOUPDATE();
 +
 +      self.solid = SOLID_BSP;
 +}
 +
 +void func_breakable_behave_destroyed()
 +{
 +      self.health = self.max_health;
 +      self.takedamage = DAMAGE_NO;
 +      self.bot_attack = false;
 +      self.event_damage = func_null;
 +      self.state = 1;
 +      func_breakable_colormod();
 +      if (self.noise1)
 +              stopsound (self, CH_TRIGGER_SINGLE);
 +}
 +
 +void func_breakable_behave_restore()
 +{
 +      self.health = self.max_health;
 +      if(self.sprite)
 +      {
 +              WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
 +              WaypointSprite_UpdateHealth(self.sprite, self.health);
 +      }
 +      self.takedamage = DAMAGE_AIM;
 +      self.bot_attack = true;
 +      self.event_damage = func_breakable_damage;
 +      self.state = 0;
 +      self.nextthink = 0; // cancel auto respawn
 +      func_breakable_colormod();
 +      if (self.noise1)
 +              sound (self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
 +}
 +
 +void func_breakable_init_for_player(entity player)
 +{
 +      if (self.noise1 && self.state == 0 && clienttype(player) == CLIENTTYPE_REAL)
 +      {
 +              msg_entity = player;
 +              soundto (MSG_ONE, self, CH_TRIGGER_SINGLE, self.noise1, VOL_BASE, ATTEN_NORM);
 +      }
 +}
 +
 +void func_breakable_destroyed()
 +{
 +      func_breakable_look_destroyed();
 +      func_breakable_behave_destroyed();
 +
 +      CSQCMODEL_AUTOUPDATE();
 +}
 +
 +void func_breakable_restore()
 +{
 +      func_breakable_look_restore();
 +      func_breakable_behave_restore();
 +
 +      CSQCMODEL_AUTOUPDATE();
 +}
 +
 +vector debrisforce; // global, set before calling this
 +void func_breakable_destroy() {
 +      float n, i;
 +      string oldmsg;
 +
 +      activator = self.owner;
 +      self.owner = world; // set by W_PrepareExplosionByDamage
 +
 +      // now throw around the debris
 +      n = tokenize_console(self.debris);
 +      for(i = 0; i < n; ++i)
 +              LaunchDebris(argv(i), debrisforce);
 +
 +      func_breakable_destroyed();
 +
 +      if(self.noise)
 +              sound (self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
 +
 +      if(self.dmg)
 +              RadiusDamage(self, activator, self.dmg, self.dmg_edge, self.dmg_radius, self, world, self.dmg_force, DEATH_HURTTRIGGER, world);
 +
 +      if(self.cnt)
 +              pointparticles(self.cnt, self.absmin * 0.5 + self.absmax * 0.5, '0 0 0', self.count);
 +
 +      if(self.respawntime)
 +      {
 +              self.think = func_breakable_restore;
 +              self.nextthink = time + self.respawntime + crandom() * self.respawntimejitter;
 +      }
 +
 +      oldmsg = self.message;
 +      self.message = "";
 +      SUB_UseTargets();
 +      self.message = oldmsg;
 +}
 +
 +void func_breakable_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
 +{
 +      if(self.state == 1)
 +              return;
 +      if(self.spawnflags & DOOR_NOSPLASH)
 +              if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
 +                      return;
 +      if(self.team)
 +              if(attacker.team == self.team)
 +                      return;
 +      self.health = self.health - damage;
 +      if(self.sprite)
 +      {
 +              WaypointSprite_Ping(self.sprite);
 +              WaypointSprite_UpdateHealth(self.sprite, self.health);
 +      }
 +      func_breakable_colormod();
 +
 +      if(self.health <= 0)
 +      {
 +              debrisforce = force;
 +              W_PrepareExplosionByDamage(attacker, func_breakable_destroy);
 +      }
 +}
 +
 +void func_breakable_reset()
 +{
 +      self.team = self.team_saved;
 +      func_breakable_look_restore();
 +      if(self.spawnflags & 1)
 +              func_breakable_behave_destroyed();
 +      else
 +              func_breakable_behave_restore();
 +
 +      CSQCMODEL_AUTOUPDATE();
 +}
 +
 +// destructible walls that can be used to trigger target_objective_decrease
 +void spawnfunc_func_breakable()
 +{
 +      float n, i;
 +      if(!self.health)
 +              self.health = 100;
 +      self.max_health = self.health;
 +
 +      // yes, I know, MOVETYPE_NONE is not available here, not that one would want it here anyway
 +      if(!self.debrismovetype) self.debrismovetype = MOVETYPE_BOUNCE;
 +      if(!self.debrissolid) self.debrissolid = SOLID_NOT;
 +      if(self.debrisvelocity == '0 0 0') self.debrisvelocity = '0 0 140';
 +      if(self.debrisvelocityjitter == '0 0 0') self.debrisvelocityjitter = '70 70 70';
 +      if(self.debrisavelocityjitter == '0 0 0') self.debrisavelocityjitter = '600 600 600';
 +      if(!self.debristime) self.debristime = 3.5;
 +      if(!self.debristimejitter) self.debristime = 2.5;
 +
 +      if(self.mdl != "")
 +              self.cnt = particleeffectnum(self.mdl);
 +      if(self.count == 0)
 +              self.count = 1;
 +
 +      if(self.message == "")
 +              self.message = "got too close to an explosion";
 +      if(self.message2 == "")
 +              self.message2 = "was pushed into an explosion by";
 +      if(!self.dmg_radius)
 +              self.dmg_radius = 150;
 +      if(!self.dmg_force)
 +              self.dmg_force = 200;
 +
 +      self.mdl = self.model;
 +      SetBrushEntityModel();
 +
 +      self.use = func_breakable_restore;
 +
 +      // precache all the models
 +      if (self.mdl_dead)
 +              precache_model(self.mdl_dead);
 +      n = tokenize_console(self.debris);
 +      for(i = 0; i < n; ++i)
 +              precache_model(argv(i));
 +      if(self.noise)
 +              precache_sound(self.noise);
 +      if(self.noise1)
 +              precache_sound(self.noise1);
 +
 +      self.team_saved = self.team;
 +      self.dropped_origin = self.origin;
 +
 +      self.reset = func_breakable_reset;
 +      func_breakable_reset();
 +
 +      self.init_for_player_needed = 1;
 +      self.init_for_player = func_breakable_init_for_player;
 +
 +      CSQCMODEL_AUTOINIT();
 +}
 +
 +// for use in maps with a "model" key set
 +void spawnfunc_misc_breakablemodel() {
 +      spawnfunc_func_breakable();
 +}
 +#endif
index 773ce6a,0000000..9b32371
mode 100644,000000..100644
--- /dev/null
@@@ -1,362 -1,0 +1,362 @@@
-       n = BGMScript(self);
 +#ifdef CSQC
 +      #include "../../../client/particles.qh"
 +#endif
 +
 +#ifdef SVQC
 +// NOTE: also contains func_sparks
 +
 +float pointparticles_SendEntity(entity to, float fl)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
 +
 +      // optional features to save space
 +      fl = fl & 0x0F;
 +      if(self.spawnflags & 2)
 +              fl |= 0x10; // absolute count on toggle-on
 +      if(self.movedir != '0 0 0' || self.velocity != '0 0 0')
 +              fl |= 0x20; // 4 bytes - saves CPU
 +      if(self.waterlevel || self.count != 1)
 +              fl |= 0x40; // 4 bytes - obscure features almost never used
 +      if(self.mins != '0 0 0' || self.maxs != '0 0 0')
 +              fl |= 0x80; // 14 bytes - saves lots of space
 +
 +      WriteByte(MSG_ENTITY, fl);
 +      if(fl & 2)
 +      {
 +              if(self.state)
 +                      WriteCoord(MSG_ENTITY, self.impulse);
 +              else
 +                      WriteCoord(MSG_ENTITY, 0); // off
 +      }
 +      if(fl & 4)
 +      {
 +              WriteCoord(MSG_ENTITY, self.origin_x);
 +              WriteCoord(MSG_ENTITY, self.origin_y);
 +              WriteCoord(MSG_ENTITY, self.origin_z);
 +      }
 +      if(fl & 1)
 +      {
 +              if(self.model != "null")
 +              {
 +                      WriteShort(MSG_ENTITY, self.modelindex);
 +                      if(fl & 0x80)
 +                      {
 +                              WriteCoord(MSG_ENTITY, self.mins_x);
 +                              WriteCoord(MSG_ENTITY, self.mins_y);
 +                              WriteCoord(MSG_ENTITY, self.mins_z);
 +                              WriteCoord(MSG_ENTITY, self.maxs_x);
 +                              WriteCoord(MSG_ENTITY, self.maxs_y);
 +                              WriteCoord(MSG_ENTITY, self.maxs_z);
 +                      }
 +              }
 +              else
 +              {
 +                      WriteShort(MSG_ENTITY, 0);
 +                      if(fl & 0x80)
 +                      {
 +                              WriteCoord(MSG_ENTITY, self.maxs_x);
 +                              WriteCoord(MSG_ENTITY, self.maxs_y);
 +                              WriteCoord(MSG_ENTITY, self.maxs_z);
 +                      }
 +              }
 +              WriteShort(MSG_ENTITY, self.cnt);
 +              if(fl & 0x20)
 +              {
 +                      WriteShort(MSG_ENTITY, compressShortVector(self.velocity));
 +                      WriteShort(MSG_ENTITY, compressShortVector(self.movedir));
 +              }
 +              if(fl & 0x40)
 +              {
 +                      WriteShort(MSG_ENTITY, self.waterlevel * 16.0);
 +                      WriteByte(MSG_ENTITY, self.count * 16.0);
 +              }
 +              WriteString(MSG_ENTITY, self.noise);
 +              if(self.noise != "")
 +              {
 +                      WriteByte(MSG_ENTITY, floor(self.atten * 64));
 +                      WriteByte(MSG_ENTITY, floor(self.volume * 255));
 +              }
 +              WriteString(MSG_ENTITY, self.bgmscript);
 +              if(self.bgmscript != "")
 +              {
 +                      WriteByte(MSG_ENTITY, floor(self.bgmscriptattack * 64));
 +                      WriteByte(MSG_ENTITY, floor(self.bgmscriptdecay * 64));
 +                      WriteByte(MSG_ENTITY, floor(self.bgmscriptsustain * 255));
 +                      WriteByte(MSG_ENTITY, floor(self.bgmscriptrelease * 64));
 +              }
 +      }
 +      return 1;
 +}
 +
 +void pointparticles_use()
 +{
 +      self.state = !self.state;
 +      self.SendFlags |= 2;
 +}
 +
 +void pointparticles_think()
 +{
 +      if(self.origin != self.oldorigin)
 +      {
 +              self.SendFlags |= 4;
 +              self.oldorigin = self.origin;
 +      }
 +      self.nextthink = time;
 +}
 +
 +void pointparticles_reset()
 +{
 +      if(self.spawnflags & 1)
 +              self.state = 1;
 +      else
 +              self.state = 0;
 +}
 +
 +void spawnfunc_func_pointparticles()
 +{
 +      if(self.model != "")
 +              setmodel(self, self.model);
 +      if(self.noise != "")
 +              precache_sound (self.noise);
 +
 +      if(!self.bgmscriptsustain)
 +              self.bgmscriptsustain = 1;
 +      else if(self.bgmscriptsustain < 0)
 +              self.bgmscriptsustain = 0;
 +
 +      if(!self.atten)
 +              self.atten = ATTEN_NORM;
 +      else if(self.atten < 0)
 +              self.atten = 0;
 +      if(!self.volume)
 +              self.volume = 1;
 +      if(!self.count)
 +              self.count = 1;
 +      if(!self.impulse)
 +              self.impulse = 1;
 +
 +      if(!self.modelindex)
 +      {
 +              setorigin(self, self.origin + self.mins);
 +              setsize(self, '0 0 0', self.maxs - self.mins);
 +      }
 +      if(!self.cnt)
 +              self.cnt = particleeffectnum(self.mdl);
 +
 +      Net_LinkEntity(self, (self.spawnflags & 4), 0, pointparticles_SendEntity);
 +
 +      IFTARGETED
 +      {
 +              self.use = pointparticles_use;
 +              self.reset = pointparticles_reset;
 +              self.reset();
 +      }
 +      else
 +              self.state = 1;
 +      self.think = pointparticles_think;
 +      self.nextthink = time;
 +}
 +
 +void spawnfunc_func_sparks()
 +{
 +      // self.cnt is the amount of sparks that one burst will spawn
 +      if(self.cnt < 1) {
 +              self.cnt = 25.0; // nice default value
 +      }
 +
 +      // self.wait is the probability that a sparkthink will spawn a spark shower
 +      // range: 0 - 1, but 0 makes little sense, so...
 +      if(self.wait < 0.05) {
 +              self.wait = 0.25; // nice default value
 +      }
 +
 +      self.count = self.cnt;
 +      self.mins = '0 0 0';
 +      self.maxs = '0 0 0';
 +      self.velocity = '0 0 -1';
 +      self.mdl = "TE_SPARK";
 +      self.impulse = 10 * self.wait; // by default 2.5/sec
 +      self.wait = 0;
 +      self.cnt = 0; // use mdl
 +
 +      spawnfunc_func_pointparticles();
 +}
 +#elif defined(CSQC)
 +
 +void Draw_PointParticles()
 +{
 +      float n, i, fail;
 +      vector p;
 +      vector sz;
 +      vector o;
 +      o = self.origin;
 +      sz = self.maxs - self.mins;
++      n = doBGMScript(self);
 +      if(self.absolute == 2)
 +      {
 +              if(n >= 0)
 +                      n = self.just_toggled ? self.impulse : 0;
 +              else
 +                      n = self.impulse * drawframetime;
 +      }
 +      else
 +      {
 +              n *= self.impulse * drawframetime;
 +              if(self.just_toggled)
 +                      if(n < 1)
 +                              n = 1;
 +      }
 +      if(n == 0)
 +              return;
 +      fail = 0;
 +      for(i = random(); i <= n && fail <= 64*n; ++i)
 +      {
 +              p = o + self.mins;
 +              p.x += random() * sz.x;
 +              p.y += random() * sz.y;
 +              p.z += random() * sz.z;
 +              if(WarpZoneLib_BoxTouchesBrush(p, p, self, world))
 +              {
 +                      if(self.movedir != '0 0 0')
 +                      {
 +                              traceline(p, p + normalize(self.movedir) * 4096, 0, world);
 +                              p = trace_endpos;
 +                              pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count);
 +                      }
 +                      else
 +                      {
 +                              pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count);
 +                      }
 +                      if(self.noise != "")
 +                      {
 +                              setorigin(self, p);
 +                              sound(self, CH_AMBIENT, self.noise, VOL_BASE * self.volume, self.atten);
 +                      }
 +                      self.just_toggled = 0;
 +              }
 +              else if(self.absolute)
 +              {
 +                      ++fail;
 +                      --i;
 +              }
 +      }
 +      setorigin(self, o);
 +}
 +
 +void Ent_PointParticles_Remove()
 +{
 +      if(self.noise)
 +              strunzone(self.noise);
 +      self.noise = string_null;
 +      if(self.bgmscript)
 +              strunzone(self.bgmscript);
 +      self.bgmscript = string_null;
 +}
 +
 +void Ent_PointParticles()
 +{
 +      float i;
 +      vector v;
 +      int f = ReadByte();
 +      if(f & 2)
 +      {
 +              i = ReadCoord(); // density (<0: point, >0: volume)
 +              if(i && !self.impulse && self.cnt) // self.cnt check is so it only happens if the ent already existed
 +                      self.just_toggled = 1;
 +              self.impulse = i;
 +      }
 +      if(f & 4)
 +      {
 +              self.origin_x = ReadCoord();
 +              self.origin_y = ReadCoord();
 +              self.origin_z = ReadCoord();
 +      }
 +      if(f & 1)
 +      {
 +              self.modelindex = ReadShort();
 +              if(f & 0x80)
 +              {
 +                      if(self.modelindex)
 +                      {
 +                              self.mins_x = ReadCoord();
 +                              self.mins_y = ReadCoord();
 +                              self.mins_z = ReadCoord();
 +                              self.maxs_x = ReadCoord();
 +                              self.maxs_y = ReadCoord();
 +                              self.maxs_z = ReadCoord();
 +                      }
 +                      else
 +                      {
 +                              self.mins    = '0 0 0';
 +                              self.maxs_x = ReadCoord();
 +                              self.maxs_y = ReadCoord();
 +                              self.maxs_z = ReadCoord();
 +                      }
 +              }
 +              else
 +              {
 +                      self.mins = self.maxs = '0 0 0';
 +              }
 +
 +              self.cnt = ReadShort(); // effect number
 +
 +              if(f & 0x20)
 +              {
 +                      self.velocity = decompressShortVector(ReadShort());
 +                      self.movedir = decompressShortVector(ReadShort());
 +              }
 +              else
 +              {
 +                      self.velocity = self.movedir = '0 0 0';
 +              }
 +              if(f & 0x40)
 +              {
 +                      self.waterlevel = ReadShort() / 16.0;
 +                      self.count = ReadByte() / 16.0;
 +              }
 +              else
 +              {
 +                      self.waterlevel = 0;
 +                      self.count = 1;
 +              }
 +              if(self.noise)
 +                      strunzone(self.noise);
 +              if(self.bgmscript)
 +                      strunzone(self.bgmscript);
 +              self.noise = strzone(ReadString());
 +              if(self.noise != "")
 +              {
 +                      self.atten = ReadByte() / 64.0;
 +                      self.volume = ReadByte() / 255.0;
 +              }
 +              self.bgmscript = strzone(ReadString());
 +              if(self.bgmscript != "")
 +              {
 +                      self.bgmscriptattack = ReadByte() / 64.0;
 +                      self.bgmscriptdecay = ReadByte() / 64.0;
 +                      self.bgmscriptsustain = ReadByte() / 255.0;
 +                      self.bgmscriptrelease = ReadByte() / 64.0;
 +              }
 +              BGMScript_InitEntity(self);
 +      }
 +
 +      if(f & 2)
 +      {
 +              self.absolute = (self.impulse >= 0);
 +              if(!self.absolute)
 +              {
 +                      v = self.maxs - self.mins;
 +                      self.impulse *= -v.x * v.y * v.z / 262144; // relative: particles per 64^3 cube
 +              }
 +      }
 +
 +      if(f & 0x10)
 +              self.absolute = 2;
 +
 +      setorigin(self, self.origin);
 +      setsize(self, self.mins, self.maxs);
 +      self.solid = SOLID_NOT;
 +      self.draw = Draw_PointParticles;
 +      self.entremove = Ent_PointParticles_Remove;
 +}
 +#endif
index 136288b,0000000..a076339
mode 100644,000000..100644
--- /dev/null
@@@ -1,330 -1,0 +1,330 @@@
-     #include "../../constants.qh"
 +#if defined(CSQC)
 +#elif defined(MENUQC)
 +#elif defined(SVQC)
 +      #include "../../../dpdefs/progsdefs.qh"
 +    #include "../../../dpdefs/dpextensions.qh"
++    #include "../../../server/_all.qh"
 +    #include "../../../server/constants.qh"
 +    #include "../../../server/defs.qh"
 +#endif
 +
 +#ifdef SVQC
 +
 +// values:
 +//   volume
 +//   noise
 +//   targetname
 +//   lifetime
 +//   fade_time
 +//   fade_rate
 +// when triggered, the music is overridden for activator until lifetime (or forever, if lifetime is 0)
 +// when targetname is not set, THIS ONE is default
 +void target_music_sendto(float to, float is)
 +{
 +      WriteByte(to, SVC_TEMPENTITY);
 +      WriteByte(to, TE_CSQC_TARGET_MUSIC);
 +      WriteShort(to, num_for_edict(self));
 +      WriteByte(to, self.volume * 255.0 * is);
 +      WriteByte(to, self.fade_time * 16.0);
 +      WriteByte(to, self.fade_rate * 16.0);
 +      WriteByte(to, self.lifetime);
 +      WriteString(to, self.noise);
 +}
 +void target_music_reset()
 +{
 +      if(self.targetname == "")
 +              target_music_sendto(MSG_ALL, 1);
 +}
 +void target_music_use()
 +{
 +      if(!activator)
 +              return;
 +      if(IS_REAL_CLIENT(activator))
 +      {
 +              msg_entity = activator;
 +              target_music_sendto(MSG_ONE, 1);
 +      }
 +      entity head;
 +      FOR_EACH_SPEC(head) if(head.enemy == activator) { msg_entity = head; target_music_sendto(MSG_ONE, 1); }
 +}
 +void spawnfunc_target_music()
 +{
 +      self.use = target_music_use;
 +      self.reset = target_music_reset;
 +      if(!self.volume)
 +              self.volume = 1;
 +      if(self.targetname == "")
 +              target_music_sendto(MSG_INIT, 1);
 +      else
 +              target_music_sendto(MSG_INIT, 0);
 +}
 +void TargetMusic_RestoreGame()
 +{
 +      for(self = world; (self = find(self, classname, "target_music")); )
 +      {
 +              if(self.targetname == "")
 +                      target_music_sendto(MSG_INIT, 1);
 +              else
 +                      target_music_sendto(MSG_INIT, 0);
 +      }
 +}
 +// values:
 +//   volume
 +//   noise
 +//   targetname
 +//   fade_time
 +// spawnflags:
 +//   1 = START_OFF
 +// when triggered, it is disabled/enabled for everyone
 +float trigger_music_SendEntity(entity to, float sf)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
 +      sf &= ~0x80;
 +      if(self.cnt)
 +              sf |= 0x80;
 +      WriteByte(MSG_ENTITY, sf);
 +      if(sf & 4)
 +      {
 +              WriteCoord(MSG_ENTITY, self.origin.x);
 +              WriteCoord(MSG_ENTITY, self.origin.y);
 +              WriteCoord(MSG_ENTITY, self.origin.z);
 +      }
 +      if(sf & 1)
 +      {
 +              if(self.model != "null")
 +              {
 +                      WriteShort(MSG_ENTITY, self.modelindex);
 +                      WriteCoord(MSG_ENTITY, self.mins.x);
 +                      WriteCoord(MSG_ENTITY, self.mins.y);
 +                      WriteCoord(MSG_ENTITY, self.mins.z);
 +                      WriteCoord(MSG_ENTITY, self.maxs.x);
 +                      WriteCoord(MSG_ENTITY, self.maxs.y);
 +                      WriteCoord(MSG_ENTITY, self.maxs.z);
 +              }
 +              else
 +              {
 +                      WriteShort(MSG_ENTITY, 0);
 +                      WriteCoord(MSG_ENTITY, self.maxs.x);
 +                      WriteCoord(MSG_ENTITY, self.maxs.y);
 +                      WriteCoord(MSG_ENTITY, self.maxs.z);
 +              }
 +              WriteByte(MSG_ENTITY, self.volume * 255.0);
 +              WriteByte(MSG_ENTITY, self.fade_time * 16.0);
 +              WriteByte(MSG_ENTITY, self.fade_rate * 16.0);
 +              WriteString(MSG_ENTITY, self.noise);
 +      }
 +      return 1;
 +}
 +void trigger_music_reset()
 +{
 +      self.cnt = !(self.spawnflags & 1);
 +      self.SendFlags |= 0x80;
 +}
 +void trigger_music_use()
 +{
 +      self.cnt = !self.cnt;
 +      self.SendFlags |= 0x80;
 +}
 +void spawnfunc_trigger_music()
 +{
 +      if(self.model != "")
 +              setmodel(self, self.model);
 +      if(!self.volume)
 +              self.volume = 1;
 +      if(!self.modelindex)
 +      {
 +              setorigin(self, self.origin + self.mins);
 +              setsize(self, '0 0 0', self.maxs - self.mins);
 +      }
 +      trigger_music_reset();
 +
 +      self.use = trigger_music_use;
 +      self.reset = trigger_music_reset;
 +
 +      Net_LinkEntity(self, false, 0, trigger_music_SendEntity);
 +}
 +#elif defined(CSQC)
 +
 +void TargetMusic_Advance()
 +{
 +      // run AFTER all the thinks!
 +      entity best, e;
 +      float vol, vol0;
 +      best = music_default;
 +      if(music_target && time < music_target.lifetime)
 +              best = music_target;
 +      if(music_trigger)
 +              best = music_trigger;
 +      for(e = world; (e = findfloat(e, enttype, ENT_CLIENT_TRIGGER_MUSIC)); ) if(e.noise)
 +      {
 +              vol0 = e.lastvol;
 +              if(getsoundtime(e, CH_BGM_SINGLE) < 0)
 +              {
 +                      vol0 = -1;
 +              }
 +              if(e == best)
 +              {
 +                      // increase volume
 +                      if(e.fade_time > 0)
 +                              e.state = bound(0, e.state + frametime / e.fade_time, 1);
 +                      else
 +                              e.state = 1;
 +              }
 +              else
 +              {
 +                      // decrease volume
 +                      if(e.fade_rate > 0)
 +                              e.state = bound(0, e.state - frametime / e.fade_rate, 1);
 +                      else
 +                              e.state = 0;
 +              }
 +              vol = e.state * e.volume * autocvar_bgmvolume;
 +              if(vol != vol0)
 +              {
 +                      if(vol0 < 0)
 +                              sound(e, CH_BGM_SINGLE, e.noise, vol, ATTEN_NONE); // restart
 +                      else
 +                              sound(e, CH_BGM_SINGLE, "", vol, ATTEN_NONE);
 +                      e.lastvol = vol;
 +              }
 +      }
 +      music_trigger = world;
 +
 +      if(best)
 +              bgmtime = getsoundtime(best, CH_BGM_SINGLE);
 +      else
 +              bgmtime = gettime(GETTIME_CDTRACK);
 +}
 +
 +void Net_TargetMusic()
 +{
 +      int id = ReadShort();
 +      float vol = ReadByte() / 255.0;
 +      float fai = ReadByte() / 16.0;
 +      float fao = ReadByte() / 16.0;
 +      float tim = ReadByte();
 +      string noi = ReadString();
 +
 +      entity e;
 +      for(e = world; (e = findfloat(e, enttype, ENT_CLIENT_TRIGGER_MUSIC)); )
 +      {
 +              if(e.count == id)
 +                      break;
 +      }
 +      if(!e)
 +      {
 +              e = spawn();
 +              e.enttype = ENT_CLIENT_TRIGGER_MUSIC;
 +              e.count = id;
 +      }
 +      if(e.noise != noi)
 +      {
 +              if(e.noise)
 +                      strunzone(e.noise);
 +              e.noise = strzone(noi);
 +              precache_sound(e.noise);
 +              sound(e, CH_BGM_SINGLE, e.noise, 0, ATTEN_NONE);
 +              if(getsoundtime(e, CH_BGM_SINGLE) < 0)
 +              {
 +                      dprintf("Cannot initialize sound %s\n", e.noise);
 +                      strunzone(e.noise);
 +                      e.noise = string_null;
 +              }
 +      }
 +      e.volume = vol;
 +      e.fade_time = fai;
 +      e.fade_rate = fao;
 +      if(vol > 0)
 +      {
 +              if(tim == 0)
 +              {
 +                      music_default = e;
 +                      if(!music_disabled)
 +                      {
 +                              e.state = 2;
 +                              cvar_settemp("music_playlist_index", "-1"); // don't use playlists
 +                              localcmd("cd stop\n"); // just in case
 +                              music_disabled = 1;
 +                      }
 +              }
 +              else
 +              {
 +                      music_target = e;
 +                      e.lifetime = time + tim;
 +              }
 +      }
 +}
 +
 +void Ent_TriggerMusic_Think()
 +{
 +      if(WarpZoneLib_BoxTouchesBrush(view_origin, view_origin, self, world))
 +      {
 +              music_trigger = self;
 +      }
 +      self.nextthink = time;
 +}
 +
 +void Ent_TriggerMusic_Remove()
 +{
 +      if(self.noise)
 +              strunzone(self.noise);
 +      self.noise = string_null;
 +}
 +
 +void Ent_ReadTriggerMusic()
 +{
 +      int f = ReadByte();
 +      if(f & 4)
 +      {
 +              self.origin_x = ReadCoord();
 +              self.origin_y = ReadCoord();
 +              self.origin_z = ReadCoord();
 +      }
 +      if(f & 1)
 +      {
 +              self.modelindex = ReadShort();
 +              if(self.modelindex)
 +              {
 +                      self.mins_x = ReadCoord();
 +                      self.mins_y = ReadCoord();
 +                      self.mins_z = ReadCoord();
 +                      self.maxs_x = ReadCoord();
 +                      self.maxs_y = ReadCoord();
 +                      self.maxs_z = ReadCoord();
 +              }
 +              else
 +              {
 +                      self.mins    = '0 0 0';
 +                      self.maxs_x = ReadCoord();
 +                      self.maxs_y = ReadCoord();
 +                      self.maxs_z = ReadCoord();
 +              }
 +
 +              self.volume = ReadByte() / 255.0;
 +              self.fade_time = ReadByte() / 16.0;
 +              self.fade_rate = ReadByte() / 16.0;
 +              string s = self.noise;
 +              if(self.noise)
 +                      strunzone(self.noise);
 +              self.noise = strzone(ReadString());
 +              if(self.noise != s)
 +              {
 +                      precache_sound(self.noise);
 +                      sound(self, CH_BGM_SINGLE, self.noise, 0, ATTEN_NONE);
 +                      if(getsoundtime(self, CH_BGM_SINGLE) < 0)
 +                      {
 +                              dprintf("Cannot initialize sound %s\n", self.noise);
 +                              strunzone(self.noise);
 +                              self.noise = string_null;
 +                      }
 +              }
 +      }
 +
 +      setorigin(self, self.origin);
 +      setsize(self, self.mins, self.maxs);
 +      self.cnt = 1;
 +      self.think = Ent_TriggerMusic_Think;
 +      self.nextthink = time;
 +}
 +
 +#endif
index 8d014c8,0000000..712d412
mode 100644,000000..100644
--- /dev/null
@@@ -1,27 -1,0 +1,28 @@@
- .int state;
- .float lastvol;
 +#ifndef TARGET_MUSIC_H
 +#define TARGET_MUSIC_H
 +
 +.float lifetime;
 +
 +#ifdef CSQC
 +float music_disabled;
 +entity music_default;
 +entity music_target;
 +entity music_trigger;
 +// FIXME also control bgmvolume here, to not require a target_music for the default track.
 +
++entityclass(TargetMusic);
++class(TargetMusic) .int state;
++class(TargetMusic) .float lastvol;
 +
 +void TargetMusic_Advance();
 +
 +void Net_TargetMusic();
 +
 +void Ent_TriggerMusic_Think();
 +
 +void Ent_TriggerMusic_Remove();
 +
 +void Ent_ReadTriggerMusic();
 +#endif
 +
 +#endif
index 7b18355,0000000..365a9e7
mode 100644,000000..100644
--- /dev/null
@@@ -1,350 -1,0 +1,350 @@@
-     #include "../../../server/defs.qh"
 +#if defined(CSQC)
 +#elif defined(MENUQC)
 +#elif defined(SVQC)
 +      #include "../../../dpdefs/progsdefs.qh"
 +    #include "../../../dpdefs/dpextensions.qh"
 +    #include "../../util.qh"
-               vector prev, new;
++    #include "../../../server/_all.qh"
 +#endif
 +
 +#ifdef SVQC
 +
 +// spawner entity
 +// "classname" "target_spawn"
 +// "message" "fieldname value fieldname value ..."
 +// "spawnflags"
 +//   1 = call the spawn function
 +//   2 = trigger on map load
 +
 +float target_spawn_initialized;
 +.void() target_spawn_spawnfunc;
 +float target_spawn_spawnfunc_field;
 +.entity target_spawn_activator;
 +.float target_spawn_id;
 +float target_spawn_count;
 +
 +void target_spawn_helper_setmodel()
 +{
 +      setmodel(self, self.model);
 +}
 +
 +void target_spawn_helper_setsize()
 +{
 +      setsize(self, self.mins, self.maxs);
 +}
 +
 +void target_spawn_edit_entity(entity e, string msg, entity kt, entity t2, entity t3, entity t4, entity act)
 +{
 +      float i, n, valuefieldpos;
 +      string key, value, valuefield, valueoffset, valueoffsetrandom;
 +      entity valueent;
 +      vector data, data2;
 +      entity oldself;
 +      entity oldactivator;
 +
 +      n = tokenize_console(msg);
 +
 +      for(i = 0; i < n-1; i += 2)
 +      {
 +              key = argv(i);
 +              value = argv(i+1);
 +              if(key == "$")
 +              {
 +                      data.x = -1;
 +                      data.y = FIELD_STRING;
 +              }
 +              else
 +              {
 +                      data = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", key)));
 +                      if(data.y == 0) // undefined field, i.e., invalid type
 +                      {
 +                              print("target_spawn: invalid/unknown entity key ", key, " specified, ignored!\n");
 +                              continue;
 +                      }
 +              }
 +              if(substring(value, 0, 1) == "$")
 +              {
 +                      value = substring(value, 1, strlen(value) - 1);
 +                      if(substring(value, 0, 1) == "$")
 +                      {
 +                              // deferred replacement
 +                              // do nothing
 +                              // useful for creating target_spawns with this!
 +                      }
 +                      else
 +                      {
 +                              // replace me!
 +                              valuefieldpos = strstrofs(value, "+", 0);
 +                              valueoffset = "";
 +                              if(valuefieldpos != -1)
 +                              {
 +                                      valueoffset = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
 +                                      value = substring(value, 0, valuefieldpos);
 +                              }
 +
 +                              valuefieldpos = strstrofs(valueoffset, "+", 0);
 +                              valueoffsetrandom = "";
 +                              if(valuefieldpos != -1)
 +                              {
 +                                      valueoffsetrandom = substring(valueoffset, valuefieldpos + 1, strlen(valueoffset) - valuefieldpos - 1);
 +                                      valueoffset = substring(valueoffset, 0, valuefieldpos);
 +                              }
 +
 +                              valuefieldpos = strstrofs(value, ".", 0);
 +                              valuefield = "";
 +                              if(valuefieldpos != -1)
 +                              {
 +                                      valuefield = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
 +                                      value = substring(value, 0, valuefieldpos);
 +                              }
 +
 +                              if(value == "self")
 +                              {
 +                                      valueent = self;
 +                                      value = "";
 +                              }
 +                              else if(value == "activator")
 +                              {
 +                                      valueent = act;
 +                                      value = "";
 +                              }
 +                              else if(value == "other")
 +                              {
 +                                      valueent = other;
 +                                      value = "";
 +                              }
 +                              else if(value == "pusher")
 +                              {
 +                                      if(time < act.pushltime)
 +                                              valueent = act.pusher;
 +                                      else
 +                                              valueent = world;
 +                                      value = "";
 +                              }
 +                              else if(value == "target")
 +                              {
 +                                      valueent = e;
 +                                      value = "";
 +                              }
 +                              else if(value == "killtarget")
 +                              {
 +                                      valueent = kt;
 +                                      value = "";
 +                              }
 +                              else if(value == "target2")
 +                              {
 +                                      valueent = t2;
 +                                      value = "";
 +                              }
 +                              else if(value == "target3")
 +                              {
 +                                      valueent = t3;
 +                                      value = "";
 +                              }
 +                              else if(value == "target4")
 +                              {
 +                                      valueent = t4;
 +                                      value = "";
 +                              }
 +                              else if(value == "time")
 +                              {
 +                                      valueent = world;
 +                                      value = ftos(time);
 +                              }
 +                              else
 +                              {
 +                                      print("target_spawn: invalid/unknown variable replacement ", value, " specified, ignored!\n");
 +                                      continue;
 +                              }
 +
 +                              if(valuefield == "")
 +                              {
 +                                      if(value == "")
 +                                              value = ftos(num_for_edict(valueent));
 +                              }
 +                              else
 +                              {
 +                                      if(value != "")
 +                                      {
 +                                              print("target_spawn: try to get a field of a non-entity, ignored!\n");
 +                                              continue;
 +                                      }
 +                                      data2 = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", valuefield)));
 +                                      if(data2_y == 0) // undefined field, i.e., invalid type
 +                                      {
 +                                              print("target_spawn: invalid/unknown entity key replacement ", valuefield, " specified, ignored!\n");
 +                                              continue;
 +                                      }
 +                                      value = getentityfieldstring(data2_x, valueent);
 +                              }
 +
 +                              if(valueoffset != "")
 +                              {
 +                                      switch(data.y)
 +                                      {
 +                                              case FIELD_STRING:
 +                                                      value = strcat(value, valueoffset);
 +                                                      break;
 +                                              case FIELD_FLOAT:
 +                                                      value = ftos(stof(value) + stof(valueoffset));
 +                                                      break;
 +                                              case FIELD_VECTOR:
 +                                                      value = vtos(stov(value) + stov(valueoffset));
 +                                                      break;
 +                                              default:
 +                                                      print("target_spawn: only string, float and vector fields can do calculations, calculation ignored!\n");
 +                                                      break;
 +                                      }
 +                              }
 +
 +                              if(valueoffsetrandom != "")
 +                              {
 +                                      switch(data.y)
 +                                      {
 +                                              case FIELD_FLOAT:
 +                                                      value = ftos(stof(value) + random() * stof(valueoffsetrandom));
 +                                                      break;
 +                                              case FIELD_VECTOR:
 +                                                      data2 = stov(valueoffsetrandom);
 +                                                      value = vtos(stov(value) + random() * data2_x * '1 0 0' + random() * data2_y * '0 1 0' + random() * data2_z * '0 0 1');
 +                                                      break;
 +                                              default:
 +                                                      print("target_spawn: only float and vector fields can do random calculations, calculation ignored!\n");
 +                                                      break;
 +                                      }
 +                              }
 +                      }
 +              }
 +              if(key == "$")
 +              {
 +                      if(substring(value, 0, 1) == "_")
 +                              value = strcat("target_spawn_helper", value);
 +                      putentityfieldstring(target_spawn_spawnfunc_field, e, value);
 +
 +                      oldself = self;
 +                      oldactivator = activator;
 +
 +                      self = e;
 +                      activator = act;
 +
 +                      self.target_spawn_spawnfunc();
 +
 +                      self = oldself;
 +                      activator = oldactivator;
 +
 +                      // We called an external function, so we have to re-tokenize msg.
 +                      n = tokenize_console(msg);
 +              }
 +              else
 +              {
 +                      if(data.y == FIELD_VECTOR)
 +                              value = strreplace("'", "", value); // why?!?
 +                      putentityfieldstring(data.x, e, value);
 +              }
 +      }
 +}
 +
 +void target_spawn_useon(entity e)
 +{
 +      self.target_spawn_activator = activator;
 +      target_spawn_edit_entity(
 +              e,
 +              self.message,
 +              find(world, targetname, self.killtarget),
 +              find(world, targetname, self.target2),
 +              find(world, targetname, self.target3),
 +              find(world, targetname, self.target4),
 +              activator
 +      );
 +}
 +
 +float target_spawn_cancreate()
 +{
 +      float c;
 +      entity e;
 +
 +      c = self.count;
 +      if(c == 0) // no limit?
 +              return 1;
 +
 +      ++c; // increase count to not include MYSELF
 +      for(e = world; (e = findfloat(e, target_spawn_id, self.target_spawn_id)); --c)
 +              ;
 +
 +      // if c now is 0, we have AT LEAST the given count (maybe more), so don't spawn any more
 +      if(c == 0)
 +              return 0;
 +      return 1;
 +}
 +
 +void target_spawn_use()
 +{
 +      entity e;
 +
 +      if(self.target == "")
 +      {
 +              // spawn new entity
 +              if(!target_spawn_cancreate())
 +                      return;
 +              e = spawn();
 +              target_spawn_useon(e);
 +              e.target_spawn_id = self.target_spawn_id;
 +      }
 +      else if(self.target == "*activator")
 +      {
 +              // edit entity
 +              if(activator)
 +                      target_spawn_useon(activator);
 +      }
 +      else
 +      {
 +              // edit entity
 +              for(e = world; (e = find(e, targetname, self.target)); )
 +                      target_spawn_useon(e);
 +      }
 +}
 +
 +void target_spawn_spawnfirst()
 +{
 +      activator = self.target_spawn_activator;
 +      if(self.spawnflags & 2)
 +              target_spawn_use();
 +}
 +
 +void initialize_field_db()
 +{
 +      if(!target_spawn_initialized)
 +      {
 +              float n, i;
 +              string fn;
-                       new = i * '1 0 0' + ft * '0 1 0' + '0 0 1';
++              vector prev, next;
 +              float ft;
 +
 +              n = numentityfields();
 +              for(i = 0; i < n; ++i)
 +              {
 +                      fn = entityfieldname(i);
 +                      ft = entityfieldtype(i);
-                               db_put(TemporaryDB, strcat("/target_spawn/field/", fn), vtos(new));
++                      next = i * '1 0 0' + ft * '0 1 0' + '0 0 1';
 +                      prev = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", fn)));
 +                      if(prev.y == 0)
 +                      {
++                              db_put(TemporaryDB, strcat("/target_spawn/field/", fn), vtos(next));
 +                              if(fn == "target_spawn_spawnfunc")
 +                                      target_spawn_spawnfunc_field = i;
 +                      }
 +              }
 +
 +              target_spawn_initialized = 1;
 +      }
 +}
 +
 +void spawnfunc_target_spawn()
 +{
 +      initialize_field_db();
 +      self.use = target_spawn_use;
 +      self.message = strzone(strreplace("'", "\"", self.message));
 +      self.target_spawn_id = ++target_spawn_count;
 +      InitializeEntity(self, target_spawn_spawnfirst, INITPRIO_LAST);
 +}
 +#endif
index 5e91d76,0000000..ca887c6
mode 100644,000000..100644
--- /dev/null
@@@ -1,252 -1,0 +1,253 @@@
-     #include "../../server/vehicles/vehicles_def.qh"
 +#include "teleporters.qh"
 +
 +#if defined(CSQC)
 +#elif defined(MENUQC)
 +#elif defined(SVQC)
 +    #include "../../warpzonelib/common.qh"
 +    #include "../../warpzonelib/util_server.qh"
 +    #include "../../warpzonelib/server.qh"
 +    #include "../constants.qh"
 +      #include "../triggers/subs.qh"
 +    #include "../util.qh"
++    #include "../../server/_all.qh"
 +    #include "../../server/weapons/csqcprojectile.qh"
 +    #include "../../server/autocvars.qh"
 +    #include "../../server/constants.qh"
 +    #include "../../server/defs.qh"
 +    #include "../deathtypes.qh"
 +    #include "../../server/tturrets/include/turrets_early.qh"
++    #include "../../server/vehicles/all.qh"
 +    #include "../mapinfo.qh"
 +    #include "../../server/anticheat.qh"
 +#endif
 +
 +#ifdef SVQC
 +
 +float check_tdeath(entity player, vector org, vector telefragmin, vector telefragmax)
 +{
 +      if (IS_PLAYER(player) && player.health >= 1)
 +      {
 +              TDEATHLOOP(org)
 +              {
 +                      if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
 +                              if(IS_PLAYER(head))
 +                                      if(head.health >= 1)
 +                                              return 1;
 +              }
 +      }
 +      return 0;
 +}
 +
 +void tdeath(entity player, entity teleporter, entity telefragger, vector telefragmin, vector telefragmax)
 +{
 +      TDEATHLOOP(player.origin)
 +      {
 +              if (IS_PLAYER(player) && player.health >= 1)
 +              {
 +                      if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
 +                      {
 +                              if(IS_PLAYER(head))
 +                                      if(head.health >= 1)
 +                                              ++tdeath_hit;
 +                              Damage (head, teleporter, telefragger, 10000, DEATH_TELEFRAG, head.origin, '0 0 0');
 +                      }
 +              }
 +              else // dead bodies and monsters gib themselves instead of telefragging
 +                      Damage (telefragger, teleporter, telefragger, 10000, DEATH_TELEFRAG, telefragger.origin, '0 0 0');
 +      }
 +}
 +
 +void spawn_tdeath(vector v0, entity e, vector v)
 +{
 +      tdeath(e, e, e, '0 0 0', '0 0 0');
 +}
 +
 +void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags)
 +{
 +      entity telefragger;
 +      vector from;
 +
 +      if(teleporter.owner)
 +              telefragger = teleporter.owner;
 +      else
 +              telefragger = player;
 +
 +      makevectors (to_angles);
 +
 +      if(player.teleportable == TELEPORT_NORMAL) // don't play sounds or show particles for anything that isn't a player, maybe change later to block only observers
 +      {
 +              if(self.pushltime < time) // only show one teleport effect per teleporter per 0.2 seconds, for better fps
 +              {
 +                      if(tflags & TELEPORT_FLAG_SOUND)
 +                              sound (player, CH_TRIGGER, "misc/teleport.wav", VOL_BASE, ATTEN_NORM);
 +                      if(tflags & TELEPORT_FLAG_PARTICLES)
 +                      {
 +                              pointparticles(particleeffectnum("teleport"), player.origin, '0 0 0', 1);
 +                              pointparticles(particleeffectnum("teleport"), to + v_forward * 32, '0 0 0', 1);
 +                      }
 +                      self.pushltime = time + 0.2;
 +              }
 +      }
 +
 +      // Relocate the player
 +      // assuming to allows PL_MIN to PL_MAX box and some more
 +      from = player.origin;
 +      setorigin (player, to);
 +      player.oldorigin = to; // don't undo the teleport by unsticking
 +      player.angles = to_angles;
 +      player.fixangle = true;
 +      player.velocity = to_velocity;
 +      BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
 +
 +      makevectors(player.angles);
 +      Reset_ArcBeam(player, v_forward);
 +      UpdateCSQCProjectileAfterTeleport(player);
 +
 +      if(IS_PLAYER(player))
 +      {
 +              if(tflags & TELEPORT_FLAG_TDEATH)
 +                      if(player.takedamage && player.deadflag == DEAD_NO && !g_race && !g_cts && (autocvar_g_telefrags || (tflags & TELEPORT_FLAG_FORCE_TDEATH)))
 +                              tdeath(player, teleporter, telefragger, telefragmin, telefragmax);
 +
 +              // player no longer is on ground
 +              player.flags &= ~FL_ONGROUND;
 +
 +              // reset tracking of oldvelocity for impact damage (sudden velocity changes)
 +              player.oldvelocity = player.velocity;
 +
 +              // reset tracking of who pushed you into a hazard (for kill credit)
 +              if(teleporter.owner)
 +              {
 +                      player.pusher = teleporter.owner;
 +                      player.pushltime = time + autocvar_g_maxpushtime;
 +                      player.istypefrag = player.BUTTON_CHAT;
 +              }
 +              else
 +              {
 +                      player.pushltime = 0;
 +                      player.istypefrag = 0;
 +              }
 +
 +              player.lastteleporttime = time;
 +      }
 +}
 +
 +entity Simple_TeleportPlayer(entity teleporter, entity player)
 +{
 +      vector locout;
 +      entity e;
 +      float p;
 +
 +      // Find the output teleporter
 +      if(teleporter.enemy)
 +      {
 +              e = teleporter.enemy;
 +      }
 +      else
 +      {
 +              RandomSelection_Init();
 +              for(e = world; (e = find(e, targetname, teleporter.target)); )
 +              {
 +                      p = 1;
 +                      if(autocvar_g_telefrags_avoid)
 +                      {
 +                              locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
 +                              if(check_tdeath(player, locout, '0 0 0', '0 0 0'))
 +                                      p = 0;
 +                      }
 +                      RandomSelection_Add(e, 0, string_null, (e.cnt ? e.cnt : 1), p);
 +              }
 +              e = RandomSelection_chosen_ent;
 +      }
 +
 +      if(!e) { sprint(player, "Teleport destination vanished. Sorry... please complain to the mapper.\n"); }
 +
 +      makevectors(e.mangle);
 +
 +      if(e.speed)
 +              if(vlen(player.velocity) > e.speed)
 +                      player.velocity = normalize(player.velocity) * max(0, e.speed);
 +
 +      if(autocvar_g_teleport_maxspeed)
 +              if(vlen(player.velocity) > autocvar_g_teleport_maxspeed)
 +                      player.velocity = normalize(player.velocity) * max(0, autocvar_g_teleport_maxspeed);
 +
 +      locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
 +      TeleportPlayer(teleporter, player, locout, e.mangle, v_forward * vlen(player.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
 +
 +      return e;
 +}
 +
 +void teleport_findtarget (void)
 +{
 +      entity e;
 +      float n;
 +
 +      n = 0;
 +      for(e = world; (e = find(e, targetname, self.target)); )
 +      {
 +              ++n;
 +              if(e.movetype == MOVETYPE_NONE)
 +                      waypoint_spawnforteleporter(self, e.origin, 0);
 +              if(e.classname != "info_teleport_destination")
 +                      print("^3MAPPER ERROR: teleporter does target an invalid teleport destination entity. Angles will not work.\n");
 +      }
 +
 +      if(n == 0)
 +      {
 +              // no dest!
 +              objerror ("Teleporter with nonexistant target");
 +              return;
 +      }
 +      else if(n == 1)
 +      {
 +              // exactly one dest - bots love that
 +              self.enemy = find(e, targetname, self.target);
 +      }
 +      else
 +      {
 +              // have to use random selection every single time
 +              self.enemy = world;
 +      }
 +
 +      // now enable touch
 +      self.touch = Teleport_Touch;
 +}
 +
 +entity Teleport_Find(vector mi, vector ma)
 +{
 +      entity e;
 +      for(e = world; (e = find(e, classname, "trigger_teleport")); )
 +              if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, world))
 +                      return e;
 +      return world;
 +}
 +
 +void WarpZone_PostTeleportPlayer_Callback(entity pl)
 +{
 +      makevectors(pl.angles);
 +      Reset_ArcBeam(pl, v_forward);
 +      UpdateCSQCProjectileAfterTeleport(pl);
 +      {
 +              entity oldself = self;
 +              self = pl;
 +              anticheat_fixangle();
 +              self = oldself;
 +      }
 +      // "disown" projectiles after teleport
 +      if(pl.owner)
 +      if(pl.owner == pl.realowner)
 +      {
 +              if(!(pl.flags & FL_PROJECTILE))
 +                      print("A non-projectile got through a warpzone and its owner cleared. It's a ", pl.classname, ".\n");
 +              pl.owner = world;
 +      }
 +      if(IS_PLAYER(pl))
 +      {
 +              // reset tracking of oldvelocity for impact damage (sudden velocity changes)
 +              pl.oldvelocity = pl.velocity;
 +              // reset teleport time tracking too (or multijump can cause insane speeds)
 +              pl.lastteleporttime = time;
 +      }
 +}
 +#endif
index 9ad0e72,0000000..e56f3c2
mode 100644,000000..100644
--- /dev/null
@@@ -1,474 -1,0 +1,475 @@@
 +// TODO: split target_push and put it in the target folder
 +#ifdef SVQC
 +#include "jumppads.qh"
 +#include "../../movetypes/movetypes.qh"
++#include "../../../server/_all.qh"
 +
 +void trigger_push_use()
 +{
 +      if(teamplay)
 +      {
 +              self.team = activator.team;
 +              self.SendFlags |= 2;
 +      }
 +}
 +#endif
 +
 +/*
 +      trigger_push_calculatevelocity
 +
 +      Arguments:
 +        org - origin of the object which is to be pushed
 +        tgt - target entity (can be either a point or a model entity; if it is
 +              the latter, its midpoint is used)
 +        ht  - jump height, measured from the higher one of org and tgt's midpoint
 +
 +      Returns: velocity for the jump
 +      the global trigger_push_calculatevelocity_flighttime is set to the total
 +      jump time
 + */
 +
 +vector trigger_push_calculatevelocity(vector org, entity tgt, float ht)
 +{
 +      float grav, sdist, zdist, vs, vz, jumpheight;
 +      vector sdir, torg;
 +
 +      torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5;
 +
 +      grav = PHYS_GRAVITY;
 +      if(PHYS_ENTGRAVITY(other))
 +              grav *= PHYS_ENTGRAVITY(other);
 +
 +      zdist = torg.z - org.z;
 +      sdist = vlen(torg - org - zdist * '0 0 1');
 +      sdir = normalize(torg - org - zdist * '0 0 1');
 +
 +      // how high do we need to push the player?
 +      jumpheight = fabs(ht);
 +      if(zdist > 0)
 +              jumpheight = jumpheight + zdist;
 +
 +      /*
 +              STOP.
 +
 +              You will not understand the following equations anyway...
 +              But here is what I did to get them.
 +
 +              I used the functions
 +
 +                s(t) = t * vs
 +                z(t) = t * vz - 1/2 grav t^2
 +
 +              and solved for:
 +
 +                s(ti) = sdist
 +                z(ti) = zdist
 +                max(z, ti) = jumpheight
 +
 +              From these three equations, you will find the three parameters vs, vz
 +              and ti.
 +       */
 +
 +      // push him so high...
 +      vz = sqrt(fabs(2 * grav * jumpheight)); // NOTE: sqrt(positive)!
 +
 +      // we start with downwards velocity only if it's a downjump and the jump apex should be outside the jump!
 +      if(ht < 0)
 +              if(zdist < 0)
 +                      vz = -vz;
 +
 +      vector solution;
 +      solution = solve_quadratic(0.5 * grav, -vz, zdist); // equation "z(ti) = zdist"
 +      // ALWAYS solvable because jumpheight >= zdist
 +      if(!solution.z)
 +              solution_y = solution.x; // just in case it is not solvable due to roundoff errors, assume two equal solutions at their center (this is mainly for the usual case with ht == 0)
 +      if(zdist == 0)
 +              solution_x = solution.y; // solution_x is 0 in this case, so don't use it, but rather use solution_y (which will be sqrt(0.5 * jumpheight / grav), actually)
 +
 +      if(zdist < 0)
 +      {
 +              // down-jump
 +              if(ht < 0)
 +              {
 +                      // almost straight line type
 +                      // jump apex is before the jump
 +                      // we must take the larger one
 +                      trigger_push_calculatevelocity_flighttime = solution.y;
 +              }
 +              else
 +              {
 +                      // regular jump
 +                      // jump apex is during the jump
 +                      // we must take the larger one too
 +                      trigger_push_calculatevelocity_flighttime = solution.y;
 +              }
 +      }
 +      else
 +      {
 +              // up-jump
 +              if(ht < 0)
 +              {
 +                      // almost straight line type
 +                      // jump apex is after the jump
 +                      // we must take the smaller one
 +                      trigger_push_calculatevelocity_flighttime = solution.x;
 +              }
 +              else
 +              {
 +                      // regular jump
 +                      // jump apex is during the jump
 +                      // we must take the larger one
 +                      trigger_push_calculatevelocity_flighttime = solution.y;
 +              }
 +      }
 +      vs = sdist / trigger_push_calculatevelocity_flighttime;
 +
 +      // finally calculate the velocity
 +      return sdir * vs + '0 0 1' * vz;
 +}
 +
 +void trigger_push_touch()
 +{
 +      if (self.active == ACTIVE_NOT)
 +              return;
 +
 +#ifdef SVQC
 +      if (!isPushable(other))
 +              return;
 +#endif
 +
 +      if(self.team)
 +              if(((self.spawnflags & 4) == 0) == (DIFF_TEAM(self, other)))
 +                      return;
 +
 +      EXACTTRIGGER_TOUCH;
 +
 +      if(self.enemy)
 +      {
 +              other.velocity = trigger_push_calculatevelocity(other.origin, self.enemy, self.height);
 +              other.move_velocity = other.velocity;
 +      }
 +      else if(self.target)
 +      {
 +              entity e;
 +              RandomSelection_Init();
 +              for(e = world; (e = find(e, targetname, self.target)); )
 +              {
 +                      if(e.cnt)
 +                              RandomSelection_Add(e, 0, string_null, e.cnt, 1);
 +                      else
 +                              RandomSelection_Add(e, 0, string_null, 1, 1);
 +              }
 +              other.velocity = trigger_push_calculatevelocity(other.origin, RandomSelection_chosen_ent, self.height);
 +              other.move_velocity = other.velocity;
 +      }
 +      else
 +      {
 +              other.velocity = self.movedir;
 +              other.move_velocity = other.velocity;
 +      }
 +
 +      UNSET_ONGROUND(other);
 +
 +      other.move_flags &= ~FL_ONGROUND;
 +
 +#ifdef SVQC
 +      if (IS_PLAYER(other))
 +      {
 +              // reset tracking of oldvelocity for impact damage (sudden velocity changes)
 +              other.oldvelocity = other.velocity;
 +
 +              if(self.pushltime < time)  // prevent "snorring" sound when a player hits the jumppad more than once
 +              {
 +                      // flash when activated
 +                      pointparticles(particleeffectnum("jumppad_activate"), other.origin, other.velocity, 1);
 +                      sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
 +                      self.pushltime = time + 0.2;
 +              }
 +              if(IS_REAL_CLIENT(other) || IS_BOT_CLIENT(other))
 +              {
 +                      bool found = false;
 +                      for(int i = 0; i < other.jumppadcount && i < NUM_JUMPPADSUSED; ++i)
 +                              if(other.(jumppadsused[i]) == self)
 +                                      found = true;
 +                      if(!found)
 +                      {
 +                              other.(jumppadsused[other.jumppadcount % NUM_JUMPPADSUSED]) = self;
 +                              other.jumppadcount = other.jumppadcount + 1;
 +                      }
 +
 +                      if(IS_REAL_CLIENT(other))
 +                      {
 +                              if(self.message)
 +                                      centerprint(other, self.message);
 +                      }
 +                      else
 +                              other.lastteleporttime = time;
 +
 +                      if (other.deadflag == DEAD_NO)
 +                              animdecide_setaction(other, ANIMACTION_JUMP, true);
 +              }
 +              else
 +                      other.jumppadcount = true;
 +
 +              // reset tracking of who pushed you into a hazard (for kill credit)
 +              other.pushltime = 0;
 +              other.istypefrag = 0;
 +      }
 +
 +      if(self.enemy.target)
 +      {
 +              entity oldself;
 +              oldself = self;
 +              activator = other;
 +              self = self.enemy;
 +              SUB_UseTargets();
 +              self = oldself;
 +      }
 +
 +      if (other.flags & FL_PROJECTILE)
 +      {
 +              other.angles = vectoangles (other.velocity);
 +              switch(other.movetype)
 +              {
 +                      case MOVETYPE_FLY:
 +                              other.movetype = MOVETYPE_TOSS;
 +                              other.gravity = 1;
 +                              break;
 +                      case MOVETYPE_BOUNCEMISSILE:
 +                              other.movetype = MOVETYPE_BOUNCE;
 +                              other.gravity = 1;
 +                              break;
 +              }
 +              UpdateCSQCProjectile(other);
 +      }
 +
 +      if (self.spawnflags & PUSH_ONCE)
 +      {
 +              self.touch = func_null;
 +              self.think = SUB_Remove;
 +              self.nextthink = time;
 +      }
 +#endif
 +}
 +
 +#ifdef SVQC
 +void trigger_push_link();
 +void trigger_push_updatelink();
 +#endif
 +void trigger_push_findtarget()
 +{
 +      entity t;
 +      vector org;
 +
 +      // first calculate a typical start point for the jump
 +      org = (self.absmin + self.absmax) * 0.5;
 +      org_z = self.absmax.z - PL_MIN.z;
 +
 +      if (self.target)
 +      {
 +              float n = 0;
 +              for(t = world; (t = find(t, targetname, self.target)); )
 +              {
 +                      ++n;
 +#ifdef SVQC
 +                      entity e = spawn();
 +                      setorigin(e, org);
 +                      setsize(e, PL_MIN, PL_MAX);
 +                      e.velocity = trigger_push_calculatevelocity(org, t, self.height);
 +                      tracetoss(e, e);
 +                      if(e.movetype == MOVETYPE_NONE)
 +                              waypoint_spawnforteleporter(self, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity));
 +                      remove(e);
 +#endif
 +              }
 +
 +              if(!n)
 +              {
 +                      // no dest!
 +#ifdef SVQC
 +                      objerror ("Jumppad with nonexistant target");
 +#endif
 +                      return;
 +              }
 +              else if(n == 1)
 +              {
 +                      // exactly one dest - bots love that
 +                      self.enemy = find(world, targetname, self.target);
 +              }
 +              else
 +              {
 +                      // have to use random selection every single time
 +                      self.enemy = world;
 +              }
 +      }
 +#ifdef SVQC
 +      else
 +      {
 +              entity e = spawn();
 +              setorigin(e, org);
 +              setsize(e, PL_MIN, PL_MAX);
 +              e.velocity = self.movedir;
 +              tracetoss(e, e);
 +              waypoint_spawnforteleporter(self, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity));
 +              remove(e);
 +      }
 +
 +      trigger_push_link();
 +      defer(0.1, trigger_push_updatelink);
 +#endif
 +}
 +
 +#ifdef SVQC
 +float trigger_push_send(entity to, float sf)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_TRIGGER_PUSH);
 +      WriteByte(MSG_ENTITY, sf);
 +
 +      if(sf & 1)
 +      {
 +              WriteByte(MSG_ENTITY, self.team);
 +              WriteInt24_t(MSG_ENTITY, self.spawnflags);
 +              WriteByte(MSG_ENTITY, self.active);
 +              WriteByte(MSG_ENTITY, self.height);
 +
 +              trigger_common_write(true);
 +      }
 +
 +      if(sf & 2)
 +      {
 +              WriteByte(MSG_ENTITY, self.team);
 +              WriteByte(MSG_ENTITY, self.active);
 +      }
 +
 +      return true;
 +}
 +
 +void trigger_push_updatelink()
 +{
 +      self.SendFlags |= 1;
 +}
 +
 +void trigger_push_link()
 +{
 +      //Net_LinkEntity(self, false, 0, trigger_push_send);
 +}
 +#endif
 +#ifdef SVQC
 +/*
 + * ENTITY PARAMETERS:
 + *
 + *   target:  target of jump
 + *   height:  the absolute value is the height of the highest point of the jump
 + *            trajectory above the higher one of the player and the target.
 + *            the sign indicates whether the highest point is INSIDE (positive)
 + *            or OUTSIDE (negative) of the jump trajectory. General rule: use
 + *            positive values for targets mounted on the floor, and use negative
 + *            values to target a point on the ceiling.
 + *   movedir: if target is not set, this * speed * 10 is the velocity to be reached.
 + */
 +void spawnfunc_trigger_push()
 +{
 +      SetMovedir ();
 +
 +      EXACTTRIGGER_INIT;
 +
 +      self.active = ACTIVE_ACTIVE;
 +      self.use = trigger_push_use;
 +      self.touch = trigger_push_touch;
 +
 +      // normal push setup
 +      if (!self.speed)
 +              self.speed = 1000;
 +      self.movedir = self.movedir * self.speed * 10;
 +
 +      if (!self.noise)
 +              self.noise = "misc/jumppad.wav";
 +      precache_sound (self.noise);
 +
 +      // this must be called to spawn the teleport waypoints for bots
 +      InitializeEntity(self, trigger_push_findtarget, INITPRIO_FINDTARGET);
 +}
 +
 +
 +float target_push_send(entity to, float sf)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_TARGET_PUSH);
 +
 +      WriteByte(MSG_ENTITY, self.cnt);
 +      WriteString(MSG_ENTITY, self.targetname);
 +      WriteCoord(MSG_ENTITY, self.origin_x);
 +      WriteCoord(MSG_ENTITY, self.origin_y);
 +      WriteCoord(MSG_ENTITY, self.origin_z);
 +
 +      return true;
 +}
 +
 +void target_push_link()
 +{
 +      Net_LinkEntity(self, false, 0, target_push_send);
 +      self.SendFlags |= 1; // update
 +}
 +
 +void spawnfunc_target_push() { target_push_link(); }
 +void spawnfunc_info_notnull() { target_push_link(); }
 +void spawnfunc_target_position() { target_push_link(); }
 +
 +#endif
 +
 +#ifdef CSQC
 +
 +void ent_trigger_push()
 +{
 +      float sf = ReadByte();
 +
 +      if(sf & 1)
 +      {
 +              self.classname = "jumppad";
 +              int mytm = ReadByte(); if(mytm) { self.team = mytm - 1; }
 +              self.spawnflags = ReadInt24_t();
 +              self.active = ReadByte();
 +              self.height = ReadByte();
 +
 +              trigger_common_read(true);
 +
 +              self.entremove = trigger_remove_generic;
 +              self.solid = SOLID_TRIGGER;
 +              self.draw = trigger_draw_generic;
 +              self.trigger_touch = trigger_push_touch;
 +              self.drawmask = MASK_NORMAL;
 +              self.move_time = time;
 +              trigger_push_findtarget();
 +      }
 +
 +      if(sf & 2)
 +      {
 +              self.team = ReadByte();
 +              self.active = ReadByte();
 +      }
 +}
 +
 +void target_push_remove()
 +{
 +      if(self.classname)
 +              strunzone(self.classname);
 +      self.classname = string_null;
 +
 +      if(self.targetname)
 +              strunzone(self.targetname);
 +      self.targetname = string_null;
 +}
 +
 +void ent_target_push()
 +{
 +      self.classname = "push_target";
 +      self.cnt = ReadByte();
 +      self.targetname = strzone(ReadString());
 +      self.origin_x = ReadCoord();
 +      self.origin_y = ReadCoord();
 +      self.origin_z = ReadCoord();
 +      setorigin(self, self.origin);
 +
 +      self.drawmask = MASK_NORMAL;
 +      self.entremove = target_push_remove;
 +}
 +#endif
index 1902b7e,0000000..c04e1f4
mode 100644,000000..100644
--- /dev/null
@@@ -1,85 -1,0 +1,85 @@@
-     #include "../../../server/defs.qh"
 +#if defined(CSQC)
 +#elif defined(MENUQC)
 +#elif defined(SVQC)
 +      #include "../../../dpdefs/progsdefs.qh"
 +    #include "../../util.qh"
++    #include "../../../server/_all.qh"
 +    #include "secret.qh"
 +#endif
 +
 +#ifdef SVQC
 +
 +void secrets_setstatus() {
 +      self.stat_secrets_total = secrets_total;
 +      self.stat_secrets_found = secrets_found;
 +}
 +
 +/**
 + * A secret has been found (maybe :P)
 + */
 +void trigger_secret_touch() {
 +      // only a player can trigger this
 +      if (!IS_PLAYER(other))
 +              return;
 +
 +      // update secrets found counter
 +      secrets_found += 1;
 +      //print("Secret found: ", ftos(secret_counter.cnt), "/");
 +      //print(ftos(secret_counter.count), "\n");
 +
 +      // centerprint message (multi_touch() doesn't always call centerprint())
 +      centerprint(other, self.message);
 +      self.message = "";
 +
 +      // handle normal trigger features
 +      multi_touch();
 +      remove(self);
 +}
 +
 +/*QUAKED trigger_secret (.5 .5 .5) ?
 +Variable sized secret trigger. Can be targeted at one or more entities.
 +Basically, it's a trigger_once (with restrictions, see notes) that additionally updates the number of secrets found.
 +-------- KEYS --------
 +sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (default: 1)
 +noise: path to sound file, if you want to play something else
 +target: trigger all entities with this targetname when triggered
 +message: print this message to the player who activated the trigger instead of the standard 'You found a secret!'
 +killtarget: remove all entities with this targetname when triggered
 +-------- NOTES --------
 +You should create a common/trigger textured brush covering the entrance to a secret room/area.
 +Trigger secret can only be trigger by a player's touch and can not be a target itself.
 +*/
 +void spawnfunc_trigger_secret() {
 +      // FIXME: should it be disabled in most modes?
 +
 +      // update secrets count
 +      secrets_total += 1;
 +
 +      // add default message
 +      if (self.message == "")
 +              self.message = "You found a secret!";
 +
 +      // set default sound
 +      if (self.noise == "")
 +      if (!self.sounds)
 +              self.sounds = 1; // misc/secret.wav
 +
 +      // this entity can't be a target itself!!!!
 +      self.targetname = "";
 +
 +      // you can't just shoot a room to find it, can you?
 +      self.health = 0;
 +
 +      // a secret can not be delayed
 +      self.delay = 0;
 +
 +      // convert this trigger to trigger_once
 +      self.classname = "trigger_once";
 +      spawnfunc_trigger_once();
 +
 +      // take over the touch() function, so we can mark secret as found
 +      self.touch = trigger_secret_touch;
 +      // ignore triggering;
 +      self.use = func_null;
 +}
 +#endif
index 8013f3b,0000000..7f1bb89
mode 100644,000000..100644
--- /dev/null
@@@ -1,154 -1,0 +1,155 @@@
-     #include "../../weapons/weapons.qh"
 +#if defined(CSQC)
 +#elif defined(MENUQC)
 +#elif defined(SVQC)
++      #include "../../../server/_all.qh"
 +      #include "../../../dpdefs/progsdefs.qh"
 +    #include "../../../warpzonelib/util_server.qh"
++    #include "../../weapons/all.qh"
 +    #include "../../../server/defs.qh"
 +    #include "../../deathtypes.qh"
 +#endif
 +
 +/*
 +*             t_swamp.c
 +*             Adds spawnfunc_trigger_swamp and suppoart routines for xonotic 1.2.1+
 +*             Author tZork (Jakob MG)
 +*             jakob@games43.se
 +*             2005 11 29
 +*/
 +
 +.float swamp_interval;        //Hurt players in swamp with this interval
 +.float swamp_slowdown;        //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
 +.entity swampslug;
 +
 +#ifdef SVQC
 +void spawnfunc_trigger_swamp(void);
 +#endif
 +void swamp_touch(void);
 +void swampslug_think();
 +
 +
 +/*
 +* Uses a entity calld swampslug to handle players in the swamp
 +* It works like this: When the plyer enters teh swamp the spawnfunc_trigger_swamp
 +* attaches a new "swampslug" to the player. As long as the plyer is inside
 +* the swamp the swamp gives the slug new health. But the slug slowly kills itself
 +* so when the player goes outside the swamp, it dies and releases the player from the
 +* swamps curses (dmg/slowdown)
 +*
 +* I do it this way becuz there is no "untouch" event.
 +*/
 +void swampslug_think(void)
 +{
 +      //Slowly kill the slug
 +      self.health = self.health - 1;
 +
 +      //Slug dead? then remove curses.
 +      if(self.health <= 0)
 +      {
 +              self.owner.in_swamp = 0;
 +              remove(self);
 +              //centerprint(self.owner,"Killing slug...\n");
 +              return;
 +      }
 +
 +      // Slug still alive, so we are still in the swamp
 +      // Or we have exited it very recently.
 +      // Do the damage and renew the timer.
 +#ifdef SVQC
 +      Damage (self.owner, self, self, self.dmg, DEATH_SWAMP, other.origin, '0 0 0');
 +#endif
 +
 +      self.nextthink = time + self.swamp_interval;
 +}
 +
 +void swamp_touch(void)
 +{
 +      // If whatever thats touching the swamp is not a player
 +      // or if its a dead player, just dont care abt it.
 +      if(!IS_PLAYER(other) || PHYS_DEAD(other))
 +              return;
 +
 +      EXACTTRIGGER_TOUCH;
 +
 +      // Chech if player alredy got a swampslug.
 +      if(other.in_swamp != 1)
 +      {
 +              // If not attach one.
 +              //centerprint(other,"Entering swamp!\n");
 +              other.swampslug = spawn();
 +              other.swampslug.health = 2;
 +              other.swampslug.think = swampslug_think;
 +              other.swampslug.nextthink = time;
 +              other.swampslug.owner = other;
 +              other.swampslug.dmg = self.dmg;
 +              other.swampslug.swamp_interval = self.swamp_interval;
 +              other.swamp_slowdown = self.swamp_slowdown;
 +              other.in_swamp = 1;
 +              return;
 +      }
 +
 +      //other.in_swamp = 1;
 +
 +      //Revitalize players swampslug
 +      other.swampslug.health = 2;
 +}
 +
 +#ifdef SVQC
 +float swamp_send(entity to, float sf)
 +{
 +      WriteByte(MSG_ENTITY, ENT_CLIENT_LADDER);
 +
 +      WriteByte(MSG_ENTITY, self.dmg); // can probably get away with using a single byte here
 +      WriteByte(MSG_ENTITY, self.swamp_slowdown);
 +      WriteByte(MSG_ENTITY, self.swamp_interval);
 +
 +      trigger_common_write(false);
 +
 +      return true;
 +}
 +
 +void swamp_link()
 +{
 +      Net_LinkEntity(self, false, 0, func_ladder_send);
 +}
 +
 +/*QUAKED spawnfunc_trigger_swamp (.5 .5 .5) ?
 +Players gettin into the swamp will
 +get slowd down and damaged
 +*/
 +void spawnfunc_trigger_swamp(void)
 +{
 +      // Init stuff
 +      EXACTTRIGGER_INIT;
 +      self.touch = swamp_touch;
 +
 +      // Setup default keys, if missing
 +      if(self.dmg <= 0)
 +              self.dmg = 5;
 +      if(self.swamp_interval <= 0)
 +              self.swamp_interval = 1;
 +      if(self.swamp_slowdown <= 0)
 +              self.swamp_slowdown = 0.5;
 +
 +      swamp_link();
 +}
 +
 +#elif defined(CSQC)
 +
 +void ent_swamp()
 +{
 +      self.dmg = ReadByte();
 +      self.swamp_slowdown = ReadByte();
 +      self.swamp_interval = ReadByte();
 +
 +      trigger_common_read(false);
 +
 +      self.classname = "trigger_swamp";
 +      self.solid = SOLID_TRIGGER;
 +      self.draw = trigger_draw_generic;
 +      self.trigger_touch = swamp_touch;
 +      self.drawmask = MASK_NORMAL;
 +      self.move_time = time;
 +      self.entremove = trigger_remove_generic;
 +}
 +#endif
index 8be1b3c,0000000..3baff30
mode 100644,000000..100644
--- /dev/null
@@@ -1,55 -1,0 +1,49 @@@
- .string bgmscript;
- .float bgmscriptattack;
- .float bgmscriptdecay;
- .float bgmscriptsustain;
- .float bgmscriptrelease;
 +#ifndef TRIGGERS_H
 +#define TRIGGERS_H
 +
 +const float SF_TRIGGER_INIT = 1;
 +const float SF_TRIGGER_UPDATE = 2;
 +const float SF_TRIGGER_RESET = 4;
 +
 +const float   SPAWNFLAG_NOMESSAGE = 1;
 +const float   SPAWNFLAG_NOTOUCH = 1;
 +
 +.void() trigger_touch;
 +
 +.float height;
 +
 +.float nottargeted;
 +#define IFTARGETED if(!self.nottargeted && self.targetname != "")
 +
 +.float lip;
 +
 +// used elsewhere (will fix)
 +#ifdef SVQC
 +void trigger_common_write(bool withtarget);
 +
 +string trigger_magicear_processmessage_forallears(entity source, float teamsay, entity privatesay, string msgin);
 +
 +void target_voicescript_next(entity pl);
 +void target_voicescript_clear(entity pl);
 +#endif
 +
 +.float volume, atten;
 +
 +.vector dest;
 +
 +#ifdef CSQC
 +void trigger_common_read(bool withtarget);
 +void trigger_remove_generic();
 +
 +.float active;
 +.string target;
 +.string targetname;
 +
 +const int ACTIVE_NOT          = 0;
 +const int ACTIVE_ACTIVE       = 1;
 +const int ACTIVE_IDLE                 = 2;
 +const int ACTIVE_BUSY                 = 2;
 +const int ACTIVE_TOGGLE               = 3;
 +#endif
 +
 +#endif
Simple merge
index 0000000,847c837..36f08ef
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,375 +1,375 @@@
 -      #include "../../client/movetypes.qh"
+ #ifndef WEAPONS_ALL_C
+ #define WEAPONS_ALL_C
+ #include "all.qh"
+ #if defined(CSQC)
+       #include "../../dpdefs/csprogsdefs.qh"
+       #include "../../client/defs.qh"
+       #include "../constants.qh"
+       #include "../stats.qh"
+       #include "../../warpzonelib/anglestransform.qh"
+       #include "../../warpzonelib/mathlib.qh"
+       #include "../../warpzonelib/common.qh"
+       #include "../../warpzonelib/client.qh"
+       #include "../util.qh"
+       #include "../buffs.qh"
+       #include "../../client/autocvars.qh"
+       #include "../deathtypes.qh"
+       #include "../../csqcmodellib/interpolate.qh"
++      #include "../movetypes/movetypes.qh"
+       #include "../../client/main.qh"
+       #include "../../csqcmodellib/cl_model.qh"
+ #elif defined(MENUQC)
+ #elif defined(SVQC)
+       #include "../../dpdefs/progsdefs.qh"
+     #include "../../dpdefs/dpextensions.qh"
+     #include "../../warpzonelib/anglestransform.qh"
+     #include "../../warpzonelib/mathlib.qh"
+     #include "../../warpzonelib/common.qh"
+     #include "../../warpzonelib/util_server.qh"
+     #include "../../warpzonelib/server.qh"
+     #include "../constants.qh"
+     #include "../stats.qh"
+     #include "../teams.qh"
+     #include "../util.qh"
+     #include "../buffs.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.qh"
+     #include "../../server/mutators/mutators_include.qh"
+     #include "../mapinfo.qh"
+     #include "../../server/command/common.qh"
+     #include "../../csqcmodellib/sv_model.qh"
+     #include "../../server/portals.qh"
+     #include "../../server/g_hook.qh"
+ #endif
+ #ifndef MENUQC
+ #include "calculations.qc"
+ #endif
+ #include "all.inc"
+ // WEAPON PLUGIN SYSTEM
+ entity weapon_info[WEP_MAXCOUNT];
+ entity dummy_weapon_info;
+ #if WEP_MAXCOUNT > 72
+ # error Kein Weltraum links auf dem Gerät
+ #endif
+ WepSet WepSet_FromWeapon(int a) {
+       a -= WEP_FIRST;
+ #if WEP_MAXCOUNT > 24
+       if(a >= 24) {
+               a -= 24;
+ #if WEP_MAXCOUNT > 48
+               if(a >= 24) {
+                       a -= 24;
+                       return '0 0 1' * power2of(a);
+               }
+ #endif
+               return '0 1 0' * power2of(a);
+       }
+ #endif
+       return '1 0 0' * power2of(a);
+ }
+ #ifdef SVQC
+ void WepSet_AddStat()
+ {
+       addstat(STAT_WEAPONS, AS_INT, weapons_x);
+ #if WEP_MAXCOUNT > 24
+       addstat(STAT_WEAPONS2, AS_INT, weapons_y);
+ #if WEP_MAXCOUNT > 48
+       addstat(STAT_WEAPONS3, AS_INT, weapons_z);
+ #endif
+ #endif
+ }
+ void WriteWepSet(float dst, WepSet w)
+ {
+ #if WEP_MAXCOUNT > 48
+       WriteInt72_t(dst, w);
+ #elif WEP_MAXCOUNT > 24
+       WriteInt48_t(dst, w);
+ #else
+       WriteInt24_t(dst, w.x);
+ #endif
+ }
+ #endif
+ #ifdef CSQC
+ WepSet WepSet_GetFromStat()
+ {
+       WepSet w = '0 0 0';
+       w.x = getstati(STAT_WEAPONS);
+ #if WEP_MAXCOUNT > 24
+       w.y = getstati(STAT_WEAPONS2);
+ #if WEP_MAXCOUNT > 48
+       w.z = getstati(STAT_WEAPONS3);
+ #endif
+ #endif
+       return w;
+ }
+ WepSet ReadWepSet()
+ {
+ #if WEP_MAXCOUNT > 48
+       return ReadInt72_t();
+ #elif WEP_MAXCOUNT > 24
+       return ReadInt48_t();
+ #else
+       return ReadInt24_t() * '1 0 0';
+ #endif
+ }
+ #endif
+ void register_weapon(
+       int id,
+       WepSet bit,
+       bool(int) func,
+       .int ammotype,
+       int i,
+       int weapontype,
+       float pickupbasevalue,
+       vector clr,
+       string modelname,
+       string simplemdl,
+       string crosshair,
+       string wepimg,
+       string refname,
+       string wepname)
+ {
+       entity e;
+       weapon_info[id - 1] = e = spawn();
+       e.classname = "weapon_info";
+       e.weapon = id;
+       e.weapons = bit;
+       e.weapon_func = func;
+       e.ammo_field = ammotype;
+       e.impulse = i;
+       e.spawnflags = weapontype;
+       e.bot_pickupbasevalue = pickupbasevalue;
+       e.wpcolor = clr;
+       e.wpmodel = strzone(strcat("wpn-", ftos(id)));
+       e.mdl = modelname;
+       e.model = strzone(strcat("models/weapons/g_", modelname, ".md3"));
+       e.w_simplemdl = strzone(simplemdl); // simpleitems weapon model/image
+       e.w_crosshair = strzone(car(crosshair));
+       string s = cdr(crosshair);
+       e.w_crosshair_size = ((s != "") ? stof(s) : 1); // so that we can scale the crosshair from code (for compat)
+       e.model2 = strzone(wepimg);
+       e.netname = refname;
+       e.message = wepname;
+       #ifdef CSQC
+       func(WR_INIT);
+       #endif
+ }
+ bool w_null(int dummy)
+ {
+       return 0;
+ }
+ void register_weapons_done()
+ {
+       dummy_weapon_info = spawn();
+       dummy_weapon_info.classname = "weapon_info";
+       dummy_weapon_info.weapon = 0; // you can recognize dummies by this
+       dummy_weapon_info.weapons = '0 0 0';
+       dummy_weapon_info.netname = "";
+       dummy_weapon_info.message = "AOL CD Thrower";
+       dummy_weapon_info.weapon_func = w_null;
+       dummy_weapon_info.wpmodel = "";
+       dummy_weapon_info.mdl = "";
+       dummy_weapon_info.model = "";
+       dummy_weapon_info.spawnflags = 0;
+       dummy_weapon_info.impulse = -1;
+       dummy_weapon_info.bot_pickupbasevalue = 0;
+       dummy_weapon_info.ammo_field = ammo_none;
+       dummy_weapon_info.w_crosshair = "gfx/crosshair1";
+       dummy_weapon_info.w_crosshair_size = 1;
+       dummy_weapon_info.model2 = "";
+       int i;
+       weaponorder_byid = "";
+       for(i = WEP_MAXCOUNT; i >= 1; --i)
+               if(weapon_info[i-1])
+                       weaponorder_byid = strcat(weaponorder_byid, " ", ftos(i));
+       weaponorder_byid = strzone(substring(weaponorder_byid, 1, strlen(weaponorder_byid) - 1));
+ }
+ entity get_weaponinfo(int id)
+ {
+       entity w;
+       if(id < WEP_FIRST || id > WEP_LAST)
+               return dummy_weapon_info;
+       w = weapon_info[id - 1];
+       if(w)
+               return w;
+       return dummy_weapon_info;
+ }
+ string W_FixWeaponOrder(string order, float complete)
+ {
+       return fixPriorityList(order, WEP_FIRST, WEP_LAST, 230 - WEP_FIRST, complete);
+ }
+ string W_NameWeaponOrder_MapFunc(string s)
+ {
+       entity wi;
+       if(s == "0" || stof(s))
+       {
+               wi = get_weaponinfo(stof(s));
+               if(wi != dummy_weapon_info)
+                       return wi.netname;
+       }
+       return s;
+ }
+ string W_UndeprecateName(string s)
+ {
+       switch ( s )
+       {
+               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;
+       }
+ }
+ string W_NameWeaponOrder(string order)
+ {
+       return mapPriorityList(order, W_NameWeaponOrder_MapFunc);
+ }
+ string W_NumberWeaponOrder_MapFunc(string s)
+ {
+       int i;
+       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);
+       return s;
+ }
+ string W_NumberWeaponOrder(string order)
+ {
+       return mapPriorityList(order, W_NumberWeaponOrder_MapFunc);
+ }
+ float W_FixWeaponOrder_BuildImpulseList_buf[WEP_MAXCOUNT];
+ string W_FixWeaponOrder_BuildImpulseList_order;
+ void W_FixWeaponOrder_BuildImpulseList_swap(int i, int j, entity pass)
+ {
+       float h;
+       h = W_FixWeaponOrder_BuildImpulseList_buf[i];
+       W_FixWeaponOrder_BuildImpulseList_buf[i] = W_FixWeaponOrder_BuildImpulseList_buf[j];
+       W_FixWeaponOrder_BuildImpulseList_buf[j] = h;
+ }
+ float W_FixWeaponOrder_BuildImpulseList_cmp(int i, int j, entity pass)
+ {
+       entity e1, e2;
+       float d;
+       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!
+ }
+ string W_FixWeaponOrder_BuildImpulseList(string o)
+ {
+       int i;
+       W_FixWeaponOrder_BuildImpulseList_order = o;
+       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);
+       o = "";
+       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);
+ }
+ string W_FixWeaponOrder_AllowIncomplete(string order)
+ {
+       return W_FixWeaponOrder(order, 0);
+ }
+ string W_FixWeaponOrder_ForceComplete(string order)
+ {
+       if(order == "")
+               order = W_NumberWeaponOrder(cvar_defstring("cl_weaponpriority"));
+       return W_FixWeaponOrder(order, 1);
+ }
+ void W_RandomWeapons(entity e, float n)
+ {
+       int i, j;
+       WepSet remaining;
+       WepSet result;
+       remaining = e.weapons;
+       result = '0 0 0';
+       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);
+               result |= WepSet_FromWeapon(RandomSelection_chosen_float);
+               remaining &= ~WepSet_FromWeapon(RandomSelection_chosen_float);
+       }
+       e.weapons = result;
+ }
+ string GetAmmoPicture(.int ammotype)
+ {
+       switch(ammotype)
+       {
+               case ammo_shells:  return "ammo_shells";
+               case ammo_nails:   return "ammo_bullets";
+               case ammo_rockets: return "ammo_rockets";
+               case ammo_cells:   return "ammo_cells";
+               case ammo_plasma:  return "ammo_cells";
+               case ammo_fuel:    return "ammo_fuel";
+               default: return ""; // wtf, no ammo type?
+       }
+ }
+ #ifdef CSQC
+ .int GetAmmoFieldFromNum(int i)
+ {
+       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)
+       {
+               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
+ #endif
index 0000000,202b840..21b7c54
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1466 +1,1467 @@@
+ /*
+ ==============================================================================
+                       SOURCE FOR GLOBALVARS_T C STRUCTURE
+                       MUST NOT BE MODIFIED, OR CRC ERRORS WILL APPEAR
+ ==============================================================================
+ */
+ //
+ // system globals
+ //
+ entity                self;
+ entity                other;
+ entity                world;
+ float         time;
+ float         frametime;
+ float                 player_localentnum;     //the entnum
+ float                 player_localnum;        //the playernum
+ float         maxclients;     //a constant filled in by the engine. gah, portability eh?
+ float         clientcommandframe;     //player movement
+ float         servercommandframe;     //clientframe echoed off the server
+ string                mapname;
+ //
+ // global variables set by built in functions
+ //
+ vector                v_forward, v_up, v_right;       // set by makevectors()
+ // set by traceline / tracebox
+ float         trace_allsolid;
+ float         trace_startsolid;
+ float         trace_fraction;
+ vector                trace_endpos;
+ vector                trace_plane_normal;
+ float         trace_plane_dist;
+ entity                trace_ent;
+ float         trace_inopen;
+ float         trace_inwater;
+ //
+ // required prog functions
+ //
+ void()                CSQC_Init;
+ void()                CSQC_Shutdown;
+ float(float f, float t, float n)      CSQC_InputEvent;
+ void(float w, float h)                CSQC_UpdateView;
+ float(string s)       CSQC_ConsoleCommand;
+ //these fields are read and set by the default player physics
+ vector                pmove_org;
+ vector                pmove_vel;
+ vector                pmove_mins;
+ vector                pmove_maxs;
+ //retrieved from the current movement commands (read by player physics)
+ float         input_timelength;
+ vector                input_angles;
+ vector                input_movevalues;       //forwards, right, up.
+ float         input_buttons;          //attack, use, jump (default physics only uses jump)
+ float         movevar_gravity;
+ float         movevar_stopspeed;
+ float         movevar_maxspeed;
+ float         movevar_spectatormaxspeed;      //used by NOCLIP movetypes.
+ float         movevar_accelerate;
+ float         movevar_airaccelerate;
+ float         movevar_wateraccelerate;
+ float         movevar_friction;
+ float         movevar_waterfriction;
+ float         movevar_entgravity;     //the local player's gravity field. Is a multiple (1 is the normal value)
+ //================================================
+ void          end_sys_globals;                // flag for structure dumping
+ //================================================
+ /*
+ ==============================================================================
+                       SOURCE FOR ENTVARS_T C STRUCTURE
+                       MUST NOT BE MODIFIED, OR CRC ERRORS WILL APPEAR
+ ==============================================================================
+ */
+ //
+ // system fields (*** = do not set in prog code, maintained by C code)
+ //
+ .float                modelindex;             // *** model index in the precached list
+ .vector               absmin, absmax; // *** origin + mins / maxs
+ .float                entnum; // *** the ent number as on the server
+ .float                drawmask;
+ .void()               predraw;
+ .float                movetype;
+ .float                solid;
+ .vector               origin;                 // ***
+ .vector               oldorigin;              // ***
+ .vector               velocity;
+ .vector               angles;
+ .vector               avelocity;
+ .string               classname;              // spawn function
+ .string               model;
+ .float                frame;
+ .float                skin;
+ .float                effects;
+ .vector               mins, maxs;             // bounding box extents reletive to origin
+ .vector               size;                   // maxs - mins
+ .void()               touch;
+ .void()               use;
+ .void()               think;
+ .void()               blocked;                // for doors or plats,&nbs