]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Weapons: Introduce concept of offhand weapons
authorTimePath <andrew.hardaker1995@gmail.com>
Tue, 29 Sep 2015 00:22:26 +0000 (10:22 +1000)
committerTimePath <andrew.hardaker1995@gmail.com>
Tue, 29 Sep 2015 00:22:26 +0000 (10:22 +1000)
33 files changed:
qcsrc/common/monsters/monster/mage.qc
qcsrc/common/turrets/turret/plasma_dual.qc
qcsrc/common/vehicles/vehicle/racer.qc
qcsrc/common/weapons/all.qh
qcsrc/common/weapons/weapon/arc.qc
qcsrc/common/weapons/weapon/blaster.qc
qcsrc/common/weapons/weapon/crylink.qc
qcsrc/common/weapons/weapon/devastator.qc
qcsrc/common/weapons/weapon/electro.qc
qcsrc/common/weapons/weapon/fireball.qc
qcsrc/common/weapons/weapon/hagar.qc
qcsrc/common/weapons/weapon/hlac.qc
qcsrc/common/weapons/weapon/hmg.qc
qcsrc/common/weapons/weapon/hook.qc
qcsrc/common/weapons/weapon/machinegun.qc
qcsrc/common/weapons/weapon/minelayer.qc
qcsrc/common/weapons/weapon/mortar.qc
qcsrc/common/weapons/weapon/porto.qc
qcsrc/common/weapons/weapon/rifle.qc
qcsrc/common/weapons/weapon/rpc.qc
qcsrc/common/weapons/weapon/seeker.qc
qcsrc/common/weapons/weapon/shockwave.qc
qcsrc/common/weapons/weapon/shotgun.qc
qcsrc/common/weapons/weapon/tuba.qc
qcsrc/common/weapons/weapon/vaporizer.qc
qcsrc/common/weapons/weapon/vortex.qc
qcsrc/server/g_hook.qc
qcsrc/server/g_hook.qh
qcsrc/server/mutators/gamemode_nexball.qc
qcsrc/server/mutators/mutator_hook.qc [new file with mode: 0644]
qcsrc/server/mutators/mutator_nades.qc
qcsrc/server/mutators/mutators_include.qc
qcsrc/server/weapons/weaponsystem.qc

index c034f992b4548205cd546fb1d75d152e723ac88c..0030a4fa81b0f0b1330bd8ee14bcbf90a4638d12 100644 (file)
@@ -39,9 +39,9 @@ REGISTER_WEAPON(MAGE_SPIKE, NEW(MageSpike));
 #ifdef SVQC
 
 void M_Mage_Attack_Spike(vector dir);
-METHOD(MageSpike, wr_think, bool(entity thiswep)) {
+METHOD(MageSpike, wr_think, bool(entity thiswep, bool fire1, bool fire2)) {
        SELFPARAM();
-       if (self.BUTTON_ATCK)
+       if (fire1)
        if (weapon_prepareattack(0, WEP_CVAR_PRI(electro, refire))) {
                if (!self.target_range) self.target_range = autocvar_g_monsters_target_range;
                self.enemy = Monster_FindTarget(self);
index bde6ebf74b683aecd14b86661baf8fb767dbfa60..3041410eccafc114cfad91da544695e404dbb358 100644 (file)
@@ -30,9 +30,9 @@ REGISTER_WEAPON(PLASMA_DUAL, NEW(PlasmaDualAttack));
 
 #ifdef SVQC
 
-METHOD(PlasmaDualAttack, wr_think, bool(entity thiswep)) {
+METHOD(PlasmaDualAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) {
        SELFPARAM();
-       if (self.BUTTON_ATCK)
+       if (fire1)
        if (weapon_prepareattack(0, WEP_CVAR_PRI(electro, refire))) {
                W_SetupShot_Dir(self, v_forward, false, 0, W_Sound("electro_fire"), CH_WEAPON_B, 0);
                self.tur_shotdir_updated = w_shotdir;
index 9dabe77c0765ead8aef10a3bef349e0934776e1e..c797e75389266f757da994256110fdf23e6c4e5c 100644 (file)
@@ -37,9 +37,9 @@ REGISTER_WEAPON(RACER, NEW(RacerAttack));
 #include "../../triggers/trigger/impulse.qh"
 
 void racer_fire_cannon(string tagname);
-METHOD(RacerAttack, wr_think, bool(entity thiswep)) {
+METHOD(RacerAttack, wr_think, bool(entity thiswep, bool fire1, bool fire2)) {
        SELFPARAM();
-       if (self.BUTTON_ATCK)
+       if (fire1)
        if (weapon_prepareattack(0, 0)) {
                W_SetupShot_Dir(self, v_forward, false, 0, W_Sound("lasergun_fire"), CH_WEAPON_B, 0);
                racer_fire_cannon("tag_fire1");
index cb13d1e22636836f2aae7bf5117e88bdf4f1c1e1..7f7e34dda605a04a8f6a68595d2076b9308a64d3 100644 (file)
@@ -34,8 +34,8 @@ const int WEP_FLAG_MUTATORBLOCKED = 0x200; // hides from impulse 99 etc. (mutato
 // weapon requests
 const int WR_SETUP          =  1; // (SERVER) setup weapon data
 .bool(entity this) wr_setup;
-const int WR_THINK          =  2; // (SERVER) logic to run every frame
-.bool(entity this) wr_think;
+/** (SERVER) logic to run every frame */
+.bool(entity this, bool fire1, bool fire2) wr_think;
 const int WR_CHECKAMMO1     =  3; // (SERVER) checks ammo for weapon primary
 .bool(entity this) wr_checkammo1;
 const int WR_CHECKAMMO2     =  4; // (SERVER) checks ammo for weapon second
@@ -69,7 +69,6 @@ const int WR_PICKUP         = 17; // (SERVER) a weapon is picked up
 
 bool w_new(entity this, int req) {
     if (req == WR_SETUP) return this.wr_setup ? this.wr_setup(this) : false;
-    if (req == WR_THINK) return this.wr_think ? this.wr_think(this) : false;
     if (req == WR_CHECKAMMO1) return this.wr_checkammo1 ? this.wr_checkammo1(this) : false;
     if (req == WR_CHECKAMMO2) return this.wr_checkammo2 ? this.wr_checkammo2(this) : false;
     if (req == WR_AIM) return this.wr_aim ? this.wr_aim(this) : false;
@@ -270,6 +269,14 @@ CLASS(Weapon, Object)
        }
 ENDCLASS(Weapon)
 
+CLASS(OffhandWeapon, Object)
+    METHOD(OffhandWeapon, offhand_think, void(OffhandWeapon this, entity player, bool key_pressed)) {}
+ENDCLASS(OffhandWeapon)
+
+#ifdef SVQC
+.OffhandWeapon offhand;
+#endif
+
 void RegisterWeapons();
 REGISTER_REGISTRY(RegisterWeapons)
 entity weapon_info[WEP_MAXCOUNT], weapon_info_first, weapon_info_last;
index 515a21efff97cfb18f6e6c380a674e246a078fc4..2853d857d5af51524d047f91a71409cf7eaf5459 100644 (file)
@@ -656,14 +656,14 @@ void Arc_Smoke()
                        }
                        return true;
                }
-               METHOD(Arc, wr_think, bool(entity thiswep))
+               METHOD(Arc, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        SELFPARAM();
                        Arc_Player_SetHeat(self);
                        Arc_Smoke();
 
                        if ( self.arc_overheat <= time )
-                       if(self.BUTTON_ATCK || self.BUTTON_ATCK2 || self.arc_beam.beam_bursting )
+                       if(fire1 || fire2 || self.arc_beam.beam_bursting )
                        {
 
                                if(self.arc_BUTTON_ATCK_prev)
@@ -678,9 +678,9 @@ void Arc_Smoke()
 
                                if((!self.arc_beam) || wasfreed(self.arc_beam))
                                {
-                                       if(weapon_prepareattack(!!self.BUTTON_ATCK2, 0))
+                                       if(weapon_prepareattack(!!fire2, 0))
                                        {
-                                               W_Arc_Beam(!!self.BUTTON_ATCK2);
+                                               W_Arc_Beam(!!fire2);
 
                                                if(!self.arc_BUTTON_ATCK_prev)
                                                {
@@ -702,7 +702,7 @@ void Arc_Smoke()
                        self.arc_BUTTON_ATCK_prev = 0;
 
                        #if 0
-                       if(self.BUTTON_ATCK2)
+                       if(fire2)
                        if(weapon_prepareattack(1, autocvar_g_balance_arc_secondary_refire))
                        {
                                W_Arc_Attack2();
index bba93388769eac8dbc7bb3fd1b1cf416b29f6370..706c07a0477c09f1857cad1b312d1ca9a4de998c 100644 (file)
@@ -162,9 +162,9 @@ void W_Blaster_Attack(
                        return true;
                }
 
-               METHOD(Blaster, wr_think, bool(entity thiswep))
+               METHOD(Blaster, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
-                       if(self.BUTTON_ATCK)
+                       if(fire1)
                        {
                                if(weapon_prepareattack(0, WEP_CVAR_PRI(blaster, refire)))
                                {
@@ -183,7 +183,7 @@ void W_Blaster_Attack(
                                        weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(blaster, animtime), w_ready);
                                }
                        }
-                       else if(self.BUTTON_ATCK2)
+                       else if(fire2)
                        {
                                switch(WEP_CVAR(blaster, secondary))
                                {
index 4d3b7dfa636984f3c73ad3d69ae1d425afa889af..902bcab4927ea6d10cc1e0c591c99584fd79afef 100644 (file)
@@ -576,13 +576,13 @@ void W_Crylink_Attack2(void)
 
                        return true;
                }
-               METHOD(Crylink, wr_think, bool(entity thiswep))
+               METHOD(Crylink, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        SELFPARAM();
                        if(autocvar_g_balance_crylink_reload_ammo && self.clip_load < min(WEP_CVAR_PRI(crylink, ammo), WEP_CVAR_SEC(crylink, ammo))) // forced reload
                                _WEP_ACTION(self.weapon, WR_RELOAD);
 
-                       if(self.BUTTON_ATCK)
+                       if(fire1)
                        {
                                if(self.crylink_waitrelease != 1)
                                if(weapon_prepareattack(0, WEP_CVAR_PRI(crylink, refire)))
@@ -592,7 +592,7 @@ void W_Crylink_Attack2(void)
                                }
                        }
 
-                       if(self.BUTTON_ATCK2 && autocvar_g_balance_crylink_secondary)
+                       if(fire2 && autocvar_g_balance_crylink_secondary)
                        {
                                if(self.crylink_waitrelease != 2)
                                if(weapon_prepareattack(1, WEP_CVAR_SEC(crylink, refire)))
@@ -602,7 +602,7 @@ void W_Crylink_Attack2(void)
                                }
                        }
 
-                       if((self.crylink_waitrelease == 1 && !self.BUTTON_ATCK) || (self.crylink_waitrelease == 2 && !self.BUTTON_ATCK2))
+                       if((self.crylink_waitrelease == 1 && !fire1) || (self.crylink_waitrelease == 2 && !fire2))
                        {
                                if(!self.crylink_lastgroup || time > self.crylink_lastgroup.teleport_time)
                                {
index 76ebd8e994ef167813539f563a64377e807cf815..c52693a6558af65aeef571c43d58f80fd8525d51 100644 (file)
@@ -522,13 +522,13 @@ void W_Devastator_Attack(void)
                        return true;
                }
                #endif
-               METHOD(Devastator, wr_think, bool(entity thiswep))
+               METHOD(Devastator, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        if(WEP_CVAR(devastator, reload_ammo) && self.clip_load < WEP_CVAR(devastator, ammo)) // forced reload
                                _WEP_ACTION(self.weapon, WR_RELOAD);
                        else
                        {
-                               if(self.BUTTON_ATCK)
+                               if(fire1)
                                {
                                        if(self.rl_release || WEP_CVAR(devastator, guidestop))
                                        if(weapon_prepareattack(0, WEP_CVAR(devastator, refire)))
@@ -541,7 +541,7 @@ void W_Devastator_Attack(void)
                                else
                                        self.rl_release = 1;
 
-                               if(self.BUTTON_ATCK2)
+                               if(fire2)
                                if(self.switchweapon == WEP_DEVASTATOR.m_id)
                                {
                                        entity rock;
index 073a4e0f597ea73fab2d6c8d77d7e5b72d3dfc43..5a23f8849c2aad63a8ddcde333a4e2845fd9d24c 100644 (file)
@@ -453,7 +453,7 @@ void W_Electro_CheckAttack(void)
 
                        return true;
                }
-               METHOD(Electro, wr_think, bool(entity thiswep))
+               METHOD(Electro, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        if(autocvar_g_balance_electro_reload_ammo) // forced reload // WEAPONTODO
                        {
@@ -472,7 +472,7 @@ void W_Electro_CheckAttack(void)
                                return true;
                        }
 
-                       if(self.BUTTON_ATCK)
+                       if(fire1)
                        {
                                if(weapon_prepareattack(0, WEP_CVAR_PRI(electro, refire)))
                                {
@@ -480,7 +480,7 @@ void W_Electro_CheckAttack(void)
                                                weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(electro, animtime), w_ready);
                                }
                        }
-                       else if(self.BUTTON_ATCK2)
+                       else if(fire2)
                        {
                                if(time >= self.electro_secondarytime)
                                if(weapon_prepareattack(1, WEP_CVAR_SEC(electro, refire)))
index 1ff37df00bf137f366835815436cd44da41783f7..13d5ed3e40a7c521819d06374ba4975741780b4a 100644 (file)
@@ -373,9 +373,9 @@ void W_Fireball_Attack2(void)
 
                        return true;
                }
-               METHOD(Fireball, wr_think, bool(entity thiswep))
+               METHOD(Fireball, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
-                       if(self.BUTTON_ATCK)
+                       if(fire1)
                        {
                                if(time >= self.fireball_primarytime)
                                if(weapon_prepareattack(0, WEP_CVAR_PRI(fireball, refire)))
@@ -384,7 +384,7 @@ void W_Fireball_Attack2(void)
                                        self.fireball_primarytime = time + WEP_CVAR_PRI(fireball, refire2) * W_WeaponRateFactor();
                                }
                        }
-                       else if(self.BUTTON_ATCK2)
+                       else if(fire2)
                        {
                                if(weapon_prepareattack(1, WEP_CVAR_SEC(fireball, refire)))
                                {
index 2c827cb220c83b7064875539999a801f7d173e8c..9ca028450a49610473faa8b1fed1d0bc62fe6103 100644 (file)
@@ -408,7 +408,7 @@ void W_Hagar_Attack2_Load(void)
 
                        return true;
                }
-               METHOD(Hagar, wr_think, bool(entity thiswep))
+               METHOD(Hagar, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        float loadable_secondary;
                        loadable_secondary = (WEP_CVAR_SEC(hagar, load) && WEP_CVAR(hagar, secondary));
@@ -417,7 +417,7 @@ void W_Hagar_Attack2_Load(void)
                                W_Hagar_Attack2_Load(); // must always run each frame
                        if(autocvar_g_balance_hagar_reload_ammo && self.clip_load < min(WEP_CVAR_PRI(hagar, ammo), WEP_CVAR_SEC(hagar, ammo))) // forced reload
                                _WEP_ACTION(self.weapon, WR_RELOAD);
-                       else if(self.BUTTON_ATCK && !self.hagar_load && !self.hagar_loadblock) // not while secondary is loaded or awaiting reset
+                       else if(fire1 && !self.hagar_load && !self.hagar_loadblock) // not while secondary is loaded or awaiting reset
                        {
                                if(weapon_prepareattack(0, WEP_CVAR_PRI(hagar, refire)))
                                {
@@ -425,7 +425,7 @@ void W_Hagar_Attack2_Load(void)
                                        weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(hagar, refire), w_ready);
                                }
                        }
-                       else if(self.BUTTON_ATCK2 && !loadable_secondary && WEP_CVAR(hagar, secondary))
+                       else if(fire2 && !loadable_secondary && WEP_CVAR(hagar, secondary))
                        {
                                if(weapon_prepareattack(1, WEP_CVAR_SEC(hagar, refire)))
                                {
index 7e4477604a4947194b5a16c117511bcfba29668b..1c4b3a0187fee3855680df04faffab41d0a0b46e 100644 (file)
@@ -211,11 +211,11 @@ void W_HLAC_Attack2_Frame(void)
                        self.BUTTON_ATCK = bot_aim(WEP_CVAR_PRI(hlac, speed), 0, WEP_CVAR_PRI(hlac, lifetime), false);
                        return true;
                }
-               METHOD(HLAC, wr_think, bool(entity thiswep))
+               METHOD(HLAC, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        if(autocvar_g_balance_hlac_reload_ammo && self.clip_load < min(WEP_CVAR_PRI(hlac, ammo), WEP_CVAR_SEC(hlac, ammo))) // forced reload
                                _WEP_ACTION(self.weapon, WR_RELOAD);
-                       else if(self.BUTTON_ATCK)
+                       else if(fire1)
                        {
                                if(weapon_prepareattack(0, WEP_CVAR_PRI(hlac, refire)))
                                {
@@ -225,7 +225,7 @@ void W_HLAC_Attack2_Frame(void)
                                }
                        }
 
-                       else if(self.BUTTON_ATCK2 && WEP_CVAR(hlac, secondary))
+                       else if(fire2 && WEP_CVAR(hlac, secondary))
                        {
                                if(weapon_prepareattack(1, WEP_CVAR_SEC(hlac, refire)))
                                {
index 8e5398745f5eeb8c5227c942d3c5501a8e61608c..bba7f127fcc37c6bc7f29b2dd399962aa59ace9a 100644 (file)
@@ -97,13 +97,13 @@ void W_HeavyMachineGun_Attack_Auto()
 
                        return true;
                }
-               METHOD(HeavyMachineGun, wr_think, bool(entity thiswep))
+               METHOD(HeavyMachineGun, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        if(WEP_CVAR(hmg, reload_ammo) && self.clip_load < WEP_CVAR(hmg, ammo)) // forced reload
                                _WEP_ACTION(self.weapon, WR_RELOAD);
                        else
                        {
-                               if (self.BUTTON_ATCK)
+                               if (fire1)
                                if (weapon_prepareattack(0, 0))
                                {
                                        self.misc_bulletcounter = 0;
index b0b8b8b3f11dcd9ffaabad70b52c4c3e73ab8033..1478d96edc8fa584ff488256186ea300bd6ed932 100644 (file)
@@ -17,6 +17,15 @@ CLASS(Hook, Weapon)
 ENDCLASS(Hook)
 REGISTER_WEAPON(HOOK, NEW(Hook));
 
+CLASS(OffhandHook, OffhandWeapon)
+    METHOD(OffhandHook, offhand_think, void(OffhandHook this, entity player, bool key_pressed))
+    {
+       Weapon wep = WEP_HOOK;
+       WITH(entity, self, player, wep.wr_think(wep, key_pressed, false));
+    }
+ENDCLASS(OffhandHook)
+OffhandHook OFFHAND_HOOK; STATIC_INIT(OFFHAND_HOOK) { OFFHAND_HOOK = NEW(OffhandHook); }
+
 #define HOOK_SETTINGS(w_cvar,w_prop) HOOK_SETTINGS_LIST(w_cvar, w_prop, HOOK, hook)
 #define HOOK_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
        w_cvar(id, sn, BOTH, animtime) \
@@ -181,9 +190,9 @@ void W_Hook_Attack2(void)
                        // no bot AI for hook (yet?)
                        return true;
                }
-               METHOD(Hook, wr_think, bool(entity thiswep))
+               METHOD(Hook, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
-                       if(self.BUTTON_ATCK || self.BUTTON_HOOK)
+                       if(fire1 || self.BUTTON_HOOK)
                        {
                                if(!self.hook)
                                if(!(self.hook_state & HOOK_WAITING_FOR_RELEASE))
@@ -197,7 +206,7 @@ void W_Hook_Attack2(void)
                                }
                        }
 
-                       if(self.BUTTON_ATCK2)
+                       if(fire2)
                        {
                                if(weapon_prepareattack(1, WEP_CVAR_SEC(hook, refire)))
                                {
@@ -257,7 +266,7 @@ void W_Hook_Attack2(void)
                        if(self.BUTTON_CROUCH)
                        {
                                self.hook_state &= ~HOOK_PULLING;
-                               if(self.BUTTON_ATCK || self.BUTTON_HOOK)
+                               if(fire1 || self.BUTTON_HOOK)
                                        self.hook_state &= ~HOOK_RELEASING;
                                else
                                        self.hook_state |= HOOK_RELEASING;
@@ -267,7 +276,7 @@ void W_Hook_Attack2(void)
                                self.hook_state |= HOOK_PULLING;
                                self.hook_state &= ~HOOK_RELEASING;
 
-                               if(self.BUTTON_ATCK || self.BUTTON_HOOK)
+                               if(fire1 || self.BUTTON_HOOK)
                                {
                                        // already fired
                                        if(self.hook)
@@ -280,6 +289,8 @@ void W_Hook_Attack2(void)
                                }
                        }
 
+                       _GrapplingHookFrame();
+
                        return true;
                }
                METHOD(Hook, wr_init, bool(entity thiswep))
index ddbc0fdb625c499c78e9d91a71fd56d5798a739d..784b9a43523ea181e3e3dc6aa9becec77a3677eb 100644 (file)
@@ -247,20 +247,20 @@ void W_MachineGun_Attack_Burst(void)
 
                        return true;
                }
-               METHOD(MachineGun, wr_think, bool(entity thiswep))
+               METHOD(MachineGun, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        if(WEP_CVAR(machinegun, reload_ammo) && self.clip_load < min(max(WEP_CVAR(machinegun, sustained_ammo), WEP_CVAR(machinegun, first_ammo)), WEP_CVAR(machinegun, burst_ammo))) // forced reload
                                _WEP_ACTION(self.weapon, WR_RELOAD);
                        else if(WEP_CVAR(machinegun, mode) == 1)
                        {
-                               if(self.BUTTON_ATCK)
+                               if(fire1)
                                if(weapon_prepareattack(0, 0))
                                {
                                        self.misc_bulletcounter = 0;
                                        W_MachineGun_Attack_Auto();
                                }
 
-                               if(self.BUTTON_ATCK2)
+                               if(fire2)
                                if(weapon_prepareattack(1, 0))
                                {
                                        if(!_WEP_ACTION(self.weapon, WR_CHECKAMMO2))
@@ -280,7 +280,7 @@ void W_MachineGun_Attack_Burst(void)
                        else
                        {
 
-                               if(self.BUTTON_ATCK)
+                               if(fire1)
                                if(weapon_prepareattack(0, 0))
                                {
                                        self.misc_bulletcounter = 1;
@@ -288,7 +288,7 @@ void W_MachineGun_Attack_Burst(void)
                                        weapon_thinkf(WFRAME_FIRE1, WEP_CVAR(machinegun, sustained_refire), W_MachineGun_Attack_Frame);
                                }
 
-                               if(self.BUTTON_ATCK2 && WEP_CVAR(machinegun, first))
+                               if(fire2 && WEP_CVAR(machinegun, first))
                                if(weapon_prepareattack(1, 0))
                                {
                                        self.misc_bulletcounter = 1;
index 7c8c63bd339ab5957e2f0894d6056cdff7ce6a6a..b6aa26343d5c46bcf02df965207efa7901404c9d 100644 (file)
@@ -499,7 +499,7 @@ float W_MineLayer_PlacedMines(float detonate)
 
                        return true;
                }
-               METHOD(MineLayer, wr_think, bool(entity thiswep))
+               METHOD(MineLayer, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        if(autocvar_g_balance_minelayer_reload_ammo && self.clip_load < WEP_CVAR(minelayer, ammo)) // forced reload
                        {
@@ -507,7 +507,7 @@ float W_MineLayer_PlacedMines(float detonate)
                                if(!(W_MineLayer_PlacedMines(false) && self.WEP_AMMO(MINE_LAYER) < WEP_CVAR(minelayer, ammo)))
                                        _WEP_ACTION(self.weapon, WR_RELOAD);
                        }
-                       else if(self.BUTTON_ATCK)
+                       else if(fire1)
                        {
                                if(weapon_prepareattack(0, WEP_CVAR(minelayer, refire)))
                                {
@@ -516,7 +516,7 @@ float W_MineLayer_PlacedMines(float detonate)
                                }
                        }
 
-                       if(self.BUTTON_ATCK2)
+                       if(fire2)
                        {
                                if(W_MineLayer_PlacedMines(true))
                                        sound(self, CH_WEAPON_B, SND_MINE_DET, VOL_BASE, ATTN_NORM);
index 0f01fcf479cd5c6ddde898da81225e98a520b86b..559c50310e8f41b388293f9dfb27df1a6fddf56b 100644 (file)
@@ -336,11 +336,11 @@ void W_Mortar_Attack2(void)
                        wepinfo_sec_dps = (WEP_CVAR_SEC(mortar, damage) * (1 / max3(sys_frametime, WEP_CVAR_SEC(mortar, refire), WEP_CVAR_SEC(mortar, animtime))));
                        wepinfo_ter_dps = 0;
                        */
-               METHOD(Mortar, wr_think, bool(entity thiswep))
+               METHOD(Mortar, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        if(autocvar_g_balance_mortar_reload_ammo && self.clip_load < min(WEP_CVAR_PRI(mortar, ammo), WEP_CVAR_SEC(mortar, ammo))) // forced reload
                                _WEP_ACTION(self.weapon, WR_RELOAD);
-                       else if(self.BUTTON_ATCK)
+                       else if(fire1)
                        {
                                if(weapon_prepareattack(0, WEP_CVAR_PRI(mortar, refire)))
                                {
@@ -348,7 +348,7 @@ void W_Mortar_Attack2(void)
                                        weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(mortar, animtime), w_ready);
                                }
                        }
-                       else if(self.BUTTON_ATCK2)
+                       else if(fire2)
                        {
                                if(WEP_CVAR_SEC(mortar, remote_detonateprimary))
                                {
index a8ad17602163f18ccc30717528ac835060cdc606..97a0203f4629e2dbda0c80ee88653201d64db0e4 100644 (file)
@@ -301,12 +301,12 @@ void W_Porto_Attack(float type)
                        PORTO_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
                        return true;
                }
-               METHOD(PortoLaunch, wr_think, bool(entity thiswep))
+               METHOD(PortoLaunch, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        SELFPARAM();
                        if(WEP_CVAR(porto, secondary))
                        {
-                               if(self.BUTTON_ATCK)
+                               if(fire1)
                                if(!self.porto_current)
                                if(!self.porto_forbidden)
                                if(weapon_prepareattack(0, WEP_CVAR_PRI(porto, refire)))
@@ -315,7 +315,7 @@ void W_Porto_Attack(float type)
                                        weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(porto, animtime), w_ready);
                                }
 
-                               if(self.BUTTON_ATCK2)
+                               if(fire2)
                                if(!self.porto_current)
                                if(!self.porto_forbidden)
                                if(weapon_prepareattack(1, WEP_CVAR_SEC(porto, refire)))
@@ -328,7 +328,7 @@ void W_Porto_Attack(float type)
                        {
                                if(self.porto_v_angle_held)
                                {
-                                       if(!self.BUTTON_ATCK2)
+                                       if(!fire2)
                                        {
                                                self.porto_v_angle_held = 0;
 
@@ -337,7 +337,7 @@ void W_Porto_Attack(float type)
                                }
                                else
                                {
-                                       if(self.BUTTON_ATCK2)
+                                       if(fire2)
                                        {
                                                self.porto_v_angle = self.v_angle;
                                                self.porto_v_angle_held = 1;
@@ -348,7 +348,7 @@ void W_Porto_Attack(float type)
                                if(self.porto_v_angle_held)
                                        makevectors(self.porto_v_angle); // override the previously set angles
 
-                               if(self.BUTTON_ATCK)
+                               if(fire1)
                                if(!self.porto_current)
                                if(!self.porto_forbidden)
                                if(weapon_prepareattack(0, WEP_CVAR_PRI(porto, refire)))
index 09df647babedab413ed605133e0c3d0762db0f67..3d69e2d8f1af585fa2c0ddec3d60f605c8fa5061 100644 (file)
@@ -162,14 +162,14 @@ void W_Rifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animt
 
                        return true;
                }
-               METHOD(Rifle, wr_think, bool(entity thiswep))
+               METHOD(Rifle, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        if(autocvar_g_balance_rifle_reload_ammo && self.clip_load < min(WEP_CVAR_PRI(rifle, ammo), WEP_CVAR_SEC(rifle, ammo))) // forced reload
                                _WEP_ACTION(self.weapon, WR_RELOAD);
                        else
                        {
                                self.rifle_accumulator = bound(time - WEP_CVAR(rifle, bursttime), self.rifle_accumulator, time);
-                               if(self.BUTTON_ATCK)
+                               if(fire1)
                                if(weapon_prepareattack_check(0, WEP_CVAR_PRI(rifle, refire)))
                                if(time >= self.rifle_accumulator + WEP_CVAR_PRI(rifle, burstcost))
                                {
@@ -177,7 +177,7 @@ void W_Rifle_BulletHail(float mode, void(void) AttackFunc, float fr, float animt
                                        W_Rifle_BulletHail(WEP_CVAR_PRI(rifle, bullethail), W_Rifle_Attack, WFRAME_FIRE1, WEP_CVAR_PRI(rifle, animtime), WEP_CVAR_PRI(rifle, refire));
                                        self.rifle_accumulator += WEP_CVAR_PRI(rifle, burstcost);
                                }
-                               if(self.BUTTON_ATCK2)
+                               if(fire2)
                                {
                                        if(WEP_CVAR(rifle, secondary))
                                        {
index 5d8ba40284c605665b03afd59b2f8e8c37540d6b..836b4be33acb7dab2325fd7e9da1d1f91c7ea56d 100644 (file)
@@ -154,13 +154,13 @@ void W_RocketPropelledChainsaw_Attack (void)
                        self.BUTTON_ATCK = bot_aim(WEP_CVAR(rpc, speed), 0, WEP_CVAR(rpc, lifetime), false);
                        return true;
                }
-               METHOD(RocketPropelledChainsaw, wr_think, bool(entity thiswep))
+               METHOD(RocketPropelledChainsaw, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        if(WEP_CVAR(rpc, reload_ammo) && self.clip_load < WEP_CVAR(rpc, ammo))
                                _WEP_ACTION(self.weapon, WR_RELOAD);
                        else
                        {
-                               if (self.BUTTON_ATCK)
+                               if (fire1)
                                {
                                        if(weapon_prepareattack(0, WEP_CVAR(rpc, refire)))
                                        {
@@ -169,7 +169,7 @@ void W_RocketPropelledChainsaw_Attack (void)
                                        }
                                }
 
-                               if (self.BUTTON_ATCK2)
+                               if (fire2)
                                {
                                        // to-do
                                }
index 4b9cf57cb2fe66dfea1e94986e618ebc75c43b9d..74be279bc308edd887a5f6332578011dbcc7ddbf 100644 (file)
@@ -609,12 +609,12 @@ void W_Seeker_Fire_Tag(void)
                                self.BUTTON_ATCK = bot_aim(WEP_CVAR(seeker, tag_speed), 0, WEP_CVAR(seeker, tag_lifetime), false);
                        return true;
                }
-               METHOD(Seeker, wr_think, bool(entity thiswep))
+               METHOD(Seeker, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        if(autocvar_g_balance_seeker_reload_ammo && self.clip_load < min(WEP_CVAR(seeker, missile_ammo), WEP_CVAR(seeker, tag_ammo))) // forced reload
                                _WEP_ACTION(self.weapon, WR_RELOAD);
 
-                       else if(self.BUTTON_ATCK)
+                       else if(fire1)
                        {
                                if(WEP_CVAR(seeker, type) == 1)
                                {
@@ -634,7 +634,7 @@ void W_Seeker_Fire_Tag(void)
                                }
                        }
 
-                       else if(self.BUTTON_ATCK2)
+                       else if(fire2)
                        {
                                if(WEP_CVAR(seeker, type) == 1)
                                {
index 859c80e898eabbe3c09c87958a1c7d676d0870ad..713ac59c75ed8aa122de7d00e65a3e0eecb1806a 100644 (file)
@@ -677,9 +677,9 @@ void W_Shockwave_Attack(void)
 
                        return true;
                }
-               METHOD(Shockwave, wr_think, bool(entity thiswep))
+               METHOD(Shockwave, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
-                       if(self.BUTTON_ATCK)
+                       if(fire1)
                        {
                                if(time >= self.shockwave_blasttime) // handle refire separately so the secondary can be fired straight after a primary
                                {
@@ -691,7 +691,7 @@ void W_Shockwave_Attack(void)
                                        }
                                }
                        }
-                       else if(self.BUTTON_ATCK2)
+                       else if(fire2)
                        {
                                //if(self.clip_load >= 0) // we are not currently reloading
                                if(!self.crouch) // no crouchmelee please
index 519cd51ad1d5de8d79a4d9d564a57468803faa71..578e9284cf796f308fb3d2e7479edb866f7f05a1 100644 (file)
@@ -234,7 +234,7 @@ void W_Shotgun_Attack3_Frame1()
 
                        return true;
                }
-               METHOD(Shotgun, wr_think, bool(entity thiswep))
+               METHOD(Shotgun, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        if(WEP_CVAR(shotgun, reload_ammo) && self.clip_load < WEP_CVAR_PRI(shotgun, ammo)) // forced reload
                        {
@@ -244,7 +244,7 @@ void W_Shotgun_Attack3_Frame1()
                        }
                        else
                        {
-                               if(self.BUTTON_ATCK)
+                               if(fire1)
                                {
                                        if(time >= self.shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary
                                        {
@@ -256,7 +256,7 @@ void W_Shotgun_Attack3_Frame1()
                                                }
                                        }
                                }
-                               else if(self.BUTTON_ATCK2 && WEP_CVAR(shotgun, secondary) == 2)
+                               else if(fire2 && WEP_CVAR(shotgun, secondary) == 2)
                                {
                                        if(time >= self.shotgun_primarytime) // handle refire separately so the secondary can be fired straight after a primary
                                        {
@@ -272,7 +272,7 @@ void W_Shotgun_Attack3_Frame1()
                        if(self.clip_load >= 0) // we are not currently reloading
                        if(!self.crouch) // no crouchmelee please
                        if(WEP_CVAR(shotgun, secondary) == 1)
-                       if((self.BUTTON_ATCK && self.WEP_AMMO(SHOTGUN) <= 0 && !(self.items & IT_UNLIMITED_WEAPON_AMMO)) || self.BUTTON_ATCK2)
+                       if((fire1 && self.WEP_AMMO(SHOTGUN) <= 0 && !(self.items & IT_UNLIMITED_WEAPON_AMMO)) || fire2)
                        if(weapon_prepareattack(1, WEP_CVAR_SEC(shotgun, refire)))
                        {
                                // attempt forcing playback of the anim by switching to another anim (that we never play) here...
index 590a576096b5d4d2a5828219c91be27046d60c2d..bf2372c7d5c4d069c824a41b0f4f8ca6c21f5c2b 100644 (file)
@@ -381,16 +381,16 @@ void W_Tuba_NoteOn(float hittype)
 
                        return true;
                }
-               METHOD(Tuba, wr_think, bool(entity thiswep))
+               METHOD(Tuba, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
-                       if(self.BUTTON_ATCK)
+                       if(fire1)
                        if(weapon_prepareattack(0, WEP_CVAR(tuba, refire)))
                        {
                                W_Tuba_NoteOn(0);
                                //weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_tuba_animtime, w_ready);
                                weapon_thinkf(WFRAME_IDLE, WEP_CVAR(tuba, animtime), w_ready);
                        }
-                       if(self.BUTTON_ATCK2)
+                       if(fire2)
                        if(weapon_prepareattack(1, WEP_CVAR(tuba, refire)))
                        {
                                W_Tuba_NoteOn(HITTYPE_SECONDARY);
@@ -399,7 +399,7 @@ void W_Tuba_NoteOn(float hittype)
                        }
                        if(self.tuba_note)
                        {
-                               if(!self.BUTTON_ATCK && !self.BUTTON_ATCK2)
+                               if(!fire1 && !fire2)
                                {
                                        WITH(entity, self, self.tuba_note, W_Tuba_NoteOff());
                                }
index 2f6d94dd7d18852fb428ef92f84a24f68bd31763..3cfbf3b38fcec971219c35e249707dd088f74ce0 100644 (file)
@@ -246,7 +246,7 @@ void W_RocketMinsta_Attack3 (void)
 
                        return true;
                }
-               METHOD(Vaporizer, wr_think, bool(entity thiswep))
+               METHOD(Vaporizer, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        float vaporizer_ammo = ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo));
                        // if the laser uses load, we also consider its ammo for reloading
@@ -254,7 +254,7 @@ void W_RocketMinsta_Attack3 (void)
                                _WEP_ACTION(self.weapon, WR_RELOAD);
                        else if(WEP_CVAR(vaporizer, reload_ammo) && self.clip_load < vaporizer_ammo) // forced reload
                                _WEP_ACTION(self.weapon, WR_RELOAD);
-                       if(self.BUTTON_ATCK && (self.ammo_cells || !autocvar_g_rm) && !forbidWeaponUse(self))
+                       if(fire1 && (self.ammo_cells || !autocvar_g_rm) && !forbidWeaponUse(self))
                        {
                                if(weapon_prepareattack(0, WEP_CVAR_PRI(vaporizer, refire)))
                                {
@@ -262,7 +262,7 @@ void W_RocketMinsta_Attack3 (void)
                                        weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(vaporizer, animtime), w_ready);
                                }
                        }
-                       if(self.BUTTON_ATCK2 || (self.BUTTON_ATCK && !self.ammo_cells && autocvar_g_rm))
+                       if(fire2 || (fire1 && !self.ammo_cells && autocvar_g_rm))
                        {
                                if((autocvar_g_rm && autocvar_g_rm_laser) || autocvar_g_rm_laser == 2)
                                {
index e9e659e0c9ed2a61b5976a64ff3a0838d9c16acb..a4e0fb5e046ed921f3560665da2ce4821fbfd6bd 100644 (file)
@@ -144,7 +144,7 @@ void W_Vortex_Attack(float issecondary)
                        }
                        return true;
                }
-               METHOD(Vortex, wr_think, bool(entity thiswep))
+               METHOD(Vortex, wr_think, bool(entity thiswep, bool fire1, bool fire2))
                {
                        if(WEP_CVAR(vortex, charge) && self.vortex_charge < WEP_CVAR(vortex, charge_limit))
                                self.vortex_charge = min(1, self.vortex_charge + WEP_CVAR(vortex, charge_rate) * frametime / W_TICSPERFRAME);
@@ -161,7 +161,7 @@ void W_Vortex_Attack(float issecondary)
                                _WEP_ACTION(self.weapon, WR_RELOAD);
                        else
                        {
-                               if(self.BUTTON_ATCK)
+                               if(fire1)
                                {
                                        if(weapon_prepareattack(0, WEP_CVAR_PRI(vortex, refire)))
                                        {
@@ -169,7 +169,7 @@ void W_Vortex_Attack(float issecondary)
                                                weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(vortex, animtime), w_ready);
                                        }
                                }
-                               if((WEP_CVAR(vortex, charge) && !WEP_CVAR(vortex, secondary)) ? (self.BUTTON_ZOOM | self.BUTTON_ZOOMSCRIPT) : self.BUTTON_ATCK2)
+                               if((WEP_CVAR(vortex, charge) && !WEP_CVAR(vortex, secondary)) ? (self.BUTTON_ZOOM | self.BUTTON_ZOOMSCRIPT) : fire2)
                                {
                                        if(WEP_CVAR(vortex, charge))
                                        {
@@ -196,7 +196,7 @@ void W_Vortex_Attack(float issecondary)
 
                                                        else if(WEP_CVAR_SEC(vortex, ammo))
                                                        {
-                                                               if(self.BUTTON_ATCK2) // only eat ammo when the button is pressed
+                                                               if(fire2) // only eat ammo when the button is pressed
                                                                {
                                                                        dt = min(dt, (1 - self.vortex_charge) / WEP_CVAR(vortex, charge_rate));
                                                                        if(!(self.items & IT_UNLIMITED_WEAPON_AMMO))
index c101d7271e3cc5bd4d2be16c30a4ce15f237c3fc..88c9783f522a8169cd3a1e689681fa4678ee65a6 100644 (file)
@@ -422,6 +422,7 @@ void FireGrapplingHook (void)
 //         // if I have no hook or it's not pulling yet, make sure I'm not flying!
 //         if((self.hook == world || !self.hook.state) && self.movetype == MOVETYPE_FLY)
 
+void _GrapplingHookFrame();
 void GrapplingHookFrame()
 {SELFPARAM();
        if(g_grappling_hook && timeout_status != TIMEOUT_ACTIVE && self.weapon != WEP_HOOK.m_id && !self.vehicle)
@@ -460,12 +461,16 @@ void GrapplingHookFrame()
        }
        self.hook_switchweapon = self.BUTTON_HOOK;
 
-       if(!g_grappling_hook && self.weapon != WEP_HOOK.m_id)
+       if(!g_grappling_hook && self.weapon != WEP_HOOK.m_id && self.offhand != OFFHAND_HOOK)
        {
                self.hook_state &= ~HOOK_FIRING;
                self.hook_state |= HOOK_REMOVING;
        }
+       _GrapplingHookFrame();
+}
 
+void _GrapplingHookFrame()
+{
        if (self.hook_state & HOOK_FIRING)
        {
                if (self.hook)
index aa641a56bc84bc927299e4715f2c456fbd05e205..26189143cf2aa4680c07350e77ec31d7b6280d15 100644 (file)
@@ -4,6 +4,7 @@
 // Wazat's grappling hook
 .entity                hook;
 void GrapplingHookFrame();
+void _GrapplingHookFrame();
 void RemoveGrapplingHook(entity pl);
 void SetGrappleHookBindings();
 // (note: you can change the hook impulse #'s to whatever you please)
index 10690001d49dd2dfa2aa20c63fef302ea931ec2b..bdcb9ee8f70532a2450ef4f09a26f3428ed405f4 100644 (file)
@@ -841,16 +841,9 @@ float ball_customize()
        return true;
 }
 
-float w_nexball_weapon(float req);
-METHOD(BallStealer, weapon_func, bool(entity this, int req)) {
-       return w_nexball_weapon(req);
-}
-
-float w_nexball_weapon(float req)
-{SELFPARAM();
-       if(req == WR_THINK)
+       METHOD(BallStealer, wr_think, bool(BallStealer thiswep, bool fire1, bool fire2))
        {
-               if(self.BUTTON_ATCK)
+               if(fire1)
                        if(weapon_prepareattack(0, autocvar_g_balance_nexball_primary_refire))
                                if(autocvar_g_nexball_basketball_meter)
                                {
@@ -864,30 +857,42 @@ float w_nexball_weapon(float req)
                                        W_Nexball_Attack(-1);
                                        weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
                                }
-               if(self.BUTTON_ATCK2)
+               if(fire2)
                        if(weapon_prepareattack(1, autocvar_g_balance_nexball_secondary_refire))
                        {
                                W_Nexball_Attack2();
                                weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
                        }
 
-               if(!self.BUTTON_ATCK && self.metertime && self.ballcarried)
+               if(!fire1 && self.metertime && self.ballcarried)
                {
                        W_Nexball_Attack(time - self.metertime);
                        // DropBall or stealing will set metertime back to 0
                        weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
                }
+               return true;
        }
-       else if(req == WR_INIT)
+       METHOD(BallStealer, wr_init, bool(BallStealer thiswep))
        {
+               return true;
        }
-       else if(req == WR_SETUP)
+       METHOD(BallStealer, wr_setup, bool(BallStealer thiswep))
        {
                //weapon_setup(WEP_PORTO.m_id);
+               return true;
+       }
+       METHOD(BallStealer, wr_aim, bool(BallStealer thiswep))
+       {
+               return true;
+       }
+       METHOD(BallStealer, wr_checkammo1, bool(BallStealer thiswep))
+       {
+               return true;
+       }
+       METHOD(BallStealer, wr_checkammo2, bool(BallStealer thiswep))
+       {
+               return true;
        }
-       // No need to check WR_CHECKAMMO* or WR_AIM, it should always return true
-       return true;
-}
 
 MUTATOR_HOOKFUNCTION(nexball_BallDrop)
 {SELFPARAM();
diff --git a/qcsrc/server/mutators/mutator_hook.qc b/qcsrc/server/mutators/mutator_hook.qc
new file mode 100644 (file)
index 0000000..dbf1681
--- /dev/null
@@ -0,0 +1,7 @@
+REGISTER_MUTATOR(hook, cvar("_g_grappling_hook"));
+
+MUTATOR_HOOKFUNCTION(hook, PlayerSpawn)
+{
+    SELFPARAM();
+    self.offhand = OFFHAND_HOOK;
+}
index 19a0aa462c688f842043f9a703cc8bfd50862e44..088f3f5294d0c8a4aad1a81f35e0f5237e4a5e58 100644 (file)
@@ -9,7 +9,7 @@
 #include "../../common/monsters/spawn.qh"
 #include "../../common/monsters/sv_monsters.qh"
 
-.float lifetime;
+.float nade_time_primed;
 
 .entity nade_spawnloc;
 
@@ -822,7 +822,7 @@ void nade_prime()
        n.colormap = self.colormap;
        n.glowmod = self.glowmod;
        n.wait = time + autocvar_g_nades_nade_lifetime;
-       n.lifetime = time;
+       n.nade_time_primed = time;
        n.think = nade_beep;
        n.nextthink = max(n.wait - 3, time);
        n.projectiledeathtype = DEATH_NADE;
@@ -868,9 +868,10 @@ void nades_CheckThrow()
        if(!CanThrowNade())
                return;
 
-       if(!self.nade)
+       entity held_nade = self.nade;
+       if (!held_nade)
        {
-               if(self.nade_refire < time)
+               if(time > self.nade_refire)
                {
                        Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_NADE_THROW);
                        nade_prime();
@@ -879,10 +880,9 @@ void nades_CheckThrow()
        }
        else
        {
-               if(time - self.nade.lifetime >= 1)
-               {
+               if (time >= held_nade.nade_time_primed + 1) {
                        makevectors(self.v_angle);
-                       float _force = time - self.nade.lifetime;
+                       float _force = time - held_nade.nade_time_primed;
                        _force /= autocvar_g_nades_nade_lifetime;
                        _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce));
                        toss_nade(self, (v_forward * 0.75 + v_up * 0.2 + v_right * 0.05) * _force, 0);
@@ -915,51 +915,46 @@ MUTATOR_HOOKFUNCTION(nades_VehicleEnter)
        return false;
 }
 
-MUTATOR_HOOKFUNCTION(nades_PlayerPreThink)
-{SELFPARAM();
-       if(!IS_PLAYER(self)) { return false; }
-
-       float key_pressed = self.BUTTON_HOOK;
-       float time_score;
-
-       if(g_grappling_hook || client_hasweapon(self, WEP_HOOK.m_id, false, false) || (weaponsInMap & WEPSET_HOOK))
-               key_pressed = self.button16; // if hook is enabled, use an alternate key
-
-       if(self.nade)
-       {
-               self.nade_timer = bound(0, (time - self.nade.lifetime) / autocvar_g_nades_nade_lifetime, 1);
-               //print(sprintf("%d %d\n", self.nade_timer, time - self.nade.lifetime));
-               makevectors(self.angles);
-               self.nade.velocity = self.velocity;
-
-               setorigin(self.nade, self.origin + self.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0);
-               self.nade.angles_y = self.angles.y;
-       }
-
-       if(self.nade)
-       if(self.nade.wait - 0.1 <= time)
-               toss_nade(self, '0 0 0', time + 0.05);
-
-       if(CanThrowNade())
-       if(self.nade_refire < time)
-       {
-               if(key_pressed)
+CLASS(NadeOffhand, OffhandWeapon)
+    METHOD(NadeOffhand, offhand_think, void(NadeOffhand this, entity player, bool key_pressed))
+    {
+       entity held_nade = player.nade;
+               if (held_nade)
                {
-                       if(!self.nade)
-                               nade_prime();
+                       player.nade_timer = bound(0, (time - held_nade.nade_time_primed) / autocvar_g_nades_nade_lifetime, 1);
+                       // LOG_TRACEF("%d %d\n", player.nade_timer, time - held_nade.nade_time_primed);
+                       makevectors(player.angles);
+                       held_nade.velocity = player.velocity;
+                       setorigin(held_nade, player.origin + player.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0);
+                       held_nade.angles_y = player.angles.y;
+
+                       if (time + 0.1 >= held_nade.wait)
+                               toss_nade(player, '0 0 0', time + 0.05);
                }
-               else if(time - self.nade.lifetime >= 1)
-               {
-                       if(self.nade)
-                       {
-                               makevectors(self.v_angle);
-                               float _force = time - self.nade.lifetime;
+
+        if (!CanThrowNade()) return;
+        if (!(time > player.nade_refire)) return;
+               if (key_pressed) {
+                       if (!held_nade) {
+                               nade_prime();
+                               held_nade = player.nade;
+                       }
+               } else if (time >= held_nade.nade_time_primed + 1) {
+                       if (held_nade) {
+                               makevectors(player.v_angle);
+                               float _force = time - held_nade.nade_time_primed;
                                _force /= autocvar_g_nades_nade_lifetime;
                                _force = autocvar_g_nades_nade_minforce + (_force * (autocvar_g_nades_nade_maxforce - autocvar_g_nades_nade_minforce));
-                               toss_nade(self, (v_forward * 0.7 + v_up * 0.2 + v_right * 0.1) * _force, 0);
+                               toss_nade(player, (v_forward * 0.7 + v_up * 0.2 + v_right * 0.1) * _force, 0);
                        }
                }
-       }
+    }
+ENDCLASS(NadeOffhand)
+NadeOffhand OFFHAND_NADE; STATIC_INIT(OFFHAND_NADE) { OFFHAND_NADE = NEW(NadeOffhand); }
+
+MUTATOR_HOOKFUNCTION(nades_PlayerPreThink)
+{SELFPARAM();
+       if (!IS_PLAYER(self)) { return false; }
 
        if(IS_PLAYER(self))
        {
@@ -969,6 +964,7 @@ MUTATOR_HOOKFUNCTION(nades_PlayerPreThink)
                        float key_count = 0;
                        FOR_EACH_KH_KEY(key) if(key.owner == self) { ++key_count; }
 
+                       float time_score;
                        if(self.flagcarried || self.ballcarried) // this player is important
                                time_score = autocvar_g_nades_bonus_score_time_flagcarrier;
                        else
@@ -1058,6 +1054,8 @@ MUTATOR_HOOKFUNCTION(nades_PlayerSpawn)
 
        self.nade_timer = 0;
 
+       self.offhand = OFFHAND_NADE;
+
        if(self.nade_spawnloc)
        {
                setorigin(self, self.nade_spawnloc.origin);
index 7f238b88e425351c5ca82e73286d8a92a7475888..92dc131cbb5d2ee5ab1f60f4da7b0f16d9dc0099 100644 (file)
 #include "mutator_bloodloss.qc"
 #include "mutator_random_gravity.qc"
 #include "mutator_multijump.qc"
+#include "mutator_hook.qc"
 #include "mutator_melee_only.qc"
 #include "mutator_nades.qc"
 #include "mutator_campcheck.qc"
index d26a6102f6c3de89c7a4b76ee7c9cda60fa3f105..20f49705435702ebb9cb6bf9d3a5adb343781d5f 100644 (file)
@@ -767,10 +767,23 @@ void W_WeaponFrame()
                v_right = ri;
                v_up = up;
 
-               if(w)
-                       _WEP_ACTION(self.weapon, WR_THINK);
-               else
+               {
+                       bool key_pressed;
+               if (g_grappling_hook || client_hasweapon(self, WEP_HOOK.m_id, false, false) || (weaponsInMap & WEPSET_HOOK))
+                       key_pressed = self.button16; // if hook is enabled, use an alternate key
+               else
+                       key_pressed = self.BUTTON_HOOK;
+
+               entity e = self.offhand;
+               if (e.offhand_think) e.offhand_think(e, self, key_pressed);
+        }
+
+               if (w) {
+                       entity e = get_weaponinfo(self.weapon);
+                       if (e.wr_think) e.wr_think(e, self.BUTTON_ATCK, self.BUTTON_ATCK2);
+               } else {
                        _WEP_ACTION(self.weapon, WR_GONETHINK);
+               }
 
                if (time + self.weapon_frametime * 0.5 >= self.weapon_nextthink)
                {