]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into TimePath/stats
authorTimePath <andrew.hardaker1995@gmail.com>
Sun, 29 Nov 2015 02:45:20 +0000 (13:45 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Sun, 29 Nov 2015 02:46:37 +0000 (13:46 +1100)
# Conflicts:
# qcsrc/client/hud/panel/ammo.qc
# qcsrc/client/hud/panel/powerups.qc
# qcsrc/client/view.qc
# qcsrc/common/mutators/mutator/nades/nades.qc
# qcsrc/common/physics.qc
# qcsrc/common/physics.qh
# qcsrc/common/weapons/weapon/vortex.qc
# qcsrc/lib/registry.qh
# qcsrc/lib/stats.qh

34 files changed:
1  2 
qcsrc/client/announcer.qc
qcsrc/client/hud/panel/ammo.qc
qcsrc/client/hud/panel/powerups.qc
qcsrc/client/main.qc
qcsrc/client/scoreboard.qc
qcsrc/client/view.qc
qcsrc/common/constants.qh
qcsrc/common/gamemodes/gamemode/nexball/nexball.qc
qcsrc/common/gamemodes/gamemode/onslaught/onslaught.qc
qcsrc/common/mutators/mutator/buffs/all.qh
qcsrc/common/mutators/mutator/buffs/buffs.qc
qcsrc/common/mutators/mutator/buffs/module.inc
qcsrc/common/mutators/mutator/nades/nades.qc
qcsrc/common/mutators/mutator/nades/nades.qh
qcsrc/common/mutators/mutator/overkill/overkill.qc
qcsrc/common/physics.qc
qcsrc/common/physics.qh
qcsrc/common/triggers/trigger/jumppads.qc
qcsrc/common/weapons/all.qc
qcsrc/common/weapons/all.qh
qcsrc/common/weapons/weapon/vortex.qc
qcsrc/dpdefs/csprogsdefs.qh
qcsrc/lib/registry.qh
qcsrc/lib/stats.qh
qcsrc/server/autocvars.qh
qcsrc/server/cl_client.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_world.qc
qcsrc/server/miscfunctions.qh
qcsrc/server/mutators/mutator/gamemode_ca.qc
qcsrc/server/mutators/mutator/gamemode_ctf.qc
qcsrc/server/mutators/mutator/gamemode_domination.qc
qcsrc/server/sv_main.qc

index a0c496abcd93b70c7b5b94d53d304cd147fb9957,6fcdbb9d69354114ce2a0f36582b885218600481..109d014374bff33184d39b5a4deafb855ea757e6
@@@ -15,15 -15,18 +15,18 @@@ string AnnouncerOption(
        return ret;
  }
  
+ entity announcer_countdown;
  void Announcer_Countdown()
  {
        SELFPARAM();
        float starttime = STAT(GAMESTARTTIME);
 -      float roundstarttime = getstatf(STAT_ROUNDSTARTTIME);
 +      float roundstarttime = STAT(ROUNDSTARTTIME);
        if(roundstarttime == -1)
        {
                Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_ROUNDSTOP);
                remove(this);
+               announcer_countdown = NULL;
                return;
        }
        if(roundstarttime >= starttime)
@@@ -39,6 -42,7 +42,7 @@@
                Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_BEGIN);
                Local_Notification(MSG_MULTI, MULTI_COUNTDOWN_BEGIN);
                remove(this);
+               announcer_countdown = NULL;
                return;
        }
        else // countdown is still going
@@@ -70,7 -74,7 +74,7 @@@
  void Announcer_Gamestart()
  {
        float startTime = STAT(GAMESTARTTIME);
 -      float roundstarttime = getstatf(STAT_ROUNDSTARTTIME);
 +      float roundstarttime = STAT(ROUNDSTARTTIME);
        if(roundstarttime > startTime)
                startTime = roundstarttime;
  
@@@ -78,7 -82,6 +82,6 @@@
        {
                if(time < startTime)
                {
-                       static entity announcer_countdown;
                        if (!announcer_countdown)
                        {
                                announcer_countdown = new(announcer_countdown);
  // Plays the 1 minute or 5 minutes (of maptime) remaining sound, if client wants it
  void Announcer_Time()
  {
 -      float timelimit = getstatf(STAT_TIMELIMIT);
 +      float timelimit = STAT(TIMELIMIT);
        float timeleft = max(0, timelimit * 60 + STAT(GAMESTARTTIME) - time);
        float warmup_timeleft = 0;
  
index dc30dbcf94f364fa060d69e0f28da7ccd072998e,236a585985e8c983696284464d02b62277feb090..80cfdd69c1791e816aec4d1efe047a1a1ac3ac0e
@@@ -10,41 -10,7 +10,7 @@@ void DrawNadeProgressBar(vector myPos, 
                autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
  }
  
- void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time)
- {
-       float bonusNades    = STAT(NADE_BONUS);
-       float bonusProgress = STAT(NADE_BONUS_SCORE);
-       float bonusType     = STAT(NADE_BONUS_TYPE);
-       Nade def = Nades_from(bonusType);
-       vector nadeColor    = def.m_color;
-       string nadeIcon     = def.m_icon;
-       vector iconPos, textPos;
-       if(autocvar_hud_panel_ammo_iconalign)
-       {
-               iconPos = myPos + eX * 2 * mySize.y;
-               textPos = myPos;
-       }
-       else
-       {
-               iconPos = myPos;
-               textPos = myPos + eX * mySize.y;
-       }
-       if(bonusNades > 0 || bonusProgress > 0)
-       {
-               DrawNadeProgressBar(myPos, mySize, bonusProgress, nadeColor);
-               if(autocvar_hud_panel_ammo_text)
-                       drawstring_aspect(textPos, ftos(bonusNades), eX * (2/3) * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               if(draw_expanding)
-                       drawpic_aspect_skin_expanding(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, expand_time);
-               drawpic_aspect_skin(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       }
- }
+ void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time); // TODO: mutator
  
  void DrawAmmoItem(vector myPos, vector mySize, .int ammoType, bool isCurrent, bool isInfinite)
  {
@@@ -147,7 -113,7 +113,7 @@@ void HUD_Ammo(
        }
  
        int rows = 0, columns, row, column;
 -      float nade_cnt = getstatf(STAT_NADE_BONUS), nade_score = getstatf(STAT_NADE_BONUS_SCORE);
 +      float nade_cnt = STAT(NADE_BONUS), nade_score = STAT(NADE_BONUS_SCORE);
        bool draw_nades = (nade_cnt > 0 || nade_score > 0);
        float nade_statuschange_elapsedtime;
        int total_ammo_count;
index 51574a3299bd2643841d72737433713115e4b31a,10446d643605477a839f61b8f6ab89ec5f78e72a..e75f21f3685a0112dc44b5c9a66d07b083a9d564
@@@ -57,7 -57,7 +57,7 @@@ int getPowerupItemAlign(int align, int 
  void HUD_Powerups()
  {
        int allItems = getstati(STAT_ITEMS, 0, 24);
 -      int allBuffs = getstati(STAT_BUFFS, 0, 24);
 +      int allBuffs = STAT(BUFFS);
        int strengthTime, shieldTime, superTime;
  
        // Initialize items
@@@ -70,7 -70,7 +70,7 @@@
  
                strengthTime = bound(0, STAT(STRENGTH_FINISHED) - time, 99);
                shieldTime = bound(0, STAT(INVINCIBLE_FINISHED) - time, 99);
 -              superTime = bound(0, getstatf(STAT_SUPERWEAPONS_FINISHED) - time, 99);
 +              superTime = bound(0, STAT(SUPERWEAPONS_FINISHED) - time, 99);
  
                if(allItems & IT_UNLIMITED_SUPERWEAPONS)
                        superTime = 99;
@@@ -97,9 -97,7 +97,7 @@@
        if(superTime)
                addPowerupItem("Superweapons", "superweapons", autocvar_hud_progressbar_superweapons_color, superTime, 30);
  
-       FOREACH(Buffs, it.m_itemid & allBuffs, LAMBDA(
-               addPowerupItem(it.m_prettyName, strcat("buff_", it.m_name), it.m_color, bound(0, STAT(BUFF_TIME) - time, 99), 60);
-       ));
+       MUTATOR_CALLHOOK(HUD_Powerups_add);
  
        if(!powerupItemsCount)
                return;
diff --combined qcsrc/client/main.qc
index 1e4720d4d111c083853acf0cbb975a3b679a1743,f4852ab7f73c9833f181862bd3e4a1e4f2fce63e..510293e76602eac4cccaad26a202b9f834d69e18
@@@ -39,7 -39,7 +39,7 @@@ void CSQC_Init(
        prvm_language = strzone(cvar_string("prvm_language"));
  
  #ifdef WATERMARK
-       LOG_TRACEF("^4CSQC Build information: ^1%s\n", WATERMARK);
+       LOG_INFOF("^4CSQC Build information: ^1%s\n", WATERMARK);
  #endif
  
        binddb = db_create();
@@@ -327,47 -327,6 +327,6 @@@ float CSQC_InputEvent(float bInputType
  // --------------------------------------------------------------------------
  // BEGIN OPTIONAL CSQC FUNCTIONS
  
- void Ent_RemoveEntCS()
- {
-       SELFPARAM();
-       entcs_receiver[this.sv_entnum] = NULL;
- }
- NET_HANDLE(ENT_CLIENT_ENTCS, bool isnew)
- {
-       make_pure(this);
-       this.classname = "entcs_receiver";
-       InterpolateOrigin_Undo();
-       int sf = ReadByte();
-       if(sf & BIT(0))
-               this.sv_entnum = ReadByte();
-       if (sf & BIT(1))
-       {
-               this.origin_x = ReadShort();
-               this.origin_y = ReadShort();
-               this.origin_z = ReadShort();
-               setorigin(this, this.origin);
-       }
-       if (sf & BIT(2))
-       {
-               this.angles_y = ReadByte() * 360.0 / 256;
-               this.angles_x = this.angles_z = 0;
-       }
-       if (sf & BIT(3))
-               this.healthvalue = ReadByte() * 10;
-       if (sf & BIT(4))
-               this.armorvalue = ReadByte() * 10;
-       return = true;
-       entcs_receiver[this.sv_entnum] = this;
-       this.entremove = Ent_RemoveEntCS;
-       this.iflags |= IFLAG_ORIGIN;
-       InterpolateOrigin_Note();
- }
  void Ent_Remove();
  
  void Ent_RemovePlayerScore()
@@@ -752,7 -711,7 +711,7 @@@ NET_HANDLE(ENT_CLIENT_SPAWNEVENT, bool 
  
  // CSQC_Ent_Update : Called every frame that the server has indicated an update to the SSQC / CSQC entity has occured.
  // The only parameter reflects if the entity is "new" to the client, meaning it just came into the client's PVS.
- void CSQC_Ent_Update(float bIsNewEntity)
+ void CSQC_Ent_Update(bool isnew)
  {
        SELFPARAM();
        this.sourceLocLine = __LINE__;
        else
        {
                serverprevtime = time;
 -              serverdeltatime = getstatf(STAT_MOVEVARS_TICRATE) * getstatf(STAT_MOVEVARS_TIMESCALE);
 +              serverdeltatime = STAT(MOVEVARS_TICRATE) * STAT(MOVEVARS_TIMESCALE);
                time = serverprevtime + serverdeltatime;
        }
  
  #ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED
-       if(this.enttype)
+       if (this.enttype)
        {
-               if(t != this.enttype || bIsNewEntity)
+               if (t != this.enttype || isnew)
                {
                        LOG_INFOF("A CSQC entity changed its type! (edict: %d, server: %d, type: %d -> %d)\n", num_for_edict(this), this.entnum, this.enttype, t);
                        Ent_Remove();
                        clearentity(this);
-                       bIsNewEntity = 1;
+                       isnew = true;
                }
        }
        else
        {
-               if(!bIsNewEntity)
+               if (!isnew)
                {
                        LOG_INFOF("A CSQC entity appeared out of nowhere! (edict: %d, server: %d, type: %d)\n", num_for_edict(this), this.entnum, t);
-                       bIsNewEntity = 1;
+                       isnew = true;
                }
        }
  #endif
        this.enttype = t;
        bool done = false;
        FOREACH(LinkedEntities, it.m_id == t, LAMBDA(
-               this.classname = it.netname;
+               if (isnew) this.classname = it.netname;
                if (autocvar_developer_csqcentities)
-             LOG_INFOF("CSQC_Ent_Update(%d) with this=%i {.entnum=%d, .enttype=%d} t=%s (%d)\n", bIsNewEntity, this, this.entnum, this.enttype, it.netname, t);
-               done = it.m_read(this, bIsNewEntity);
+             LOG_INFOF("CSQC_Ent_Update(%d) at %f with this=%i {.entnum=%d, .enttype=%d} t=%s (%d)\n", isnew, savetime, this, this.entnum, this.enttype, this.classname, t);
+               done = it.m_read(this, isnew);
                break;
        ));
        time = savetime;
        if (!done)
        {
-               //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), this.enttype));
-               error(sprintf("Unknown entity type in CSQC_Ent_Update (enttype: %d, edict: %d, classname: %s)\n", this.enttype, num_for_edict(this), this.classname));
+               LOG_FATALF("CSQC_Ent_Update(%d) at %f with this=%i {.entnum=%d, .enttype=%d} t=%s (%d)\n", isnew, savetime, this, this.entnum, this.enttype, this.classname, t);
        }
  }
  
index f25a368fb472ac6be4427012bfb8a52a68f558c2,288c52566991c5484df7267886397067c33ca728..965e98068b49678439e74b030955cac3e5b9a6e6
@@@ -1002,12 -1002,14 +1002,14 @@@ vector HUD_DrawScoreboardAccuracyStats(
        float initial_posx = pos.x;
        int disownedcnt = 0;
        for (int i = WEP_FIRST; i <= WEP_LAST; ++i) {
-               setself(get_weaponinfo(i));
+               Weapon e = get_weaponinfo(i);
+               setself(e);
                if (!self.weapon) continue;
  
                int weapon_stats = weapon_accuracy[i - WEP_FIRST];
  
-               if (weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
+               WepSet set = e.m_wepset;
+               if (weapon_stats < 0 && !(weapons_stat & set || weapons_inmap & set))
                        ++disownedcnt;
        }
  
  
        int column = 0;
        for (int i = WEP_FIRST; i <= WEP_LAST; ++i) {
-               setself(get_weaponinfo(i));
+               Weapon e = get_weaponinfo(i);
+               setself(e);
                if (!self.weapon) continue;
                int weapon_stats = weapon_accuracy[i - WEP_FIRST];
  
-               if (weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
+               WepSet set = e.m_wepset;
+               if (weapon_stats < 0 && !(weapons_stat & set || weapons_inmap & set))
                        continue;
  
                float weapon_alpha;
@@@ -1133,12 -1137,12 +1137,12 @@@ vector HUD_DrawMapStats(vector pos, vec
        string val;
  
        // get monster stats
 -      stat_monsters_killed = getstatf(STAT_MONSTERS_KILLED);
 -      stat_monsters_total = getstatf(STAT_MONSTERS_TOTAL);
 +      stat_monsters_killed = STAT(MONSTERS_KILLED);
 +      stat_monsters_total = STAT(MONSTERS_TOTAL);
  
        // get secrets stats
 -      stat_secrets_found = getstatf(STAT_SECRETS_FOUND);
 -      stat_secrets_total = getstatf(STAT_SECRETS_TOTAL);
 +      stat_secrets_found = STAT(SECRETS_FOUND);
 +      stat_secrets_total = STAT(SECRETS_TOTAL);
  
        // get number of rows
        if(stat_secrets_total)
@@@ -1402,9 -1406,9 +1406,9 @@@ void HUD_DrawScoreboard(
        // Print info string
        float tl, fl, ll;
        str = sprintf(_("playing ^3%s^7 on ^2%s^7"), MapInfo_Type_ToText(gametype), shortmapname);
 -      tl = getstatf(STAT_TIMELIMIT);
 -      fl = getstatf(STAT_FRAGLIMIT);
 -      ll = getstatf(STAT_LEADLIMIT);
 +      tl = STAT(TIMELIMIT);
 +      fl = STAT(FRAGLIMIT);
 +      ll = STAT(LEADLIMIT);
        if(gametype == MAPINFO_TYPE_LMS)
        {
                if(tl > 0)
        drawcolorcodedstring(pos + '0.5 0 0' * (sbwidth - stringwidth(str, true, hud_fontsize)), str, hud_fontsize, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
  
        // print information about respawn status
 -      float respawn_time = getstatf(STAT_RESPAWN_TIME);
 +      float respawn_time = STAT(RESPAWN_TIME);
        if(!intermission)
        if(respawn_time)
        {
diff --combined qcsrc/client/view.qc
index 87adec58b0851a67b1e747068453e35e7cb39839,0f1a43e2faa21ec3a701a8266a407283f6148396..c98400df56760fb56814319b836458b39a0ecb44
@@@ -13,7 -13,7 +13,7 @@@
  #include "../common/debug.qh"
  #include "../common/mapinfo.qh"
  #include "../common/gamemodes/all.qh"
- #include "../common/nades/all.qh"
+ #include "../common/physics.qh"
  #include "../common/stats.qh"
  #include "../common/triggers/target/music.qh"
  #include "../common/teams.qh"
@@@ -360,9 -360,9 +360,9 @@@ float TrueAimCheck(
                        break;
        }
  
-       vector traceorigin = getplayerorigin(player_localentnum-1) + (eZ * getstati(STAT_VIEWHEIGHT));
+       vector traceorigin = entcs_receiver(player_localentnum - 1).origin + (eZ * getstati(STAT_VIEWHEIGHT));
  
 -      vecs = decompressShotOrigin(getstati(STAT_SHOTORG));
 +      vecs = decompressShotOrigin(STAT(SHOTORG));
  
        traceline(traceorigin, traceorigin + view_forward * MAX_SHOT_DISTANCE, mv, ta);
        trueaimpoint = trace_endpos;
@@@ -443,7 -443,7 +443,7 @@@ bool WantEventchase(
                        return true;
                if(MUTATOR_CALLHOOK(WantEventchase, self))
                        return true;
-               if(autocvar_cl_eventchase_nexball && gametype == MAPINFO_TYPE_NEXBALL && !(WepSet_GetFromStat() & WepSet_FromWeapon(WEP_NEXBALL.m_id)))
+               if(autocvar_cl_eventchase_nexball && gametype == MAPINFO_TYPE_NEXBALL && !(WepSet_GetFromStat() & WEPSET(NEXBALL)))
                        return true;
                if(autocvar_cl_eventchase_death && (getstati(STAT_HEALTH) <= 0))
                {
@@@ -475,12 -475,12 +475,12 @@@ void UpdateDamage(
  {
        // accumulate damage with each stat update
        static float damage_total_prev = 0;
 -      float damage_total = getstati(STAT_DAMAGE_DEALT_TOTAL);
 +      float damage_total = STAT(DAMAGE_DEALT_TOTAL);
        float unaccounted_damage_new = COMPARE_INCREASING(damage_total, damage_total_prev);
        damage_total_prev = damage_total;
  
        static float damage_dealt_time_prev = 0;
 -      float damage_dealt_time = getstatf(STAT_HIT_TIME);
 +      float damage_dealt_time = STAT(HIT_TIME);
        if (damage_dealt_time != damage_dealt_time_prev)
        {
                unaccounted_damage += unaccounted_damage_new;
@@@ -536,7 -536,7 +536,7 @@@ void HitSound(
        }
  
        static float typehit_time_prev = 0;
 -      float typehit_time = getstatf(STAT_TYPEHIT_TIME);
 +      float typehit_time = STAT(TYPEHIT_TIME);
        if (COMPARE_INCREASING(typehit_time, typehit_time_prev) > autocvar_cl_hitsound_antispam_time)
        {
                sound(world, CH_INFO, SND_TYPEHIT, VOL_BASE, ATTN_NONE);
@@@ -712,7 -712,7 +712,7 @@@ void HUD_Crosshair(
  
                if(autocvar_crosshair_pickup)
                {
 -                      float stat_pickup_time = getstatf(STAT_LAST_PICKUP);
 +                      float stat_pickup_time = STAT(LAST_PICKUP);
  
                        if(pickup_crosshair_time < stat_pickup_time)
                        {
                                ring_scale = autocvar_crosshair_ring_size;
  
                                float weapon_clipload, weapon_clipsize;
 -                              weapon_clipload = getstati(STAT_WEAPON_CLIPLOAD);
 -                              weapon_clipsize = getstati(STAT_WEAPON_CLIPSIZE);
 +                              weapon_clipload = STAT(WEAPON_CLIPLOAD);
 +                              weapon_clipsize = STAT(WEAPON_CLIPSIZE);
  
                                float ok_ammo_charge, ok_ammo_chargepool;
 -                              ok_ammo_charge = getstatf(STAT_OK_AMMO_CHARGE);
 -                              ok_ammo_chargepool = getstatf(STAT_OK_AMMO_CHARGEPOOL);
 +                              ok_ammo_charge = STAT(OK_AMMO_CHARGE);
 +                              ok_ammo_chargepool = STAT(OK_AMMO_CHARGEPOOL);
  
                                float vortex_charge, vortex_chargepool;
 -                              vortex_charge = getstatf(STAT_VORTEX_CHARGE);
 -                              vortex_chargepool = getstatf(STAT_VORTEX_CHARGEPOOL);
 +                              vortex_charge = STAT(VORTEX_CHARGE);
 +                              vortex_chargepool = STAT(VORTEX_CHARGEPOOL);
  
                                float arc_heat = STAT(ARC_HEAT);
  
                                }
                                else if (autocvar_crosshair_ring && activeweapon == WEP_MINE_LAYER.m_id && minelayer_maxmines && autocvar_crosshair_ring_minelayer)
                                {
 -                                      ring_value = bound(0, getstati(STAT_LAYED_MINES) / minelayer_maxmines, 1); // if you later need to use the count of bullets in another place, then add a float for it. For now, no need to.
 +                                      ring_value = bound(0, STAT(LAYED_MINES) / minelayer_maxmines, 1); // if you later need to use the count of bullets in another place, then add a float for it. For now, no need to.
                                        ring_alpha = autocvar_crosshair_ring_minelayer_alpha;
                                        ring_rgb = wcross_color;
                                        ring_image = "gfx/crosshair_ring.tga";
                                }
 -                              else if (activeweapon == WEP_HAGAR.m_id && getstati(STAT_HAGAR_LOAD) && autocvar_crosshair_ring_hagar)
 +                              else if (activeweapon == WEP_HAGAR.m_id && STAT(HAGAR_LOAD) && autocvar_crosshair_ring_hagar)
                                {
 -                                      ring_value = bound(0, getstati(STAT_HAGAR_LOAD) / hagar_maxrockets, 1);
 +                                      ring_value = bound(0, STAT(HAGAR_LOAD) / hagar_maxrockets, 1);
                                        ring_alpha = autocvar_crosshair_ring_hagar_alpha;
                                        ring_rgb = wcross_color;
                                        ring_image = "gfx/crosshair_ring.tga";
                                        wcross_color = stov(autocvar_crosshair_dot_color);
  
                                CROSSHAIR_DRAW(wcross_resolution * autocvar_crosshair_dot_size, "gfx/crosshairdot.tga", f * autocvar_crosshair_dot_alpha);
-                               // FIXME why don't we use wcross_alpha here?cl_notice_run();
+                               // FIXME why don't we use wcross_alpha here?
                                wcross_color = wcross_color_old;
                        }
                }
  
  void HUD_Draw()
  {
-       if(STAT(FROZEN))
-               drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, ((STAT(REVIVE_PROGRESS)) ? ('0.25 0.90 1' + ('1 0 0' * STAT(REVIVE_PROGRESS)) + ('0 1 1' * STAT(REVIVE_PROGRESS) * -1)) : '0.25 0.90 1'), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
-       else if (STAT(HEALING_ORB)>time)
-               drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, NADE_TYPE_HEAL.m_color, autocvar_hud_colorflash_alpha*STAT(HEALING_ORB_ALPHA), DRAWFLAG_ADDITIVE);
+       vector rgb = '0 0 0';
+       float a = 1;
+       if (MUTATOR_CALLHOOK(HUD_Draw_overlay))
+       {
+               rgb = MUTATOR_ARGV(0, vector);
+               a = MUTATOR_ARGV(0, float);
+       }
 -      else if(getstati(STAT_FROZEN))
++      else if(STAT(FROZEN))
+       {
 -              rgb = ((getstatf(STAT_REVIVE_PROGRESS)) ? ('0.25 0.90 1' + ('1 0 0' * getstatf(STAT_REVIVE_PROGRESS)) + ('0 1 1' * getstatf(STAT_REVIVE_PROGRESS) * -1)) : '0.25 0.90 1');
++              rgb = ((STAT(REVIVE_PROGRESS)) ? ('0.25 0.90 1' + ('1 0 0' * STAT(REVIVE_PROGRESS)) + ('0 1 1' * STAT(REVIVE_PROGRESS) * -1)) : '0.25 0.90 1');
+       }
+       drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, rgb, autocvar_hud_colorflash_alpha * a, DRAWFLAG_ADDITIVE);
        if(!intermission)
 -      if(getstatf(STAT_NADE_TIMER) && autocvar_cl_nade_timer) // give nade top priority, as it's a matter of life and death
 +      if(STAT(NADE_TIMER) && autocvar_cl_nade_timer) // give nade top priority, as it's a matter of life and death
        {
 -              DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_NADE_TIMER), '0.25 0.90 1' + ('1 0 0' * getstatf(STAT_NADE_TIMER)) - ('0 1 1' * getstatf(STAT_NADE_TIMER)), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
 +              DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", STAT(NADE_TIMER), '0.25 0.90 1' + ('1 0 0' * STAT(NADE_TIMER)) - ('0 1 1' * STAT(NADE_TIMER)), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
                drawstring_aspect(eY * 0.64 * vid_conheight, ((autocvar_cl_nade_timer == 2) ? _("Nade timer") : ""), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL);
        }
 -      else if(getstatf(STAT_REVIVE_PROGRESS))
 +      else if(STAT(REVIVE_PROGRESS))
        {
 -              DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
 +              DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", STAT(REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
                drawstring_aspect(eY * 0.64 * vid_conheight, _("Revival progress"), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL);
        }
  
@@@ -1045,9 -1053,7 +1053,7 @@@ float oldr_novis
  float oldr_useportalculling;
  float oldr_useinfinitefarclip;
  
- const int BUTTON_3 = 4;
- const int BUTTON_4 = 8;
- float cl_notice_run();
+ void cl_notice_run();
  float prev_myteam;
  int lasthud;
  float vh_notice_time;
@@@ -1065,7 -1071,7 +1071,7 @@@ void CSQC_UpdateView(float w, float h
        ++framecount;
  
        stats_get();
 -      hud = getstati(STAT_HUD);
 +      hud = STAT(HUD);
  
        if(hud != HUD_NORMAL && lasthud == HUD_NORMAL)
                vh_notice_time = time + autocvar_cl_vehicles_notify_time;
        else
                view_quality = 1;
  
-       button_attack2 = (input_buttons & BUTTON_3);
-       button_zoom = (input_buttons & BUTTON_4);
+       button_attack2 = PHYS_INPUT_BUTTON_ATCK2(self);
+       button_zoom = PHYS_INPUT_BUTTON_ZOOM(self);
  
        vf_size = getpropertyvec(VF_SIZE);
        vf_min = getpropertyvec(VF_MIN);
                prev_myteam = myteam;
        }
  
 -      ticrate = getstatf(STAT_MOVEVARS_TICRATE) * getstatf(STAT_MOVEVARS_TIMESCALE);
 +      ticrate = STAT(MOVEVARS_TICRATE) * STAT(MOVEVARS_TIMESCALE);
  
        float is_dead = (getstati(STAT_HEALTH) <= 0);
  
        if(autocvar_chase_active <= 0) // greater than 0 means it's enabled manually, and this code is skipped
        {
                float vehicle_chase = (hud != HUD_NORMAL && (autocvar_cl_eventchase_vehicle || spectatee_status > 0));
 -              float ons_roundlost = (gametype == MAPINFO_TYPE_ONSLAUGHT && getstati(STAT_ROUNDLOST));
 +              float ons_roundlost = (gametype == MAPINFO_TYPE_ONSLAUGHT && STAT(ROUNDLOST));
                entity gen = world;
  
                if(ons_roundlost)
        ColorTranslateMode = autocvar_cl_stripcolorcodes;
  
        // currently switching-to weapon (for crosshair)
 -      switchingweapon = getstati(STAT_SWITCHINGWEAPON);
 +      switchingweapon = STAT(SWITCHINGWEAPON);
  
        // actually active weapon (for zoom)
        activeweapon = getstati(STAT_ACTIVEWEAPON);
           mousepos = mousepos*0.5 + getmousepos();
         */
  
-       for(entity e = NULL; (e = nextent(e)); ) if (e.draw) {
-               WITH(entity, self, e, e.draw(e));
-       }
+       FOREACH_ENTITY(it.draw, LAMBDA(WITH(entity, self, it, it.draw(it))));
  
        addentities(MASK_NORMAL | MASK_ENGINE | MASK_ENGINEVIEWMODELS);
        renderscene();
                }
        }
  
 -      if(autocvar_hud_damage && !getstati(STAT_FROZEN))
 +      if(autocvar_hud_damage && !STAT(FROZEN))
        {
                splash_size.x = max(vid_conwidth, vid_conheight);
                splash_size.y = max(vid_conwidth, vid_conheight);
          } else */
  
        // draw 2D entities
-       for (entity e = NULL; (e = nextent(e)); ) if (e.draw2d) {
-               WITH(entity, self, e, e.draw2d(e));
-       }
+       FOREACH_ENTITY(it.draw2d, LAMBDA(WITH(entity, self, it, it.draw2d(it))));
        Draw_ShowNames_All();
        Debug_Draw();
  
index 7d8624df4cdd21b52ba6b84854101b004bb3a6b9,1ea5a8bff56aa213d54992e529f7030bc0a65efc..96368bd15d2901f6d141d5e499bb15fad5fbe5e8
@@@ -55,7 -55,6 +55,6 @@@ NET_HANDLE(_ENT_CLIENT_INIT, bool isnew
  /** Sent as a temp entity from a persistent linked entity */
  REGISTER_NET_TEMP(ENT_CLIENT_INIT)
  
- REGISTER_NET_LINKED(ENT_CLIENT_ENTCS)
  REGISTER_NET_LINKED(ENT_CLIENT_SCORES_INFO)
  REGISTER_NET_LINKED(ENT_CLIENT_SCORES)
  REGISTER_NET_LINKED(ENT_CLIENT_TEAMSCORES)
@@@ -164,34 -163,6 +163,6 @@@ const int SP_DMG = 10
  const int SP_DMGTAKEN = 11;
  // game mode specific indices are not in common/, but in server/scores_rules.qc!
  
- const int CH_INFO = 0;
- const int CH_TRIGGER = -3;
- const int CH_WEAPON_A = -1;
- const int CH_WEAPON_SINGLE = 1;
- const int CH_VOICE = -2;
- const int CH_BGM_SINGLE = 8;
- const int CH_AMBIENT = -9;
- const int CH_TRIGGER_SINGLE = 3;
- const int CH_SHOTS = -4;
- const int CH_SHOTS_SINGLE = 4;
- const int CH_WEAPON_B = -1;
- const int CH_PAIN = -6;
- const int CH_PAIN_SINGLE = 6;
- const int CH_PLAYER = -7;
- const int CH_PLAYER_SINGLE = 7;
- const int CH_TUBA_SINGLE = 5;
- const float ATTEN_NONE = 0;
- const float ATTEN_MIN = 0.015625;
- const float ATTEN_NORM = 0.5;
- const float ATTEN_LARGE = 1;
- const float ATTEN_IDLE = 2;
- const float ATTEN_STATIC = 3;
- const float ATTEN_MAX = 3.984375;
- const float VOL_BASE = 0.7;
- const float VOL_BASEVOICE = 1.0;
  // WEAPONTODO: move this into separate/new projectile handling code // this sets sounds and other properties of the projectiles in csqc
  const int PROJECTILE_ELECTRO = 1;
  const int PROJECTILE_ROCKET = 2;
@@@ -267,12 -238,22 +238,12 @@@ vector autocvar_sv_player_headsize = '2
  
  
  // not so constant
 -#ifdef SVQC
 -#define PL_VIEW_OFS autocvar_sv_player_viewoffset
 -#define PL_MIN autocvar_sv_player_mins
 -#define PL_MAX autocvar_sv_player_maxs
 -#define PL_CROUCH_VIEW_OFS autocvar_sv_player_crouch_viewoffset
 -#define PL_CROUCH_MIN autocvar_sv_player_crouch_mins
 -#define PL_CROUCH_MAX autocvar_sv_player_crouch_maxs
 -#define PL_HEAD autocvar_sv_player_headsize
 -#elif defined(CSQC)
 -#define PL_VIEW_OFS vec3(getstatf(STAT_PL_VIEW_OFS1), getstatf(STAT_PL_VIEW_OFS2), getstatf(STAT_PL_VIEW_OFS3))
 -#define PL_MIN vec3(getstatf(STAT_PL_MIN1), getstatf(STAT_PL_MIN2), getstatf(STAT_PL_MIN3))
 -#define PL_MAX vec3(getstatf(STAT_PL_MAX1), getstatf(STAT_PL_MAX2), getstatf(STAT_PL_MAX3))
 -#define PL_CROUCH_VIEW_OFS vec3(getstatf(STAT_PL_CROUCH_VIEW_OFS1), getstatf(STAT_PL_CROUCH_VIEW_OFS2), getstatf(STAT_PL_CROUCH_VIEW_OFS3))
 -#define PL_CROUCH_MIN vec3(getstatf(STAT_PL_CROUCH_MIN1), getstatf(STAT_PL_CROUCH_MIN2), getstatf(STAT_PL_CROUCH_MIN3))
 -#define PL_CROUCH_MAX vec3(getstatf(STAT_PL_CROUCH_MAX1), getstatf(STAT_PL_CROUCH_MAX2), getstatf(STAT_PL_CROUCH_MAX3))
 -#endif
 +#define PL_VIEW_OFS STAT(PL_VIEW_OFS, NULL)
 +#define PL_CROUCH_VIEW_OFS STAT(PL_CROUCH_VIEW_OFS, NULL)
 +#define PL_MIN STAT(PL_MIN, NULL)
 +#define PL_CROUCH_MIN STAT(PL_CROUCH_MIN, NULL)
 +#define PL_MAX STAT(PL_MAX, NULL)
 +#define PL_CROUCH_MAX STAT(PL_CROUCH_MAX, NULL)
  
  // a bit more constant
  const vector PL_MAX_CONST = '16 16 45';
index 8ffdb08f9e6533a177c1c30d3735291598307829,1850b460c7675a5a9a2499f6652e5f7b43aa9dbe..cc418df5e4da015f0a5600a41c6b66f5232ed58d
@@@ -2,7 -2,7 +2,7 @@@
  
  #ifdef IMPLEMENTATION
  #ifdef SVQC
 -.float metertime;
 +.float metertime = _STAT(NB_METERSTART);
  
  int autocvar_g_nexball_goalleadlimit;
  #define autocvar_g_nexball_goallimit cvar("g_nexball_goallimit")
@@@ -78,10 -78,10 +78,10 @@@ void LogNB(string mode, entity actor
        GameLogEcho(s);
  }
  
- void ball_restart()
- {SELFPARAM();
-       if(self.owner)
-               DropBall(self, self.owner.origin, '0 0 0');
+ void ball_restart(entity this)
+ {
+       if(this.owner)
+               DropBall(this, this.owner.origin, '0 0 0');
        ResetBall();
  }
  
@@@ -816,7 -816,7 +816,7 @@@ void W_Nexball_Attack2(
        W_SetupProjVelocity_Basic(missile, autocvar_g_balance_nexball_secondary_speed, 0);
        missile.angles = vectoangles(missile.velocity);
        missile.touch = W_Nexball_Touch;
-       missile.think = SUB_Remove;
+       missile.think = SUB_Remove_self;
        missile.nextthink = time + autocvar_g_balance_nexball_secondary_lifetime; //FIXME: use a distance instead?
  
        missile.effects = EF_BRIGHTFIELD | EF_LOWPRECISION;
@@@ -1072,6 -1072,7 +1072,6 @@@ REGISTER_MUTATOR(nb, g_nexball
                if(g_nexball_meter_period <= 0)
                        g_nexball_meter_period = 2; // avoid division by zero etc. due to silly users
                g_nexball_meter_period = rint(g_nexball_meter_period * 32) / 32; //Round to 1/32ths to send as a byte multiplied by 32
 -              addstat(STAT_NB_METERSTART, AS_FLOAT, metertime);
  
                // General settings
                /*
index 06465187a3d4d28a736b664dc99e4afa051aa44a,ae62e5db797d2a22cb9467fc41ff7e431d2f50e3..8c8237aeed626d99994af52dafedb48e06e4e93b
@@@ -76,7 -76,7 +76,7 @@@ bool ons_stalemate
  
  .float teleport_antispam;
  
 -.bool ons_roundlost;
 +.bool ons_roundlost = _STAT(ROUNDLOST);
  
  // waypoint sprites
  .entity bot_basewaypoint; // generator waypointsprite
@@@ -195,10 -195,10 +195,10 @@@ void ons_CaptureShield_Touch(
        }
  }
  
- void ons_CaptureShield_Reset()
- {SELFPARAM();
-       self.colormap = self.enemy.colormap;
-       self.team = self.enemy.team;
+ void ons_CaptureShield_Reset(entity this)
+ {
+       this.colormap = this.enemy.colormap;
+       this.team = this.enemy.team;
  }
  
  void ons_CaptureShield_Spawn(entity generator, bool is_generator)
@@@ -845,31 -845,31 +845,31 @@@ void ons_ControlPoint_Think(
        CSQCMODEL_AUTOUPDATE(self);
  }
  
- void ons_ControlPoint_Reset()
- {SELFPARAM();
-       if(self.goalentity)
-               remove(self.goalentity);
-       self.goalentity = world;
-       self.team = 0;
-       self.colormap = 1024;
-       self.iscaptured = false;
-       self.islinked = false;
-       self.isshielded = true;
-       self.think = ons_ControlPoint_Think;
-       self.ons_toucher = world;
-       self.nextthink = time + ONS_CP_THINKRATE;
-       setmodel_fixsize(self, MDL_ONS_CP_PAD1);
-       WaypointSprite_UpdateMaxHealth(self.sprite, 0);
-       WaypointSprite_UpdateRule(self.sprite,self.team,SPRITERULE_TEAMPLAY);
+ void ons_ControlPoint_Reset(entity this)
+ {
+       if(this.goalentity)
+               remove(this.goalentity);
+       this.goalentity = world;
+       this.team = 0;
+       this.colormap = 1024;
+       this.iscaptured = false;
+       this.islinked = false;
+       this.isshielded = true;
+       this.think = ons_ControlPoint_Think;
+       this.ons_toucher = world;
+       this.nextthink = time + ONS_CP_THINKRATE;
+       setmodel_fixsize(this, MDL_ONS_CP_PAD1);
+       WaypointSprite_UpdateMaxHealth(this.sprite, 0);
+       WaypointSprite_UpdateRule(this.sprite,this.team,SPRITERULE_TEAMPLAY);
  
        onslaught_updatelinks();
  
-       activator = self;
+       activator = this;
        SUB_UseTargets(); // to reset the structures, playerspawns etc.
  
-       CSQCMODEL_AUTOUPDATE(self);
+       CSQCMODEL_AUTOUPDATE(this);
  }
  
  void ons_DelayedControlPoint_Setup()
@@@ -1076,27 -1076,27 +1076,27 @@@ void ons_GeneratorThink(
        }
  }
  
- void ons_GeneratorReset()
- {SELFPARAM();
-       self.team = self.team_saved;
-       self.lasthealth = self.max_health = self.health = autocvar_g_onslaught_gen_health;
-       self.takedamage = DAMAGE_AIM;
-       self.bot_attack = true;
-       self.iscaptured = true;
-       self.islinked = true;
-       self.isshielded = true;
-       self.event_damage = ons_GeneratorDamage;
-       self.think = ons_GeneratorThink;
-       self.nextthink = time + GEN_THINKRATE;
-       Net_LinkEntity(self, false, 0, generator_send);
-       self.SendFlags = GSF_SETUP; // just incase
-       self.SendFlags |= GSF_STATUS;
-       WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
-       WaypointSprite_UpdateHealth(self.sprite, self.health);
-       WaypointSprite_UpdateRule(self.sprite,self.team,SPRITERULE_TEAMPLAY);
+ void ons_GeneratorReset(entity this)
+ {
+       this.team = this.team_saved;
+       this.lasthealth = this.max_health = this.health = autocvar_g_onslaught_gen_health;
+       this.takedamage = DAMAGE_AIM;
+       this.bot_attack = true;
+       this.iscaptured = true;
+       this.islinked = true;
+       this.isshielded = true;
+       this.event_damage = ons_GeneratorDamage;
+       this.think = ons_GeneratorThink;
+       this.nextthink = time + GEN_THINKRATE;
+       Net_LinkEntity(this, false, 0, generator_send);
+       this.SendFlags = GSF_SETUP; // just incase
+       this.SendFlags |= GSF_STATUS;
+       WaypointSprite_UpdateMaxHealth(this.sprite, this.max_health);
+       WaypointSprite_UpdateHealth(this.sprite, this.health);
+       WaypointSprite_UpdateRule(this.sprite,this.team,SPRITERULE_TEAMPLAY);
  
        onslaught_updatelinks();
  }
@@@ -2318,6 -2318,8 +2318,6 @@@ void ons_Initialize(
        g_onslaught = true;
        ons_captureshield_force = autocvar_g_onslaught_shield_force;
  
 -      addstat(STAT_ROUNDLOST, AS_INT, ons_roundlost);
 -
        InitializeEntity(world, ons_DelayedInit, INITPRIO_GAMETYPE);
  }
  
index 0000000000000000000000000000000000000000,db22d314115f510c7a58369af9c2c8b1d9678754..76ecff8be1bac913082922b65dc297de6d4ba10b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,73 +1,73 @@@
 -      .int buffs;
+ #ifndef BUFFS_ALL_H
+ #define BUFFS_ALL_H
+ // Welcome to the stuff behind the scenes
+ // Below, you will find the list of buffs
+ // Add new buffs here!
+ // Note: Buffs also need spawnfuncs, which are set below
+ #include "../../../teams.qh"
+ #include "../../../util.qh"
+ REGISTER_WAYPOINT(Buff, _("Buff"), '1 0.5 0', 1);
+ REGISTER_RADARICON(Buff, 1);
+ REGISTRY(Buffs, BITS(4))
+ #define Buffs_from(i) _Buffs_from(i, BUFF_Null)
+ REGISTER_REGISTRY(Buffs)
+ REGISTRY_CHECK(Buffs)
+ #define REGISTER_BUFF(id) \
+     REGISTER(Buffs, BUFF_##id, m_id, NEW(Buff)); \
+     REGISTER_INIT_POST(BUFF_##id) { \
+         this.netname = this.m_name; \
+         this.m_itemid = BIT(this.m_id - 1); \
+         this.m_sprite = strzone(strcat("buff-", this.m_name)); \
+     } \
+     REGISTER_INIT(BUFF_##id)
+ #include "../../../items/item/pickup.qh"
+ CLASS(Buff, Pickup)
+       /** bit index */
+       ATTRIB(Buff, m_itemid, int, 0)
+       ATTRIB(Buff, m_name, string, "buff")
+       ATTRIB(Buff, m_color, vector, '1 1 1')
+       ATTRIB(Buff, m_prettyName, string, "Buff")
+       ATTRIB(Buff, m_skin, int, 0)
+       ATTRIB(Buff, m_sprite, string, "")
+       METHOD(Buff, display, void(entity this, void(string name, string icon) returns)) {
+               returns(this.m_prettyName, sprintf("/gfx/hud/%s/buff_%s", cvar_string("menu_skin"), this.m_name));
+       }
+ #ifdef SVQC
+       METHOD(Buff, m_time, float(Buff this))
+       { return cvar(strcat("g_buffs_", this.netname, "_time")); }
+ #endif
+ ENDCLASS(Buff)
+ #ifdef SVQC
++      // .int buffs = _STAT(BUFFS);
+       void buff_Init(entity ent);
+       void buff_Init_Compat(entity ent, entity replacement);
+       #define BUFF_SPAWNFUNC(e, b, t) spawnfunc(item_buff_##e) { \
+               self.buffs = b.m_itemid; \
+               self.team = t; \
+               buff_Init(self); \
+       }
+       #define BUFF_SPAWNFUNCS(e, b)                       \
+                       BUFF_SPAWNFUNC(e,           b,  0)          \
+                       BUFF_SPAWNFUNC(e##_team1,   b,  NUM_TEAM_1) \
+                       BUFF_SPAWNFUNC(e##_team2,   b,  NUM_TEAM_2) \
+                       BUFF_SPAWNFUNC(e##_team3,   b,  NUM_TEAM_3) \
+                       BUFF_SPAWNFUNC(e##_team4,   b,  NUM_TEAM_4)
+       #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r) spawnfunc(item_##o) { buff_Init_Compat(self, r); }
+ #else
+       #define BUFF_SPAWNFUNC(e, b, t)
+       #define BUFF_SPAWNFUNCS(e, b)
+       #define BUFF_SPAWNFUNC_Q3TA_COMPAT(o, r)
+ #endif
+ REGISTER_BUFF(Null);
+ BUFF_SPAWNFUNCS(random, BUFF_Null)
+ #include "all.inc"
+ #endif
index fbddd037bc140942d562f267f50c152dde95c8d0,9eb113a96ff86355b809b690b43ceaff159cc79e..dbabdd2e2f49bc427b245329c593bf569be42f31
@@@ -75,15 -75,17 +75,14 @@@ const vector BUFF_MAX = ('16 16 20')
  
  #include "../../../triggers/target/music.qh"
  #include "../../../gamemodes/all.qh"
- #include "../../../buffs/all.qh"
  
 -.float buff_time;
 +.float buff_time = _STAT(BUFF_TIME);
  void buffs_DelayedInit();
  
  REGISTER_MUTATOR(buffs, cvar("g_buffs"))
  {
        MUTATOR_ONADD
        {
 -              addstat(STAT_BUFFS, AS_INT, buffs);
 -              addstat(STAT_BUFF_TIME, AS_FLOAT, buff_time);
 -
                InitializeEntity(world, buffs_DelayedInit, INITPRIO_FINDTARGET);
        }
  }
@@@ -379,17 -381,17 +378,17 @@@ void buff_Waypoint_Reset(
        if(self.buff_activetime) { buff_Waypoint_Spawn(self); }
  }
  
- void buff_Reset()
- {SELFPARAM();
+ void buff_Reset(entity this)
+ {
        if(autocvar_g_buffs_randomize)
-               buff_NewType(self, self.buffs);
-       self.owner = world;
+               buff_NewType(this, this.buffs);
+       this.owner = world;
        buff_SetCooldown(autocvar_g_buffs_cooldown_activate);
        buff_Waypoint_Reset();
-       self.buff_activetime_updated = false;
+       this.buff_activetime_updated = false;
  
-       if(autocvar_g_buffs_random_location || (self.spawnflags & 64))
-               buff_Respawn(self);
+       if(autocvar_g_buffs_random_location || (this.spawnflags & 64))
+               buff_Respawn(this);
  }
  
  float buff_Customize()
@@@ -786,6 -788,11 +785,11 @@@ MUTATOR_HOOKFUNCTION(buffs, CustomizeWa
  
  MUTATOR_HOOKFUNCTION(buffs, OnEntityPreSpawn, CBC_ORDER_LAST)
  {SELFPARAM();
+       if (self.classname == "item_flight" && cvar("g_buffs") && cvar("g_buffs_flight"))
+       {
+               buff_Init_Compat(self, BUFF_FLIGHT);
+               return true;
+       }
        if(autocvar_g_buffs_replace_powerups)
        switch(self.classname)
        {
index 89d31a1b317fc9e86f3fe59509d5a68b0a10ca4c,5f24f627e7a5879b06dc1a98cecffec9d1b256ca..be00977148ef05ad8bdf2a55ff534454c8305e65
@@@ -1,3 -1,46 +1,46 @@@
+ #include "all.qc"
  #ifdef SVQC
  #include "buffs.qc"
  #endif
 -    int allBuffs = getstati(STAT_BUFFS, 0, 24);
+ #ifdef IMPLEMENTATION
+ string BUFF_NAME(int i)
+ {
+     Buff b = Buffs_from(i);
+     return sprintf("%s%s", rgb_to_hexcolor(b.m_color), b.m_prettyName);
+ }
+ #ifndef MENUQC
+ REGISTER_MUTATOR(buffs_flight, true);
+ MUTATOR_HOOKFUNCTION(buffs_flight, IsFlying)
+ {
+     noref entity e = MUTATOR_ARGV(0, entity);
+       return BUFFS_STAT(e) & BUFF_FLIGHT.m_itemid;
+ }
+ #endif
+ #ifdef CSQC
+ REGISTER_MUTATOR(cl_buffs, true);
+ MUTATOR_HOOKFUNCTION(cl_buffs, HUD_Powerups_add)
+ {
 -              addPowerupItem(it.m_prettyName, strcat("buff_", it.m_name), it.m_color, bound(0, getstatf(STAT_BUFF_TIME) - time, 99), 60);
++    int allBuffs = STAT(BUFFS);
+     FOREACH(Buffs, it.m_itemid & allBuffs, LAMBDA(
++              addPowerupItem(it.m_prettyName, strcat("buff_", it.m_name), it.m_color, bound(0, STAT(BUFF_TIME) - time, 99), 60);
+       ));
+ }
+ MUTATOR_HOOKFUNCTION(cl_buffs, WP_Format)
+ {
+     entity this = MUTATOR_ARGV(0, entity);
+     string s = MUTATOR_ARGV(0, string);
+     if (s == WP_Buff.netname || s == RADARICON_Buff.netname)
+     {
+         Buff b = Buffs_from(this.wp_extra);
+         MUTATOR_ARGV(0, vector) = b.m_color;
+         MUTATOR_ARGV(0, string) = b.m_prettyName;
+         return true;
+     }
+ }
+ #endif
+ #endif
index 0c3018699431d10d87b8f631e5e1f4e5b63bb0b4,12a53ff1392bef5bffb9e2efb89f1a60541b7573..ec57e94c1e63b63bb2b6f73a3a4ea013d56cd415
- #ifndef MUTATOR_NADES_H
- #define MUTATOR_NADES_H
+ #include "nades.qh"
  
- #ifdef SVQC
- #include "../../../../server/mutators/mutator/gamemode_freezetag.qc"
+ #ifdef IMPLEMENTATION
+ #ifndef MENUQC
+ entity Nade_TrailEffect(int proj, int nade_team)
+ {
+     switch (proj)
+     {
+         case PROJECTILE_NADE:       return EFFECT_NADE_TRAIL(nade_team);
+         case PROJECTILE_NADE_BURN:  return EFFECT_NADE_TRAIL_BURN(nade_team);
+     }
+     FOREACH(Nades, true, LAMBDA(
+         for (int j = 0; j < 2; j++)
+         {
+             if (it.m_projectile[j] == proj)
+             {
+                 string trail = it.m_trail[j].eent_eff_name;
+                 if (trail) return it.m_trail[j];
+                 break;
+             }
+         }
+     ));
+     return EFFECT_Null;
+ }
  #endif
  
- .entity nade;
- .entity fake_nade;
- .float nade_timer = _STAT(NADE_TIMER);
- .float nade_refire;
- .float bonus_nades = _STAT(NADE_BONUS);
- .float nade_special_time;
- .float bonus_nade_score = _STAT(NADE_BONUS_SCORE);
- .int nade_type = _STAT(NADE_BONUS_TYPE);
- .string pokenade_type;
- .entity nade_damage_target;
- .float cvar_cl_nade_type;
- .string cvar_cl_pokenade_type;
- .float toss_time;
- .float stat_healing_orb = _STAT(HEALING_ORB);
- .float stat_healing_orb_alpha = _STAT(HEALING_ORB_ALPHA);
- .float nade_show_particles;
- // Remove nades that are being thrown
- void nades_Clear(entity player);
- // Give a bonus grenade to a player
- void(entity player, float score) nades_GiveBonus;
- /**
-  * called to adjust nade damage and force on hit
-  */
- #define EV_Nade_Damage(i, o) \
-       /** weapon */ i(entity, MUTATOR_ARGV_0_entity) \
-     /** force */  i(vector, MUTATOR_ARGV_0_vector) \
-     /**/          o(vector, MUTATOR_ARGV_0_vector) \
-       /** damage */ i(float,  MUTATOR_ARGV_0_float) \
-     /**/          o(float,  MUTATOR_ARGV_0_float) \
-     /**/
- MUTATOR_HOOKABLE(Nade_Damage, EV_Nade_Damage);
+ #ifdef CSQC
+ REGISTER_MUTATOR(cl_nades, true);
+ MUTATOR_HOOKFUNCTION(cl_nades, HUD_Draw_overlay)
+ {
 -      if (getstatf(STAT_HEALING_ORB) <= time) return false;
++      if (STAT(HEALING_ORB) <= time) return false;
+       MUTATOR_ARGV(0, vector) = NADE_TYPE_HEAL.m_color;
 -      MUTATOR_ARGV(0, float) = getstatf(STAT_HEALING_ORB_ALPHA);
++      MUTATOR_ARGV(0, float) = STAT(HEALING_ORB_ALPHA);
+       return true;
+ }
+ MUTATOR_HOOKFUNCTION(cl_nades, Ent_Projectile)
+ {
+       if (self.cnt == PROJECTILE_NAPALM_FOUNTAIN)
+       {
+               self.modelindex = 0;
+               self.traileffect = EFFECT_FIREBALL.m_id;
+               return true;
+       }
+       if (Nade_FromProjectile(self.cnt) != NADE_TYPE_Null)
+       {
+               setmodel(self, MDL_PROJECTILE_NADE);
+               entity trail = Nade_TrailEffect(self.cnt, self.team);
+               if (trail.eent_eff_name) self.traileffect = trail.m_id;
+               return true;
+       }
+ }
+ MUTATOR_HOOKFUNCTION(cl_nades, EditProjectile)
+ {
+       if (self.cnt == PROJECTILE_NAPALM_FOUNTAIN)
+       {
+               loopsound(self, CH_SHOTS_SINGLE, SND(FIREBALL_FLY2), VOL_BASE, ATTEN_NORM);
+               self.mins = '-16 -16 -16';
+               self.maxs = '16 16 16';
+       }
+       entity nade_type = Nade_FromProjectile(self.cnt);
+       if (nade_type == NADE_TYPE_Null) return;
+       self.mins = '-16 -16 -16';
+       self.maxs = '16 16 16';
+       self.colormod = nade_type.m_color;
+       self.move_movetype = MOVETYPE_BOUNCE;
+       self.move_touch = func_null;
+       self.scale = 1.5;
+       self.avelocity = randomvec() * 720;
+       if (nade_type == NADE_TYPE_TRANSLOCATE || nade_type == NADE_TYPE_SPAWN)
+               self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+       else
+               self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
+ }
+ bool Projectile_isnade(int p)
+ {
+       return Nade_FromProjectile(p) != NADE_TYPE_Null;
+ }
+ void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time)
+ {
 -      float bonusNades    = getstatf(STAT_NADE_BONUS);
 -      float bonusProgress = getstatf(STAT_NADE_BONUS_SCORE);
 -      float bonusType     = getstati(STAT_NADE_BONUS_TYPE);
++      float bonusNades    = STAT(NADE_BONUS);
++      float bonusProgress = STAT(NADE_BONUS_SCORE);
++      float bonusType     = STAT(NADE_BONUS_TYPE);
+       Nade def = Nades_from(bonusType);
+       vector nadeColor    = def.m_color;
+       string nadeIcon     = def.m_icon;
+       vector iconPos, textPos;
+       if(autocvar_hud_panel_ammo_iconalign)
+       {
+               iconPos = myPos + eX * 2 * mySize.y;
+               textPos = myPos;
+       }
+       else
+       {
+               iconPos = myPos;
+               textPos = myPos + eX * mySize.y;
+       }
+       if(bonusNades > 0 || bonusProgress > 0)
+       {
+               DrawNadeProgressBar(myPos, mySize, bonusProgress, nadeColor);
+               if(autocvar_hud_panel_ammo_text)
+                       drawstring_aspect(textPos, ftos(bonusNades), eX * (2/3) * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               if(draw_expanding)
+                       drawpic_aspect_skin_expanding(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL, expand_time);
  
+               drawpic_aspect_skin(iconPos, nadeIcon, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       }
+ }
  #endif
  
- #ifdef IMPLEMENTATION
+ #ifdef SVQC
  
- #include "../../../nades/all.qh"
  #include "../../../gamemodes/all.qh"
  #include "../../../monsters/spawn.qh"
  #include "../../../monsters/sv_monsters.qh"
  #include "../../../../server/g_subs.qh"
  
 -REGISTER_MUTATOR(nades, cvar("g_nades"))
 -{
 -      MUTATOR_ONADD
 -      {
 -              addstat(STAT_NADE_TIMER, AS_FLOAT, nade_timer);
 -              addstat(STAT_NADE_BONUS, AS_FLOAT, bonus_nades);
 -              addstat(STAT_NADE_BONUS_TYPE, AS_INT, nade_type);
 -              addstat(STAT_NADE_BONUS_SCORE, AS_FLOAT, bonus_nade_score);
 -              addstat(STAT_HEALING_ORB, AS_FLOAT, stat_healing_orb);
 -              addstat(STAT_HEALING_ORB_ALPHA, AS_FLOAT, stat_healing_orb_alpha);
 -      }
 -
 -      return false;
 -}
 +REGISTER_MUTATOR(nades, cvar("g_nades"));
  
  .float nade_time_primed;
  
@@@ -871,7 -958,7 +945,7 @@@ void nade_prime(
        fn.colormod = Nades_from(n.nade_type).m_color;
        fn.colormap = self.colormap;
        fn.glowmod = self.glowmod;
-       fn.think = SUB_Remove;
+       fn.think = SUB_Remove_self;
        fn.nextthink = n.wait;
  
        self.nade = n;
@@@ -1233,3 -1320,4 +1307,4 @@@ MUTATOR_HOOKFUNCTION(nades, BuildMutato
        return false;
  }
  #endif
+ #endif
index 0000000000000000000000000000000000000000,2e4829354ac67b8081cf5af0dd7b6f1bb9361237..312cf4ae2dd606e1013890c552db826f261b1b1c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,103 +1,103 @@@
 -.float nade_timer;
+ #ifndef NADES_ALL_H
+ #define NADES_ALL_H
+ #include "../../../teams.qh"
+ // use slots 70-100
+ const int PROJECTILE_NADE = 71;
+ const int PROJECTILE_NADE_BURN = 72;
+ const int PROJECTILE_NADE_NAPALM = 73;
+ const int PROJECTILE_NADE_NAPALM_BURN = 74;
+ const int PROJECTILE_NAPALM_FOUNTAIN = 75;
+ const int PROJECTILE_NADE_ICE = 76;
+ const int PROJECTILE_NADE_ICE_BURN = 77;
+ const int PROJECTILE_NADE_TRANSLOCATE = 78;
+ const int PROJECTILE_NADE_SPAWN = 79;
+ const int PROJECTILE_NADE_HEAL = 80;
+ const int PROJECTILE_NADE_HEAL_BURN = 81;
+ const int PROJECTILE_NADE_MONSTER = 82;
+ const int PROJECTILE_NADE_MONSTER_BURN = 83;
+ REGISTRY(Nades, BITS(4))
+ #define Nades_from(i) _Nades_from(i, NADE_TYPE_Null)
+ REGISTER_REGISTRY(Nades)
+ REGISTRY_CHECK(Nades)
+ #define REGISTER_NADE(id) REGISTER(Nades, NADE_TYPE, id, m_id, NEW(Nade))
+ CLASS(Nade, Object)
+     ATTRIB(Nade, m_id, int, 0)
+     ATTRIB(Nade, m_color, vector, '0 0 0')
+     ATTRIB(Nade, m_name, string, _("Grenade"))
+     ATTRIB(Nade, m_icon, string, "nade_normal")
+     ATTRIBARRAY(Nade, m_projectile, int, 2)
+     ATTRIBARRAY(Nade, m_trail, entity, 2)
+     METHOD(Nade, display, void(entity this, void(string name, string icon) returns)) {
+         returns(this.m_name, sprintf("/gfx/hud/%s/%s", cvar_string("menu_skin"), this.m_icon));
+     }
+ ENDCLASS(Nade)
+ REGISTER_NADE(Null);
+ Nade Nade_FromProjectile(int proj)
+ {
+     FOREACH(Nades, true, LAMBDA(
+         for (int j = 0; j < 2; j++)
+         {
+             if (it.m_projectile[j] == proj) return it;
+         }
+     ));
+     return NADE_TYPE_Null;
+ }
+ #ifndef MENUQC
+ #include "effects.inc"
+ #endif
+ #include "nades.inc"
+ .float healer_lifetime;
+ .float healer_radius;
+ #ifdef SVQC
+ .entity nade;
+ .entity fake_nade;
 -.float bonus_nades;
++.float nade_timer = _STAT(NADE_TIMER);
+ .float nade_refire;
 -.float bonus_nade_score;
 -.float nade_type;
++.float bonus_nades = _STAT(NADE_BONUS);
+ .float nade_special_time;
 -.float stat_healing_orb;
 -.float stat_healing_orb_alpha;
++.float bonus_nade_score = _STAT(NADE_BONUS_SCORE);
++.int nade_type = _STAT(NADE_BONUS_TYPE);
+ .string pokenade_type;
+ .entity nade_damage_target;
+ .float cvar_cl_nade_type;
+ .string cvar_cl_pokenade_type;
+ .float toss_time;
++.float stat_healing_orb = _STAT(HEALING_ORB);
++.float stat_healing_orb_alpha = _STAT(HEALING_ORB_ALPHA);
+ .float nade_show_particles;
+ bool healer_send(entity this, entity to, int sf);
+ // Remove nades that are being thrown
+ void nades_Clear(entity player);
+ // Give a bonus grenade to a player
+ void(entity player, float score) nades_GiveBonus;
+ /**
+  * called to adjust nade damage and force on hit
+  */
+ #define EV_Nade_Damage(i, o) \
+       /** weapon */ i(entity, MUTATOR_ARGV_0_entity) \
+     /** force */  i(vector, MUTATOR_ARGV_0_vector) \
+     /**/          o(vector, MUTATOR_ARGV_0_vector) \
+       /** damage */ i(float,  MUTATOR_ARGV_0_float) \
+     /**/          o(float,  MUTATOR_ARGV_0_float) \
+     /**/
+ MUTATOR_HOOKABLE(Nade_Damage, EV_Nade_Damage);
+ #endif
+ #endif
index 987074f49cb97d6d6297e23bf605966d887bbbde,151e094c9eb72ce16b0cabfb86c0182f1c32d75b..5528bdf80bb8bdca536eb7eb1b8b6b6da19f32fe
@@@ -14,8 -14,8 +14,8 @@@ float autocvar_g_overkill_ammo_charge_l
  
  .float ok_notice_time;
  .float ammo_charge[Weapons_MAX];
 -.float ok_use_ammocharge;
 -.float ok_ammo_charge;
 +.float ok_use_ammocharge = _STAT(OK_AMMO_CHARGE);
 +.float ok_ammo_charge = _STAT(OK_AMMO_CHARGEPOOL);
  
  .float ok_pauseregen_finished;
  
@@@ -260,8 -260,8 +260,8 @@@ MUTATOR_HOOKFUNCTION(ok, PlayerSpawn
        return false;
  }
  
- void _spawnfunc_weapon_hmg() { SELFPARAM(); spawnfunc_weapon_hmg(this); }
- void _spawnfunc_weapon_rpc() { SELFPARAM(); spawnfunc_weapon_rpc(this); }
+ void self_spawnfunc_weapon_hmg() { SELFPARAM(); spawnfunc_weapon_hmg(this); }
+ void self_spawnfunc_weapon_rpc() { SELFPARAM(); spawnfunc_weapon_rpc(this); }
  
  MUTATOR_HOOKFUNCTION(ok, OnEntityPreSpawn)
  {SELFPARAM();
                        wep.team = self.team;
                        wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
                        wep.pickup_anyway = true;
-                       wep.think = _spawnfunc_weapon_hmg;
+                       wep.think = self_spawnfunc_weapon_hmg;
                        wep.nextthink = time + 0.1;
                        return true;
                }
                        wep.team = self.team;
                        wep.respawntime = autocvar_g_overkill_superguns_respawn_time;
                        wep.pickup_anyway = true;
-                       wep.think = _spawnfunc_weapon_rpc;
+                       wep.think = self_spawnfunc_weapon_rpc;
                        wep.nextthink = time + 0.1;
                        return true;
                }
@@@ -372,6 -372,9 +372,6 @@@ void ok_Initialize(
  
        precache_all_playermodels("models/ok_player/*.dpm");
  
 -      addstat(STAT_OK_AMMO_CHARGE, AS_FLOAT, ok_use_ammocharge);
 -      addstat(STAT_OK_AMMO_CHARGEPOOL, AS_FLOAT, ok_ammo_charge);
 -
        WEP_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
        WEP_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
  
diff --combined qcsrc/common/physics.qc
index 71bc63e1beb059b28eef78d6bb5864dc52d74a57,63e7ae7e91dae4ee1caa28bf8d66ea993c1c2454..0526742b4a56c6c8ceef92c00b4db5e5ac07e959
@@@ -30,37 -30,147 +30,37 @@@ float Physics_ClientOption(entity pl, s
        return cvar(strcat("sv_", option));
  }
  
 -void Physics_AddStats()
 +void Physics_UpdateStats(entity this, float maxspd_mod)
  {
 -      // 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_CL_TRACK_CANJUMP, AS_INT, cvar_cl_movement_track_canjump);
 -      addstat(STAT_MOVEVARS_TRACK_CANJUMP, AS_INT, stat_sv_track_canjump);
 -
 -      // double jump
 -      addstat(STAT_DOUBLEJUMP, AS_INT, stat_doublejump);
 -
 -      // jump speed caps
 -      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);
 -
 -      // new properties
 -      addstat(STAT_MOVEVARS_JUMPVELOCITY, AS_FLOAT, stat_sv_jumpvelocity);
 -      addstat(STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, AS_FLOAT, stat_sv_airaccel_qw_stretchfactor);
 -      addstat(STAT_MOVEVARS_MAXAIRSTRAFESPEED, AS_FLOAT, stat_sv_maxairstrafespeed);
 -      addstat(STAT_MOVEVARS_MAXAIRSPEED, AS_FLOAT, stat_sv_maxairspeed);
 -      addstat(STAT_MOVEVARS_AIRSTRAFEACCELERATE, AS_FLOAT, stat_sv_airstrafeaccelerate);
 -      addstat(STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL, AS_FLOAT, stat_sv_warsowbunny_turnaccel);
 -      addstat(STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, AS_FLOAT, stat_sv_airaccel_sideways_friction);
 -      addstat(STAT_MOVEVARS_AIRCONTROL, AS_FLOAT, stat_sv_aircontrol);
 -      addstat(STAT_MOVEVARS_AIRCONTROL_POWER, AS_FLOAT, stat_sv_aircontrol_power);
 -      addstat(STAT_MOVEVARS_AIRCONTROL_PENALTY, AS_FLOAT, stat_sv_aircontrol_penalty);
 -      addstat(STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL, AS_FLOAT, stat_sv_warsowbunny_airforwardaccel);
 -      addstat(STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED, AS_FLOAT, stat_sv_warsowbunny_topspeed);
 -      addstat(STAT_MOVEVARS_WARSOWBUNNY_ACCEL, AS_FLOAT, stat_sv_warsowbunny_accel);
 -      addstat(STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO, AS_FLOAT, stat_sv_warsowbunny_backtosideratio);
 -      addstat(STAT_MOVEVARS_FRICTION, AS_FLOAT, stat_sv_friction);
 -      addstat(STAT_MOVEVARS_ACCELERATE, AS_FLOAT, stat_sv_accelerate);
 -      addstat(STAT_MOVEVARS_STOPSPEED, AS_FLOAT, stat_sv_stopspeed);
 -      addstat(STAT_MOVEVARS_AIRACCELERATE, AS_FLOAT, stat_sv_airaccelerate);
 -      addstat(STAT_MOVEVARS_AIRSTOPACCELERATE, AS_FLOAT, stat_sv_airstopaccelerate);
 -
 -      addstat(STAT_GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND, AS_INT, stat_gameplayfix_upvelocityclearsonground);
 -}
 -
 -void Physics_UpdateStats(float maxspd_mod)
 -{SELFPARAM();
 -      // 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(Physics_ClientOption(self, "airaccel_qw"), maxspd_mod);
 -      if(Physics_ClientOption(self, "airstrafeaccel_qw"))
 -              self.stat_sv_airstrafeaccel_qw = AdjustAirAccelQW(Physics_ClientOption(self, "airstrafeaccel_qw"), maxspd_mod);
 -      else
 -              self.stat_sv_airstrafeaccel_qw = 0;
 -      self.stat_sv_airspeedlimit_nonqw = Physics_ClientOption(self, "airspeedlimit_nonqw") * maxspd_mod;
 -      self.stat_sv_maxspeed = Physics_ClientOption(self, "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_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;
 -
 +      STAT(MOVEVARS_AIRACCEL_QW, this) = AdjustAirAccelQW(Physics_ClientOption(this, "airaccel_qw"), maxspd_mod);
 +      STAT(MOVEVARS_AIRSTRAFEACCEL_QW, this) = (Physics_ClientOption(this, "airstrafeaccel_qw"))
 +              ? AdjustAirAccelQW(Physics_ClientOption(this, "airstrafeaccel_qw"), maxspd_mod)
 +              : 0;
 +      STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW, this) = Physics_ClientOption(this, "airspeedlimit_nonqw") * maxspd_mod;
 +      STAT(MOVEVARS_MAXSPEED, this) = Physics_ClientOption(this, "maxspeed") * maxspd_mod; // also slow walking
  
        // old stats
        // fix some new settings
 -      self.stat_sv_airaccel_qw_stretchfactor = Physics_ClientOption(self, "airaccel_qw_stretchfactor");
 -      self.stat_sv_maxairstrafespeed = Physics_ClientOption(self, "maxairstrafespeed");
 -      self.stat_sv_maxairspeed = Physics_ClientOption(self, "maxairspeed");
 -      self.stat_sv_airstrafeaccelerate = Physics_ClientOption(self, "airstrafeaccelerate");
 -      self.stat_sv_warsowbunny_turnaccel = Physics_ClientOption(self, "warsowbunny_turnaccel");
 -      self.stat_sv_airaccel_sideways_friction = Physics_ClientOption(self, "airaccel_sideways_friction");
 -      self.stat_sv_aircontrol = Physics_ClientOption(self, "aircontrol");
 -      self.stat_sv_aircontrol_power = Physics_ClientOption(self, "aircontrol_power");
 -      self.stat_sv_aircontrol_penalty = Physics_ClientOption(self, "aircontrol_penalty");
 -      self.stat_sv_warsowbunny_airforwardaccel = Physics_ClientOption(self, "warsowbunny_airforwardaccel");
 -      self.stat_sv_warsowbunny_topspeed = Physics_ClientOption(self, "warsowbunny_topspeed");
 -      self.stat_sv_warsowbunny_accel = Physics_ClientOption(self, "warsowbunny_accel");
 -      self.stat_sv_warsowbunny_backtosideratio = Physics_ClientOption(self, "warsowbunny_backtosideratio");
 -      self.stat_sv_friction = Physics_ClientOption(self, "friction");
 -      self.stat_sv_accelerate = Physics_ClientOption(self, "accelerate");
 -      self.stat_sv_stopspeed = Physics_ClientOption(self, "stopspeed");
 -      self.stat_sv_airaccelerate = Physics_ClientOption(self, "airaccelerate");
 -      self.stat_sv_airstopaccelerate = Physics_ClientOption(self, "airstopaccelerate");
 -      self.stat_sv_jumpvelocity = Physics_ClientOption(self, "jumpvelocity");
 -
 -      self.stat_sv_track_canjump = Physics_ClientOption(self, "track_canjump");
 -
 -      self.stat_gameplayfix_upvelocityclearsonground = UPWARD_VELOCITY_CLEARS_ONGROUND;
 +      STAT(MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, this) = Physics_ClientOption(this, "airaccel_qw_stretchfactor");
 +      STAT(MOVEVARS_MAXAIRSTRAFESPEED, this) = Physics_ClientOption(this, "maxairstrafespeed");
 +      STAT(MOVEVARS_MAXAIRSPEED, this) = Physics_ClientOption(this, "maxairspeed");
 +      STAT(MOVEVARS_AIRSTRAFEACCELERATE, this) = Physics_ClientOption(this, "airstrafeaccelerate");
 +      STAT(MOVEVARS_WARSOWBUNNY_TURNACCEL, this) = Physics_ClientOption(this, "warsowbunny_turnaccel");
 +      STAT(MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, this) = Physics_ClientOption(this, "airaccel_sideways_friction");
 +      STAT(MOVEVARS_AIRCONTROL, this) = Physics_ClientOption(this, "aircontrol");
 +      STAT(MOVEVARS_AIRCONTROL_POWER, this) = Physics_ClientOption(this, "aircontrol_power");
 +      STAT(MOVEVARS_AIRCONTROL_PENALTY, this) = Physics_ClientOption(this, "aircontrol_penalty");
 +      STAT(MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL, this) = Physics_ClientOption(this, "warsowbunny_airforwardaccel");
 +      STAT(MOVEVARS_WARSOWBUNNY_TOPSPEED, this) = Physics_ClientOption(this, "warsowbunny_topspeed");
 +      STAT(MOVEVARS_WARSOWBUNNY_ACCEL, this) = Physics_ClientOption(this, "warsowbunny_accel");
 +      STAT(MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO, this) = Physics_ClientOption(this, "warsowbunny_backtosideratio");
 +      STAT(MOVEVARS_FRICTION, this) = Physics_ClientOption(this, "friction");
 +      STAT(MOVEVARS_ACCELERATE, this) = Physics_ClientOption(this, "accelerate");
 +      STAT(MOVEVARS_STOPSPEED, this) = Physics_ClientOption(this, "stopspeed");
 +      STAT(MOVEVARS_AIRACCELERATE, this) = Physics_ClientOption(this, "airaccelerate");
 +      STAT(MOVEVARS_AIRSTOPACCELERATE, this) = Physics_ClientOption(this, "airstopaccelerate");
 +      STAT(MOVEVARS_JUMPVELOCITY, this) = Physics_ClientOption(this, "jumpvelocity");
 +      STAT(MOVEVARS_TRACK_CANJUMP, this) = Physics_ClientOption(this, "track_canjump");
  }
  #endif
  
@@@ -82,113 -192,108 +82,108 @@@ float GeomLerp(float a, float lerp, flo
  
  noref float pmove_waterjumptime;
  
- const float unstick_count = 27;
- vector unstick_offsets[unstick_count] =
+ #define unstick_offsets(X) \
+ /* 1 no nudge (just return the original if this test passes) */ \
+       X(' 0.000  0.000  0.000') \
+ /* 6 simple nudges */ \
+       X(' 0.000  0.000  0.125') X('0.000  0.000 -0.125') \
+       X('-0.125  0.000  0.000') X('0.125  0.000  0.000') \
+       X(' 0.000 -0.125  0.000') X('0.000  0.125  0.000') \
+ /* 4 diagonal flat nudges */ \
+       X('-0.125 -0.125  0.000') X('0.125 -0.125  0.000') \
+       X('-0.125  0.125  0.000') X('0.125  0.125  0.000') \
+ /* 8 diagonal upward nudges */ \
+       X('-0.125  0.000  0.125') X('0.125  0.000  0.125') \
+       X(' 0.000 -0.125  0.125') X('0.000  0.125  0.125') \
+       X('-0.125 -0.125  0.125') X('0.125 -0.125  0.125') \
+       X('-0.125  0.125  0.125') X('0.125  0.125  0.125') \
+ /* 8 diagonal downward nudges */ \
+       X('-0.125  0.000 -0.125') X('0.125  0.000 -0.125') \
+       X(' 0.000 -0.125 -0.125') X('0.000  0.125 -0.125') \
+       X('-0.125 -0.125 -0.125') X('0.125 -0.125 -0.125') \
+       X('-0.125  0.125 -0.125') X('0.125  0.125 -0.125') \
+ /**/
+ void PM_ClientMovement_Unstick(entity this)
  {
- // 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()
- {SELFPARAM();
-       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;
-               }
+       #define X(unstick_offset) \
+       { \
+               vector neworigin = unstick_offset + this.origin; \
+               tracebox(neworigin, PL_CROUCH_MIN, PL_CROUCH_MAX, neworigin, MOVE_NORMAL, this); \
+               if (!trace_startsolid) \
+               { \
+                       setorigin(this, neworigin); \
+                       return; \
+               } \
        }
+       unstick_offsets(X);
+       #undef X
  }
  
- void PM_ClientMovement_UpdateStatus(bool ground)
- {SELFPARAM();
+ void PM_ClientMovement_UpdateStatus(entity this, bool ground)
+ {
        // make sure player is not stuck
-       PM_ClientMovement_Unstick();
+       PM_ClientMovement_Unstick(this);
  
        // set crouched
-       if (PHYS_INPUT_BUTTON_CROUCH(self))
+       if (PHYS_INPUT_BUTTON_CROUCH(this))
        {
-               // wants to crouch, this always works..
-               if (!IS_DUCKED(self))
-                       SET_DUCKED(self);
+               // wants to crouch, this always works
+               if (!IS_DUCKED(this)) SET_DUCKED(this);
        }
        else
        {
-               // wants to stand, if currently crouching we need to check for a
-               // low ceiling first
-               if (IS_DUCKED(self))
+               // wants to stand, if currently crouching we need to check for a low ceiling first
+               if (IS_DUCKED(this))
                {
-                       tracebox(self.origin, PL_MIN, PL_MAX, self.origin, MOVE_NORMAL, self);
-                       if (!trace_startsolid)
-                               UNSET_DUCKED(self);
+                       tracebox(this.origin, PL_MIN, PL_MAX, this.origin, MOVE_NORMAL, this);
+                       if (!trace_startsolid) UNSET_DUCKED(this);
                }
        }
  
        // set onground
-       vector origin1 = self.origin + '0 0 1';
-       vector origin2 = self.origin - '0 0 1';
+       vector origin1 = this.origin + '0 0 1';
+       vector origin2 = this.origin - '0 0 1';
  
-       if(ground)
+       if (ground)
        {
-               tracebox(origin1, self.mins, self.maxs, origin2, MOVE_NORMAL, self);
-               if (trace_fraction < 1.0 && trace_plane_normal_z > 0.7)
+               tracebox(origin1, this.mins, this.maxs, origin2, MOVE_NORMAL, this);
+               if (trace_fraction < 1.0 && trace_plane_normal.z > 0.7)
                {
-                       SET_ONGROUND(self);
+                       SET_ONGROUND(this);
  
                        // 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;
+                       this.velocity -= this.velocity * trace_plane_normal * trace_plane_normal;
                }
                else
-                       UNSET_ONGROUND(self);
+                       UNSET_ONGROUND(this);
        }
  
        // set watertype/waterlevel
-       origin1 = self.origin;
-       origin1_z += self.mins_z + 1;
-       self.waterlevel = WATERLEVEL_NONE;
+       origin1 = this.origin;
+       origin1.z += this.mins_z + 1;
+       this.waterlevel = WATERLEVEL_NONE;
  
        int thepoint = pointcontents(origin1);
  
-       self.watertype = (thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME);
+       this.watertype = (thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME);
  
-       if(self.watertype)
+       if (this.watertype)
        {
-               self.waterlevel = WATERLEVEL_WETFEET;
-               origin1_z = self.origin_z + (self.mins_z + self.maxs_z) * 0.5;
+               this.waterlevel = WATERLEVEL_WETFEET;
+               origin1.z = this.origin.z + (this.mins.z + this.maxs.z) * 0.5;
                thepoint = pointcontents(origin1);
-               if(thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME)
+               if (thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME)
                {
-                       self.waterlevel = WATERLEVEL_SWIMMING;
-                       origin1_z = self.origin_z + 22;
+                       this.waterlevel = WATERLEVEL_SWIMMING;
+                       origin1.z = this.origin.z + 22;
                        thepoint = pointcontents(origin1);
-                       if(thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME)
-                               self.waterlevel = WATERLEVEL_SUBMERGED;
+                       if (thepoint == CONTENT_WATER || thepoint == CONTENT_LAVA || thepoint == CONTENT_SLIME)
+                               this.waterlevel = WATERLEVEL_SUBMERGED;
                }
        }
  
-       if(IS_ONGROUND(self) || self.velocity_z <= 0 || pmove_waterjumptime <= 0)
+       if (IS_ONGROUND(this) || this.velocity.z <= 0 || pmove_waterjumptime <= 0)
                pmove_waterjumptime = 0;
  }
  
@@@ -214,7 -319,7 +209,7 @@@ void PM_ClientMovement_Move(
        vector trace3_plane_normal = '0 0 0';
  
  
-       PM_ClientMovement_UpdateStatus(false);
+       PM_ClientMovement_UpdateStatus(this, false);
        primalvelocity = self.velocity;
        for(bump = 0, t = PHYS_INPUT_TIMELENGTH; bump < 8 && (self.velocity * self.velocity) > 0; bump++)
        {
@@@ -755,7 -860,7 +750,7 @@@ void RaceCarPhysics(
                vector rigvel_xy, neworigin, up;
                float mt;
  
 -              rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY; // 4x gravity plays better
 +              rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY(this); // 4x gravity plays better
                rigvel_xy = vec2(rigvel);
  
                if (g_bugrigs_planar_movement_car_jumping)
        }
        else
        {
 -              rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY; // 4x gravity plays better
 +              rigvel_z -= PHYS_INPUT_TIMELENGTH * PHYS_GRAVITY(this); // 4x gravity plays better
                self.velocity = rigvel;
                self.movetype = MOVETYPE_FLY;
        }
@@@ -990,27 -1095,19 +985,19 @@@ void PM_check_frozen(
  void PM_check_hitground()
  {SELFPARAM();
  #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);
-                       }
-               }
-       }
+       if (!IS_PLAYER(this)) return; // no fall sounds for observers thank you very much
+       if (!IS_ONGROUND(this)) return;
+       if (!this.wasFlying) return;
+     this.wasFlying = false;
+     if (this.waterlevel >= WATERLEVEL_SWIMMING) return;
+     if (time < this.ladder_time) return;
+     if (this.hook) return;
+     this.nextstep = time + 0.3 + random() * 0.1;
+     trace_dphitq3surfaceflags = 0;
+     tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 1', MOVE_NOMONSTERS, this);
+     if ((trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS)) return;
+     entity fall = (trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS) ? GS_FALL_METAL : GS_FALL;
+     GlobalSound(fall, CH_PLAYER, VOICETYPE_PLAYERSOUND);
  #endif
  }
  
@@@ -1150,7 -1247,7 +1137,7 @@@ void PM_ladder(float maxspd_mod
        UNSET_ONGROUND(self);
  
        float g;
 -      g = PHYS_GRAVITY * PHYS_INPUT_TIMELENGTH;
 +      g = PHYS_GRAVITY(this) * PHYS_INPUT_TIMELENGTH;
        if (PHYS_ENTGRAVITY(self))
                g *= PHYS_ENTGRAVITY(self);
        if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
@@@ -1216,7 -1313,7 +1203,7 @@@ void PM_jetpack(float maxspd_mod
        // 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;
 +      float a_add = PHYS_JETPACK_ANTIGRAVITY * PHYS_GRAVITY(this);
  
        wishvel_x *= a_side;
        wishvel_y *= a_side;
  
        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)
 +      if (wishvel_z - PHYS_GRAVITY(this) > 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);
        fvel = vlen(wishvel);
        wishvel_x *= fxy;
        wishvel_y *= fxy;
 -      wishvel_z = (wishvel_z - PHYS_GRAVITY) * fz + PHYS_GRAVITY;
 +      wishvel_z = (wishvel_z - PHYS_GRAVITY(this)) * fz + PHYS_GRAVITY(this);
  
        fvel = min(1, vlen(wishvel) / best);
        if (PHYS_JETPACK_FUEL && !(ITEMS_STAT(self) & IT_UNLIMITED_WEAPON_AMMO))
        }
  
  #ifdef CSQC
 -      float g = PHYS_GRAVITY * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH;
 +      float g = PHYS_GRAVITY(this) * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH;
        if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
                self.velocity_z -= g * 0.5;
        else
  #endif
  }
  
- void PM_walk(float buttons_prev, float maxspd_mod)
- {SELFPARAM();
-       if (!WAS_ONGROUND(self))
+ void PM_walk(entity this, float maxspd_mod)
+ {
+       if (!WAS_ONGROUND(this))
        {
  #ifdef SVQC
                if (autocvar_speedmeter)
-                       LOG_TRACE(strcat("landing velocity: ", vtos(self.velocity), " (abs: ", ftos(vlen(self.velocity)), ")\n"));
+                       LOG_TRACE(strcat("landing velocity: ", vtos(this.velocity), " (abs: ", ftos(vlen(this.velocity)), ")\n"));
  #endif
-               if (self.lastground < time - 0.3)
-                       self.velocity *= (1 - PHYS_FRICTION_ONLAND);
+               if (this.lastground < time - 0.3)
+                       this.velocity *= (1 - PHYS_FRICTION_ONLAND);
  #ifdef SVQC
-               if (self.jumppadcount > 1)
-                       LOG_TRACE(strcat(ftos(self.jumppadcount), "x jumppad combo\n"));
-               self.jumppadcount = 0;
+               if (this.jumppadcount > 1)
+                       LOG_TRACE(strcat(ftos(this.jumppadcount), "x jumppad combo\n"));
+               this.jumppadcount = 0;
  #endif
        }
  
        // walking
-       makevectors(self.v_angle.y * '0 1 0');
-       vector wishvel = v_forward * self.movement.x
-                                       + v_right * self.movement.y;
+       makevectors(this.v_angle.y * '0 1 0');
+       const vector wishvel = v_forward * this.movement.x
+                                               + v_right * this.movement.y;
        // acceleration
-       vector wishdir = normalize(wishvel);
+       const vector wishdir = normalize(wishvel);
        float wishspeed = vlen(wishvel);
-       wishspeed = min(wishspeed, PHYS_MAXSPEED(self) * maxspd_mod);
-       if (IS_DUCKED(self))
-               wishspeed *= 0.5;
+       wishspeed = min(wishspeed, PHYS_MAXSPEED(this) * maxspd_mod);
+       if (IS_DUCKED(this)) wishspeed *= 0.5;
  
        // apply edge friction
-       float f = vlen(vec2(self.velocity));
-       if (f > 0)
+       const float f2 = vlen2(vec2(this.velocity));
+       if (f2 > 0)
        {
-               float realfriction;
                trace_dphitq3surfaceflags = 0;
-               tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 1', MOVE_NOMONSTERS, self);
+               tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 1', MOVE_NOMONSTERS, this);
                // TODO: apply edge friction
                // apply ground friction
-               if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK)
-                       realfriction = PHYS_FRICTION_SLICK;
-               else
-                       realfriction = PHYS_FRICTION;
+               const int realfriction = (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK)
+                       ? PHYS_FRICTION_SLICK
+                       : PHYS_FRICTION;
  
+               float f = sqrt(f2);
                f = 1 - PHYS_INPUT_TIMELENGTH * realfriction * ((f < PHYS_STOPSPEED) ? (PHYS_STOPSPEED / f) : 1);
                f = max(0, f);
-               self.velocity *= f;
+               this.velocity *= f;
                /*
                   Mathematical analysis time!
  
                        v >= PHYS_STOPSPEED * (1 - PHYS_INPUT_TIMELENGTH * PHYS_FRICTION)
                 */
        }
-       float addspeed = wishspeed - self.velocity * wishdir;
+       const float addspeed = wishspeed - this.velocity * wishdir;
        if (addspeed > 0)
        {
-               float accelspeed = min(PHYS_ACCELERATE * PHYS_INPUT_TIMELENGTH * wishspeed, addspeed);
-               self.velocity += accelspeed * wishdir;
+               const float accelspeed = min(PHYS_ACCELERATE * PHYS_INPUT_TIMELENGTH * wishspeed, addspeed);
+               this.velocity += accelspeed * wishdir;
        }
-       float g = PHYS_GRAVITY(this) * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH;
 -      const float g = PHYS_GRAVITY * PHYS_ENTGRAVITY(this) * PHYS_INPUT_TIMELENGTH;
++      const float g = PHYS_GRAVITY(this) * PHYS_ENTGRAVITY(this) * PHYS_INPUT_TIMELENGTH;
        if (!(GAMEPLAYFIX_NOGRAVITYONGROUND))
-               self.velocity_z -= g * (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE ? 0.5 : 1);
-       if (self.velocity * self.velocity)
+               this.velocity_z -= g * (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE ? 0.5 : 1);
+       if (vdist(this.velocity, >, 0))
                PM_ClientMovement_Move();
        if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
-               if (!IS_ONGROUND(self) || !GAMEPLAYFIX_NOGRAVITYONGROUND)
-                       self.velocity_z -= g * 0.5;
+               if (!IS_ONGROUND(this) || !GAMEPLAYFIX_NOGRAVITYONGROUND)
+                       this.velocity_z -= g * 0.5;
  }
  
  void PM_air(float buttons_prev, float maxspd_mod)
                if (PHYS_AIRCONTROL)
                        CPM_PM_Aircontrol(wishdir, wishspeed2);
        }
 -      float g = PHYS_GRAVITY * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH;
 +      float g = PHYS_GRAVITY(this) * PHYS_ENTGRAVITY(self) * PHYS_INPUT_TIMELENGTH;
        if (GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE)
                self.velocity_z -= g * 0.5;
        else
@@@ -1484,25 -1578,25 +1468,25 @@@ bool IsFlying(entity a
        return true;
  }
  
- void PM_Main()
- {SELFPARAM();
-       int buttons = PHYS_INPUT_BUTTON_MASK(self);
+ void PM_Main(entity this)
+ {
+       int buttons = PHYS_INPUT_BUTTON_MASK(this);
  #ifdef CSQC
-       self.items = getstati(STAT_ITEMS, 0, 24);
+       this.items = getstati(STAT_ITEMS, 0, 24);
  
-       self.movement = PHYS_INPUT_MOVEVALUES(self);
+       this.movement = PHYS_INPUT_MOVEVALUES(this);
  
-       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);
+       vector oldv_angle = this.v_angle;
+       vector oldangles = this.angles; // we need to save these, as they're abused by other code
+       this.v_angle = PHYS_INPUT_ANGLES(this);
+       this.angles = PHYS_WORLD_ANGLES(this);
  
-       self.team = myteam + 1; // is this correct?
-       if (!(PHYS_INPUT_BUTTON_JUMP(self))) // !jump
-               UNSET_JUMP_HELD(self); // canjump = true
+       this.team = myteam + 1; // is this correct?
+       if (!(PHYS_INPUT_BUTTON_JUMP(this))) // !jump
+               UNSET_JUMP_HELD(this); // canjump = true
        pmove_waterjumptime -= PHYS_INPUT_TIMELENGTH;
  
-       PM_ClientMovement_UpdateStatus(true);
+       PM_ClientMovement_UpdateStatus(this, true);
  #endif
  
  
        maxspeed_mod *= PHYS_HIGHSPEED;
  
  #ifdef SVQC
 -      Physics_UpdateStats(maxspeed_mod);
 +      Physics_UpdateStats(this, maxspeed_mod);
  
-       if (self.PlayerPhysplug)
-               if (self.PlayerPhysplug())
+       if (this.PlayerPhysplug)
+               if (this.PlayerPhysplug())
                        return;
  #endif
  
  #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;
+               if (buttons != this.buttons_old || this.movement != this.movement_old || this.v_angle != this.v_angle_old)
+                       this.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;
+       int buttons_prev = this.buttons_old;
+       this.buttons_old = buttons;
+       this.movement_old = this.movement;
+       this.v_angle_old = this.v_angle;
  
        PM_check_nickspam();
  
        PM_check_punch();
  #ifdef SVQC
-       if (IS_BOT_CLIENT(self))
+       if (IS_BOT_CLIENT(this))
        {
                if (playerdemo_read())
                        return;
                bot_think();
        }
-       if (IS_PLAYER(self))
- #endif
-       {
-               bool not_allowed_to_move = false;
- #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
+       if (IS_PLAYER(this))
+       {
+               const bool allowed_to_move = (time >= game_starttime);
+               if (!allowed_to_move)
+               {
+                       this.velocity = '0 0 0';
+                       this.movetype = MOVETYPE_NONE;
+                       this.disableclientprediction = 2;
                }
- #ifdef SVQC
-               else if (self.disableclientprediction == 2)
+               else if (this.disableclientprediction == 2)
                {
-                       if (self.movetype == MOVETYPE_NONE)
-                               self.movetype = MOVETYPE_WALK;
-                       self.disableclientprediction = 0;
+                       if (this.movetype == MOVETYPE_NONE)
+                               this.movetype = MOVETYPE_WALK;
+                       this.disableclientprediction = 0;
                }
- #endif
        }
+ #endif
  
  #ifdef SVQC
-       if (self.movetype == MOVETYPE_NONE)
+       if (this.movetype == MOVETYPE_NONE)
                return;
  
        // when we get here, disableclientprediction cannot be 2
-       self.disableclientprediction = 0;
+       this.disableclientprediction = 0;
  #endif
  
        viewloc_PlayerPhysics();
  
        maxspeed_mod = 1;
  
-       if (self.in_swamp)
-               maxspeed_mod *= self.swamp_slowdown; //cvar("g_balance_swamp_moverate");
+       if (this.in_swamp)
+               maxspeed_mod *= this.swamp_slowdown; //cvar("g_balance_swamp_moverate");
  
        // conveyors: first fix velocity
-       if (self.conveyor.state)
-               self.velocity -= self.conveyor.movedir;
+       if (this.conveyor.state)
+               this.velocity -= this.conveyor.movedir;
  
  #ifdef SVQC
        MUTATOR_CALLHOOK(PlayerPhysics);
  //    }
  
  #ifdef SVQC
-       if (!IS_PLAYER(self))
+       if (!IS_PLAYER(this))
        {
                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 (!this.spectatorspeed)
+                       this.spectatorspeed = maxspeed_mod;
+               if (this.impulse && this.impulse <= 19 || (this.impulse >= 200 && this.impulse <= 209) || (this.impulse >= 220 && this.impulse <= 229))
                {
-                       if (self.lastclassname != "player")
+                       if (this.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);
+                               if (this.impulse == 10 || this.impulse == 15 || this.impulse == 18 || (this.impulse >= 200 && this.impulse <= 209))
+                                       this.spectatorspeed = bound(1, this.spectatorspeed + 0.5, 5);
+                               else if (this.impulse == 11)
+                                       this.spectatorspeed = maxspeed_mod;
+                               else if (this.impulse == 12 || this.impulse == 16  || this.impulse == 19 || (this.impulse >= 220 && this.impulse <= 229))
+                                       this.spectatorspeed = bound(1, this.spectatorspeed - 0.5, 5);
+                               else if (this.impulse >= 1 && this.impulse <= 9)
+                                       this.spectatorspeed = 1 + 0.5 * (this.impulse - 1);
                        } // otherwise just clear
-                       self.impulse = 0;
+                       this.impulse = 0;
                }
-               maxspeed_mod = self.spectatorspeed;
+               maxspeed_mod = this.spectatorspeed;
        }
  
-       float spd = max(PHYS_MAXSPEED(self), PHYS_MAXAIRSPEED(self)) * maxspeed_mod;
-       if(self.speed != spd)
+       float spd = max(PHYS_MAXSPEED(this), PHYS_MAXAIRSPEED(this)) * maxspeed_mod;
+       if(this.speed != spd)
        {
-               self.speed = spd;
+               this.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"));
+               stuffcmd(this, strcat("cl_forwardspeed ", temps, "\n"));
+               stuffcmd(this, strcat("cl_backspeed ", temps, "\n"));
+               stuffcmd(this, strcat("cl_sidespeed ", temps, "\n"));
+               stuffcmd(this, strcat("cl_upspeed ", temps, "\n"));
        }
  
-       if(self.stat_jumpspeedcap_min != PHYS_JUMPSPEEDCAP_MIN)
+       if(this.stat_jumpspeedcap_min != PHYS_JUMPSPEEDCAP_MIN)
        {
-               self.stat_jumpspeedcap_min = PHYS_JUMPSPEEDCAP_MIN;
-               stuffcmd(self, strcat("cl_jumpspeedcap_min ", PHYS_JUMPSPEEDCAP_MIN, "\n"));
+               this.stat_jumpspeedcap_min = PHYS_JUMPSPEEDCAP_MIN;
+               stuffcmd(this, strcat("cl_jumpspeedcap_min ", PHYS_JUMPSPEEDCAP_MIN, "\n"));
        }
-       if(self.stat_jumpspeedcap_max != PHYS_JUMPSPEEDCAP_MAX)
+       if(this.stat_jumpspeedcap_max != PHYS_JUMPSPEEDCAP_MAX)
        {
-               self.stat_jumpspeedcap_min = PHYS_JUMPSPEEDCAP_MAX;
-               stuffcmd(self, strcat("cl_jumpspeedcap_max ", PHYS_JUMPSPEEDCAP_MAX, "\n"));
+               this.stat_jumpspeedcap_min = PHYS_JUMPSPEEDCAP_MAX;
+               stuffcmd(this, strcat("cl_jumpspeedcap_max ", PHYS_JUMPSPEEDCAP_MAX, "\n"));
        }
  #endif
  
-       if(PHYS_DEAD(self))
+       if(PHYS_DEAD(this))
        {
                // handle water here
-               vector midpoint = ((self.absmin + self.absmax) * 0.5);
+               vector midpoint = ((this.absmin + this.absmax) * 0.5);
                if(pointcontents(midpoint) == CONTENT_WATER)
                {
-                       self.velocity = self.velocity * 0.5;
+                       this.velocity = this.velocity * 0.5;
  
                        // do we want this?
                        //if(pointcontents(midpoint + '0 0 2') == CONTENT_WATER)
-                               //{ self.velocity_z = 70; }
+                               //{ this.velocity_z = 70; }
                }
                goto end;
        }
  
  #ifdef SVQC
-       if (!self.fixangle && !g_bugrigs)
-               self.angles = '0 1 0' * self.v_angle.y;
+       if (!this.fixangle && !g_bugrigs)
+               this.angles = '0 1 0' * this.v_angle.y;
  #endif
  
        PM_check_hitground();
  
-       if(IsFlying(self))
-               self.wasFlying = 1;
+       if(IsFlying(this))
+               this.wasFlying = 1;
  
-       if (IS_PLAYER(self))
+       if (IS_PLAYER(this))
                CheckPlayerJump();
  
-       if (self.flags & FL_WATERJUMP)
+       if (this.flags & FL_WATERJUMP)
        {
-               self.velocity_x = self.movedir_x;
-               self.velocity_y = self.movedir_y;
-               if (time > self.teleport_time || self.waterlevel == WATERLEVEL_NONE)
+               this.velocity_x = this.movedir.x;
+               this.velocity_y = this.movedir.y;
+               if (time > this.teleport_time || this.waterlevel == WATERLEVEL_NONE)
                {
-                       self.flags &= ~FL_WATERJUMP;
-                       self.teleport_time = 0;
+                       this.flags &= ~FL_WATERJUMP;
+                       this.teleport_time = 0;
                }
        }
  
  #ifdef SVQC
-       else if (g_bugrigs && IS_PLAYER(self))
+       else if (g_bugrigs && IS_PLAYER(this))
                RaceCarPhysics();
  #endif
  
-       else if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY || self.movetype == MOVETYPE_FLY_WORLDONLY || (BUFFS_STAT(self) & BUFF_FLIGHT.m_itemid))
+       else if (this.movetype == MOVETYPE_NOCLIP || this.movetype == MOVETYPE_FLY || this.movetype == MOVETYPE_FLY_WORLDONLY || MUTATOR_CALLHOOK(IsFlying, this))
                PM_fly(maxspeed_mod);
  
-       else if (self.waterlevel >= WATERLEVEL_SWIMMING)
+       else if (this.waterlevel >= WATERLEVEL_SWIMMING)
                PM_swim(maxspeed_mod);
  
-       else if (time < self.ladder_time)
+       else if (time < this.ladder_time)
                PM_ladder(maxspeed_mod);
  
-       else if (ITEMS_STAT(self) & IT_USING_JETPACK)
+       else if (ITEMS_STAT(this) & IT_USING_JETPACK)
                PM_jetpack(maxspeed_mod);
  
-       else if (IS_ONGROUND(self))
-               PM_walk(buttons_prev, maxspeed_mod);
+       else if (IS_ONGROUND(this))
+               PM_walk(this, maxspeed_mod);
  
        else
                PM_air(buttons_prev, maxspeed_mod);
        PM_check_vortex();
  
  :end
-       if (IS_ONGROUND(self))
-               self.lastground = time;
+       if (IS_ONGROUND(this))
+               this.lastground = time;
  
        // conveyors: then break velocity again
-       if(self.conveyor.state)
-               self.velocity += self.conveyor.movedir;
+       if(this.conveyor.state)
+               this.velocity += this.conveyor.movedir;
  
-       self.lastflags = self.flags;
+       this.lastflags = this.flags;
  
-       self.lastclassname = self.classname;
+       this.lastclassname = this.classname;
  
  #ifdef CSQC
-       self.v_angle = oldv_angle;
-       self.angles = oldangles;
+       this.v_angle = oldv_angle;
+       this.angles = oldangles;
  #endif
  }
  
- #ifdef SVQC
+ #if defined(SVQC)
  void SV_PlayerPhysics()
  #elif defined(CSQC)
- void CSQC_ClientMovement_PlayerMove_Frame()
+ void CSQC_ClientMovement_PlayerMove_Frame(entity this)
  #endif
- {SELFPARAM();
-       PM_Main();
+ {
+ #ifdef SVQC
+       SELFPARAM();
+ #endif
+       PM_Main(this);
  #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);
+       this.pmove_flags =
+                       ((this.flags & FL_DUCKED) ? PMF_DUCKED : 0) |
+                       (!(this.flags & FL_JUMPRELEASED) ? PMF_JUMP_HELD : 0) |
+                       ((this.flags & FL_ONGROUND) ? PMF_ONGROUND : 0);
  #endif
  }
diff --combined qcsrc/common/physics.qh
index 682e58712fe718a15c5639fcbbe6d893391fd35c,639776593c1cece2ed3bc6ba1ec07af3588785c8..fb396d1596291b1ed51947a2a38093762e0e95bf
@@@ -24,91 -24,6 +24,91 @@@ float AdjustAirAccelQW(float accelqw, f
  
  bool IsFlying(entity a);
  
 +#define BUFFS_STAT(s)                       STAT(BUFFS, s)
 +
 +#define GAMEPLAYFIX_DOWNTRACEONGROUND       STAT(GAMEPLAYFIX_DOWNTRACEONGROUND, this)
 +#define GAMEPLAYFIX_EASIERWATERJUMP         STAT(GAMEPLAYFIX_EASIERWATERJUMP, this)
 +#define GAMEPLAYFIX_STEPDOWN                STAT(GAMEPLAYFIX_STEPDOWN, this)
 +#define GAMEPLAYFIX_STEPMULTIPLETIMES       STAT(GAMEPLAYFIX_STEPMULTIPLETIMES, this)
 +#define GAMEPLAYFIX_UNSTICKPLAYERS          STAT(GAMEPLAYFIX_UNSTICKPLAYERS, this)
 +
 +#define PHYS_ACCELERATE                     STAT(MOVEVARS_ACCELERATE, this)
 +#define PHYS_AIRACCELERATE                  STAT(MOVEVARS_AIRACCELERATE, this)
 +#define PHYS_AIRACCEL_QW(s)                 STAT(MOVEVARS_AIRACCEL_QW, s)
 +#define PHYS_AIRACCEL_QW_STRETCHFACTOR(s)   STAT(MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, s)
 +#define PHYS_AIRACCEL_SIDEWAYS_FRICTION     STAT(MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, this)
 +#define PHYS_AIRCONTROL                     STAT(MOVEVARS_AIRCONTROL, this)
 +#define PHYS_AIRCONTROL_PENALTY             STAT(MOVEVARS_AIRCONTROL_PENALTY, this)
 +#define PHYS_AIRCONTROL_POWER               STAT(MOVEVARS_AIRCONTROL_POWER, this)
 +#define PHYS_AIRSPEEDLIMIT_NONQW(s)         STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW, s)
 +#define PHYS_AIRSTOPACCELERATE              STAT(MOVEVARS_AIRSTOPACCELERATE, this)
 +#define PHYS_AIRSTRAFEACCELERATE(s)         STAT(MOVEVARS_AIRSTRAFEACCELERATE, this)
 +#define PHYS_AIRSTRAFEACCEL_QW(s)           STAT(MOVEVARS_AIRSTRAFEACCEL_QW, s)
 +
 +#define PHYS_AMMO_FUEL(s)                   STAT(FUEL, s)
 +
 +#define PHYS_BUGRIGS                        STAT(BUGRIGS, this)
 +#define PHYS_BUGRIGS_ACCEL                  STAT(BUGRIGS_ACCEL, this)
 +#define PHYS_BUGRIGS_AIR_STEERING           STAT(BUGRIGS_AIR_STEERING, this)
 +#define PHYS_BUGRIGS_ANGLE_SMOOTHING        STAT(BUGRIGS_ANGLE_SMOOTHING, this)
 +#define PHYS_BUGRIGS_CAR_JUMPING            STAT(BUGRIGS_CAR_JUMPING, this)
 +#define PHYS_BUGRIGS_FRICTION_AIR           STAT(BUGRIGS_FRICTION_AIR, this)
 +#define PHYS_BUGRIGS_FRICTION_BRAKE         STAT(BUGRIGS_FRICTION_BRAKE, this)
 +#define PHYS_BUGRIGS_FRICTION_FLOOR         STAT(BUGRIGS_FRICTION_FLOOR, this)
 +#define PHYS_BUGRIGS_PLANAR_MOVEMENT        STAT(BUGRIGS_PLANAR_MOVEMENT, this)
 +#define PHYS_BUGRIGS_REVERSE_SPEEDING       STAT(BUGRIGS_REVERSE_SPEEDING, this)
 +#define PHYS_BUGRIGS_REVERSE_SPINNING       STAT(BUGRIGS_REVERSE_SPINNING, this)
 +#define PHYS_BUGRIGS_REVERSE_STOPPING       STAT(BUGRIGS_REVERSE_STOPPING, this)
 +#define PHYS_BUGRIGS_SPEED_POW              STAT(BUGRIGS_SPEED_POW, this)
 +#define PHYS_BUGRIGS_SPEED_REF              STAT(BUGRIGS_SPEED_REF, this)
 +#define PHYS_BUGRIGS_STEER                  STAT(BUGRIGS_STEER, this)
 +
 +#define PHYS_DODGING_FROZEN                                   STAT(DODGING_FROZEN, this)
 +
 +#define PHYS_DOUBLEJUMP                     STAT(DOUBLEJUMP, this)
 +
 +#define PHYS_FRICTION                       STAT(MOVEVARS_FRICTION, this)
 +#define PHYS_FRICTION_ONLAND                STAT(MOVEVARS_FRICTION_ONLAND, this)
 +#define PHYS_FRICTION_SLICK                 STAT(MOVEVARS_FRICTION_SLICK, this)
 +
 +#define PHYS_FROZEN(s)                      STAT(FROZEN, s)
 +
 +#define PHYS_GRAVITY(s)                     STAT(MOVEVARS_GRAVITY, s)
 +
 +#define PHYS_HIGHSPEED                      STAT(MOVEVARS_HIGHSPEED, this)
 +
 +#define PHYS_JETPACK_ACCEL_SIDE                       STAT(JETPACK_ACCEL_SIDE, this)
 +#define PHYS_JETPACK_ACCEL_UP                                 STAT(JETPACK_ACCEL_UP, this)
 +#define PHYS_JETPACK_ANTIGRAVITY                      STAT(JETPACK_ANTIGRAVITY, this)
 +#define PHYS_JETPACK_FUEL                                     STAT(JETPACK_FUEL, this)
 +#define PHYS_JETPACK_MAXSPEED_SIDE                    STAT(JETPACK_MAXSPEED_SIDE, this)
 +#define PHYS_JETPACK_MAXSPEED_UP                      STAT(JETPACK_MAXSPEED_UP, this)
 +
 +#define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS   STAT(MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS, this)
 +#define PHYS_JUMPSTEP                                         STAT(MOVEVARS_JUMPSTEP, this)
 +#define PHYS_JUMPVELOCITY                   STAT(MOVEVARS_JUMPVELOCITY, this)
 +
 +#define PHYS_MAXAIRSPEED(s)                 STAT(MOVEVARS_MAXAIRSPEED, s)
 +#define PHYS_MAXAIRSTRAFESPEED              STAT(MOVEVARS_MAXAIRSTRAFESPEED, this)
 +#define PHYS_MAXSPEED(s)                    STAT(MOVEVARS_MAXSPEED, s)
 +
 +#define PHYS_NOSTEP                                                   STAT(NOSTEP, this)
 +#define PHYS_STEPHEIGHT                     STAT(MOVEVARS_STEPHEIGHT, this)
 +
 +#define PHYS_STOPSPEED                      STAT(MOVEVARS_STOPSPEED, this)
 +
 +#define PHYS_TRACK_CANJUMP(s)               STAT(MOVEVARS_TRACK_CANJUMP, s)
 +
 +#define PHYS_WALLFRICTION                                     STAT(MOVEVARS_WALLFRICTION, this)
 +
 +#define PHYS_WARSOWBUNNY_ACCEL              STAT(MOVEVARS_WARSOWBUNNY_ACCEL, this)
 +#define PHYS_WARSOWBUNNY_AIRFORWARDACCEL    STAT(MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL, this)
 +#define PHYS_WARSOWBUNNY_BACKTOSIDERATIO    STAT(MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO, this)
 +#define PHYS_WARSOWBUNNY_TOPSPEED           STAT(MOVEVARS_WARSOWBUNNY_TOPSPEED, this)
 +#define PHYS_WARSOWBUNNY_TURNACCEL          STAT(MOVEVARS_WARSOWBUNNY_TURNACCEL, this)
 +
 +#define UPWARD_VELOCITY_CLEARS_ONGROUND     STAT(GAMEPLAYFIX_UPVELOCITYCLEARSONGROUND, this)
 +
  #ifdef CSQC
  
        const int FL_WATERJUMP = 2048;  // player jumping out of water
        //float player_multijump;
        //float player_jumpheight;
  
 +      #define TICRATE ticrate
 +
        #define PHYS_INPUT_ANGLES(s)                            input_angles
  // TODO
        #define PHYS_WORLD_ANGLES(s)                            input_angles
  
        #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_INPUT_BUTTON_MASK(s)               (input_buttons | BIT(7) * (input_movevalues.x < 0) | BIT(8) * (input_movevalues.x > 0) | BIT(9) * (input_movevalues.y < 0) | BIT(10) * (input_movevalues.y > 0))
+       #define PHYS_INPUT_BUTTON_ATCK(s)                       boolean(input_buttons & BIT(0))
+       #define PHYS_INPUT_BUTTON_JUMP(s)                       boolean(input_buttons & BIT(1))
+       #define PHYS_INPUT_BUTTON_ATCK2(s)                      boolean(input_buttons & BIT(2))
+       #define PHYS_INPUT_BUTTON_ZOOM(s)                       boolean(input_buttons & BIT(3))
+       #define PHYS_INPUT_BUTTON_CROUCH(s)                     boolean(input_buttons & BIT(4))
+       #define PHYS_INPUT_BUTTON_HOOK(s)                       boolean(input_buttons & BIT(5))
+       #define PHYS_INPUT_BUTTON_USE(s)                        boolean(input_buttons & BIT(6))
+       #define PHYS_INPUT_BUTTON_BACKWARD(s)           boolean(input_buttons & BIT(7))
+       #define PHYS_INPUT_BUTTON_FORWARD(s)            boolean(input_buttons & BIT(8))
+       #define PHYS_INPUT_BUTTON_LEFT(s)                       boolean(input_buttons & BIT(9))
+       #define PHYS_INPUT_BUTTON_RIGHT(s)                      boolean(input_buttons & BIT(10))
+       #define PHYS_INPUT_BUTTON_JETPACK(s)            boolean(input_buttons & BIT(12))
  
        #define PHYS_DEAD(s)                                            s.csqcmodel_isdead
  
 -      #define GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE  boolean(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 GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE  (boolean(moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE))
 +      #define GAMEPLAYFIX_NOGRAVITYONGROUND                   (boolean(moveflags & MOVEFLAG_NOGRAVITYONGROUND))
 +      #define GAMEPLAYFIX_Q2AIRACCELERATE                             (boolean(moveflags & MOVEFLAG_Q2AIRACCELERATE))
  
-       #define IS_DUCKED(s)                                            !!(s.flags & FL_DUCKED)
+       #define IS_DUCKED(s)                                            boolean(s.flags & FL_DUCKED)
        #define SET_DUCKED(s)                                           s.flags |= FL_DUCKED
        #define UNSET_DUCKED(s)                                         s.flags &= ~FL_DUCKED
  
        #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 IS_ONGROUND(s)                                          boolean(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 WAS_ONGROUND(s)                                         boolean(s.lastflags & FL_ONGROUND)
  
        #define ITEMS_STAT(s)                                           (s).items
 -      #define BUFFS_STAT(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                           cvar_string("cl_jumpspeedcap_min")
        #define PHYS_JUMPSPEEDCAP_MAX                           cvar_string("cl_jumpspeedcap_max")
 -      #define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS       getstati(STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS)
 -
 -      #define PHYS_CL_TRACK_CANJUMP(s)                        getstati(STAT_MOVEVARS_CL_TRACK_CANJUMP)
 -      #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(s)                     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(s)                                     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)
 +
 +      #define PHYS_CL_TRACK_CANJUMP(s)            STAT(MOVEVARS_CL_TRACK_CANJUMP, s)
 +      // FIXME: 0 doesn't mean zero gravity
 +      #define PHYS_ENTGRAVITY(s)                  STAT(MOVEVARS_ENTGRAVITY, s)
  
  #elif defined(SVQC)
  
        bool Physics_Valid(string thecvar);
  
 -      .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;
 -
 -      .string stat_jumpspeedcap_min;
 -      .string 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;
 -
 -      // new properties
 -      .float stat_sv_jumpvelocity;
 -      .float stat_sv_airaccel_qw_stretchfactor;
 -      .float stat_sv_maxairstrafespeed;
 -      .float stat_sv_maxairspeed;
 -      .float stat_sv_airstrafeaccelerate;
 -      .float stat_sv_warsowbunny_turnaccel;
 -      .float stat_sv_airaccel_sideways_friction;
 -      .float stat_sv_aircontrol;
 -      .float stat_sv_aircontrol_power;
 -      .float stat_sv_aircontrol_penalty;
 -      .float stat_sv_warsowbunny_airforwardaccel;
 -      .float stat_sv_warsowbunny_topspeed;
 -      .float stat_sv_warsowbunny_accel;
 -      .float stat_sv_warsowbunny_backtosideratio;
 -      .float stat_sv_friction;
 -      .float stat_sv_accelerate;
 -      .float stat_sv_stopspeed;
 -      .float stat_sv_airaccelerate;
 -      .float stat_sv_airstopaccelerate;
 -
 -      .float stat_nostep;
 -      .float stat_jumpstep;
 -
 -      .bool stat_sv_track_canjump;
 +      .float stat_sv_airspeedlimit_nonqw = _STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW);
 +      .float stat_sv_maxspeed = _STAT(MOVEVARS_MAXSPEED);
 +
 +      /** Not real stats */
 +      .string stat_jumpspeedcap_min, stat_jumpspeedcap_max;
 +
 +      #define TICRATE sys_frametime
  
        #define PHYS_INPUT_ANGLES(s)                            s.v_angle
        #define PHYS_WORLD_ANGLES(s)                            s.angles
        #define PHYS_DEAD(s)                                            s.deadflag != DEAD_NO
  
        #define GAMEPLAYFIX_GRAVITYUNAFFECTEDBYTICRATE  autocvar_sv_gameplayfix_gravityunaffectedbyticrate
 -      #define GAMEPLAYFIX_NOGRAVITYONGROUND                   cvar("sv_gameplayfix_nogravityonground")
 +      #define GAMEPLAYFIX_NOGRAVITYONGROUND                   autocvar_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 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 IS_ONGROUND(s)                                          boolean(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 WAS_ONGROUND(s)                                         boolean((s).lastflags & FL_ONGROUND)
  
        #define ITEMS_STAT(s)                                           s.items
 -      #define BUFFS_STAT(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_CL_TRACK_CANJUMP(s)                        s.cvar_cl_movement_track_canjump
 -      #define PHYS_TRACK_CANJUMP(s)                           s.stat_sv_track_canjump
 -      #define PHYS_ACCELERATE                                         self.stat_sv_accelerate
 -      #define PHYS_AIRACCEL_QW(s)                                     s.stat_sv_airaccel_qw
 -      #define PHYS_AIRACCEL_QW_STRETCHFACTOR(s)       self.stat_sv_airaccel_qw_stretchfactor
 -      #define PHYS_AIRACCEL_SIDEWAYS_FRICTION         self.stat_sv_airaccel_sideways_friction
 -      #define PHYS_AIRACCELERATE                                      self.stat_sv_airaccelerate
 -      #define PHYS_AIRCONTROL                                         self.stat_sv_aircontrol
 -      #define PHYS_AIRCONTROL_PENALTY                         self.stat_sv_aircontrol_penalty
 -      #define PHYS_AIRCONTROL_POWER                           self.stat_sv_aircontrol_power
 -      #define PHYS_AIRSPEEDLIMIT_NONQW(s)                     s.stat_sv_airspeedlimit_nonqw
 -      #define PHYS_AIRSTOPACCELERATE                          self.stat_sv_airstopaccelerate
 -      #define PHYS_AIRSTRAFEACCEL_QW(s)                       s.stat_sv_airstrafeaccel_qw
 -      #define PHYS_AIRSTRAFEACCELERATE(s)                     s.stat_sv_airstrafeaccelerate
        #define PHYS_ENTGRAVITY(s)                                      s.gravity
 -      #define PHYS_FRICTION                                           self.stat_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                                       self.stat_sv_jumpvelocity
 -      #define PHYS_MAXAIRSPEED(s)                                     self.stat_sv_maxairspeed
 -      #define PHYS_MAXAIRSTRAFESPEED                          self.stat_sv_maxairstrafespeed
 -      #define PHYS_MAXSPEED(s)                                        s.stat_sv_maxspeed
 -      #define PHYS_STEPHEIGHT                                         autocvar_sv_stepheight
 -      #define PHYS_STOPSPEED                                          self.stat_sv_stopspeed
 -      #define PHYS_WARSOWBUNNY_ACCEL                          self.stat_sv_warsowbunny_accel
 -      #define PHYS_WARSOWBUNNY_BACKTOSIDERATIO        self.stat_sv_warsowbunny_backtosideratio
 -      #define PHYS_WARSOWBUNNY_AIRFORWARDACCEL        self.stat_sv_warsowbunny_airforwardaccel
 -      #define PHYS_WARSOWBUNNY_TOPSPEED                       self.stat_sv_warsowbunny_topspeed
 -      #define PHYS_WARSOWBUNNY_TURNACCEL                      self.stat_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
index 21c32478189a4a1b9e0316601b1dea646ec6925e,8c521e7dd899c1af1319585faf049e8b778c9422..be3671b924db4fcb909977129ddd174f60be7e49
@@@ -37,7 -37,7 +37,7 @@@ vector trigger_push_calculatevelocity(v
  
        torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5;
  
 -      grav = PHYS_GRAVITY;
 +      grav = PHYS_GRAVITY(other);
        if(PHYS_ENTGRAVITY(other))
                grav *= PHYS_ENTGRAVITY(other);
  
  
  void trigger_push_touch()
  {SELFPARAM();
-       if (self.active == ACTIVE_NOT)
+       if (this.active == ACTIVE_NOT)
                return;
  
  #ifdef SVQC
                return;
  #endif
  
-       if(self.team)
-               if(((self.spawnflags & 4) == 0) == (DIFF_TEAM(self, other)))
+       if(this.team)
+               if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, other)))
                        return;
  
        EXACTTRIGGER_TOUCH;
  
-       if(self.enemy)
+       if(this.enemy)
        {
-               other.velocity = trigger_push_calculatevelocity(other.origin, self.enemy, self.height);
+               other.velocity = trigger_push_calculatevelocity(other.origin, this.enemy, this.height);
                other.move_velocity = other.velocity;
        }
-       else if(self.target)
+       else if(this.target)
        {
                entity e;
                RandomSelection_Init();
-               for(e = world; (e = find(e, targetname, self.target)); )
+               for(e = world; (e = find(e, targetname, this.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.velocity = trigger_push_calculatevelocity(other.origin, RandomSelection_chosen_ent, this.height);
                other.move_velocity = other.velocity;
        }
        else
        {
-               other.velocity = self.movedir;
+               other.velocity = this.movedir;
                other.move_velocity = other.velocity;
        }
  
                // 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
+               if(this.pushltime < time)  // prevent "snorring" sound when a player hits the jumppad more than once
                {
                        // flash when activated
                        Send_Effect(EFFECT_JUMPPAD, other.origin, other.velocity, 1);
-                       _sound (other, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
-                       self.pushltime = time + 0.2;
+                       _sound (other, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+                       this.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)
+                               if(other.(jumppadsused[i]) == this)
                                        found = true;
                        if(!found)
                        {
-                               other.(jumppadsused[other.jumppadcount % NUM_JUMPPADSUSED]) = self;
+                               other.(jumppadsused[other.jumppadcount % NUM_JUMPPADSUSED]) = this;
                                other.jumppadcount = other.jumppadcount + 1;
                        }
  
                        if(IS_REAL_CLIENT(other))
                        {
-                               if(self.message)
-                                       centerprint(other, self.message);
+                               if(this.message)
+                                       centerprint(other, this.message);
                        }
                        else
                                other.lastteleporttime = time;
                other.istypefrag = 0;
        }
  
-       if(self.enemy.target)
+       if(this.enemy.target)
        {
                activator = other;
-               WITH(entity, self, self.enemy, SUB_UseTargets());
+               WITH(entity, self, this.enemy, SUB_UseTargets());
        }
  
        if (other.flags & FL_PROJECTILE)
                UpdateCSQCProjectile(other);
        }
  
-       if (self.spawnflags & PUSH_ONCE)
+       if (this.spawnflags & PUSH_ONCE)
        {
-               self.touch = func_null;
-               self.think = SUB_Remove;
-               self.nextthink = time;
+               this.touch = func_null;
+               this.think = SUB_Remove_self;
+               this.nextthink = time;
        }
  #endif
  }
@@@ -313,7 -313,7 +313,7 @@@ void trigger_push_findtarget(
        }
  
        trigger_push_link();
-       defer(0.1, trigger_push_updatelink);
+       defer(self, 0.1, trigger_push_updatelink);
  #endif
  }
  
index 214f0d2c5c88e9c13d3737d3b2200fc6fd28c24a,fcadd2d43432cc7d2cc996cbb896483d5e1b2aa0..f7ba35cc407ed9e2cea30a5bd6af2dc604da5fef
@@@ -11,7 -11,6 +11,6 @@@
        #include "../../lib/warpzone/common.qh"
        #include "../../lib/warpzone/client.qh"
        #include "../util.qh"
-       #include "../buffs/all.qh"
        #include "../../client/autocvars.qh"
        #include "../deathtypes/all.qh"
        #include "../../lib/csqcmodel/interpolate.qh"
@@@ -28,7 -27,6 +27,6 @@@
      #include "../stats.qh"
      #include "../teams.qh"
      #include "../util.qh"
-     #include "../buffs/all.qh"
      #include "../monsters/all.qh"
      #include "config.qh"
      #include "../../server/weapons/csqcprojectile.qh"
@@@ -55,7 -53,7 +53,7 @@@
  
  // WEAPON PLUGIN SYSTEM
  
- WepSet WepSet_FromWeapon(int a) {
+ WepSet _WepSet_FromWeapon(int a) {
        a -= WEP_FIRST;
        if (Weapons_MAX > 24)
        if (a >= 24) {
        return '1 0 0' * power2of(a);
  }
  #ifdef SVQC
 -void WepSet_AddStat()
 -{
 -      addstat(STAT_WEAPONS, AS_INT, weapons_x);
 -      if (Weapons_MAX > 24)
 -      addstat(STAT_WEAPONS2, AS_INT, weapons_y);
 -      if (Weapons_MAX > 48)
 -      addstat(STAT_WEAPONS3, AS_INT, weapons_z);
 -}
 -void WepSet_AddStat_InMap()
 -{
 -      addstat(STAT_WEAPONSINMAP, AS_INT, weaponsinmap_x);
 -      if (Weapons_MAX > 24)
 -      addstat(STAT_WEAPONSINMAP2, AS_INT, weaponsinmap_y);
 -      if (Weapons_MAX > 48)
 -      addstat(STAT_WEAPONSINMAP3, AS_INT, weaponsinmap_z);
 -}
  void WriteWepSet(float dst, WepSet w)
  {
        if (Weapons_MAX > 48)
  #ifdef CSQC
  WepSet WepSet_GetFromStat()
  {
 -      WepSet w = '0 0 0';
 -      w.x = getstati(STAT_WEAPONS);
 -      if (Weapons_MAX > 24)
 -      w.y = getstati(STAT_WEAPONS2);
 -      if (Weapons_MAX > 48)
 -      w.z = getstati(STAT_WEAPONS3);
 -      return w;
 +      return STAT(WEAPONS);
  }
  WepSet WepSet_GetFromStat_InMap()
  {
 -      WepSet w = '0 0 0';
 -      w_x = getstati(STAT_WEAPONSINMAP);
 -      if (Weapons_MAX > 24)
 -      w_y = getstati(STAT_WEAPONSINMAP2);
 -      if (Weapons_MAX > 48)
 -      w_z = getstati(STAT_WEAPONSINMAP3);
 -      return w;
 +      return STAT(WEAPONSINMAP);
  }
  WepSet ReadWepSet()
  {
@@@ -254,8 -280,8 +252,8 @@@ int GetAmmoStat(.int ammotype
                case ammo_nails: return STAT_NAILS;
                case ammo_rockets: return STAT_ROCKETS;
                case ammo_cells: return STAT_CELLS;
 -              case ammo_plasma: return STAT_PLASMA;
 -              case ammo_fuel: return STAT_FUEL;
 +              case ammo_plasma: return STAT_PLASMA.m_id;
 +              case ammo_fuel: return STAT_FUEL.m_id;
                default: return -1;
        }
  }
index baa11371acb4f598c34975eeb770876fcf136516,8d62426daf61ccf15ccded49523d5d50499c559c..eb7a48f7ff6a68c2c41a1c75adc105c8ee1037c2
@@@ -7,9 -7,9 +7,7 @@@
  
  // weapon sets
  typedef vector WepSet;
- #define WEPSET(id) WepSet_FromWeapon(WEP_##id.m_id)
- WepSet WepSet_FromWeapon(int a);
  #ifdef SVQC
 -void WepSet_AddStat();
 -void WepSet_AddStat_InMap();
  void WriteWepSet(float dest, WepSet w);
  #endif
  
@@@ -35,9 -35,17 +33,17 @@@ WepSet ReadWepSet()
  REGISTRY(Weapons, 72) // Increase as needed. Can be up to 72.
  #define Weapons_from(i) _Weapons_from(i, WEP_Null)
  #define get_weaponinfo(i) Weapons_from(i)
- REGISTER_REGISTRY(RegisterWeapons)
+ REGISTER_REGISTRY(Weapons)
  STATIC_INIT(WeaponPickup) { FOREACH(Weapons, true, LAMBDA(it.m_pickup = NEW(WeaponPickup, it))); }
  
+ .WepSet m_wepset;
+ #define WEPSET(id) (WEP_##id.m_wepset)
+ #define WepSet_FromWeapon(i) (Weapons_from(i).m_wepset)
+ WepSet _WepSet_FromWeapon(int i);
+ STATIC_INIT(WepSets)
+ {
+     FOREACH(Weapons, true, LAMBDA(it.m_wepset = _WepSet_FromWeapon(it.m_id)));
+ }
  
  GENERIC_COMMAND(dumpweapons, "Dump all weapons into weapons_dump.txt") // WEAPONTODO: make this work with other progs than just server
  {
  
  #define REGISTER_WEAPON(id, inst) \
      /* WepSet WEPSET_##id; */ \
-     REGISTER(RegisterWeapons, WEP, Weapons, id, m_id, inst)
+     REGISTER(Weapons, WEP, id, m_id, inst)
  
  // create cvars for weapon settings
  #define WEP_ADD_CVAR_NONE(wepname,name) [[last]] float autocvar_g_balance_##wepname##_##name;
@@@ -145,7 -153,7 +151,7 @@@ STATIC_INIT(register_weapons_done
  {
      FOREACH(Weapons, true, LAMBDA(
          it.m_id = i;
-         WepSet set = WepSet_FromWeapon(it.m_id);
+         WepSet set = it.m_wepset;
          WEPSET_ALL |= set;
          if ((it.spawnflags) & WEP_FLAG_SUPERWEAPON) WEPSET_SUPERWEAPONS |= set;
          it.weapon = it.m_id;
index 072bc1cbee3356264fbde69cc1a2cecc2191e6aa,8a90679b81a2690428328e79dd4598ccf40ce183..5e31fbdbeee71536b8dcf7c19dc10b0417a131d6
@@@ -91,7 -91,8 +91,8 @@@ NET_HANDLE(TE_CSQC_VORTEXBEAMPARTICLE, 
        charge = sqrt(charge); // divide evenly among trail spacing and alpha
        particles_alphamin = particles_alphamax = particles_fade = charge;
  
-       if (autocvar_cl_particles_oldvortexbeam && (STAT(ALLOW_OLDVORTEXBEAM) || isdemo()))
+       if(!MUTATOR_CALLHOOK(Particles_VortexBeam, shotorg, endpos))
 -      if(autocvar_cl_particles_oldvortexbeam && (getstati(STAT_ALLOW_OLDVORTEXBEAM) || isdemo()))
++      if(autocvar_cl_particles_oldvortexbeam && (STAT(ALLOW_OLDVORTEXBEAM) || isdemo()))
                WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM_OLD), shotorg, endpos, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
        else
                WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum(EFFECT_VORTEX_BEAM), shotorg, endpos, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
index 79cfe76c6ae205178718acc53989b509630ad0a3,b9bcec58e60c6df31679667ea4a7ded1397333b5..ce39bca1bda2ff74ead4a9bb5d9a1399a120c132
  #define pointparticles __pointparticles
  #define setmodel _setmodel
  
 +#define STAT_FRAGLIMIT _STAT_FRAGLIMIT
 +#define STAT_TIMELIMIT _STAT_TIMELIMIT
 +#define STAT_MOVEVARS_TICRATE _STAT_MOVEVARS_TICRATE
 +#define STAT_MOVEVARS_TIMESCALE _STAT_MOVEVARS_TIMESCALE
 +#define STAT_MOVEVARS_GRAVITY _STAT_MOVEVARS_GRAVITY
 +
  #include "upstream/csprogsdefs.qc"
  
  #undef true
  #undef pointparticles
  #undef setmodel
  
 +#undef STAT_FRAGLIMIT
 +#undef STAT_TIMELIMIT
 +#undef STAT_MOVEVARS_TICRATE
 +#undef STAT_MOVEVARS_TIMESCALE
 +#undef STAT_MOVEVARS_GRAVITY
 +
  #pragma noref 0
  
- #define ReadFloat() ReadCoord()
  #endif
diff --combined qcsrc/lib/registry.qh
index 8ad8be56e213f7704276f9b3e77dd2b479181aa5,40a39395bcf34884e6d9b2610d6a2c108b295cab..f2bdd1e26199984910fd35f0384985ac593de4e7
  
  #include "oo.qh"
  
- #define REGISTER_REGISTRY(func) ACCUMULATE_FUNCTION(__static_init, func)
- #define REGISTER_INIT(ns, id) [[accumulate]] void Register_##ns##_##id##_init(entity this)
- #define REGISTER_INIT_POST(ns, id) [[accumulate]] void Register_##ns##_##id##_init_post(entity this)
+ #if 1
+       #define _R_MAP(r, max) AL_declare(r); STATIC_INIT(r) { AL_init(r, max, NULL, e); }
+       #define _R_GET(r, i) AL_gete(r, i)
+       #define _R_SET(r, i, e) AL_sete(r, i, e)
+ #else
+       #define _R_MAP(r, max) entity r[max]
+       #define _R_GET(r, i) r[i]
+       #define _R_SET(r, i, e) r[i] = e
+ #endif
  
+ /**
+  * Declare a new registry.
+  *
+  * Don't forget to call `REGISTER_REGISTRY`:
+  *     REGISTER_REGISTRY(Foos)
+  */
  #define REGISTRY(id, max) \
        void Register##id() {} \
        const int id##_MAX = max; \
-       noref entity _##id[id##_MAX], id##_first, id##_last; \
+       noref entity id##_first, id##_last; \
+       _R_MAP(_##id, id##_MAX); \
        int id##_COUNT; \
-       entity _##id##_from(int i, entity null) { if (i >= 0 && i < id##_COUNT) { entity e = _##id[i]; if (e) return e; } return null; }
+       entity _##id##_from(int i, entity null) { if (i >= 0 && i < id##_COUNT) { entity e = _R_GET(_##id, i); if (e) return e; } return null; }
+ REGISTRY(Registries, BITS(8))
  
  /** registered item identifier */
  .string registered_id;
  
  /**
-  * Register a new entity with a global constructor.
+  * Register a new entity with a registry.
   * Must be followed by a semicolon or a function body with a `this` parameter.
   * Wrapper macros may perform actions after user initialization like so:
   *     #define REGISTER_FOO(id) \
-  *         REGISTER(RegisterFoos, FOO, FOOS, id, m_id, NEW(Foo)); \
+  *         REGISTER(Foos, FOO, id, m_id, NEW(Foo)); \
   *         REGISTER_INIT_POST(FOO, id) { \
   *             print("Registering foo #", this.m_id + 1, "\n"); \
   *         } \
   *         REGISTER_INIT(FOO, id)
   *
-  * Don't forget to forward declare `initfunc` and call `REGISTER_REGISTRY`:
-  *     void RegisterFoos();
-  *     REGISTER_REGISTRY(RegisterFoos)
   *
-  * @param initfunc  The global constructor to accumulate into
+  * @param registry  The registry to add each entity to.
   * @param ns        Short for namespace, prefix for each global (ns##_##id)
-  * @param array     The array to add each entity to. Also requires `array##_first` and `array##_last` to be defined
   * @param id        The identifier of the current entity being registered
-  * @param fld       The field to store the current count into
+  * @param fld       The field to store the locally unique unique entity id
   * @param inst      An expression to create a new instance, invoked for every registration
   */
- #define REGISTER(initfunc, ns, array, id, fld, inst) \
-       entity ns##_##id; \
-       REGISTER_INIT(ns, id) {} \
-       REGISTER_INIT_POST(ns, id) {} \
-       void Register_##ns##_##id() \
+ #define REGISTER(...) EVAL(OVERLOAD(REGISTER, __VA_ARGS__))
+ #define REGISTER_5(registry, ns, id, fld, inst) REGISTER_4(registry, ns##_##id, fld, inst)
+ #define REGISTER_4(registry, id, fld, inst) \
+       entity id; \
+       REGISTER_INIT(id) {} \
+       REGISTER_INIT_POST(id) {} \
+       void Register_##id() \
        { \
-               if (array##_COUNT >= array##_MAX) LOG_FATALF("Registry capacity exceeded (%s)", ftos(array##_MAX)); \
-               entity this = inst; \
-               ns##_##id = this; \
+               if (registry##_COUNT >= registry##_MAX) LOG_FATALF("Registry capacity exceeded (%s)", ftos(registry##_MAX)); \
+               entity this = id = inst; \
                this.registered_id = #id; \
-               REGISTRY_PUSH(array, fld, this); \
-               Register_##ns##_##id##_init(this); \
-               Register_##ns##_##id##_init_post(this); \
 -              this.fld = registry##_COUNT; \
 -              _R_SET(_##registry, registry##_COUNT, this); \
 -              ++registry##_COUNT; \
 -              if (!registry##_first) registry##_first = this; \
 -              if (registry##_last)   registry##_last.REGISTRY_NEXT = this; \
 -              registry##_last = this; \
++              REGISTRY_PUSH(registry, fld, this); \
+               Register_##id##_init(this); \
+               Register_##id##_init_post(this); \
        } \
-       ACCUMULATE_FUNCTION(initfunc, Register_##ns##_##id) \
-       REGISTER_INIT(ns, id)
- #define REGISTRY_PUSH(array, fld, it) do { \
-       it.fld = array##_COUNT; \
-       _##array[array##_COUNT++] = it; \
-       if (!array##_first) array##_first = it; \
-       if (array##_last)   array##_last.REGISTRY_NEXT = it; \
-       array##_last = it; \
+       ACCUMULATE_FUNCTION(Register##registry, Register_##id) \
+       REGISTER_INIT(id)
++#define REGISTRY_PUSH(registry, fld, it) do { \
++      it.fld = registry##_COUNT; \
++      _R_SET(_##registry, registry##_COUNT, it); \
++      ++registry##_COUNT; \
++      if (!registry##_first) registry##_first = it; \
++      if (registry##_last)   registry##_last.REGISTRY_NEXT = it; \
++      registry##_last = it; \
 +} while (0)
 +
 +#define REGISTRY_RESERVE(registry, fld, id, suffix) do { \
 +      entity e = new(registry_reserved); \
-       e.registered_id = #id #suffix; \
++      e.registered_id = #id "/" #suffix; \
 +      REGISTRY_PUSH(registry, fld, e); \
 +} while (0)
 +
+ #define REGISTER_INIT(id) [[accumulate]] void Register_##id##_init(entity this)
+ #define REGISTER_INIT_POST(id) [[accumulate]] void Register_##id##_init_post(entity this)
  /** internal next pointer */
  #define REGISTRY_NEXT enemy
  .entity REGISTRY_NEXT;
  
- #define REGISTRY_SORT(id, skip) \
+ #define REGISTRY_SORT(...) EVAL(OVERLOAD(REGISTRY_SORT, __VA_ARGS__))
+ #define REGISTRY_SORT_1(id) REGISTRY_SORT_2(id, 0)
+ #define REGISTRY_SORT_2(id, skip) \
        void _REGISTRY_SWAP_##id(int i, int j, entity pass) \
        { \
                i += skip; j += skip; \
                \
-               entity a = _##id[i], b = _##id[j]; \
-               _##id[i] = b; \
-               _##id[j] = a; \
+               entity a = _R_GET(_##id, i), b = _R_GET(_##id, j); \
+               _R_SET(_##id, i, b); \
+               _R_SET(_##id, j, a); \
          \
                entity a_next = a.REGISTRY_NEXT, b_next = b.REGISTRY_NEXT; \
                a.REGISTRY_NEXT = b_next; \
                b.REGISTRY_NEXT = a_next; \
          \
                if (i == 0) id##_first = b; \
-               else _##id[i - 1].REGISTRY_NEXT = b; \
+               else _R_GET(_##id, i - 1).REGISTRY_NEXT = b; \
          \
                if (j == 0) id##_first = a; \
-               else _##id[j - 1].REGISTRY_NEXT = a; \
+               else _R_GET(_##id, j - 1).REGISTRY_NEXT = a; \
        } \
        int _REGISTRY_CMP_##id(int i, int j, entity pass) \
        { \
                i += skip; j += skip; \
-               string a = _##id[i].registered_id; \
-               string b = _##id[j].registered_id; \
+               string a = _R_GET(_##id, i).registered_id; \
+               string b = _R_GET(_##id, j).registered_id; \
                return strcmp(a, b); \
        } \
        STATIC_INIT(Registry_sort_##id) \
@@@ -129,7 -136,7 +146,7 @@@ void Registry_send(string id, string ha
                string h = REGISTRY_HASH(id) = strzone(digest_hex(algo, s)); \
                LOG_TRACEF(#id ": %s\n[%s]\n", h, s); \
        } \
-       [[accumulate]] void Registry_check(string r, string sv) \
+       void Registry_check(string r, string sv) \
        { \
                if (r == #id) \
                { \
                        } \
                } \
        } \
-       [[accumulate]] void Registry_send_all() { Registry_send(#id, REGISTRY_HASH(id)); } \
+       void Registry_send_all() { Registry_send(#id, REGISTRY_HASH(id)); } \
+ #define REGISTER_REGISTRY(...) EVAL(OVERLOAD(REGISTER_REGISTRY, __VA_ARGS__))
+ #define REGISTER_REGISTRY_1(id) REGISTER_REGISTRY_2(id, #id)
+ #define REGISTER_REGISTRY_2(id, str) \
+       ACCUMULATE_FUNCTION(__static_init, Register##id) \
+       CLASS(id##Registry, Object) \
+               ATTRIB(id##Registry, m_name, string, str) \
+               ATTRIB(id##Registry, REGISTRY_NEXT, entity, id##_first) \
+       ENDCLASS(id##Registry) \
+       REGISTER(Registries, REGISTRY, id, m_id, NEW(id##Registry));
  
  #endif
diff --combined qcsrc/lib/stats.qh
index 32927f4bd8b7793eecfcdb0fad49908662e53254,12dc425cd356e876a78e3406d4cb58126a6ea4d8..da796b910f5fd69745323de0b3493e7530ea5843
@@@ -1,15 -1,11 +1,15 @@@
  #ifndef LIB_STATS_H
  #define LIB_STATS_H
  
 +// TODO: rename to 'netvars'
 +
  #include "registry.qh"
  #include "sort.qh"
  
  .int m_id;
 +typedef vector vectori;
  
 +#define REGISTER_STAT(...) EVAL(OVERLOAD(REGISTER_STAT, __VA_ARGS__))
  #if defined(CSQC)
        /** Get all stats and store them as globals, access with `STAT(ID)` */
        void stats_get() {}
        #define getstat_int(id) getstati(id, 0, 24)
        #define getstat_bool(id) boolean(getstati(id))
        #define getstat_float(id) getstatf(id)
 +      #define getstat_vector(id) vec3(getstat_float(id + 0), getstat_float(id + 1), getstat_float(id + 2))
 +      #define getstat_vectori(id) vec3(getstat_int(id + 0), getstat_int(id + 1), getstat_int(id + 2))
  
        #define _STAT(id) g_stat_##id
 -      #define REGISTER_STAT(id, type) \
 -              type _STAT(id); \
 -              REGISTER(Stats, STAT, id, m_id, new(stat)) \
 +      #define REGISTER_STAT_2(id, T) \
 +              T _STAT(id); \
-               REGISTER(RegisterStats, STAT, Stats, id, m_id, new(stat)) \
++              REGISTER(Stats, STAT_##id, m_id, new(stat)) \
                { \
                        make_pure(this); \
-                               REGISTRY_RESERVE(Stats, m_id, id, _y); \
-                               REGISTRY_RESERVE(Stats, m_id, id, _z); \
 +                      if (#T == "vector" || #T == "vectori") { \
++                              REGISTRY_RESERVE(Stats, m_id, STAT_##id, y); \
++                              REGISTRY_RESERVE(Stats, m_id, STAT_##id, z); \
 +                      } \
                } \
                [[accumulate]] void stats_get() \
                { \
 -                      _STAT(id) = getstat_##type(STAT_##id.m_id); \
 +                      _STAT(id) = getstat_##T(STAT_##id.m_id); \
                }
 +      #define REGISTER_STAT_3(x, T, expr) REGISTER_STAT(x, T)
  #elif defined(SVQC)
        /** Add all registered stats, access with `STAT(ID, player)` or `.type stat = _STAT(ID); player.stat` */
        void stats_add() {}
        #define addstat_int(id, fld) addstat(id, AS_INT, fld)
        #define addstat_bool(id, fld) addstat(id, AS_INT, fld)
        #define addstat_float(id, fld) addstat(id, AS_FLOAT, fld)
 +      #define addstat_vector(id, fld) do { \
 +              addstat_float(id + 0, fld##_x); \
 +              addstat_float(id + 1, fld##_y); \
 +              addstat_float(id + 2, fld##_z); \
 +      } while (0)
 +      #define addstat_vectori(id, fld) do { \
 +              addstat_int(id + 0, fld##_x); \
 +              addstat_int(id + 1, fld##_y); \
 +              addstat_int(id + 2, fld##_z); \
 +      } while (0)
        const int AS_STRING = 1;
        const int AS_INT = 2;
        const int AS_FLOAT = 8;
  
 +      .int __stat_null;
 +      /** Prevent engine stats being sent */
 +      STATIC_INIT(stats_clear)
 +      {
 +              int r = 32;
 +              for (int i = 0, n = 256 - r; i < n; ++i) {
 +                      addstat(r + i, AS_INT, __stat_null);
 +              }
 +      }
 +
        #define _STAT(id) stat_##id
 -      #define REGISTER_STAT(id, type) \
 -              .type _STAT(id); \
 -              REGISTER(Stats, STAT, id, m_id, new(stat)) \
 +      #define REGISTER_STAT_2(id, T) \
 +              .T _STAT(id); \
-               REGISTER(RegisterStats, STAT, Stats, id, m_id, new(stat)) \
++              REGISTER(Stats, STAT_##id, m_id, new(stat)) \
                { \
                        make_pure(this); \
-                               REGISTRY_RESERVE(Stats, m_id, id, _y); \
-                               REGISTRY_RESERVE(Stats, m_id, id, _z); \
 +                      if (#T == "vector" || #T == "vectori") { \
++                              REGISTRY_RESERVE(Stats, m_id, STAT_##id, y); \
++                              REGISTRY_RESERVE(Stats, m_id, STAT_##id, z); \
 +                      } \
                } \
                [[accumulate]] void stats_add() \
                { \
 -                      addstat_##type(STAT_##id.m_id, _STAT(id)); \
 +                      addstat_##T(STAT_##id.m_id, _STAT(id)); \
                }
 +      void GlobalStats_update(entity this) {}
 +    #define REGISTER_STAT_3(x, T, expr) \
 +      REGISTER_STAT(x, T); \
 +      [[accumulate]] void GlobalStats_update(entity this) { STAT(x, this) = (expr); } \
 +      STATIC_INIT(worldstat_##x) { entity this = world; STAT(x, this) = (expr); }
  #else
 -      #define REGISTER_STAT(id, type)
 +      #define REGISTER_STAT_2(id, type)
 +    #define REGISTER_STAT_3(x, T, expr)
  #endif
  
 -const int STATS_ENGINE_RESERVE = 32 + (8 * 3); // Not sure how to handle vector stats yet, reserve them too
 +const int STATS_ENGINE_RESERVE = 32;
  
 -REGISTRY(Stats, 220 - STATS_ENGINE_RESERVE)
 +REGISTRY(Stats, 256 - STATS_ENGINE_RESERVE)
- REGISTER_REGISTRY(RegisterStats)
- REGISTRY_SORT(Stats, 0)
+ REGISTER_REGISTRY(Stats)
+ REGISTRY_SORT(Stats)
  REGISTRY_CHECK(Stats)
  STATIC_INIT(RegisterStats_renumber)
  {
index ac151c38cc2232063d8beedb598c5b212ba18b2a,c271b65b49523721b47972de15f7a6caf9e6b8de..0ca8a0432e392cdac4a8e015f3363178413a252e
@@@ -55,7 -55,6 +55,6 @@@ bool autocvar_bot_navigation_ignoreplay
  bool autocvar_bot_nofire;
  #define autocvar_bot_number cvar("bot_number")
  #define autocvar_bot_prefix cvar_string("bot_prefix")
- bool autocvar_bot_sound_monopoly;
  #define autocvar_bot_suffix cvar_string("bot_suffix")
  bool autocvar_bot_usemodelnames;
  int autocvar_bot_vs_human;
@@@ -347,6 -346,7 +346,6 @@@ string autocvar_sv_defaultplayermodel_p
  string autocvar_sv_defaultplayermodel_red;
  string autocvar_sv_defaultplayermodel_yellow;
  int autocvar_sv_defaultplayerskin;
 -bool autocvar_sv_dodging_frozen;
  bool autocvar_sv_doublejump;
  bool autocvar_sv_eventlog;
  bool autocvar_sv_eventlog_console;
@@@ -437,7 -437,6 +436,6 @@@ bool autocvar_waypoint_benchmark
  float autocvar_sv_gameplayfix_gravityunaffectedbyticrate;
  bool autocvar_sv_gameplayfix_upwardvelocityclearsongroundflag;
  float autocvar_g_trueaim_minrange;
- bool autocvar_g_debug_defaultsounds;
  float autocvar_g_grab_range;
  int autocvar_g_max_info_autoscreenshot;
  bool autocvar_physics_ode;
index ddbbfd9e457401059059d42f0cdbadf2fc430144,47aff4a0b0c4dacad39a7263b960b63cc0984c06..06df42cde9e149e43c2fb19a5d4869cb79d90236
@@@ -3,7 -3,6 +3,6 @@@
  #include "anticheat.qh"
  #include "cl_impulse.qh"
  #include "cl_player.qh"
- #include "ent_cs.qh"
  #include "ipban.qh"
  #include "miscfunctions.qh"
  #include "portals.qh"
@@@ -23,6 -22,7 +22,7 @@@
  #include "bot/bot.qh"
  #include "bot/navigation.qh"
  
+ #include "../common/ent_cs.qh"
  #include "../common/vehicles/all.qh"
  #include "../common/triggers/teleporters.qh"
  
@@@ -175,7 -175,6 +175,6 @@@ void setplayermodel(entity e, string mo
        precache_model(modelname);
        _setmodel(e, modelname);
        player_setupanimsformodel();
-       UpdatePlayerSounds();
  }
  
  /*
@@@ -319,6 -318,15 +318,15 @@@ void PutObserverInServer(
        self.event_damage = func_null;
  }
  
+ int player_getspecies(entity this)
+ {
+       get_model_parameters(this.model, this.skin);
+       int s = get_model_parameters_species;
+       get_model_parameters(string_null, 0);
+       if (s < 0) return SPECIES_HUMAN;
+       return s;
+ }
  .float model_randomizer;
  void FixPlayermodel(entity player)
  {
  
        if(chmdl || oldskin != player.skin) // model or skin has changed
        {
-               player.species = player_getspecies(); // update species
-               UpdatePlayerSounds(); // update skin sounds
+               player.species = player_getspecies(player); // update species
        }
  
        if(!teamplay)
@@@ -1171,7 -1178,7 +1178,7 @@@ void ClientConnect (
        else
                stuffcmd(self, "set _teams_available 0\n");
  
-       attach_entcs(self);
+       entcs_attach(self);
  
        bot_relinkplayerlist();
  
        self.model_randomizer = random();
  
        if(IS_REAL_CLIENT(self))
-               sv_notice_join();
+               sv_notice_join(self);
  
        for (entity e = world; (e = findfloat(e, init_for_player_needed, 1)); ) {
                WITH(entity, self, e, e.init_for_player(this));
@@@ -1257,7 -1264,7 +1264,7 @@@ void ClientDisconnect (
  
        bot_clientdisconnect();
  
-       detach_entcs(self);
+       entcs_detach(self);
  
        if(autocvar_sv_eventlog)
                GameLogEcho(strcat(":part:", ftos(self.playerid)));
        if(self.weaponorder_byimpulse)
                strunzone(self.weaponorder_byimpulse);
  
-       ClearPlayerSounds();
        if(self.personal)
                remove(self.personal);
  
@@@ -2424,8 -2429,8 +2429,8 @@@ void PlayerPreThink (
                        if (!self.crouch)
                        {
                                self.crouch = true;
 -                              self.view_ofs = self.stat_pl_crouch_view_ofs;
 -                              setsize (self, self.stat_pl_crouch_min, self.stat_pl_crouch_max);
 +                              self.view_ofs = STAT(PL_CROUCH_VIEW_OFS, self);
 +                              setsize (self, STAT(PL_CROUCH_MIN, self), STAT(PL_CROUCH_MAX, self));
                                // setanim(self, self.anim_duck, false, true, true); // this anim is BROKEN anyway
                        }
                }
                {
                        if (self.crouch)
                        {
 -                              tracebox(self.origin, self.stat_pl_min, self.stat_pl_max, self.origin, false, self);
 +                              tracebox(self.origin, STAT(PL_MIN, self), STAT(PL_MAX, self), self.origin, false, self);
                                if (!trace_startsolid)
                                {
                                        self.crouch = false;
 -                                      self.view_ofs = self.stat_pl_view_ofs;
 -                                      setsize (self, self.stat_pl_min, self.stat_pl_max);
 +                                      self.view_ofs = STAT(PL_VIEW_OFS, self);
 +                                      setsize (self, STAT(PL_MIN, self), STAT(PL_MAX, self));
                                }
                        }
                }
diff --combined qcsrc/server/defs.qh
index e52801a92c87e6be0688eb76662dd96b6cf82be0,c04acac1593aa6bb8880c9ea77bf96d2b0ffcc64..9c2dc4064097acbd97f5cc0ffb6260b3a89c57c4
@@@ -54,8 -54,6 +54,6 @@@ void UpdateFrags(entity player, float f
  
  float team1_score, team2_score, team3_score, team4_score;
  
- float maxclients;
  // flag set on worldspawn so that the code knows if it is dedicated or not
  float server_is_dedicated;
  
@@@ -79,7 -77,7 +77,7 @@@
  
  .float        strength_finished = _STAT(STRENGTH_FINISHED);
  .float        invincible_finished = _STAT(INVINCIBLE_FINISHED);
 -.float        superweapons_finished;
 +.float        superweapons_finished = _STAT(SUPERWEAPONS_FINISHED);
  
  .float cnt; // used in too many places
  .float count;
@@@ -158,7 -156,7 +156,7 @@@ const float MAX_DAMAGEEXTRARADIUS = 16
  
  //.int weapon; // current weapon
  .int switchweapon = _STAT(SWITCHWEAPON);
 -.int switchingweapon; // weapon currently being switched to (is copied from switchweapon once switch is possible)
 +.int switchingweapon = _STAT(SWITCHINGWEAPON); // weapon currently being switched to (is copied from switchweapon once switch is possible)
  .string weaponname; // name of .weapon
  
  // WEAPONTODO
@@@ -227,7 -225,7 +225,7 @@@ float default_weapon_alpha
  .float cvar_cl_clippedspectating;
  .float cvar_cl_autoscreenshot;
  .float cvar_cl_jetpack_jump;
 -.float cvar_cl_movement_track_canjump;
 +.float cvar_cl_movement_track_canjump = _STAT(MOVEVARS_CL_TRACK_CANJUMP);
  .float cvar_cl_newusekeysupported;
  
  .string cvar_g_xonoticversion;
@@@ -256,8 -254,7 +254,8 @@@ void FixClientCvars(entity e)
  // WEAPONTODO: remove this
  WepSet weaponsInMap;
  
 -.WepSet weaponsinmap;
 +#define weapons _STAT(WEAPONS)
 +#define weaponsinmap _STAT(WEAPONSINMAP)
  
  .float respawn_countdown; // next number to count
  
@@@ -304,75 -301,6 +302,6 @@@ float tracebox_hits_trigger_hurt(vecto
  
  float next_pingtime;
  
- // player sounds, voice messages
- // TODO implemented fall and falling
- #define ALLPLAYERSOUNDS \
-               _VOICEMSG(death) \
-               _VOICEMSG(drown) \
-               _VOICEMSG(fall) \
-               _VOICEMSG(falling) \
-               _VOICEMSG(gasp) \
-               _VOICEMSG(jump) \
-               _VOICEMSG(pain100) \
-               _VOICEMSG(pain25) \
-               _VOICEMSG(pain50) \
-               _VOICEMSG(pain75)
- #define ALLVOICEMSGS \
-               _VOICEMSG(attack) \
-               _VOICEMSG(attackinfive) \
-               _VOICEMSG(coverme) \
-               _VOICEMSG(defend) \
-               _VOICEMSG(freelance) \
-               _VOICEMSG(incoming) \
-               _VOICEMSG(meet) \
-               _VOICEMSG(needhelp) \
-               _VOICEMSG(seenflag) \
-               _VOICEMSG(taunt) \
-               _VOICEMSG(teamshoot)
- #define _VOICEMSG(m) .string playersound_##m;
- ALLPLAYERSOUNDS
- ALLVOICEMSGS
- #undef _VOICEMSG
- // reserved sound names for the future (some models lack sounds for them):
- //            _VOICEMSG(flagcarriertakingdamage) \
- //            _VOICEMSG(getflag) \
- // reserved sound names for the future (ALL models lack sounds for them):
- //            _VOICEMSG(affirmative) \
- //            _VOICEMSG(attacking) \
- //            _VOICEMSG(defending) \
- //            _VOICEMSG(roaming) \
- //            _VOICEMSG(onmyway) \
- //            _VOICEMSG(droppedflag) \
- //            _VOICEMSG(negative) \
- //            _VOICEMSG(seenenemy) \
- //      /**/
- string globalsound_fall;
- string globalsound_metalfall;
- string globalsound_step;
- string globalsound_metalstep;
- const float VOICETYPE_PLAYERSOUND = 10;
- const float VOICETYPE_TEAMRADIO = 11;
- const float VOICETYPE_LASTATTACKER = 12;
- const float VOICETYPE_LASTATTACKER_ONLY = 13;
- const float VOICETYPE_AUTOTAUNT = 14;
- const float VOICETYPE_TAUNT = 15;
- void PrecachePlayerSounds(string f);
- void PrecacheGlobalSound(string samplestring);
- void UpdatePlayerSounds();
- void ClearPlayerSounds();
- void PlayerSound(.string samplefield, float channel, float voicetype);
- void GlobalSound(string samplestring, float channel, float voicetype);
- void FakeGlobalSound(string samplestring, float channel, float voicetype);
- void VoiceMessage(string type, string message);
- float GetPlayerSoundSampleField_notFound;
- .string GetVoiceMessageSampleField(string type);
  // autotaunt system
  .float cvar_cl_autotaunt;
  .float cvar_cl_voice_directional;
@@@ -388,7 -316,7 +317,7 @@@ bool independent_players
  
  string clientstuff;
  .float phase;
 -.int pressedkeys;
 +.int pressedkeys = _STAT(PRESSED_KEYS);
  
  .string fog;
  
@@@ -399,7 -327,7 +328,7 @@@ float cvar_purechanges_count
  float game_starttime; //point in time when the countdown to game start is over
  float round_starttime; //point in time when the countdown to round start is over
  .float stat_game_starttime = _STAT(GAMESTARTTIME);
 -.float stat_round_starttime;
 +.float stat_round_starttime = _STAT(ROUNDSTARTTIME);
  
  void W_Porto_Remove (entity p);
  
  
  .string message2;
  
 -.float stat_allow_oldvortexbeam;
 +.bool stat_allow_oldvortexbeam = _STAT(ALLOW_OLDVORTEXBEAM);
  
  // reset to 0 on weapon switch
  // may be useful to all weapons
@@@ -420,7 -348,7 +349,7 @@@ float g_nexball_meter_period
  void SUB_DontUseTargets();
  void SUB_UseTargets();
  
- .void() reset; // if set, an entity is reset using this
+ .void(entity this) reset; // if set, an entity is reset using this
  .void() reset2; // if set, an entity is reset using this (after calling ALL the reset functions for other entities)
  
  void ClientData_Touch(entity e);
@@@ -444,18 -372,18 +373,18 @@@ float servertime, serverprevtime, serve
  .float floodcontrol_voice;
  .float floodcontrol_voiceteam;
  
 -.float stat_shotorg; // networked stat for trueaim HUD
 +.float stat_shotorg = _STAT(SHOTORG); // networked stat for trueaim HUD
  
  string matchid;
  
 -.float last_pickup;
 +.float last_pickup = _STAT(LAST_PICKUP);
  
 -.float hit_time;
 -.float typehit_time;
 +.float hit_time = _STAT(HIT_TIME);
 +.float typehit_time = _STAT(TYPEHIT_TIME);
  
 -.float damage_dealt_total;
 +.float damage_dealt_total = _STAT(DAMAGE_DEALT_TOTAL);
  
 -.float stat_leadlimit;
 +.float stat_leadlimit = _STAT(LEADLIMIT);
  
  bool radar_showennemies;
  
@@@ -466,15 -394,15 +395,15 @@@ float client_cefc_accumulatortime
  
  .float weapon_load[Weapons_MAX];
  .int ammo_none; // used by the reloading system, must always be 0
 -.float clip_load;
 +.float clip_load = _STAT(WEAPON_CLIPLOAD);
  .float old_clip_load;
 -.float clip_size;
 +.float clip_size = _STAT(WEAPON_CLIPSIZE);
  
 -.float minelayer_mines;
 -.float vortex_charge;
 +.float minelayer_mines = _STAT(LAYED_MINES);
 +.float vortex_charge = _STAT(VORTEX_CHARGE);
  .float vortex_charge_rottime;
 -.float vortex_chargepool_ammo;
 -.float hagar_load;
 +.float vortex_chargepool_ammo = _STAT(VORTEX_CHARGEPOOL);
 +.float hagar_load = _STAT(HAGAR_LOAD);
  
  .int grab; // 0 = can't grab, 1 = owner can grab, 2 = owner and team mates can grab, 3 = anyone can grab
  
@@@ -514,8 -442,8 +443,8 @@@ const float ACTIVE_TOGGLE  = 3
  .float player_blocked;
  .float weapon_blocked; // weapon use disabled
  
 -.float frozen; // for freeze attacks
 -.float revive_progress;
 +.float frozen = _STAT(FROZEN); // for freeze attacks
 +.float revive_progress = _STAT(REVIVE_PROGRESS);
  .float revival_time; // time at which player was last revived
  .float revive_speed; // NOTE: multiplier (anything above 1 is instaheal)
  .entity iceblock;
  .entity muzzle_flash;
  .float misc_bulletcounter;    // replaces uzi & hlac bullet counter.
  
 -.float stat_respawn_time; // shows respawn time, and is negative when awaiting respawn
 +.float stat_respawn_time = _STAT(RESPAWN_TIME); // shows respawn time, and is negative when awaiting respawn
  
  void PlayerUseKey();
  
diff --combined qcsrc/server/g_damage.qc
index 5d9436f684ea4c3b87c2b1dcd6587b3bd214ceeb,dc306eee097ee18631039db4d66ae5104ec74081..dcd75023e6a9c393be0be286b7b2ed1d00f5eb0f
@@@ -12,7 -12,6 +12,6 @@@
  #include "weapons/accuracy.qh"
  #include "weapons/csqcprojectile.qh"
  #include "weapons/selection.qh"
- #include "../common/buffs/all.qh"
  #include "../common/constants.qh"
  #include "../common/deathtypes/all.qh"
  #include "../common/notifications.qh"
@@@ -62,10 -61,8 +61,8 @@@ void GiveFrags (entity attacker, entit
        {
                // after a frag, exchange the current weapon (or the culprit, if detectable) by a new random weapon
                Weapon culprit = DEATH_WEAPONOF(deathtype);
-               if(!culprit)
-                       culprit = get_weaponinfo(attacker.weapon);
-               else if(!(attacker.weapons & WepSet_FromWeapon(culprit.m_id)))
-                       culprit = get_weaponinfo(attacker.weapon);
+               if(!culprit) culprit = get_weaponinfo(attacker.weapon);
+               else if(!(attacker.weapons & (culprit.m_wepset))) culprit = get_weaponinfo(attacker.weapon);
  
                if(g_weaponarena_random_with_blaster && culprit == WEP_BLASTER) // WEAPONTODO: Shouldn't this be in a mutator?
                {
@@@ -85,7 -82,7 +82,7 @@@
  
                        // all others (including the culprit): remove
                        GiveFrags_randomweapons.weapons &= ~attacker.weapons;
-                       GiveFrags_randomweapons.weapons &= ~WepSet_FromWeapon(culprit.m_id);
+                       GiveFrags_randomweapons.weapons &= ~(culprit.m_wepset);
  
                        // among the remaining ones, choose one by random
                        W_RandomWeapons(GiveFrags_randomweapons, 1);
@@@ -93,7 -90,7 +90,7 @@@
                        if(GiveFrags_randomweapons.weapons)
                        {
                                attacker.weapons |= GiveFrags_randomweapons.weapons;
-                               attacker.weapons &= ~WepSet_FromWeapon(culprit.m_id);
+                               attacker.weapons &= ~(culprit.m_wepset);
                        }
                }
  
@@@ -262,6 -259,8 +259,8 @@@ float Obituary_WeaponDeath
        return false;
  }
  
 -.int buffs; // TODO: remove
++.int buffs = _STAT(BUFFS); // TODO: remove
  void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
  {
        // Sanity check
@@@ -856,7 -855,7 +855,7 @@@ void Damage (entity targ, entity inflic
                        farcent.origin = hitloc;
                        farcent.forcetype = FORCETYPE_FORCEATPOS;
                        farcent.nextthink = time + 0.1;
-                       farcent.think = SUB_Remove;
+                       farcent.think = SUB_Remove_self;
                }
                else
                {
diff --combined qcsrc/server/g_world.qc
index 2fc291b9663b3ae30ec779a3a86507e29541cdfc,de20273b809a2b180c06afa77193df7e68467d34..9c7fb11fbd1c04e67787da0978fb9c077de3c5be
@@@ -18,7 -18,6 +18,6 @@@
  #include "scores.qh"
  #include "teamplay.qh"
  #include "weapons/weaponstats.qh"
- #include "../common/buffs/all.qh"
  #include "../common/constants.qh"
  #include "../common/deathtypes/all.qh"
  #include "../common/mapinfo.qh"
@@@ -558,6 -557,7 +557,6 @@@ void Nagger_Init()
  void ClientInit_Spawn();
  void WeaponStats_Init();
  void WeaponStats_Shutdown();
 -void Physics_AddStats();
  spawnfunc(worldspawn)
  {
        float fd, l, j, n;
  
        compressShortVector_init();
  
-       entity head;
-       head = nextent(world);
        maxclients = 0;
-       while(head)
+       for (entity head = nextent(world); head; head = nextent(head))
        {
                ++maxclients;
-               head = nextent(head);
        }
  
        server_is_dedicated = (stof(cvar_defstring("is_dedicated")) ? true : false);
  
        WeaponStats_Init();
  
 -      WepSet_AddStat();
 -      WepSet_AddStat_InMap();
 -      addstat(STAT_SWITCHINGWEAPON, AS_INT, switchingweapon);
 -      addstat(STAT_ROUNDSTARTTIME, AS_FLOAT, stat_round_starttime);
 -      addstat(STAT_ALLOW_OLDVORTEXBEAM, AS_INT, stat_allow_oldvortexbeam);
        Nagger_Init();
  
 -      addstat(STAT_SUPERWEAPONS_FINISHED, AS_FLOAT, superweapons_finished);
 -      addstat(STAT_PRESSED_KEYS, AS_FLOAT, pressedkeys);
 -      addstat(STAT_FUEL, AS_INT, ammo_fuel);
 -      addstat(STAT_PLASMA, AS_INT, ammo_plasma);
 -      addstat(STAT_SHOTORG, AS_INT, stat_shotorg);
 -      addstat(STAT_LEADLIMIT, AS_FLOAT, stat_leadlimit);
 -      addstat(STAT_WEAPON_CLIPLOAD, AS_INT, clip_load);
 -      addstat(STAT_WEAPON_CLIPSIZE, AS_INT, clip_size);
 -      addstat(STAT_LAST_PICKUP, AS_FLOAT, last_pickup);
 -      addstat(STAT_HIT_TIME, AS_FLOAT, hit_time);
 -      addstat(STAT_DAMAGE_DEALT_TOTAL, AS_INT, damage_dealt_total);
 -      addstat(STAT_TYPEHIT_TIME, AS_FLOAT, typehit_time);
 -      addstat(STAT_LAYED_MINES, AS_INT, minelayer_mines);
 -
 -      addstat(STAT_VORTEX_CHARGE, AS_FLOAT, vortex_charge);
 -      addstat(STAT_VORTEX_CHARGEPOOL, AS_FLOAT, vortex_chargepool_ammo);
 -
 -      addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load);
 -
 -      // freeze attacks
 -      addstat(STAT_FROZEN, AS_INT, frozen);
 -      addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, revive_progress);
 -
 -      // physics
 -      Physics_AddStats();
 -
 -      // new properties
 -      addstat(STAT_MOVEVARS_JUMPVELOCITY, AS_FLOAT, stat_sv_jumpvelocity);
 -      addstat(STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, AS_FLOAT, stat_sv_airaccel_qw_stretchfactor);
 -      addstat(STAT_MOVEVARS_MAXAIRSTRAFESPEED, AS_FLOAT, stat_sv_maxairstrafespeed);
 -      addstat(STAT_MOVEVARS_MAXAIRSPEED, AS_FLOAT, stat_sv_maxairspeed);
 -      addstat(STAT_MOVEVARS_AIRSTRAFEACCELERATE, AS_FLOAT, stat_sv_airstrafeaccelerate);
 -      addstat(STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL, AS_FLOAT, stat_sv_warsowbunny_turnaccel);
 -      addstat(STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, AS_FLOAT, stat_sv_airaccel_sideways_friction);
 -      addstat(STAT_MOVEVARS_AIRCONTROL, AS_FLOAT, stat_sv_aircontrol);
 -      addstat(STAT_MOVEVARS_AIRCONTROL_POWER, AS_FLOAT, stat_sv_aircontrol_power);
 -      addstat(STAT_MOVEVARS_AIRCONTROL_PENALTY, AS_FLOAT, stat_sv_aircontrol_penalty);
 -      addstat(STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL, AS_FLOAT, stat_sv_warsowbunny_airforwardaccel);
 -      addstat(STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED, AS_FLOAT, stat_sv_warsowbunny_topspeed);
 -      addstat(STAT_MOVEVARS_WARSOWBUNNY_ACCEL, AS_FLOAT, stat_sv_warsowbunny_accel);
 -      addstat(STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO, AS_FLOAT, stat_sv_warsowbunny_backtosideratio);
 -      addstat(STAT_MOVEVARS_FRICTION, AS_FLOAT, stat_sv_friction);
 -      addstat(STAT_MOVEVARS_ACCELERATE, AS_FLOAT, stat_sv_accelerate);
 -      addstat(STAT_MOVEVARS_STOPSPEED, AS_FLOAT, stat_sv_stopspeed);
 -      addstat(STAT_MOVEVARS_AIRACCELERATE, AS_FLOAT, stat_sv_airaccelerate);
 -      addstat(STAT_MOVEVARS_AIRSTOPACCELERATE, AS_FLOAT, stat_sv_airstopaccelerate);
 -
 -      // secrets
 -      addstat(STAT_SECRETS_TOTAL, AS_FLOAT, stat_secrets_total);
 -      addstat(STAT_SECRETS_FOUND, AS_FLOAT, stat_secrets_found);
 -
 -      // monsters
 -      addstat(STAT_MONSTERS_TOTAL, AS_FLOAT, stat_monsters_total);
 -      addstat(STAT_MONSTERS_KILLED, AS_FLOAT, stat_monsters_killed);
 -
 -      // misc
 -      addstat(STAT_RESPAWN_TIME, AS_FLOAT, stat_respawn_time);
 -
        next_pingtime = time + 5;
  
        detect_maptype();
@@@ -1395,7 -1455,6 +1391,6 @@@ void DumpStats(float final
  
  void FixIntermissionClient(entity e)
  {
-       string s;
        if(!e.autoscreenshot) // initial call
        {
                e.autoscreenshot = time + 0.8;  // used for autoscreenshot
                if(IS_REAL_CLIENT(e))
                {
                        stuffcmd(e, "\nscr_printspeed 1000000\n");
-                       s = autocvar_sv_intermission_cdtrack;
-                       if(s != "")
-                               stuffcmd(e, strcat("\ncd loop ", s, "\n"));
+                       string list = autocvar_sv_intermission_cdtrack;
+                       for(string it; (it = car(list)); list = cdr(list))
+                               RandomSelection_Add(world, 0, it, 1, 1);
+                       if(RandomSelection_chosen_string && RandomSelection_chosen_string != "")
+                               stuffcmd(e, strcat("\ncd loop ", RandomSelection_chosen_string, "\n"));
                        msg_entity = e;
                        WriteByte(MSG_ONE, SVC_INTERMISSION);
                }
index c79add85bce6cbf3ff810db5c74f165f2beaa1c3,f7479af965ee8246f531d2c1885bcf3ae26c9d4d..781ce5695a74c81f3ef8d62d1e62229d057b1ee2
@@@ -58,7 -58,6 +58,6 @@@ void soundtoat(float _dest, entity e, v
  
  void objerror(string s);
  void droptofloor();
- void() SUB_Remove;
  
  void attach_sameorigin(entity e, entity to, string tag);
  
@@@ -124,32 -123,6 +123,6 @@@ void WarpZone_traceline_antilag (entit
  
  #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
  
- const string STR_PLAYER = "player";
- const string STR_SPECTATOR = "spectator";
- const string STR_OBSERVER = "observer";
- #define IS_PLAYER(v)                  ((v).classname == STR_PLAYER)
- #define IS_SPEC(v)                            ((v).classname == STR_SPECTATOR)
- #define IS_OBSERVER(v)                        ((v).classname == STR_OBSERVER)
- #define IS_CLIENT(v)                  (v.flags & FL_CLIENT)
- #define IS_BOT_CLIENT(v)              (clienttype(v) == CLIENTTYPE_BOT)
- #define IS_REAL_CLIENT(v)             (clienttype(v) == CLIENTTYPE_REAL)
- #define IS_NOT_A_CLIENT(v)            (clienttype(v) == CLIENTTYPE_NOTACLIENT)
- #define IS_MONSTER(v)                 (v.flags & FL_MONSTER)
- #define IS_VEHICLE(v)                 (v.vehicle_flags & VHF_ISVEHICLE)
- #define IS_TURRET(v)                  (v.turret_flags & TUR_FLAG_ISTURRET)
- #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
- #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(IS_CLIENT(v))
- #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(IS_REAL_CLIENT(v))
- #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(IS_PLAYER(v))
- #define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if (!IS_PLAYER(v)) // Samual: shouldn't this be IS_SPEC(v)? and rather create a separate macro to include observers too
- #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(IS_PLAYER(v))
- #define FOR_EACH_MONSTER(v) for(v = world; (v = findflags(v, flags, FL_MONSTER)) != world; )
  #define CENTER_OR_VIEWOFS(ent) (ent.origin + (IS_PLAYER(ent) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5)))
  
  // copies a string to a tempstring (so one can strunzone it)
@@@ -267,6 -240,22 +240,6 @@@ float g_weapon_stay
  float want_weapon(entity weaponinfo, float allguns); // WEAPONTODO: what still needs done?
  void readplayerstartcvars();
  
 -float g_bugrigs;
 -float g_bugrigs_planar_movement;
 -float g_bugrigs_planar_movement_car_jumping;
 -float g_bugrigs_reverse_spinning;
 -float g_bugrigs_reverse_speeding;
 -float g_bugrigs_reverse_stopping;
 -float g_bugrigs_air_steering;
 -float g_bugrigs_angle_smoothing;
 -float g_bugrigs_friction_floor;
 -float g_bugrigs_friction_brake;
 -float g_bugrigs_friction_air;
 -float g_bugrigs_accel;
 -float g_bugrigs_speed_ref;
 -float g_bugrigs_speed_pow;
 -float g_bugrigs_steer;
 -
  float sv_autotaunt;
  float sv_taunt;
  
@@@ -392,17 -381,6 +365,6 @@@ void readlevelcvars(
  
  //#NO AUTOCVARS END
  
- // Sound functions
- //string precache_sound (string s) = #19;
- // hack
- float precache_sound_index (string s) = #19;
- const float SND_VOLUME = BIT(0);
- const float SND_ATTENUATION = BIT(1);
- const float SND_LARGEENTITY = BIT(3);
- const float SND_LARGESOUND = BIT(4);
  const float INITPRIO_FIRST                            = 0;
  const float INITPRIO_GAMETYPE                         = 0;
  const float INITPRIO_GAMETYPE_FALLBACK        = 1;
index cdd2d4d4de512cfb53c9685ef12858909398fc4f,9b9c8a05b6cedaca9daa36d8fb16d23f14224ce6..d4ca5cb3cc26ed4463de2ff1cef39b95c92a7fc9
@@@ -202,28 -202,24 +202,24 @@@ float ca_isEliminated(entity e
        return false;
  }
  
- // Returns next available player to spectate if g_ca_spectate_enemies == 0
+ /** Returns next available player to spectate if g_ca_spectate_enemies == 0 */
  entity CA_SpectateNext(entity player, entity start)
  {
-       if(SAME_TEAM(start, player))
-               return start;
-       entity spec_other = start;
+     if (SAME_TEAM(start, player)) return start;
        // continue from current player
-       while(spec_other && DIFF_TEAM(spec_other, player))
-               spec_other = find(spec_other, classname, "player");
-       if (!spec_other)
+       for (entity e = start; (e = find(e, classname, "player")); )
        {
-               // restart from begining
-               spec_other = find(spec_other, classname, "player");
-               while(spec_other && DIFF_TEAM(spec_other, player))
-                       spec_other = find(spec_other, classname, "player");
+               if (SAME_TEAM(player, e)) return e;
        }
-       return spec_other;
+       // restart from begining
+       for (entity e = NULL; (e = find(e, classname, "player")); )
+       {
+               if (SAME_TEAM(player, e)) return e;
+       }
+       return start;
  }
  
  MUTATOR_HOOKFUNCTION(ca, PlayerSpawn)
  {SELFPARAM();
        self.caplayer = 1;
@@@ -522,6 -518,11 +518,6 @@@ void ca_Initialize(
        round_handler_Spawn(CA_CheckTeams, CA_CheckWinner, CA_RoundStart);
        round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
  
 -      addstat(STAT_REDALIVE, AS_INT, redalive_stat);
 -      addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat);
 -      addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat);
 -      addstat(STAT_PINKALIVE, AS_INT, pinkalive_stat);
 -
        EliminatedPlayers_Init(ca_isEliminated);
  }
  
index f0c84257ad0ed06f84b00a2ec692f520fbbe2ab3,95b219ea034b8d49e8009a0410868b1abfb15124..df5403b595ce638b21351555ae9d70d6a85c5a1b
@@@ -183,7 -183,7 +183,7 @@@ void havocbot_role_ctf_setrole(entity b
  #define CTF_DIFFTEAM(a,b) ((autocvar_g_ctf_reverse || (ctf_oneflag && autocvar_g_ctf_oneflag_reverse)) ? SAME_TEAM(a,b) : DIFF_TEAM(a,b))
  
  // networked flag statuses
 -.int ctf_flagstatus;
 +.int ctf_flagstatus = _STAT(CTF_FLAGSTATUS);
  #endif
  
  const int CTF_RED_FLAG_TAKEN                  = 1;
@@@ -249,6 -249,7 +249,7 @@@ bool autocvar_g_ctf_flag_dropped_floati
  bool autocvar_g_ctf_flag_glowtrails;
  int autocvar_g_ctf_flag_health;
  bool autocvar_g_ctf_flag_return;
+ bool autocvar_g_ctf_flag_return_carrying;
  float autocvar_g_ctf_flag_return_carried_radius;
  float autocvar_g_ctf_flag_return_time;
  bool autocvar_g_ctf_flag_return_when_unreachable;
@@@ -1246,7 -1247,7 +1247,7 @@@ METHOD(Flag, giveTo, bool(Flag this, en
  
                case FLAG_DROPPED:
                {
-                       if(CTF_SAMETEAM(toucher, flag) && (autocvar_g_ctf_flag_return || num_perteam <= 1) && flag.team) // automatically return if there's only 1 player on the team
+                       if(CTF_SAMETEAM(toucher, flag) && (autocvar_g_ctf_flag_return || num_perteam <= 1 || (autocvar_g_ctf_flag_return_carrying && toucher.flagcarried)) && flag.team) // automatically return if there's only 1 player on the team
                                ctf_Handle_Return(flag, toucher); // toucher just returned his own flag
                        else if(is_not_monster && (!toucher.flagcarried) && ((toucher != flag.ctf_dropper) || (time > flag.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
                                ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
@@@ -1325,13 -1326,12 +1326,12 @@@ void ctf_RespawnFlag(entity flag
        ctf_CheckStalemate();
  }
  
- void ctf_Reset()
- {SELFPARAM();
-       if(self.owner)
-               if(IS_PLAYER(self.owner))
-                       ctf_Handle_Throw(self.owner, world, DROP_RESET);
+ void ctf_Reset(entity this)
+ {
+       if(this.owner && IS_PLAYER(this.owner))
+         ctf_Handle_Throw(this.owner, world, DROP_RESET);
  
-       ctf_RespawnFlag(self);
+       ctf_RespawnFlag(this);
  }
  
  void ctf_DelayedFlagSetup() // called after a flag is placed on a map by ctf_FlagSetup()
@@@ -2774,6 -2774,8 +2774,6 @@@ void ctf_Initialize(
        ctf_captureshield_max_ratio = autocvar_g_ctf_shield_max_ratio;
        ctf_captureshield_force = autocvar_g_ctf_shield_force;
  
 -      addstat(STAT_CTF_FLAGSTATUS, AS_INT, ctf_flagstatus);
 -
        InitializeEntity(world, ctf_DelayedInit, INITPRIO_GAMETYPE);
  }
  
index 73927fe201245e2cd913db3a1c31953720b3e5a1,9be5e108aa895be8d962c623c78dc4dd018611c2..da839e5171c3810418a44de41ff6211bd785338b
@@@ -42,11 -42,11 +42,11 @@@ const float ST_DOM_CAPS = 1
  const float SP_DOM_CAPS = 4;
  
  // pps: points per second
 -.float dom_total_pps;
 -.float dom_pps_red;
 -.float dom_pps_blue;
 -.float dom_pps_yellow;
 -.float dom_pps_pink;
 +.float dom_total_pps = _STAT(DOM_TOTAL_PPS);
 +.float dom_pps_red = _STAT(DOM_PPS_RED);
 +.float dom_pps_blue = _STAT(DOM_PPS_BLUE);
 +.float dom_pps_yellow = _STAT(DOM_PPS_YELLOW);
 +.float dom_pps_pink = _STAT(DOM_PPS_PINK);
  float total_pps;
  float pps_red;
  float pps_blue;
@@@ -315,8 -315,10 +315,10 @@@ void dompointtouch(
        dompoint_captured();
  }
  
- void dom_controlpoint_setup()
- {SELFPARAM();
+ void dom_controlpoint_setup(entity this);
+ void dom_controlpoint_setup_self() { SELFPARAM(); dom_controlpoint_setup(this); }
+ void dom_controlpoint_setup(entity this)
+ {
        entity head;
        // find the spawnfunc_dom_team representing unclaimed points
        head = find(world, classname, "dom_team");
@@@ -551,7 -553,7 +553,7 @@@ spawnfunc(dom_controlpoint
                remove(self);
                return;
        }
-       self.think = dom_controlpoint_setup;
+       self.think = dom_controlpoint_setup_self;
        self.nextthink = time + 0.1;
        self.reset = dom_controlpoint_setup;
  
@@@ -664,12 -666,12 +666,12 @@@ void dom_spawnteam (string teamname, fl
        setself(this);
  }
  
- void _spawnfunc_dom_controlpoint() { SELFPARAM(); spawnfunc_dom_controlpoint(self); }
+ void self_spawnfunc_dom_controlpoint() { SELFPARAM(); spawnfunc_dom_controlpoint(self); }
  void dom_spawnpoint(vector org)
  {SELFPARAM();
        setself(spawn());
        self.classname = "dom_controlpoint";
-       self.think = _spawnfunc_dom_controlpoint;
+       self.think = self_spawnfunc_dom_controlpoint;
        self.nextthink = time;
        setorigin(self, org);
        spawnfunc_dom_controlpoint(this);
@@@ -693,7 -695,7 +695,7 @@@ void dom_DelayedInit() // Do this chec
        // if no teams are found, spawn defaults
        if(find(world, classname, "dom_team") == world || autocvar_g_domination_teams_override >= 2)
        {
 -              LOG_INFO("No ""dom_team"" entities found on this map, creating them anyway.\n");
 +              LOG_INFO("No \"dom_team\" entities found on this map, creating them anyway.\n");
                domination_teams = bound(2, ((autocvar_g_domination_teams_override < 2) ? autocvar_g_domination_default_teams : autocvar_g_domination_teams_override), 4);
                dom_spawnteams(domination_teams);
        }
        CheckAllowedTeams(world);
        domination_teams = ((c4>=0) ? 4 : (c3>=0) ? 3 : 2);
  
 -      addstat(STAT_DOM_TOTAL_PPS, AS_FLOAT, dom_total_pps);
 -      addstat(STAT_DOM_PPS_RED, AS_FLOAT, dom_pps_red);
 -      addstat(STAT_DOM_PPS_BLUE, AS_FLOAT, dom_pps_blue);
 -      if(domination_teams >= 3) addstat(STAT_DOM_PPS_YELLOW, AS_FLOAT, dom_pps_yellow);
 -      if(domination_teams >= 4) addstat(STAT_DOM_PPS_PINK, AS_FLOAT, dom_pps_pink);
 -
        domination_roundbased = autocvar_g_domination_roundbased;
  
        ScoreRules_dom(domination_teams);
diff --combined qcsrc/server/sv_main.qc
index 9989cb9ab1b814aca66362f6c52106e5ad6386b5,0d5fa234f974ebe6bbdd10c7fc2cb35e36d2c9c4..20a473e357348bf52942f98bf9ceae869e44205f
@@@ -159,9 -159,9 +159,9 @@@ void CreatureFrame (
                                        if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS))
                                        {
                                                if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS)
-                                                       GlobalSound(globalsound_metalstep, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+                                                       GlobalSound(GS_STEP_METAL, CH_PLAYER, VOICETYPE_PLAYERSOUND);
                                                else
-                                                       GlobalSound(globalsound_step, CH_PLAYER, VOICETYPE_PLAYERSOUND);
+                                                       GlobalSound(GS_STEP, CH_PLAYER, VOICETYPE_PLAYERSOUND);
                                        }
                                }
                        }
@@@ -262,13 -262,6 +262,13 @@@ void StartFrame(
        bot_serverframe();
        anticheat_startframe();
        MUTATOR_CALLHOOK(SV_StartFrame);
 +      {
 +        entity e;
 +        FOR_EACH_CLIENT(e)
 +        {
 +            GlobalStats_update(e);
 +        }
 +    }
  }
  
  .vector originjitter;