Merge remote-tracking branch 'origin/master' into morosophos/rankings_cnt
authorMorosophos <ahcie0op@yandex.ru>
Thu, 7 Jun 2018 19:46:03 +0000 (22:46 +0300)
committerMorosophos <ahcie0op@yandex.ru>
Thu, 7 Jun 2018 19:46:03 +0000 (22:46 +0300)
40 files changed:
.gitlab-ci.yml
qcsrc/common/gamemodes/gamemode/nexball/nexball.qc
qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc
qcsrc/common/mutators/base.qh
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
qcsrc/common/mutators/mutator/damagetext/sv_damagetext.qc
qcsrc/common/mutators/mutator/instagib/sv_instagib.qc
qcsrc/common/mutators/mutator/instagib/sv_instagib.qh
qcsrc/common/mutators/mutator/itemstime/itemstime.qc
qcsrc/common/mutators/mutator/melee_only/sv_melee_only.qc
qcsrc/common/mutators/mutator/nades/nades.qc
qcsrc/common/mutators/mutator/new_toys/sv_new_toys.qc
qcsrc/common/mutators/mutator/nix/sv_nix.qc
qcsrc/common/mutators/mutator/overkill/sv_overkill.qc
qcsrc/common/mutators/mutator/overkill/sv_overkill.qh
qcsrc/common/mutators/mutator/pinata/sv_pinata.qc
qcsrc/common/mutators/mutator/random_items/sv_random_items.qc
qcsrc/common/mutators/mutator/random_items/sv_random_items.qh
qcsrc/common/mutators/mutator/vampire/sv_vampire.qc
qcsrc/common/mutators/mutator/weaponarena_random/sv_weaponarena_random.qc
qcsrc/common/t_items.qc
qcsrc/common/t_items.qh
qcsrc/common/turrets/turret/plasma.qc
qcsrc/common/turrets/turret/plasma_dual.qc
qcsrc/common/weapons/all.qc
qcsrc/common/weapons/all.qh
qcsrc/common/weapons/weapon.qh
qcsrc/common/weapons/weapon/porto.qc
qcsrc/server/bot/default/havocbot/havocbot.qc
qcsrc/server/bot/default/havocbot/roles.qc
qcsrc/server/cheats.qc
qcsrc/server/client.qc
qcsrc/server/compat/quake3.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/mutators/events.qh
qcsrc/server/weapons/common.qc
qcsrc/server/weapons/selection.qc
qcsrc/server/weapons/throwing.qc
qcsrc/server/weapons/weaponsystem.qc

index ebcfe7c5eeeedd00c372b044047393ffd138f937..e50392ca6a8e1c49df20f3465838b7a6052041c0 100644 (file)
@@ -29,7 +29,7 @@ test_sv_game:
     - wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints
     - wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache
     - make
-    - EXPECT=9730e88a37991b9df5253bd4e83927d4
+    - EXPECT=033546d32426e6409458fb39d0130f56
     - HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
       | tee /dev/stderr
       | grep '^:'
@@ -44,7 +44,7 @@ test_sv_game:
 test_sv_unit:
   stage: test
   script:
-    - git clone --depth=1 --branch=master https://gitlab.com/xonotic/darkplaces.git darkplaces
+    - git clone --depth=1 --branch=div0-stable https://gitlab.com/xonotic/darkplaces.git darkplaces
     - cd darkplaces && make sv-debug -j $(nproc) && export ENGINE="$PWD/darkplaces-dedicated -xonotic"
     - cd ..
 
index fa718eb16fe9884a74512688212372359fd026b6..426b341a63a077b1316305a435d0975241b490ea 100644 (file)
@@ -195,9 +195,9 @@ void GiveBall(entity plyr, entity ball)
                ball.nextthink = time + autocvar_g_nexball_basketball_delay_hold;
        }
 
-       plyr.(weaponentity).weapons = plyr.weapons;
+       STAT(WEAPONS, plyr.(weaponentity)) = STAT(WEAPONS, plyr);
        plyr.m_switchweapon = plyr.(weaponentity).m_weapon;
-       plyr.weapons = WEPSET(NEXBALL);
+       STAT(WEAPONS, plyr) = WEPSET(NEXBALL);
        Weapon w = WEP_NEXBALL;
        w.wr_resetplayer(w, plyr);
        plyr.(weaponentity).m_switchweapon = WEP_NEXBALL;
@@ -828,15 +828,15 @@ MUTATOR_HOOKFUNCTION(nb, PlayerPreThink)
                        {
                                .entity weaponentity = weaponentities[slot];
 
-                               if(player.(weaponentity).weapons)
+                               if(STAT(WEAPONS, player.(weaponentity)))
                                {
-                                       player.weapons = player.(weaponentity).weapons;
+                                       STAT(WEAPONS, player) = STAT(WEAPONS, player.(weaponentity));
                                        Weapon w = WEP_NEXBALL;
                                        w.wr_resetplayer(w, player);
                                        player.(weaponentity).m_switchweapon = player.m_switchweapon;
                                        W_SwitchWeapon(player, player.(weaponentity).m_switchweapon, weaponentity);
 
-                                       player.(weaponentity).weapons = '0 0 0';
+                                       STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
                                }
                        }
                }
@@ -862,13 +862,13 @@ MUTATOR_HOOKFUNCTION(nb, PlayerSpawn)
        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
        {
                .entity weaponentity = weaponentities[slot];
-               player.(weaponentity).weapons = '0 0 0';
+               STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
        }
 
        if (nexball_mode & NBM_BASKETBALL)
-               player.weapons |= WEPSET(NEXBALL);
+               STAT(WEAPONS, player) |= WEPSET(NEXBALL);
        else
-               player.weapons = '0 0 0';
+               STAT(WEAPONS, player) = '0 0 0';
 
        return false;
 }
index 2637aeef212b5415a589b42848b99f1b1290fef6..c4f4d32c4262f282d49a12872d9f23a7970ae313 100644 (file)
@@ -1229,7 +1229,7 @@ void havocbot_goalrating_ons_offenseitems(entity this, float ratingscale, vector
        // Needs weapons?
        int c = 0;
        FOREACH(Weapons, it != WEP_Null, {
-               if(this.weapons & (it.m_wepset))
+               if(STAT(WEAPONS, this) & (it.m_wepset))
                if(++c >= 4)
                        break;
        });
@@ -1248,7 +1248,7 @@ void havocbot_goalrating_ons_offenseitems(entity this, float ratingscale, vector
        {
                // gather health and armor only
                if (it.solid)
-               if ( ((it.health || it.armorvalue) && needarmor) || (it.weapons && needweapons ) )
+               if ( ((it.health || it.armorvalue) && needarmor) || (STAT(WEAPONS, it) && needweapons ) )
                if (vdist(it.origin - org, <, sradius))
                {
                        int t = it.bot_pickupevalfunc(this, it);
index 565e39998d7d4186d20ef3937f60ceddc9d53830..163960ba5f5d9ee2d4841b277d28bbe2b316f464 100644 (file)
@@ -171,6 +171,8 @@ void Mutator_Remove(Mutator mut);
 bool mutator_log = false;
 .bool m_added;
 
+#define MUTATOR_IS_ENABLED(this) MUTATOR_##this.mutatorcheck()
+
 #ifdef GAMEQC
 /** server mutators activate corresponding client mutators for all clients */
 REGISTER_NET_LINKED(Mutator)
index 4a54d8117d24ba4ae80bf772e792d1ec1286464f..5afb965076965b484fb01b44b8184fa1e89cad98 100644 (file)
@@ -926,7 +926,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
 
                BUFF_ONADD(BUFF_INVISIBLE)
                {
-                       if(time < player.strength_finished && autocvar_g_instagib)
+                       if(time < player.strength_finished && MUTATOR_IS_ENABLED(mutator_instagib))
                                player.buff_invisible_prev_alpha = default_player_alpha; // we don't want to save the powerup's alpha, as player may lose the powerup while holding the buff
                        else
                                player.buff_invisible_prev_alpha = player.alpha;
@@ -935,7 +935,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
 
                BUFF_ONREM(BUFF_INVISIBLE)
                {
-                       if(time < player.strength_finished && autocvar_g_instagib)
+                       if(time < player.strength_finished && MUTATOR_IS_ENABLED(mutator_instagib))
                                player.alpha = autocvar_g_instagib_invis_alpha;
                        else
                                player.alpha = player.buff_invisible_prev_alpha;
index 4a18cc930879ad34e28ef7551c7af1e381bf8d46..b88d96d700307fbf05480fb88befac6a4824b6bd 100644 (file)
@@ -4,7 +4,7 @@ AUTOCVAR(sv_damagetext, int, 2, "<= 0: disabled, >= 1: visible to spectators, >=
 
 REGISTER_MUTATOR(damagetext, true);
 
-#define SV_DAMAGETEXT_DISABLED()        (autocvar_sv_damagetext <= 0 || autocvar_g_instagib)
+#define SV_DAMAGETEXT_DISABLED()        (autocvar_sv_damagetext <= 0 || MUTATOR_IS_ENABLED(mutator_instagib))
 #define SV_DAMAGETEXT_SPECTATORS_ONLY() (autocvar_sv_damagetext >= 1)
 #define SV_DAMAGETEXT_PLAYERS()         (autocvar_sv_damagetext >= 2)
 #define SV_DAMAGETEXT_ALL()             (autocvar_sv_damagetext >= 3)
index 616a05da3c93e9c77294028f469ae9a1c649a9ce..f93b69235df1213ce71b19aa5e446c8c0383dda7 100644 (file)
@@ -17,22 +17,6 @@ float autocvar_g_instagib_speed_highspeed;
 
 #include <common/items/_mod.qh>
 
-REGISTER_MUTATOR(mutator_instagib, autocvar_g_instagib && !g_nexball)
-{
-       MUTATOR_ONADD
-       {
-               ITEM_VaporizerCells.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_Invisibility.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_Speed.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-       }
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               ITEM_VaporizerCells.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_Invisibility.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_Speed.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
-       }
-}
-
 void instagib_invisibility(entity this)
 {
        this.strength_finished = autocvar_g_instagib_invisibility_time;
index 9020b93124777851f80a80eb1e2dc4b0edab75fa..56f4ac7daaaace7d5d831d281107ed0632d75eaf 100644 (file)
@@ -7,3 +7,19 @@ float autocvar_g_instagib_invis_alpha;
 void instagib_invisibility(entity this);
 void instagib_extralife(entity this);
 void instagib_speed(entity this);
+
+REGISTER_MUTATOR(mutator_instagib, autocvar_g_instagib && !g_nexball)
+{
+       MUTATOR_ONADD
+       {
+               ITEM_VaporizerCells.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_Invisibility.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_Speed.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+       }
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               ITEM_VaporizerCells.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_Invisibility.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_Speed.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+       }
+}
index c2402ef4608c95d7b1f5fbb84e8f70768ffed1e9..1379d586f10fd4da14b9f82d98571cd00bbe6c78 100644 (file)
@@ -124,7 +124,7 @@ void Item_ItemsTime_SetTime(entity e, float t)
     {
                if (!item.instanceOfWeaponPickup)
                        it_times[item.m_id] = t;
-               else if (e.weapons & WEPSET_SUPERWEAPONS)
+               else if (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS)
                        it_times[Items_MAX] = t;
     }
 }
@@ -139,7 +139,7 @@ float Item_ItemsTime_UpdateTime(entity e, float t)
     bool isavailable = (t == 0);
     IL_EACH(g_items, it != e,
     {
-        if(!(it.itemdef == e.itemdef || ((e.weapons & WEPSET_SUPERWEAPONS) && (it.weapons & WEPSET_SUPERWEAPONS))))
+        if(!(it.itemdef == e.itemdef || ((STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS) && (STAT(WEAPONS, it) & WEPSET_SUPERWEAPONS))))
             continue;
         if (it.scheduledrespawntime <= time)
             isavailable = true;
index 2f8b45a99b46f09450ab44c93867b236b4ef4639..a56efaf83cffbf086b2cbca93f5798cfce6b7d20 100644 (file)
@@ -1,7 +1,9 @@
 #include "sv_melee_only.qh"
 
+#include "../overkill/sv_overkill.qh"
+
 string autocvar_g_melee_only;
-REGISTER_MUTATOR(melee_only, expr_evaluate(autocvar_g_melee_only) && !autocvar_g_instagib && !cvar("g_overkill") && !g_nexball);
+REGISTER_MUTATOR(melee_only, expr_evaluate(autocvar_g_melee_only) && !MUTATOR_IS_ENABLED(mutator_instagib) && !MUTATOR_IS_ENABLED(ok) && !g_nexball);
 
 MUTATOR_HOOKFUNCTION(melee_only, SetStartItems, CBC_ORDER_LAST)
 {
index 9e0f50d925875eca3575cd78d9993b58d4ef6bdc..dbd04a70acc9af324cdd06371a52768855e083ff 100644 (file)
@@ -1253,7 +1253,7 @@ MUTATOR_HOOKFUNCTION(nades, ForbidThrowCurrentWeapon, CBC_ORDER_LAST)
 {
     entity player = M_ARGV(0, entity);
 
-       if (player.offhand != OFFHAND_NADE || (player.weapons & WEPSET(HOOK)) || autocvar_g_nades_override_dropweapon) {
+       if (player.offhand != OFFHAND_NADE || (STAT(WEAPONS, player) & WEPSET(HOOK)) || autocvar_g_nades_override_dropweapon) {
                nades_CheckThrow(player);
                return true;
        }
@@ -1265,7 +1265,7 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
 
        if (!IS_PLAYER(player)) { return; }
 
-       if (player.nade && (player.offhand != OFFHAND_NADE || (player.weapons & WEPSET(HOOK)))) OFFHAND_NADE.offhand_think(OFFHAND_NADE, player, player.nade_altbutton);
+       if (player.nade && (player.offhand != OFFHAND_NADE || (STAT(WEAPONS, player) & WEPSET(HOOK)))) OFFHAND_NADE.offhand_think(OFFHAND_NADE, player, player.nade_altbutton);
 
        entity held_nade = player.nade;
        if (held_nade)
index 3ac652d7807df5d1ee4797dad9f16134b25dd756..540edc69d9c6578c7ef4277a9f35b1a2f37cfb4b 100644 (file)
@@ -74,7 +74,7 @@ roflsound "New toys, new toys!" sound.
 
 bool nt_IsNewToy(int w);
 
-REGISTER_MUTATOR(nt, expr_evaluate(cvar_string("g_new_toys")) && !autocvar_g_instagib && !cvar("g_overkill"))
+REGISTER_MUTATOR(nt, expr_evaluate(cvar_string("g_new_toys")) && !MUTATOR_IS_ENABLED(mutator_instagib) && !MUTATOR_IS_ENABLED(ok))
 {
        MUTATOR_ONADD
        {
@@ -195,7 +195,7 @@ MUTATOR_HOOKFUNCTION(nt, SetStartItems)
 
 MUTATOR_HOOKFUNCTION(nt, SetWeaponreplace)
 {
-       if (autocvar_g_random_items)
+       if (MUTATOR_IS_ENABLED(random_items))
        {
                // Do not replace weapons when random items are enabled.
                return;
index e88ff9b552984feb7a083932173d64939709ab52..da5dcc234e32b4df646150465d7dee849f3193ae 100644 (file)
@@ -36,7 +36,7 @@ float nix_nextweapon;
 
 bool NIX_CanChooseWeapon(int wpn);
 
-REGISTER_MUTATOR(nix, expr_evaluate(cvar_string("g_nix")) && !autocvar_g_instagib && !cvar("g_overkill"))
+REGISTER_MUTATOR(nix, expr_evaluate(cvar_string("g_nix")) && !MUTATOR_IS_ENABLED(mutator_instagib) && !MUTATOR_IS_ENABLED(ok))
 {
        MUTATOR_ONADD
        {
@@ -63,7 +63,7 @@ REGISTER_MUTATOR(nix, expr_evaluate(cvar_string("g_nix")) && !autocvar_g_instagi
                        SetResourceAmount(it, RESOURCE_CELLS, start_ammo_cells);
                        SetResourceAmount(it, RESOURCE_PLASMA, start_ammo_plasma);
                        SetResourceAmount(it, RESOURCE_FUEL, start_ammo_fuel);
-                       it.weapons = start_weapons;
+                       STAT(WEAPONS, it) = start_weapons;
                        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                        {
                                .entity weaponentity = weaponentities[slot];
@@ -208,10 +208,10 @@ void NIX_GiveCurrentWeapon(entity this)
                this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
        }
 
-       this.weapons = '0 0 0';
+       STAT(WEAPONS, this) = '0 0 0';
        if(g_nix_with_blaster)
-               this.weapons |= WEPSET(BLASTER);
-       this.weapons |= e.m_wepset;
+               STAT(WEAPONS, this) |= WEPSET(BLASTER);
+       STAT(WEAPONS, this) |= e.m_wepset;
 
     Weapon w = Weapons_from(nix_weapon);
     for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
index 33deb64fcb2484569de8105870fbdc97a9a3e7a4..f4432a9cbb830973f25fea4a1e6dffc4e6203f77 100644 (file)
@@ -1,70 +1,11 @@
 #include "sv_overkill.qh"
 
-#include "okshotgun.qh"
-#include "okhmg.qh"
-#include "okrpc.qh"
-
-string autocvar_g_overkill;
-
 bool autocvar_g_overkill_powerups_replace;
 
 bool autocvar_g_overkill_itemwaypoints = true;
 
 .Weapon ok_lastwep[MAX_WEAPONSLOTS];
 
-REGISTER_MUTATOR(ok, expr_evaluate(autocvar_g_overkill) && !autocvar_g_instagib && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
-{
-       MUTATOR_ONADD
-       {
-               precache_all_playermodels("models/ok_player/*.dpm");
-
-               if (autocvar_g_overkill_filter_healthmega)
-               {
-                       ITEM_HealthMega.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
-               }
-               if (autocvar_g_overkill_filter_armormedium)
-               {
-                       ITEM_ArmorMedium.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
-               }
-               if (autocvar_g_overkill_filter_armorbig)
-               {
-                       ITEM_ArmorBig.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
-               }
-               if (autocvar_g_overkill_filter_armormega)
-               {
-                       ITEM_ArmorMega.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
-               }
-
-               WEP_OVERKILL_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-               WEP_OVERKILL_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-
-               WEP_OVERKILL_SHOTGUN.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-               WEP_OVERKILL_MACHINEGUN.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-               WEP_OVERKILL_NEX.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-
-               //WEP_SHOTGUN.mdl = "ok_shotgun";
-               //WEP_MACHINEGUN.mdl = "ok_mg";
-               //WEP_VORTEX.mdl = "ok_sniper";
-       }
-
-       MUTATOR_ONREMOVE
-       {
-               ITEM_HealthMega.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_ArmorMedium.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_ArmorBig.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_ArmorMega.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-
-               WEP_OVERKILL_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-               WEP_OVERKILL_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-
-               WEP_OVERKILL_SHOTGUN.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-               WEP_OVERKILL_MACHINEGUN.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-               WEP_OVERKILL_NEX.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-       }
-}
-
-void W_Blaster_Attack(entity, .entity, float, float, float, float, float, float, float, float, float, float);
-
 MUTATOR_HOOKFUNCTION(ok, Damage_Calculate, CBC_ORDER_LAST)
 {
        entity frag_attacker = M_ARGV(1, entity);
index 72324e6dbb01b375b00010231235a03d7a35e649..4949edb1e82fdac49e7edf57b69efb092ceef229 100644 (file)
@@ -1,8 +1,61 @@
 #pragma once
 
+#include "okshotgun.qh"
+#include "okmachinegun.qh"
+#include "okhmg.qh"
+#include "okrpc.qh"
+
+string autocvar_g_overkill;
 bool autocvar_g_overkill_filter_healthmega;
 bool autocvar_g_overkill_filter_armormedium;
 bool autocvar_g_overkill_filter_armorbig;
 bool autocvar_g_overkill_filter_armormega;
 
 .float ok_item;
+
+REGISTER_MUTATOR(ok, expr_evaluate(autocvar_g_overkill) && !MUTATOR_IS_ENABLED(mutator_instagib) && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
+{
+       MUTATOR_ONADD
+       {
+               precache_all_playermodels("models/ok_player/*.dpm");
+
+               if (autocvar_g_overkill_filter_healthmega)
+               {
+                       ITEM_HealthMega.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+               }
+               if (autocvar_g_overkill_filter_armormedium)
+               {
+                       ITEM_ArmorMedium.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+               }
+               if (autocvar_g_overkill_filter_armorbig)
+               {
+                       ITEM_ArmorBig.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+               }
+               if (autocvar_g_overkill_filter_armormega)
+               {
+                       ITEM_ArmorMega.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+               }
+
+               WEP_OVERKILL_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+
+               WEP_OVERKILL_SHOTGUN.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_MACHINEGUN.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_NEX.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               ITEM_HealthMega.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_ArmorMedium.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_ArmorBig.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_ArmorMega.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+
+               WEP_OVERKILL_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+
+               WEP_OVERKILL_SHOTGUN.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_MACHINEGUN.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_NEX.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+       }
+}
index c5bf2262eb35e37523c3ac83caa559d4ef1e8d6d..779e562b4a4286235891a56c8e43e43cfd0fb716 100644 (file)
@@ -1,7 +1,7 @@
 #include "sv_pinata.qh"
 
 string autocvar_g_pinata;
-REGISTER_MUTATOR(pinata, expr_evaluate(autocvar_g_pinata) && !autocvar_g_instagib && !cvar("g_overkill"));
+REGISTER_MUTATOR(pinata, expr_evaluate(autocvar_g_pinata) && !MUTATOR_IS_ENABLED(mutator_instagib) && !MUTATOR_IS_ENABLED(ok));
 
 MUTATOR_HOOKFUNCTION(pinata, PlayerDies)
 {
@@ -15,7 +15,7 @@ MUTATOR_HOOKFUNCTION(pinata, PlayerDies)
                        continue;
 
                FOREACH(Weapons, it != WEP_Null, {
-                       if(frag_target.weapons & WepSet_FromWeapon(it))
+                       if(STAT(WEAPONS, frag_target) & WepSet_FromWeapon(it))
                        if(frag_target.(weaponentity).m_weapon != it)
                        if(W_IsWeaponThrowable(frag_target, it.m_id))
                                W_ThrowNewWeapon(frag_target, it.m_id, false, CENTER_OR_VIEWOFS(frag_target), randomvec() * 175 + '0 0 325', weaponentity);
index 6afcd72e9cc2f8e3e2a558d7b5eff2e129aa50ab..251e57b8749cad4a70dbfe747daa8303d08bf3aa 100644 (file)
@@ -24,8 +24,6 @@
 
 // Loot
 
-bool autocvar_g_random_loot; ///< Whether to enable random loot.
-
 float autocvar_g_random_loot_min; ///< Minimum amount of loot items.
 float autocvar_g_random_loot_max; ///< Maximum amount of loot items.
 float autocvar_g_random_loot_time; ///< Amount of time the loot will stay.
@@ -55,11 +53,11 @@ string RandomItems_GetRandomItemClassNameWithProperty(string prefix,
 
 string RandomItems_GetRandomItemClassName(string prefix)
 {
-       if (autocvar_g_instagib)
+       if (MUTATOR_IS_ENABLED(mutator_instagib))
        {
                return RandomItems_GetRandomInstagibItemClassName(prefix);
        }
-       if (expr_evaluate(autocvar_g_overkill))
+       if (MUTATOR_IS_ENABLED(ok))
        {
                return RandomItems_GetRandomOverkillItemClassName(prefix);
        }
@@ -328,7 +326,7 @@ entity RandomItems_ReplaceMapItem(entity item)
        }
        random_items_is_spawning = true;
        entity new_item;
-       if (!expr_evaluate(autocvar_g_overkill))
+       if (!MUTATOR_IS_ENABLED(ok))
        {
                new_item = Item_Create(strzone(new_classname), item.origin,
                        Item_ShouldKeepPosition(item));
@@ -374,7 +372,7 @@ void RandomItems_SpawnLootItem(vector position)
        spread.z = autocvar_g_random_loot_spread / 2;
        spread += randomvec() * autocvar_g_random_loot_spread;
        random_items_is_spawning = true;
-       if (!expr_evaluate(autocvar_g_overkill))
+       if (!MUTATOR_IS_ENABLED(ok))
        {
                Item_CreateLoot(class_name, position, spread,
                        autocvar_g_random_loot_time);
@@ -392,9 +390,6 @@ void RandomItems_SpawnLootItem(vector position)
 
 //============================= Hooks ========================================
 
-REGISTER_MUTATOR(random_items, (autocvar_g_random_items ||
-       autocvar_g_random_loot));
-
 MUTATOR_HOOKFUNCTION(random_items, BuildMutatorsString)
 {
        M_ARGV(0, string) = strcat(M_ARGV(0, string), ":random_items");
index 9ac738ca68ede11020c348c1a681d0b65a0eb7ca..d49e3effa83fed685b08f5144fad4d8cfb19f6d0 100644 (file)
@@ -6,6 +6,7 @@
 /// \copyright GNU GPLv2 or any later version.
 
 bool autocvar_g_random_items; ///< Whether to enable random items.
+bool autocvar_g_random_loot; ///< Whether to enable random loot.
 
 enum
 {
@@ -41,3 +42,6 @@ string RandomItems_GetRandomInstagibItemClassName(string prefix);
 /// \param[in] prefix Prefix of the cvars that hold probabilities.
 /// \return Random classname of the overkill item.
 string RandomItems_GetRandomOverkillItemClassName(string prefix);
+
+REGISTER_MUTATOR(random_items, (autocvar_g_random_items ||
+       autocvar_g_random_loot));
index b599805a45774f6d971087191a259ebffef342c1..b446c927052e0fc824a07708f03a9633f4c4fdad 100644 (file)
@@ -1,7 +1,7 @@
 #include "sv_vampire.qh"
 
 string autocvar_g_vampire;
-REGISTER_MUTATOR(vampire, expr_evaluate(autocvar_g_vampire) && !autocvar_g_instagib);
+REGISTER_MUTATOR(vampire, expr_evaluate(autocvar_g_vampire) && !MUTATOR_IS_ENABLED(mutator_instagib));
 
 MUTATOR_HOOKFUNCTION(vampire, PlayerDamage_SplitHealthArmor)
 {
index 7ac4504ec9049aaf0083a7a4b7e59008a6eda376..f4f7e344743319d65b57d19834c4c9110617d6c5 100644 (file)
@@ -8,7 +8,7 @@ MUTATOR_HOOKFUNCTION(weaponarena_random, PlayerSpawn)
     if (!g_weaponarena_random) return;
     entity player = M_ARGV(0, entity);
 
-    if (g_weaponarena_random_with_blaster) player.weapons &= ~WEPSET(BLASTER);
-    W_RandomWeapons(player, g_weaponarena_random);
-    if (g_weaponarena_random_with_blaster) player.weapons |= WEPSET(BLASTER);
+    if (g_weaponarena_random_with_blaster) STAT(WEAPONS, player) &= ~WEPSET(BLASTER);
+    STAT(WEAPONS, player) = W_RandomWeapons(player, STAT(WEAPONS, player), g_weaponarena_random);
+    if (g_weaponarena_random_with_blaster) STAT(WEAPONS, player) |= WEPSET(BLASTER);
 }
index 37a29f101ea36c08c67f1123e1c953c309c67003..8be48b53001a313cfb40ad288bb3401430df40b8 100644 (file)
@@ -396,39 +396,12 @@ bool have_pickup_item(entity this)
                if(autocvar_g_pickup_items == 0)
                        return false;
                if(g_weaponarena)
-                       if(this.weapons || this.itemdef.instanceOfAmmo) // no item or ammo pickups in weaponarena
+                       if(STAT(WEAPONS, this) || this.itemdef.instanceOfAmmo) // no item or ammo pickups in weaponarena
                                return false;
        }
        return true;
 }
 
-/*
-float Item_Customize()
-{
-       if(this.spawnshieldtime)
-               return true;
-       if(this.weapons & ~other.weapons)
-       {
-               this.colormod = '0 0 0';
-               this.glowmod = this.colormod;
-               this.alpha = 0.5 + 0.5 * g_ghost_items; // halfway more alpha
-               return true;
-       }
-       else
-       {
-               if(g_ghost_items)
-               {
-                       this.colormod = stov(autocvar_g_ghost_items_color);
-                       this.glowmod = this.colormod;
-                       this.alpha = g_ghost_items;
-                       return true;
-               }
-               else
-                       return false;
-       }
-}
-*/
-
 void Item_Show (entity e, float mode)
 {
        e.effects &= ~(EF_ADDITIVE | EF_STARDUST | EF_FULLBRIGHT | EF_NODEPTHTEST);
@@ -452,7 +425,7 @@ void Item_Show (entity e, float mode)
        }
        else
        {
-               bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.weapons & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
+               bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.m_wepset & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
                        || e.team // weapon stay isn't supported for teamed weapons
                        ;
                if(def.instanceOfWeaponPickup && !nostay && g_weapon_stay)
@@ -512,7 +485,7 @@ void Item_Respawn (entity this)
        sound(this, CH_TRIGGER, this.itemdef.m_respawnsound, VOL_BASE, ATTEN_NORM);     // play respawn sound
        setorigin(this, this.origin);
 
-    if (Item_ItemsTime_Allow(this.itemdef) || (this.weapons & WEPSET_SUPERWEAPONS))
+    if (Item_ItemsTime_Allow(this.itemdef) || (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS))
        {
                float t = Item_ItemsTime_UpdateTime(this, 0);
                Item_ItemsTime_SetTime(this, t);
@@ -597,13 +570,13 @@ void Item_RespawnThink(entity this)
 void Item_ScheduleRespawnIn(entity e, float t)
 {
        // if the respawn time is longer than 10 seconds, show a waypoint, otherwise, just respawn normally
-       if ((Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS) || MUTATOR_CALLHOOK(Item_ScheduleRespawn, e, t)) && (t - ITEM_RESPAWN_TICKS) > 0)
+       if ((Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS) || MUTATOR_CALLHOOK(Item_ScheduleRespawn, e, t)) && (t - ITEM_RESPAWN_TICKS) > 0)
        {
                setthink(e, Item_RespawnCountdown);
                e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
                e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
                e.item_respawncounter = 0;
-               if(Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS))
+               if(Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
                {
                        t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
                        Item_ItemsTime_SetTime(e, t);
@@ -617,7 +590,7 @@ void Item_ScheduleRespawnIn(entity e, float t)
                e.scheduledrespawntime = time + t;
                e.wait = time + t;
 
-               if(Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS))
+               if(Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
                {
                        t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
                        Item_ItemsTime_SetTime(e, t);
@@ -728,7 +701,7 @@ void GiveRandomWeapons(entity receiver, int num_weapons, string weapon_names,
                        FOREACH(Weapons, it != WEP_Null,
                        {
                                // Finding a weapon which player doesn't have.
-                               if (!(receiver.weapons & it.m_wepset) && (it.netname == weapon))
+                               if (!(STAT(WEAPONS, receiver) & it.m_wepset) && (it.netname == weapon))
                                {
                                        RandomSelection_AddEnt(it, 1, 1);
                                        break;
@@ -739,7 +712,7 @@ void GiveRandomWeapons(entity receiver, int num_weapons, string weapon_names,
                {
                        return;
                }
-               receiver.weapons |= RandomSelection_chosen_ent.m_wepset;
+               STAT(WEAPONS, receiver) |= RandomSelection_chosen_ent.m_wepset;
                if (RandomSelection_chosen_ent.ammo_type == RESOURCE_NONE)
                {
                        continue;
@@ -801,7 +774,7 @@ float Item_GiveTo(entity item, entity player)
                                if(player.(weaponentity).m_switchweapon == w_getbestweapon(player, weaponentity))
                                        _switchweapon |= BIT(slot);
 
-                               if(!(player.weapons & WepSet_FromWeapon(player.(weaponentity).m_switchweapon)))
+                               if(!(STAT(WEAPONS, player) & WepSet_FromWeapon(player.(weaponentity).m_switchweapon)))
                                        _switchweapon |= BIT(slot);
                        }
                }
@@ -817,8 +790,8 @@ float Item_GiveTo(entity item, entity player)
        if (item.itemdef.instanceOfWeaponPickup)
        {
                WepSet w;
-               w = item.weapons;
-               w &= ~player.weapons;
+               w = STAT(WEAPONS, item);
+               w &= ~STAT(WEAPONS, player);
 
                if (w || (item.spawnshieldtime && item.pickup_anyway > 0))
                {
@@ -1008,7 +981,7 @@ void Item_Reset(entity this)
        {
                WaypointSprite_Kill(this.waypointsprite_attached);
        }
-       if (this.itemdef.instanceOfPowerup || (this.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
+       if (this.itemdef.instanceOfPowerup || (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
        {
                Item_ScheduleInitialRespawn(this);
        }
@@ -1067,7 +1040,7 @@ float generic_pickupevalfunc(entity player, entity item) {return item.bot_pickup
 float weapon_pickupevalfunc(entity player, entity item)
 {
        // See if I have it already
-       if(player.weapons & item.weapons)
+       if(STAT(WEAPONS, player) & STAT(WEAPONS, item))
        {
                // If I can pick it up
                if(!item.spawnshieldtime)
@@ -1078,7 +1051,7 @@ float weapon_pickupevalfunc(entity player, entity item)
        // reduce weapon value if bot already got a good arsenal
        float c = 1;
        int weapons_value = 0;
-       FOREACH(Weapons, it != WEP_Null && (player.weapons & it.m_wepset), {
+       FOREACH(Weapons, it != WEP_Null && (STAT(WEAPONS, player) & it.m_wepset), {
                weapons_value += it.bot_pickupbasevalue;
        });
        c -= bound(0, weapons_value / 20000, 1) * 0.5;
@@ -1112,7 +1085,7 @@ float ammo_pickupevalfunc(entity player, entity item)
        else
        {
                FOREACH(Weapons, it != WEP_Null, {
-                       if(!(player.weapons & (it.m_wepset)))
+                       if(!(STAT(WEAPONS, player) & (it.m_wepset)))
                                continue;
 
                        switch(it.ammo_type)
@@ -1228,7 +1201,7 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
        }
 
        if(weaponid)
-               this.weapons = WepSet_FromWeapon(Weapons_from(weaponid));
+               STAT(WEAPONS, this) = WepSet_FromWeapon(Weapons_from(weaponid));
 
        this.flags = FL_ITEM | itemflags;
        IL_PUSH(g_items, this);
@@ -1537,7 +1510,7 @@ spawnfunc(target_items)
                                        s = W_UndeprecateName(argv(j));
                                        if(s == it.netname)
                                        {
-                                               this.weapons |= (it.m_wepset);
+                                               STAT(WEAPONS, this) |= (it.m_wepset);
                                                if(this.spawnflags == 0 || this.spawnflags == 2)
                                                        it.wr_init(it);
                                                break;
@@ -1590,7 +1563,7 @@ spawnfunc(target_items)
                if(this.health != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.health), "health");
                if(this.armorvalue != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.armorvalue), "armor");
                FOREACH(Buffs, it != BUFF_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(BUFFS, this) & (it.m_itemid)), it.m_name));
-               FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(this.weapons & (it.m_wepset)), it.netname));
+               FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(WEAPONS, this) & (it.m_wepset)), it.netname));
        }
        this.netname = strzone(this.netname);
        //print(this.netname, "\n");
@@ -1609,30 +1582,30 @@ float GiveWeapon(entity e, float wpn, float op, float val)
 {
        WepSet v0, v1;
        WepSet s = WepSet_FromWeapon(Weapons_from(wpn));
-       v0 = (e.weapons & s);
+       v0 = (STAT(WEAPONS, e) & s);
        switch(op)
        {
                case OP_SET:
                        if(val > 0)
-                               e.weapons |= s;
+                               STAT(WEAPONS, e) |= s;
                        else
-                               e.weapons &= ~s;
+                               STAT(WEAPONS, e) &= ~s;
                        break;
                case OP_MIN:
                case OP_PLUS:
                        if(val > 0)
-                               e.weapons |= s;
+                               STAT(WEAPONS, e) |= s;
                        break;
                case OP_MAX:
                        if(val <= 0)
-                               e.weapons &= ~s;
+                               STAT(WEAPONS, e) &= ~s;
                        break;
                case OP_MINUS:
                        if(val > 0)
-                               e.weapons &= ~s;
+                               STAT(WEAPONS, e) &= ~s;
                        break;
        }
-       v1 = (e.weapons & s);
+       v1 = (STAT(WEAPONS, e) & s);
        return (v0 != v1);
 }
 
@@ -1850,7 +1823,7 @@ float GiveItems(entity e, float beginarg, float endarg)
        FOREACH(Weapons, it != WEP_Null, {
                POSTGIVE_WEAPON(e, it, SND_WEAPONPICKUP, SND_Null);
                if(!(save_weapons & (it.m_wepset)))
-                       if(e.weapons & (it.m_wepset))
+                       if(STAT(WEAPONS, e) & (it.m_wepset))
                                it.wr_init(it);
        });
        POSTGIVE_VALUE(e, strength_finished, 1, SND_POWERUP, SND_POWEROFF);
@@ -1866,7 +1839,7 @@ float GiveItems(entity e, float beginarg, float endarg)
        POSTGIVE_VALUE_ROT(e, health, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_MEGAHEALTH, SND_Null);
 
        if(e.superweapons_finished <= 0)
-               if(e.weapons & WEPSET_SUPERWEAPONS)
+               if(STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS)
                        e.superweapons_finished = autocvar_g_balance_superweapons_time;
 
        if(e.strength_finished <= 0)
@@ -1886,7 +1859,7 @@ float GiveItems(entity e, float beginarg, float endarg)
        {
                .entity weaponentity = weaponentities[slot];
                if(e.(weaponentity).m_weapon != WEP_Null || slot == 0)
-               if(!(e.weapons & WepSet_FromWeapon(e.(weaponentity).m_switchweapon)))
+               if(!(STAT(WEAPONS, e) & WepSet_FromWeapon(e.(weaponentity).m_switchweapon)))
                        _switchweapon |= BIT(slot);
        }
 
index 315a100375bd4fc7cfd45911919d0ac9ce42d60d..bd46599aa39ed1ae750ebdca4dcc2f57c802a5a7 100644 (file)
@@ -124,9 +124,9 @@ void GiveSound(entity e, float v0, float v1, float t, Sound snd_incr, Sound snd_
 
 void GiveRot(entity e, float v0, float v1, .float rotfield, float rottime, .float regenfield, float regentime);
 
-#define PREGIVE_WEAPONS(e) WepSet save_weapons; save_weapons = e.weapons
+#define PREGIVE_WEAPONS(e) WepSet save_weapons; save_weapons = STAT(WEAPONS, e)
 #define PREGIVE(e,f) float save_##f; save_##f = (e).f
-#define POSTGIVE_WEAPON(e,b,snd_incr,snd_decr) GiveSound((e), !!(save_weapons & WepSet_FromWeapon(b)), !!(e.weapons & WepSet_FromWeapon(b)), 0, snd_incr, snd_decr)
+#define POSTGIVE_WEAPON(e,b,snd_incr,snd_decr) GiveSound((e), !!(save_weapons & WepSet_FromWeapon(b)), !!(STAT(WEAPONS, e) & WepSet_FromWeapon(b)), 0, snd_incr, snd_decr)
 #define POSTGIVE_BIT(e,f,b,snd_incr,snd_decr) GiveSound((e), save_##f & (b), (e).f & (b), 0, snd_incr, snd_decr)
 #define POSTGIVE_VALUE(e,f,t,snd_incr,snd_decr) GiveSound((e), save_##f, (e).f, t, snd_incr, snd_decr)
 #define POSTGIVE_VALUE_ROT(e,f,t,rotfield,rottime,regenfield,regentime,snd_incr,snd_decr) GiveRot((e), save_##f, (e).f, rotfield, rottime, regenfield, regentime); GiveSound((e), save_##f, (e).f, t, snd_incr, snd_decr)
index c4e50a7e71f058be20cd74201a619a5878e20777..89ddfbd4f1ca6a28df7f9d45339b016d01923144 100644 (file)
@@ -6,7 +6,7 @@ spawnfunc(turret_plasma) { if (!turret_initialize(this, TUR_PLASMA)) delete(this
 
 METHOD(PlasmaTurret, tr_attack, void(PlasmaTurret this, entity it))
 {
-    if(autocvar_g_instagib)
+    if(MUTATOR_IS_ENABLED(mutator_instagib))
     {
         .entity weaponentity = weaponentities[0]; // TODO: unhardcode
         FireRailgunBullet (it, weaponentity, it.tur_shotorg, it.tur_shotorg + it.tur_shotdir_updated * max_shot_distance, 10000000000,
index 8d20da5b6eed40b3c9f66eddffbe3b0c780b228a..9fa10eefff01e8a2c7cf0a9cbd305014f7be13e4 100644 (file)
@@ -6,7 +6,7 @@ spawnfunc(turret_plasma_dual) { if (!turret_initialize(this, TUR_PLASMA_DUAL)) d
 
 METHOD(DualPlasmaTurret, tr_attack, void(DualPlasmaTurret thistur, entity it))
 {
-    if (autocvar_g_instagib) {
+    if (MUTATOR_IS_ENABLED(mutator_instagib)) {
         .entity weaponentity = weaponentities[0]; // TODO: unhardcode
         FireRailgunBullet (it, weaponentity, it.tur_shotorg, it.tur_shotorg + it.tur_shotdir_updated * max_shot_distance, 10000000000,
                            800, 0, 0, 0, 0, DEATH_TURRET_PLASMA.m_id);
index 898889149a0ef1fccceb6613e468ae42c92f7107..f118a04667f39c181eb0dee13eede8cc59d42973 100644 (file)
@@ -194,9 +194,8 @@ string W_FixWeaponOrder_ForceComplete(string order)
        return W_FixWeaponOrder(order, 1);
 }
 
-void W_RandomWeapons(entity e, int n)
+WepSet W_RandomWeapons(entity e, WepSet remaining, int n)
 {
-       WepSet remaining = e.weapons;
        WepSet result = '0 0 0';
        for (int j = 0; j < n; ++j)
        {
@@ -209,7 +208,7 @@ void W_RandomWeapons(entity e, int n)
                result |= WepSet_FromWeapon(w);
                remaining &= ~WepSet_FromWeapon(w);
        }
-       e.weapons = result;
+       return result;
 }
 
 string GetAmmoPicture(int ammotype)
index 0af47590078a8dde4c44257de429ff240e0dd19e..2a151d1afcc0d402acc31fd6689ace7f50b0624e 100644 (file)
@@ -304,7 +304,6 @@ STATIC_INIT(register_weapons_done)
         WepSet set = it.m_wepset = _WepSet_FromWeapon(it.m_id = i);
         WEPSET_ALL |= set;
         if ((it.spawnflags) & WEP_FLAG_SUPERWEAPON) WEPSET_SUPERWEAPONS |= set;
-        it.weapons = set;
         if (it == WEP_Null) continue;
         int imp = WEP_IMPULSE_BEGIN + it.m_id - 1;
         if (imp <= WEP_IMPULSE_END)
index 460d95af65e685253865e8cdd65d1abc35fd6ece..a3f2336a9487b275a8a130a031295c462072d77b 100644 (file)
@@ -44,8 +44,6 @@ CLASS(Weapon, Object)
     ATTRIB(Weapon, m_canonical_spawnfunc, string);
     /** control what happens when this weapon is spawned */
     METHOD(Weapon, m_spawnfunc_hookreplace, Weapon(Weapon this, entity e)) { return this; }
-    /** A: WEPSET_id : WEPSET_... */
-    ATTRIB(Weapon, weapons, WepSet, '0 0 0');
     /** M: ammotype  : main ammo type */
     ATTRIB(Weapon, ammo_type, int, RESOURCE_NONE);
     /** M: impulse   : weapon impulse */
@@ -211,7 +209,7 @@ string W_NumberWeaponOrder(string order);
 string W_FixWeaponOrder_BuildImpulseList(string o);
 string W_FixWeaponOrder_AllowIncomplete(entity this, string order);
 string W_FixWeaponOrder_ForceComplete(string order);
-void W_RandomWeapons(entity e, int n);
+WepSet W_RandomWeapons(entity e, WepSet remaining, int n);
 
 string GetAmmoPicture(int ammotype);
 
index f778e164bd9e60a00c0fea8547d820a69bda9ca7..ca460f089db61b60cbcee1ed447e35fc645590f4 100644 (file)
@@ -37,7 +37,7 @@ void W_Porto_Fail(entity this, float failhard)
 
        this.realowner.porto_current = NULL;
 
-       if(this.cnt < 0 && !failhard && this.realowner.playerid == this.playerid && !IS_DEAD(this.realowner) && !(this.realowner.weapons & WEPSET(PORTO)))
+       if(this.cnt < 0 && !failhard && this.realowner.playerid == this.playerid && !IS_DEAD(this.realowner) && !(STAT(WEAPONS, this.realowner) & WEPSET(PORTO)))
        {
                setsize(this, '-16 -16 0', '16 16 32');
                setorigin(this, this.origin + trace_plane_normal);
index 7ce6efa45fc63af8e3bd50991b1bdac3dcf1336c..f52974020faf371949431647c569d61ea101b62b 100644 (file)
@@ -109,7 +109,7 @@ void havocbot_ai(entity this)
                this.aistatus |= AI_STATUS_ATTACKING;
                this.aistatus &= ~AI_STATUS_ROAMING;
 
-               if(this.weapons)
+               if(STAT(WEAPONS, this))
                {
                        if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(this))
                        {
@@ -204,7 +204,7 @@ void havocbot_ai(entity this)
                        if(this.(weaponentity).clip_load >= 0) // only if we're not reloading a weapon already
                        {
                                FOREACH(Weapons, it != WEP_Null, {
-                                       if((this.weapons & (it.m_wepset)) && (it.spawnflags & WEP_FLAG_RELOADABLE) && (this.(weaponentity).weapon_load[it.m_id] < it.reloading_ammo))
+                                       if((STAT(WEAPONS, this) & (it.m_wepset)) && (it.spawnflags & WEP_FLAG_RELOADABLE) && (this.(weaponentity).weapon_load[it.m_id] < it.reloading_ammo))
                                        {
                                                this.(weaponentity).m_switchweapon = it;
                                                break;
@@ -1238,7 +1238,7 @@ LABEL(scan_targets)
 
                // I want to do a second scan if no enemy was found or I don't have weapons
                // TODO: Perform the scan when using the rifle (requires changes on the rifle code)
-               if(best || this.weapons) // || this.weapon == WEP_RIFLE.m_id
+               if(best || STAT(WEAPONS, this)) // || this.weapon == WEP_RIFLE.m_id
                        break;
                if(scan_transparent)
                        break;
index e469436014e1e030cc7dd1fc3bad16e61ad9fb11..4c70c1b1bda385a12ee7edf1b25bc97273f36da5 100644 (file)
@@ -51,7 +51,7 @@ bool havocbot_goalrating_item_can_be_left_to_teammate(entity this, entity player
 {
        if (item.health && player.health <= this.health) {return true;}
        if (item.armorvalue && player.armorvalue <= this.armorvalue) {return true;}
-       if (item.weapons && !(player.weapons & item.weapons)) {return true;}
+       if (STAT(WEAPONS, item) && !(STAT(WEAPONS, player) & STAT(WEAPONS, item))) {return true;}
        if (item.ammo_shells && player.ammo_shells <= this.ammo_shells) {return true;}
        if (item.ammo_nails && player.ammo_nails <= this.ammo_nails) {return true;}
        if (item.ammo_rockets && player.ammo_rockets <= this.ammo_rockets) {return true;}
index 976d5a7b94d6e4caa2ca7982529cde04b88e5a80..22e77b4eacf941a27fc41c334924d8dff7644173 100644 (file)
@@ -159,7 +159,7 @@ float CheatImpulse(entity this, int imp)
                        this.personal.ammo_fuel = this.ammo_fuel;
                        this.personal.health = max(1, this.health);
                        this.personal.armorvalue = this.armorvalue;
-                       this.personal.weapons = this.weapons;
+                       STAT(WEAPONS, this.personal) = STAT(WEAPONS, this);
                        this.personal.items = this.items;
                        this.personal.pauserotarmor_finished = this.pauserotarmor_finished;
                        this.personal.pauserothealth_finished = this.pauserothealth_finished;
@@ -218,7 +218,7 @@ float CheatImpulse(entity this, int imp)
                                this.ammo_fuel = this.personal.ammo_fuel;
                                this.health = this.personal.health;
                                this.armorvalue = this.personal.armorvalue;
-                               this.weapons = this.personal.weapons;
+                               STAT(WEAPONS, this) = STAT(WEAPONS, this.personal);
                                this.items = this.personal.items;
                                this.pauserotarmor_finished = time + this.personal.pauserotarmor_finished - this.personal.teleport_time;
                                this.pauserothealth_finished = time + this.personal.pauserothealth_finished - this.personal.teleport_time;
index 270a4d1af3c4940da7a1102c5286e5bca81b80d7..bd71d982d0402085f96235874e79e2fc8bb46b97 100644 (file)
@@ -49,6 +49,7 @@
 #include "../common/items/_mod.qh"
 
 #include "../common/mutators/mutator/waypoints/all.qh"
+#include "../common/mutators/mutator/instagib/sv_instagib.qh"
 
 #include "../common/triggers/subs.qh"
 #include "../common/triggers/triggers.qh"
@@ -361,7 +362,7 @@ void PutObserverInServer(entity this)
        this.revival_time = 0;
 
        this.items = 0;
-       this.weapons = '0 0 0';
+       STAT(WEAPONS, this) = '0 0 0';
        this.drawonlytoclient = this;
 
        this.viewloc = NULL;
@@ -563,7 +564,7 @@ void PutPlayerInServer(entity this)
                this.ammo_fuel = warmup_start_ammo_fuel;
                this.health = warmup_start_health;
                this.armorvalue = warmup_start_armorvalue;
-               this.weapons = WARMUP_START_WEAPONS;
+               STAT(WEAPONS, this) = WARMUP_START_WEAPONS;
        } else {
                this.ammo_shells = start_ammo_shells;
                this.ammo_nails = start_ammo_nails;
@@ -573,7 +574,7 @@ void PutPlayerInServer(entity this)
                this.ammo_fuel = start_ammo_fuel;
                this.health = start_health;
                this.armorvalue = start_armorvalue;
-               this.weapons = start_weapons;
+               STAT(WEAPONS, this) = start_weapons;
                if (MUTATOR_CALLHOOK(ForbidRandomStartWeapons, this) == false)
                {
                        GiveRandomWeapons(this, random_start_weapons_count,
@@ -584,7 +585,7 @@ void PutPlayerInServer(entity this)
 
        PS(this).dual_weapons = '0 0 0';
 
-       this.superweapons_finished = (this.weapons & WEPSET_SUPERWEAPONS) ? time + autocvar_g_balance_superweapons_time : 0;
+       this.superweapons_finished = (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS) ? time + autocvar_g_balance_superweapons_time : 0;
 
        this.items = start_items;
 
@@ -1503,7 +1504,7 @@ void player_powerups(entity this)
        Fire_ApplyDamage(this);
        Fire_ApplyEffect(this);
 
-       if (!autocvar_g_instagib)
+       if (!MUTATOR_IS_ENABLED(mutator_instagib))
        {
                if (this.items & ITEM_Strength.m_itemid)
                {
@@ -1549,7 +1550,7 @@ void player_powerups(entity this)
                }
                if (this.items & IT_SUPERWEAPON)
                {
-                       if (!(this.weapons & WEPSET_SUPERWEAPONS))
+                       if (!(STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS))
                        {
                                this.superweapons_finished = 0;
                                this.items = this.items - (this.items & IT_SUPERWEAPON);
@@ -1566,13 +1567,13 @@ void player_powerups(entity this)
                                if (time > this.superweapons_finished)
                                {
                                        this.items = this.items - (this.items & IT_SUPERWEAPON);
-                                       this.weapons &= ~WEPSET_SUPERWEAPONS;
+                                       STAT(WEAPONS, this) &= ~WEPSET_SUPERWEAPONS;
                                        //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_BROKEN, this.netname);
                                        Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_SUPERWEAPON_BROKEN);
                                }
                        }
                }
-               else if(this.weapons & WEPSET_SUPERWEAPONS)
+               else if(STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS)
                {
                        if (time < this.superweapons_finished || (this.items & IT_UNLIMITED_SUPERWEAPONS))
                        {
@@ -1584,7 +1585,7 @@ void player_powerups(entity this)
                        else
                        {
                                this.superweapons_finished = 0;
-                               this.weapons &= ~WEPSET_SUPERWEAPONS;
+                               STAT(WEAPONS, this) &= ~WEPSET_SUPERWEAPONS;
                        }
                }
                else
@@ -1786,7 +1787,7 @@ void SpectateCopy(entity this, entity spectatee)
        this.invincible_finished = spectatee.invincible_finished;
        this.superweapons_finished = spectatee.superweapons_finished;
        STAT(PRESSED_KEYS, this) = STAT(PRESSED_KEYS, spectatee);
-       this.weapons = spectatee.weapons;
+       STAT(WEAPONS, this) = STAT(WEAPONS, spectatee);
        this.punchangle = spectatee.punchangle;
        this.view_ofs = spectatee.view_ofs;
        this.velocity = spectatee.velocity;
index a1e1294027e5adb10ba52117a407ff95983cfa67..4f973bb9e75548e11bf67ddbed53aec3bb99b3ea 100644 (file)
@@ -107,7 +107,7 @@ void target_init_use(entity this, entity actor, entity trigger)
                SetResourceAmount(actor, RESOURCE_PLASMA, start_ammo_plasma);
                SetResourceAmount(actor, RESOURCE_FUEL, start_ammo_fuel);
 
-               actor.weapons = start_weapons;
+               STAT(WEAPONS, actor) = start_weapons;
                if (this.spawnflags & 32)
                {
                        // TODO
index afe5814a516140630f3e9a1f60d39943e2e9b129..5230bd8ea6ac1279c964cf61a8f052cedfa5806a 100644 (file)
@@ -190,8 +190,6 @@ void FixClientCvars(entity e);
 // WEAPONTODO: remove this
 //WepSet weaponsInMap;
 
-#define weapons _STAT(WEAPONS)
-
 .float respawn_countdown; // next number to count
 
 float bot_waypoints_for_items;
index f87bce9e85d56976a6d7b2b9405e24d2bf008c19..dcbc20342df2294a3e60be5426316d3362be9d0f 100644 (file)
@@ -13,6 +13,7 @@
 #include "../common/vehicles/all.qh"
 #include "../common/items/_mod.qh"
 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
+#include "../common/mutators/mutator/instagib/sv_instagib.qh"
 #include "weapons/accuracy.qh"
 #include "weapons/csqcprojectile.qh"
 #include "weapons/selection.qh"
@@ -66,7 +67,7 @@ void GiveFrags (entity attacker, entity targ, float f, int deathtype, .entity we
                // 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 = attacker.(weaponentity).m_weapon;
-               else if(!(attacker.weapons & (culprit.m_wepset))) culprit = attacker.(weaponentity).m_weapon;
+               else if(!(STAT(WEAPONS, attacker) & (culprit.m_wepset))) culprit = attacker.(weaponentity).m_weapon;
 
                if(g_weaponarena_random_with_blaster && culprit == WEP_BLASTER) // WEAPONTODO: Shouldn't this be in a mutator?
                {
@@ -80,26 +81,26 @@ void GiveFrags (entity attacker, entity targ, float f, int deathtype, .entity we
                        }
 
                        if(warmup_stage)
-                               GiveFrags_randomweapons.weapons = WARMUP_START_WEAPONS;
+                               STAT(WEAPONS, GiveFrags_randomweapons) = WARMUP_START_WEAPONS;
                        else
-                               GiveFrags_randomweapons.weapons = start_weapons;
+                               STAT(WEAPONS, GiveFrags_randomweapons) = start_weapons;
 
                        // all others (including the culprit): remove
-                       GiveFrags_randomweapons.weapons &= ~attacker.weapons;
-                       GiveFrags_randomweapons.weapons &= ~(culprit.m_wepset);
+                       STAT(WEAPONS, GiveFrags_randomweapons) &= ~STAT(WEAPONS, attacker);
+                       STAT(WEAPONS, GiveFrags_randomweapons) &= ~(culprit.m_wepset);
 
                        // among the remaining ones, choose one by random
-                       W_RandomWeapons(GiveFrags_randomweapons, 1);
+                       STAT(WEAPONS, GiveFrags_randomweapons) = W_RandomWeapons(GiveFrags_randomweapons, STAT(WEAPONS, GiveFrags_randomweapons), 1);
 
-                       if(GiveFrags_randomweapons.weapons)
+                       if(STAT(WEAPONS, GiveFrags_randomweapons))
                        {
-                               attacker.weapons |= GiveFrags_randomweapons.weapons;
-                               attacker.weapons &= ~(culprit.m_wepset);
+                               STAT(WEAPONS, attacker) |= STAT(WEAPONS, GiveFrags_randomweapons);
+                               STAT(WEAPONS, attacker) &= ~(culprit.m_wepset);
                        }
                }
 
                // after a frag, choose another random weapon set
-               if (!(attacker.weapons & WepSet_FromWeapon(attacker.(weaponentity).m_weapon)))
+               if (!(STAT(WEAPONS, attacker) & WepSet_FromWeapon(attacker.(weaponentity).m_weapon)))
                        W_SwitchWeapon_Force(attacker, w_getbestweapon(attacker, weaponentity), weaponentity);
        }
 
@@ -779,7 +780,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
                        }
                }
 
-               if(!autocvar_g_instagib)
+               if(!MUTATOR_IS_ENABLED(mutator_instagib))
                {
                        // apply strength multiplier
                        if (attacker.items & ITEM_Strength.m_itemid)
index d1ba087a2e0ba9e2e2d1743e9d63669560f900f8..3f35fe9eaa39e816f3a8bf9c063cc4977c735087 100644 (file)
@@ -241,7 +241,7 @@ MUTATOR_HOOKABLE(CustomizeWaypoint, EV_CustomizeWaypoint);
 MUTATOR_HOOKABLE(FilterItemDefinition, EV_FilterItemDefinition);
 
 /**
- * checks if the current item may be spawned (.items and .weapons may be read and written to, as well as the ammo_ fields)
+ * checks if the current item may be spawned (.items may be read and written to, as well as the ammo_ fields)
  * return error to request removal
  */
 #define EV_FilterItem(i, o) \
index 90aca172cc83f600e77c7d19e6a52405e7222547..06615c4eac8575465aed85fe57cbe5181c423940 100644 (file)
@@ -30,7 +30,7 @@ void W_GiveWeapon(entity e, int wep)
 {
        if (!wep) return;
 
-       e.weapons |= WepSet_FromWeapon(Weapons_from(wep));
+       STAT(WEAPONS, e) |= WepSet_FromWeapon(Weapons_from(wep));
 
        if (IS_PLAYER(e)) {
            Send_Notification(NOTIF_ONE, e, MSG_MULTI, ITEM_WEAPON_GOT, wep);
index f059dfba9bccd79a97da944a5c9eaea77a98e0be..c2a9c32acdef778fac3191045753e8ee80032c60 100644 (file)
@@ -52,7 +52,7 @@ bool client_hasweapon(entity this, Weapon wpn, .entity weaponentity, float andam
 
        // ignore hook button when using other offhand equipment
        if (this.offhand != OFFHAND_HOOK)
-       if (wpn == WEP_HOOK && !((this.weapons | weaponsInMap) & WepSet_FromWeapon(wpn)))
+       if (wpn == WEP_HOOK && !((STAT(WEAPONS, this) | weaponsInMap) & WepSet_FromWeapon(wpn)))
            complain = 0;
 
        if (complain)
@@ -66,7 +66,7 @@ bool client_hasweapon(entity this, Weapon wpn, .entity weaponentity, float andam
        }
        if (autocvar_g_weaponswitch_debug == 2 && weaponslot(weaponentity) > 0 && !(wpn.spawnflags & WEP_FLAG_DUALWIELD) && !(PS(this).dual_weapons & wpn.m_wepset))
                return false; // no complaints needed
-       if (this.weapons & WepSet_FromWeapon(wpn))
+       if (STAT(WEAPONS, this) & WepSet_FromWeapon(wpn))
        {
                if (andammo)
                {
@@ -161,12 +161,12 @@ float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, fl
                FOREACH(Weapons, it != WEP_Null, {
                        if(i != weaponwant)
                        if(it.impulse == imp || imp < 0)
-                       if((this.weapons & (it.m_wepset)) || (weaponsInMap & (it.m_wepset)))
+                       if((STAT(WEAPONS, this) & (it.m_wepset)) || (weaponsInMap & (it.m_wepset)))
                                have_other = true;
                });
 
                // skip weapons we don't own that aren't normal and aren't in the map
-               if(!(this.weapons & wepset))
+               if(!(STAT(WEAPONS, this) & wepset))
                if(!(weaponsInMap & wepset))
                if((wep.spawnflags & WEP_FLAG_MUTATORBLOCKED) || have_other)
                        continue;
@@ -217,12 +217,12 @@ float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, fl
                        FOREACH(Weapons, it != WEP_Null, {
                                if(i != weaponwant)
                                if(it.impulse == imp || imp < 0)
-                               if((this.weapons & (it.m_wepset)) || (weaponsInMap & (it.m_wepset)))
+                               if((STAT(WEAPONS, this) & (it.m_wepset)) || (weaponsInMap & (it.m_wepset)))
                                        have_other = true;
                        });
 
                        // skip weapons we don't own that aren't normal and aren't in the map
-                       if(!(this.weapons & wepset))
+                       if(!(STAT(WEAPONS, this) & wepset))
                        if(!(weaponsInMap & wepset))
                        if((wep.spawnflags & WEP_FLAG_MUTATORBLOCKED) || have_other)
                                continue;
@@ -252,11 +252,11 @@ void W_SwitchToOtherWeapon(entity this, .entity weaponentity)
        // hack to ensure it switches to an OTHER weapon (in case the other fire mode still has ammo, we want that anyway)
        Weapon ww;
        WepSet set = WepSet_FromWeapon(this.(weaponentity).m_weapon);
-       if (this.weapons & set)
+       if (STAT(WEAPONS, this) & set)
        {
-               this.weapons &= ~set;
+               STAT(WEAPONS, this) &= ~set;
                ww = w_getbestweapon(this, weaponentity);
-               this.weapons |= set;
+               STAT(WEAPONS, this) |= set;
        }
        else
        {
index ae745efd6fdaa90f6ed39b9d8b59e4736a3c26fa..821a02327b19ff273f460459dc9f5038a18888d9 100644 (file)
@@ -65,7 +65,7 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto
                        int superweapons = 1;
                        FOREACH(Weapons, it != WEP_Null, {
                                WepSet set = it.m_wepset;
-                               if((set & WEPSET_SUPERWEAPONS) && (own.weapons & set)) ++superweapons;
+                               if((set & WEPSET_SUPERWEAPONS) && (STAT(WEAPONS, own) & set)) ++superweapons;
                        });
                        if(superweapons <= 1)
                        {
@@ -183,8 +183,8 @@ void W_ThrowWeapon(entity this, .entity weaponentity, vector velo, vector delta,
                return;
 
        WepSet set = WepSet_FromWeapon(w);
-       if(!(this.weapons & set)) return;
-       this.weapons &= ~set;
+       if(!(STAT(WEAPONS, this) & set)) return;
+       STAT(WEAPONS, this) &= ~set;
 
        W_SwitchWeapon_Force(this, w_getbestweapon(this, weaponentity), weaponentity);
        string a = W_ThrowNewWeapon(this, w.m_id, doreduce, this.origin + delta, velo, weaponentity);
@@ -197,7 +197,7 @@ void SpawnThrownWeapon(entity this, vector org, Weapon wep, .entity weaponentity
 {
        //entity wep = this.(weaponentity).m_weapon;
 
-       if(this.weapons & WepSet_FromWeapon(wep))
+       if(STAT(WEAPONS, this) & WepSet_FromWeapon(wep))
                if(W_IsWeaponThrowable(this, wep.m_id))
                        W_ThrowNewWeapon(this, wep.m_id, false, org, randomvec() * 125 + '0 0 200', weaponentity);
 }
index 8bfcbb79cfb37d58734f12493f2e3f922d844ea7..011d5cbc11b19c13ca5b946d4dd75fabd4e9f51c 100644 (file)
@@ -559,7 +559,7 @@ void W_WeaponFrame(Player actor, .entity weaponentity)
        // server framerate is very low and the weapon fire rate very high
        for (int c = 0; c < W_TICSPERFRAME; ++c)
        {
-               if (w != WEP_Null && !(actor.weapons & WepSet_FromWeapon(w)))
+               if (w != WEP_Null && !(STAT(WEAPONS, actor) & WepSet_FromWeapon(w)))
                {
                        if (this.m_weapon == this.m_switchweapon) W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
                        w = WEP_Null;
@@ -576,7 +576,7 @@ void W_WeaponFrame(Player actor, .entity weaponentity)
                                key_pressed = false;
 
                        Weapon off = actor.offhand;
-                       if (off && (!(actor.weapons & WEPSET(HOOK)) || off != OFFHAND_HOOK))
+                       if (off && (!(STAT(WEAPONS, actor) & WEPSET(HOOK)) || off != OFFHAND_HOOK))
                        {
                                if (off.offhand_think) off.offhand_think(off, actor, key_pressed);
                        }