]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into drjaska/mgdamageaccumulation
authordrjaska <drjaska83@gmail.com>
Sun, 27 Nov 2022 03:24:08 +0000 (05:24 +0200)
committerdrjaska <drjaska83@gmail.com>
Sun, 27 Nov 2022 03:24:08 +0000 (05:24 +0200)
.gitlab-ci.yml
bal-wep-mario.cfg
bal-wep-nexuiz25.cfg
bal-wep-samual.cfg
bal-wep-xdf.cfg
bal-wep-xonotic.cfg
qcsrc/common/weapons/weapon/machinegun.qc
qcsrc/common/weapons/weapon/machinegun.qh

index 6a12c61c1f291c6ae49247e39ee27cbfdadb7be4..89da455570211408435d492f9a32e6ded480dbe5 100644 (file)
@@ -55,7 +55,7 @@ test_sv_game:
     - wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints\r
     - wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache\r
 \r
-    - EXPECT=757e5413dab5085242502ca47740b83c\r
+    - EXPECT=610c882151eb61a60dbee5ba9bee06f7\r
     - HASH=$(${ENGINE} +timestamps 1 +exec serverbench.cfg\r
       | tee /dev/stderr\r
       | sed -e 's,^\[[^]]*\] ,,'\r
index adb7cc654fa3565e82441a1ca9115936191ebfc1..d63a11d5d6e9fe571125e2fed1090149e9f14d66 100644 (file)
@@ -83,8 +83,11 @@ set g_balance_machinegun_reload_ammo 60
 set g_balance_machinegun_reload_time 2
 set g_balance_machinegun_solidpenetration 13.1
 set g_balance_machinegun_spread_add 0.012
+set g_balance_machinegun_spread_decay 0.036
 set g_balance_machinegun_spread_max 0.05
 set g_balance_machinegun_spread_min 0.02
+set g_balance_machinegun_spread_cold_damagemultiplier 1
+set g_balance_machinegun_spread_heat_damagemultiplier 1
 set g_balance_machinegun_sustained_ammo 1
 set g_balance_machinegun_sustained_damage 10
 set g_balance_machinegun_sustained_force 3
index 17f5b31cab3b29b313e70f27606e6cf42bd7e082..3bd90b9eb363372666c03008a0ed8dcf33d3adbd 100644 (file)
@@ -83,8 +83,11 @@ set g_balance_machinegun_reload_ammo 0
 set g_balance_machinegun_reload_time 2
 set g_balance_machinegun_solidpenetration 13.1
 set g_balance_machinegun_spread_add 0.02
+set g_balance_machinegun_spread_decay -666
 set g_balance_machinegun_spread_max 0.6
 set g_balance_machinegun_spread_min 0.02
+set g_balance_machinegun_spread_cold_damagemultiplier 1
+set g_balance_machinegun_spread_heat_damagemultiplier 1
 set g_balance_machinegun_sustained_ammo 1
 set g_balance_machinegun_sustained_damage 15
 set g_balance_machinegun_sustained_force 27
index 2799a2496b47fb4debea904aa6b051b95c59a621..3452369b0e7ea1c504a4a7f8e18ed23fa9457c6b 100644 (file)
@@ -83,8 +83,11 @@ set g_balance_machinegun_reload_ammo 60
 set g_balance_machinegun_reload_time 2
 set g_balance_machinegun_solidpenetration 13.1
 set g_balance_machinegun_spread_add 0.012
+set g_balance_machinegun_spread_decay 0.036
 set g_balance_machinegun_spread_max 0.05
 set g_balance_machinegun_spread_min 0.02
+set g_balance_machinegun_spread_cold_damagemultiplier 1
+set g_balance_machinegun_spread_heat_damagemultiplier 1
 set g_balance_machinegun_sustained_ammo 1
 set g_balance_machinegun_sustained_damage 10
 set g_balance_machinegun_sustained_force 5
index 09466acce81bcb3949c256133dce2a9675c89acc..7330bd05f44abce27bf9f30871795ee7c19bc333 100644 (file)
@@ -83,8 +83,11 @@ set g_balance_machinegun_reload_ammo 0
 set g_balance_machinegun_reload_time 2
 set g_balance_machinegun_solidpenetration 13.1
 set g_balance_machinegun_spread_add 0
+set g_balance_machinegun_spread_decay 0
 set g_balance_machinegun_spread_max 0
 set g_balance_machinegun_spread_min 0
+set g_balance_machinegun_spread_cold_damagemultiplier 1
+set g_balance_machinegun_spread_heat_damagemultiplier 1
 set g_balance_machinegun_sustained_ammo 1
 set g_balance_machinegun_sustained_damage 10
 set g_balance_machinegun_sustained_force 3
index 319d77923035e150b23bf90fa1ca4321d5564e55..2627060f3275a483867e69f83ab45aa42d4573ae 100644 (file)
@@ -83,8 +83,11 @@ set g_balance_machinegun_reload_ammo 60
 set g_balance_machinegun_reload_time 2
 set g_balance_machinegun_solidpenetration 13.1
 set g_balance_machinegun_spread_add 0.012
+set g_balance_machinegun_spread_decay 0.036
 set g_balance_machinegun_spread_max 0.05
-set g_balance_machinegun_spread_min 0.02
+set g_balance_machinegun_spread_min 0
+set g_balance_machinegun_spread_cold_damagemultiplier 1
+set g_balance_machinegun_spread_heat_damagemultiplier 1
 set g_balance_machinegun_sustained_ammo 1
 set g_balance_machinegun_sustained_damage 10
 set g_balance_machinegun_sustained_force 3
index 15a4d6a3c180f809cd9ade5fd6de424c00e972a2..0a436d529a02c49e08761f00c08ccabb2a8676fe 100644 (file)
@@ -2,6 +2,14 @@
 
 #ifdef SVQC
 
+.float machinegun_spread_accumulation;
+.float lastShotTime;
+
+float lowerEndOfSpreadSpectrum;
+float higherEndOfSpreadSpectrum;
+float spreadSpectrumDistance;
+bool inversedSpread;
+
 void W_MachineGun_Attack(Weapon thiswep, int deathtype, entity actor, .entity weaponentity)
 {
        W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, ((actor.(weaponentity).misc_bulletcounter == 1) ? WEP_CVAR(machinegun, first_damage) : WEP_CVAR(machinegun, sustained_damage)), deathtype);
@@ -63,6 +71,21 @@ void W_MachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity
 {
        float machinegun_spread;
 
+       //check if max is lower or higher than min so it can be used invertedly, accurate with more firing, like Hyperion weapons from Borderlands
+       if (WEP_CVAR(machinegun, spread_max) > WEP_CVAR(machinegun, spread_min))
+       {
+               lowerEndOfSpreadSpectrum = WEP_CVAR(machinegun, spread_min);
+               higherEndOfSpreadSpectrum = WEP_CVAR(machinegun, spread_max);
+               inversedSpread = false;
+       }
+       else
+       {
+               lowerEndOfSpreadSpectrum = WEP_CVAR(machinegun, spread_max);
+               higherEndOfSpreadSpectrum = WEP_CVAR(machinegun, spread_min);
+               inversedSpread = true;
+       }
+       spreadSpectrumDistance = higherEndOfSpreadSpectrum - lowerEndOfSpreadSpectrum;
+
        if(!(fire & 1) || !weapon_prepareattack_check(thiswep, actor, weaponentity, false, -1))
        {
                w_ready(thiswep, actor, weaponentity, fire);
@@ -86,10 +109,116 @@ void W_MachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity
                actor.punchangle_y = random() - 0.5;
        }
 
-       machinegun_spread = bound(WEP_CVAR(machinegun, spread_min), WEP_CVAR(machinegun, spread_min) + (WEP_CVAR(machinegun, spread_add) * actor.(weaponentity).misc_bulletcounter), WEP_CVAR(machinegun, spread_max));
-       fireBullet(actor, weaponentity, w_shotorg, w_shotdir, machinegun_spread, WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), 0, WEP_CVAR(machinegun, sustained_force), thiswep.m_id, EFFECT_BULLET);
+       // debug print opt-in
+       #if 0
+               // Step by step calculations for machinegun_spread_accumulation with optional debug printing
+               // done before inversed spread support was added but still should give a fairly good idea
+
+               // the time of the last shot
+               print(sprintf("old     time: %f \n", actor.(weaponentity).lastShotTime));
+
+               // check current time
+               print(sprintf("current time: %f \n", time));
+
+               // seconds passed since the last shot
+               // lastShotTime is given value at the end of the calculations
+               float secondsSinceLastShot = (time - actor.(weaponentity).lastShotTime);
+               print(sprintf("seconds between last time and this time: %f \n", secondsSinceLastShot));
+
+               // use seconds passed since last shot to calculate how much spread should have decayed since then
+               float spreadReduction = secondsSinceLastShot * WEP_CVAR(machinegun, spread_decay);
+               print(sprintf("spread accumulation reduction: %f \n", spreadReduction));
+
+               // reduce spread by the calculated amount
+               float stepByStep = actor.(weaponentity).machinegun_spread_accumulation - spreadReduction;
+
+               // if spread is reduced to the negatives make it 0 instead
+               // the following if block is replaced by max(accumulation, 0);
+               if (stepByStep < 0) {
+                       print("step by step spread was less than 0, it was reset to 0 before firing \n");
+                       stepByStep = 0;
+               }
+
+               print(sprintf("current spread accumulation: %f \n", stepByStep));
+
+               // calculate spread on one line
+               float oneliner = max(actor.(weaponentity).machinegun_spread_accumulation - ((time - actor.(weaponentity).lastShotTime) * WEP_CVAR(machinegun, spread_decay)), 0);
+               print(sprintf("oneline spread accumulation: %f \n", oneliner));
+
+               // check that the step by step and oneliner match
+               if (stepByStep != oneliner)
+                       print("MISMATCH BETWEEN STEP BY STEP AND ONELINER!\n");
+
+               actor.(weaponentity).machinegun_spread_accumulation = oneliner;
+
+               if (inversedSpread) {
+                       machinegun_spread = bound(WEP_CVAR(machinegun, spread_max), WEP_CVAR(machinegun, spread_min) - actor.(weaponentity).machinegun_spread_accumulation, WEP_CVAR(machinegun, spread_min));
+                       print(sprintf("final inversed machinegun_spread: %f \n\n", machinegun_spread));
+               } else {
+                       machinegun_spread = bound(WEP_CVAR(machinegun, spread_min), WEP_CVAR(machinegun, spread_min) + actor.(weaponentity).machinegun_spread_accumulation, WEP_CVAR(machinegun, spread_max));
+                       print(sprintf("final non-inverse machinegun_spread: %f \n\n", machinegun_spread));
+               }
+       #else
+               actor.(weaponentity).machinegun_spread_accumulation = max(actor.(weaponentity).machinegun_spread_accumulation - ((time - actor.(weaponentity).lastShotTime) * WEP_CVAR(machinegun, spread_decay)), 0);
+
+               if (inversedSpread) {
+                       machinegun_spread = bound(WEP_CVAR(machinegun, spread_max), WEP_CVAR(machinegun, spread_min) - actor.(weaponentity).machinegun_spread_accumulation, WEP_CVAR(machinegun, spread_min));
+               } else {
+                       machinegun_spread = bound(WEP_CVAR(machinegun, spread_min), WEP_CVAR(machinegun, spread_min) + actor.(weaponentity).machinegun_spread_accumulation, WEP_CVAR(machinegun, spread_max));
+               }
+       #endif
+       actor.(weaponentity).lastShotTime = time;
+
+       if (WEP_CVAR(machinegun, spread_decay) == 0) {
+               actor.(weaponentity).machinegun_spread_accumulation = bound(0, (WEP_CVAR(machinegun, spread_add) * actor.(weaponentity).misc_bulletcounter), spreadSpectrumDistance);
+       }
+
+       // function for reducing mg's damage with no spread and adding damage with heated up barrel or vice versa depending on the values of exposed cvars
+       float coldMultiplierApplicationPercent = 1;
+       float heatMultiplierApplicationPercent = 1;
+
+       if (spreadSpectrumDistance > 0) { //avoid division by 0, can never be < 0 either due to how it is set when defined
+               coldMultiplierApplicationPercent = (spreadSpectrumDistance - actor.(weaponentity).machinegun_spread_accumulation) / spreadSpectrumDistance;
+               heatMultiplierApplicationPercent =                           actor.(weaponentity).machinegun_spread_accumulation  / spreadSpectrumDistance;
+               // these formulas seem to give numbers which are used as the distance from one end to the other
+               // cold = lower end, heat = higher end, spreadSpectrumDistance = higherEndOfSpreadSpectrum - lowerEndOfSpreadSpectrum = 30 for these examples
+               //
+               // examples for cold barrel / coldMultiplierApplicationPercent:
+               // min 5 , spread buildup 100% , max 35
+               // (30 - 30) / 30 = 0   apply none of the multiplier
+               // min 5 , spread buildup  50% , max 35
+               // (30 - 15) / 30 = 0.5 apply half of the multiplier
+               // min 5 , spread buildup   0% , max 35
+               // (30 -  0) / 30 = 1   apply all  of the multiplier
+               //
+               // examples for warm barrel / heatMultiplierApplicationPercent:
+               // min 5 , spread buildup   0% , max 35
+               // 30 / 30 = 1   apply all  of the multiplier
+               // min 5 , spread buildup  50% , max 35
+               // 15 / 30 = 0.5 apply half of the multiplier
+               // min 5 , spread buildup 100% , max 35
+               //  0 / 30 = 0   apply none of the multiplier
+       }
+
+       // example where low end has halved damage and high end has tripled damage:
+       // with 50% spread accumulation: heat = (0.5 * 0.5) + (0.5 * 3) = 0.25 + 1.5 = 1.75 damage multiplier
+       // with 90% spread accumulation: heat = (0.1 * 0.5) + (0.9 * 3) = 0.05 + 2.7 = 2.75 damage multiplier
+       float heat = (coldMultiplierApplicationPercent * WEP_CVAR(machinegun, spread_cold_damagemultiplier))
+                  + (heatMultiplierApplicationPercent * WEP_CVAR(machinegun, spread_heat_damagemultiplier));
+
+       // avoid damage doubling from (1 * 1) + (1 * 1) = 2
+       // this also averages the 2 multipliers when spreadSpectrumDistance == 0
+       // so 0.5 cold to 4 heat would average out to 2.25 with no spectrum distance for spread
+       if (spreadSpectrumDistance == 0) heat = heat / 2;
+
+       fireBullet(actor, weaponentity, w_shotorg, w_shotdir, machinegun_spread, WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage) * heat, 
+                  0, WEP_CVAR(machinegun, sustained_force), thiswep.m_id, EFFECT_BULLET);
 
        actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
+       actor.(weaponentity).machinegun_spread_accumulation = actor.(weaponentity).machinegun_spread_accumulation + WEP_CVAR(machinegun, spread_add);
+       if(actor.(weaponentity).machinegun_spread_accumulation > spreadSpectrumDistance){
+               actor.(weaponentity).machinegun_spread_accumulation = spreadSpectrumDistance;
+       }
 
        W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, w_shotdir);
 
@@ -123,7 +252,13 @@ void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, .entity weaponentit
        }
 
        actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
-       if(actor.(weaponentity).misc_bulletcounter == 0)
+       actor.(weaponentity).machinegun_spread_accumulation = actor.(weaponentity).machinegun_spread_accumulation + (WEP_CVAR(machinegun, spread_add) * 0.5);
+
+       if (actor.(weaponentity).machinegun_spread_accumulation > spreadSpectrumDistance) {
+               actor.(weaponentity).machinegun_spread_accumulation = spreadSpectrumDistance;
+       }
+
+       if (actor.(weaponentity).misc_bulletcounter == 0)
        {
                ATTACK_FINISHED(actor, weaponentity) = time + WEP_CVAR(machinegun, burst_refire2) * W_WeaponRateFactor(actor);
                weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR(machinegun, burst_animtime), w_ready);
@@ -164,6 +299,15 @@ METHOD(MachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponen
         if(fire & 2)
         if(weapon_prepareattack(thiswep, actor, weaponentity, true, 0))
         {
+            if(WEP_CVAR(machinegun, spread_decay) != 0){
+                actor.(weaponentity).machinegun_spread_accumulation = max(actor.(weaponentity).machinegun_spread_accumulation - ((time - actor.(weaponentity).lastShotTime) * WEP_CVAR(machinegun, spread_decay)), 0);
+                actor.(weaponentity).lastShotTime = time;
+                if(actor.(weaponentity).machinegun_spread_accumulation > 0){
+                    w_ready(thiswep, actor, weaponentity, fire);
+                    return;
+                }
+            }
+
             if(!thiswep.wr_checkammo2(thiswep, actor, weaponentity))
             if(!(actor.items & IT_UNLIMITED_AMMO))
             {
index 9a2adf46c94d42d17dfda956578c249857e09181..ea8cdb7978600bd61e53c659a11b1f54945a0455 100644 (file)
@@ -38,8 +38,11 @@ CLASS(MachineGun, Weapon)
         P(class, prefix, reload_time, float, NONE) \
                P(class, prefix, solidpenetration, float, NONE) \
                P(class, prefix, spread_add, float, NONE) \
+               P(class, prefix, spread_decay, float, NONE) \
                P(class, prefix, spread_max, float, NONE) \
                P(class, prefix, spread_min, float, NONE) \
+               P(class, prefix, spread_cold_damagemultiplier, float, NONE) \
+               P(class, prefix, spread_heat_damagemultiplier, float, NONE) \
                P(class, prefix, sustained_ammo, float, NONE) \
                P(class, prefix, sustained_damage, float, NONE) \
                P(class, prefix, sustained_force, float, NONE) \