]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
make shotgun chargeable like hagar secondary (enable with g_balance_shotgun_secondary 3)
authorFreddy <schro.sb@gmail.com>
Tue, 26 Jul 2016 21:34:42 +0000 (23:34 +0200)
committerFreddy <schro.sb@gmail.com>
Tue, 26 Jul 2016 21:34:42 +0000 (23:34 +0200)
needs a bit of code cleanup

bal-wep-xonotic.cfg
qcsrc/client/view.qc
qcsrc/common/stats.qh
qcsrc/common/weapons/weapon/shotgun.qc
qcsrc/server/defs.qh

index b074aadda4ec4c7d245a8a8df330ef2fb230669e..2aa7037ee522deaf4bf42a2f9239c5984f009163 100644 (file)
@@ -52,11 +52,12 @@ set g_balance_shotgun_primary_force 15
 set g_balance_shotgun_primary_refire 0.75
 set g_balance_shotgun_primary_solidpenetration 3.8
 set g_balance_shotgun_primary_spread 0
-set g_balance_shotgun_primary_conespread 0.3
-set g_balance_shotgun_primary_numcircles 2
+set g_balance_shotgun_conespread 0.3
+set g_balance_shotgun_numcircles 2
 set g_balance_shotgun_reload_ammo 0
 set g_balance_shotgun_reload_time 2
 set g_balance_shotgun_secondary 1
+set g_balance_shotgun_secondary_bullets 4
 set g_balance_shotgun_secondary_animtime 1.15
 set g_balance_shotgun_secondary_damage 70
 set g_balance_shotgun_secondary_force 200
@@ -72,6 +73,12 @@ set g_balance_shotgun_secondary_melee_traces 10
 set g_balance_shotgun_secondary_refire 1.25
 set g_balance_shotgun_secondary_alt_animtime 0.2
 set g_balance_shotgun_secondary_alt_refire 1.2
+set g_balance_shotgun_secondary_load_abort 1
+set g_balance_shotgun_secondary_load_animtime 0.2
+set g_balance_shotgun_secondary_load_hold 3
+set g_balance_shotgun_secondary_load_max 3
+set g_balance_shotgun_secondary_load_releasedeath 0
+set g_balance_shotgun_secondary_load_speed 0.5
 set g_balance_shotgun_switchdelay_drop 0.2
 set g_balance_shotgun_switchdelay_raise 0.2
 set g_balance_shotgun_weaponreplace ""
index 4ca30d4a8de656478a7bc75ebf54ee4b33c9b73b..d96e9b35e63fad1ccf4766aaddf8884b03510d0a 100644 (file)
@@ -1186,6 +1186,13 @@ void HUD_Crosshair(entity this)
                                        ring_rgb = wcross_color;
                                        ring_image = "gfx/crosshair_ring.tga";
                                }
+                               else if (activeweapon == WEP_SHOTGUN && STAT(SHOTGUN_LOAD) && autocvar_crosshair_ring_hagar)
+                               {
+                                       ring_value = bound(0, STAT(SHOTGUN_LOAD) / WEP_CVAR_SEC(shotgun, load_max), 1);
+                                       ring_alpha = autocvar_crosshair_ring_hagar_alpha;
+                                       ring_rgb = wcross_color;
+                                       ring_image = "gfx/crosshair_ring.tga";
+                               }
                                else if (ok_ammo_charge)
                                {
                                        ring_value = ok_ammo_chargepool;
index 2ed679e30f4e975b1590bddfcb643d1282de91e0..36409aaa167e403e6a8a4196178665aeae2c949d 100644 (file)
@@ -92,6 +92,7 @@ REGISTER_STAT(DAMAGE_DEALT_TOTAL, int)
 REGISTER_STAT(TYPEHIT_TIME, float)
 REGISTER_STAT(LAYED_MINES, int)
 REGISTER_STAT(HAGAR_LOAD, int)
+REGISTER_STAT(SHOTGUN_LOAD, int)
 REGISTER_STAT(SUPERWEAPONS_FINISHED, float)
 REGISTER_STAT(VEHICLESTAT_HEALTH, int)
 REGISTER_STAT(VEHICLESTAT_SHIELD, int)
index ec964add3c844e56510539e2f7e1743e6ac4fb6b..ba58d993eee61f140302c4055dffb967a9dedc28 100644 (file)
@@ -19,11 +19,11 @@ CLASS(Shotgun, Weapon)
        BEGIN(class) \
                P(class, prefix, alt_animtime, float, SEC) \
                P(class, prefix, alt_refire, float, SEC) \
-               P(class, prefix, ammo, float, PRI) \
-               P(class, prefix, conespread, float, PRI) \
-               P(class, prefix, numcircles, float, PRI) \
+               P(class, prefix, ammo, float, BOTH) \
+               P(class, prefix, conespread, float, NONE) \
+               P(class, prefix, numcircles, float, NONE) \
                P(class, prefix, animtime, float, BOTH) \
-               P(class, prefix, bullets, float, PRI) \
+               P(class, prefix, bullets, float, BOTH) \
                P(class, prefix, damage, float, BOTH) \
                P(class, prefix, force, float, BOTH) \
                P(class, prefix, melee_delay, float, SEC) \
@@ -35,6 +35,12 @@ CLASS(Shotgun, Weapon)
                P(class, prefix, melee_swing_up, float, SEC) \
                P(class, prefix, melee_time, float, SEC) \
                P(class, prefix, melee_traces, float, SEC) \
+        P(class, prefix, load_abort, float, SEC) \
+        P(class, prefix, load_animtime, float, SEC) \
+        P(class, prefix, load_hold, float, SEC) \
+        P(class, prefix, load_max, float, SEC) \
+        P(class, prefix, load_releasedeath, float, SEC) \
+        P(class, prefix, load_speed, float, SEC) \
                P(class, prefix, refire, float, BOTH) \
                P(class, prefix, reload_ammo, float, NONE) \
         P(class, prefix, reload_time, float, NONE) \
@@ -66,24 +72,24 @@ void W_Shotgun_Attack(Weapon thiswep, entity actor, float isprimary)
        entity flash;
 
        W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(shotgun, ammo));
+       float numcircles = WEP_CVAR(shotgun, numcircles);
 
-       float shots = WEP_CVAR_PRI(shotgun, bullets);
-       W_SetupShot(actor, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), WEP_CVAR_PRI(shotgun, damage) * shots);
+       float streaks = WEP_CVAR_PRI(shotgun, bullets);
+       W_SetupShot(actor, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), WEP_CVAR_PRI(shotgun, damage) * (streaks*numcircles+1));
        vector right = v_right;
        vector up = v_up;
        vector s;
 
-       float mu = WEP_CVAR_PRI(shotgun, conespread);
-       float numcircles = WEP_CVAR_PRI(shotgun, numcircles);
+       float mu = WEP_CVAR(shotgun, conespread);
        // fire one bullet straight
        fireBullet(actor, w_shotorg, w_shotdir, WEP_CVAR_PRI(shotgun, spread), WEP_CVAR_PRI(shotgun, solidpenetration), WEP_CVAR_PRI(shotgun, damage), WEP_CVAR_PRI(shotgun, force), WEP_SHOTGUN.m_id, 0);
 
-       for(sc = 0;sc < shots;++sc)
+       for(sc = 0;sc < streaks;++sc)
        {
                vector dir;
 
                s = '0 0 0';
-               makevectors('0 360 0' * (0.75 + sc/shots));
+               makevectors('0 360 0' * (0.75 + sc/streaks));
                s.y = v_forward.x;
                s.z = v_forward.y;
 
@@ -250,6 +256,187 @@ void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, .entity weaponentity
        weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame2);
 }
 
+// alternate secondary (load more bullets)
+.float shotgun_loadstep, shotgun_loadblock, shotgun_loadbeep, shotgun_warning;
+void W_Shotgun_Attack2_Load_Release(entity actor, .entity weaponentity)
+{
+       // time to release the bullets we've loaded
+       float counter, shots, sc, cc;
+       vector forward, right, up;
+
+       if(!actor.shotgun_load)
+               return;
+       shots = actor.shotgun_load;
+
+       float streaks = WEP_CVAR_SEC(shotgun, bullets);
+       float mu = WEP_CVAR(shotgun, conespread);
+       float numcircles = WEP_CVAR(shotgun, numcircles);
+
+       W_SetupShot(actor, false, 2, SND_SHOTGUN_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(shotgun, damage)*shots*(streaks*numcircles+1));
+       Send_Effect(EFFECT_SHOTGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+
+       forward = v_forward;
+       right = v_right;
+       up = v_up;
+
+       vector org;
+       for(counter = 0; counter < shots; ++counter)
+       {
+               float alpha = 2*M_PI*(counter/WEP_CVAR_SEC(shotgun, load_max));
+               org = w_shotorg + right * sin(alpha)*10 + up * cos(alpha)*10;
+
+               // TODO: move this into its own function because primary and secondary fire share much here code
+               // calling W_Shotgun_Attack here does not show the desired results
+
+               // fire one bullet straight
+               fireBullet(actor, org, w_shotdir, WEP_CVAR_PRI(shotgun, spread), WEP_CVAR_PRI(shotgun, solidpenetration), WEP_CVAR_PRI(shotgun, damage), WEP_CVAR_PRI(shotgun, force), WEP_SHOTGUN.m_id, 0);
+
+               vector s;
+               for(sc = 0;sc < streaks;++sc)
+               {
+                       vector dir;
+
+                       s = '0 0 0';
+                       makevectors('0 360 0' * (0.75 + sc/streaks));
+                       s.y = v_forward.x;
+                       s.z = v_forward.y;
+
+                       for(cc = 1; cc <= numcircles; ++cc)
+                       {
+                               s = s * mu * cc/numcircles;
+                               dir = w_shotdir + right * s.y + up * s.z;
+                               fireBullet(actor, org, dir, WEP_CVAR_PRI(shotgun, spread), WEP_CVAR_PRI(shotgun, solidpenetration), WEP_CVAR_PRI(shotgun, damage), WEP_CVAR_PRI(shotgun, force), WEP_SHOTGUN.m_id, 0);
+                       }
+               }
+
+               // casing code
+               if(autocvar_g_casings >= 1)
+                       for(sc = 0;sc < WEP_CVAR_PRI(shotgun, ammo);sc = sc + 1)
+                               SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 30) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 1, actor);
+       }
+       Send_Effect(EFFECT_SHOTGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, WEP_CVAR_PRI(shotgun, ammo));
+
+               // muzzle flash for 1st person view
+       entity flash = spawn();
+       setmodel(flash, MDL_SHOTGUN_MUZZLEFLASH); // precision set below
+       setthink(flash, SUB_Remove);
+       flash.nextthink = time + 0.06;
+       flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
+       W_AttachToShotorg(actor, flash, '5 0 0');
+
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, load_animtime), w_ready);
+       actor.shotgun_loadstep = time + WEP_CVAR_SEC(shotgun, refire) * W_WeaponRateFactor(actor);
+       actor.shotgun_load = 0;
+}
+
+void W_Shotgun_Attack2_Load(Weapon thiswep, entity actor, .entity weaponentity)
+{
+       // loadable shotgun secondary attack, must always run each frame
+
+       if(time < game_starttime)
+               return;
+
+       bool loaded = actor.shotgun_load >= WEP_CVAR_SEC(shotgun, load_max);
+
+       // this is different than WR_CHECKAMMO when it comes to reloading
+       bool enough_ammo;
+       if(actor.items & IT_UNLIMITED_WEAPON_AMMO)
+               enough_ammo = true;
+       else if(autocvar_g_balance_shotgun_reload_ammo)
+               enough_ammo = actor.(weapon_load[WEP_SHOTGUN.m_id]) >= WEP_CVAR_SEC(shotgun, ammo);
+       else
+               enough_ammo = actor.(thiswep.ammo_field) >= WEP_CVAR_SEC(shotgun, ammo);
+
+       bool stopped = loaded || !enough_ammo;
+
+       if(PHYS_INPUT_BUTTON_ATCK2(actor))
+       {
+               if(PHYS_INPUT_BUTTON_ATCK(actor) && WEP_CVAR_SEC(shotgun, load_abort))
+               {
+                       if(actor.shotgun_load)
+                       {
+                               // if we pressed primary fire while loading, unload all rockets and abort
+                               actor.(weaponentity).state = WS_READY;
+                               W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(shotgun, ammo) * actor.shotgun_load * -1); // give back ammo
+                               actor.shotgun_load = 0;
+                               sound(actor, CH_WEAPON_A, SND_HAGAR_BEEP, VOL_BASE, ATTN_NORM);
+
+                               // pause until we can load rockets again, once we re-press the alt fire button
+                               actor.shotgun_loadstep = time + WEP_CVAR_SEC(shotgun, load_speed) * W_WeaponRateFactor(actor);
+
+                               // require letting go of the alt fire button before we can load again
+                               actor.shotgun_loadblock = true;
+                       }
+               }
+               else
+               {
+                       // check if we can attempt to load another rocket
+                       if(!stopped)
+                       {
+                               if(!actor.shotgun_loadblock && actor.shotgun_loadstep < time)
+                               {
+                                       W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(shotgun, ammo));
+                                       actor.(weaponentity).state = WS_INUSE;
+                                       actor.shotgun_load += 1;
+                                       sound(actor, CH_WEAPON_B, SND_HAGAR_LOAD, VOL_BASE * 0.8, ATTN_NORM); // sound is too loud according to most
+
+                                       if(actor.shotgun_load >= WEP_CVAR_SEC(shotgun, load_max))
+                                               stopped = true;
+                                       else
+                                               actor.shotgun_loadstep = time + WEP_CVAR_SEC(shotgun, load_speed) * W_WeaponRateFactor(actor);
+                               }
+                       }
+                       if(stopped && !actor.shotgun_loadbeep && actor.shotgun_load) // prevents the beep from playing each frame
+                       {
+                               // if this is the last rocket we can load, play a beep sound to notify the player
+                               sound(actor, CH_WEAPON_A, SND_HAGAR_BEEP, VOL_BASE, ATTN_NORM);
+                               actor.shotgun_loadbeep = true;
+                               actor.shotgun_loadstep = time + WEP_CVAR_SEC(shotgun, load_hold) * W_WeaponRateFactor(actor);
+                       }
+               }
+       }
+       else if(actor.shotgun_loadblock)
+       {
+               // the alt fire button has been released, so re-enable loading if blocked
+               actor.shotgun_loadblock = false;
+       }
+
+       if(actor.shotgun_load)
+       {
+               // play warning sound if we're about to release
+               if(stopped && actor.shotgun_loadstep - 0.5 < time && WEP_CVAR_SEC(shotgun, load_hold) >= 0)
+               {
+                       if(!actor.shotgun_warning) // prevents the beep from playing each frame
+                       {
+                               // we're about to automatically release after holding time, play a beep sound to notify the player
+                               sound(actor, CH_WEAPON_A, SND_HAGAR_BEEP, VOL_BASE, ATTN_NORM);
+                               actor.shotgun_warning = true;
+                       }
+               }
+
+               // release if player let go of button or if they've held it in too long
+               if(!PHYS_INPUT_BUTTON_ATCK2(actor) || (stopped && actor.shotgun_loadstep < time && WEP_CVAR_SEC(shotgun, load_hold) >= 0))
+               {
+                       actor.(weaponentity).state = WS_READY;
+                       W_Shotgun_Attack2_Load_Release(actor, weaponentity);
+               }
+       }
+       else
+       {
+               actor.shotgun_loadbeep = false;
+               actor.shotgun_warning = false;
+
+               // we aren't checking ammo during an attack, so we must do it here
+               if(!(thiswep.wr_checkammo1(thiswep, actor) + thiswep.wr_checkammo2(thiswep, actor)))
+               if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
+               {
+                       // note: this doesn't force the switch
+                       W_SwitchToOtherWeapon(actor);
+                       return;
+               }
+       }
+}
+
 .float shotgun_primarytime;
 
 METHOD(Shotgun, wr_aim, void(entity thiswep, entity actor))
@@ -261,6 +448,10 @@ METHOD(Shotgun, wr_aim, void(entity thiswep, entity actor))
 }
 METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
 {
+       if(WEP_CVAR(shotgun, secondary) == 3)
+       {
+               W_Shotgun_Attack2_Load(thiswep, actor, weaponentity); // must always run each frame
+       }
     if(WEP_CVAR(shotgun, reload_ammo) && actor.clip_load < WEP_CVAR_PRI(shotgun, ammo)) // forced reload
     {
         // don't force reload an empty shotgun if its melee attack is active
index df791a62627fa7986966e1e3d15b94334bef1a07..b084caa136552c03ce39b3fcd5abcff32d864f80 100644 (file)
@@ -356,6 +356,7 @@ float client_cefc_accumulatortime;
 .float vortex_charge_rottime;
 .float vortex_chargepool_ammo = _STAT(VORTEX_CHARGEPOOL);
 .float hagar_load = _STAT(HAGAR_LOAD);
+.float shotgun_load = _STAT(SHOTGUN_LOAD);
 
 .int grab; // 0 = can't grab, 1 = owner can grab, 2 = owner and team mates can grab, 3 = anyone can grab