From b11d3dc7c365f762aa5d78a129eb5d1067796fcc Mon Sep 17 00:00:00 2001 From: Marisa Kirisame Date: Wed, 22 Sep 2021 19:04:47 +0200 Subject: [PATCH] Rebalance ammo fabricators. --- README.md | 2 +- language.version | 4 +- zscript/items/swwm_ammoextra.zsc | 199 ++++++++++++++++++------------- 3 files changed, 118 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index e80ebd062..952865e85 100644 --- a/README.md +++ b/README.md @@ -393,7 +393,7 @@ Note: In multiplayer, these can be traded between players, but do note that the ### Universal Ammo Fabricator ~ Replaces Mana / Krater of Might ![](docimg/fabricator.png) -Separated into four tiers, they work pretty much like the ammo cubes in **Doom Tournament**, except they try to *"balance"* the total ammo given. The max tier fabricator is the only one capable of producing ammo for superweapons (excluding the **Ynykron Artifact**). +Separated into four tiers, they work pretty much like the ammo cubes in **Doom Tournament**, except they try to *"balance"* the total ammo given. The max tier fabricator is the only one capable of producing ammo for all weapons (excluding the **Ynykron Artifact**). Due to some unspecified reasons, they cannot be held in your inventory. ### Lamp ~ Replaces Lite-Amp, Torch ![](docimg/lamp.png) diff --git a/language.version b/language.version index a8364572b..bc9e5f810 100644 --- a/language.version +++ b/language.version @@ -1,3 +1,3 @@ [default] -SWWM_MODVER="\chSWWM \czGZ\c- \cw1.1.7 r4 \cu(Wed 22 Sep 16:50:24 CEST 2021)\c-"; -SWWM_SHORTVER="\cw1.1.7 r4 \cu(2021-09-22 16:50:24)\c-"; +SWWM_MODVER="\chSWWM \czGZ\c- \cw1.1.7 r5 \cu(Wed 22 Sep 19:04:47 CEST 2021)\c-"; +SWWM_SHORTVER="\cw1.1.7 r5 \cu(2021-09-22 19:04:47)\c-"; diff --git a/zscript/items/swwm_ammoextra.zsc b/zscript/items/swwm_ammoextra.zsc index dab5cf3c7..ba5053cff 100644 --- a/zscript/items/swwm_ammoextra.zsc +++ b/zscript/items/swwm_ammoextra.zsc @@ -9,11 +9,18 @@ Class AmmoFabricator : Inventory abstract Mixin SWWMRespawn; Mixin SWWMPickupGlow; - int budget, pertype, maxunitprice; + int budget, pertype, maxunits, maxtypes, maxunitprice, txtcol; + int chancediv; + + String pickupmsgextra; Property Budget : budget; Property PerType : pertype; + Property MaxUnits : maxunits; + Property MaxTypes : maxtypes; Property MaxUnitPrice : maxunitprice; + Property ChanceFactor : chancediv; + Property TextColor : txtcol; override Inventory CreateCopy( Actor other ) { @@ -22,7 +29,7 @@ Class AmmoFabricator : Inventory abstract return Super.CreateCopy(other); } - private bool CmpFabAmmo( Class a, Class b ) + private bool CmpFabAmmo( Class a, Class b ) { let ia = Owner.FindInventory(a); int cnta = ia?ia.Amount:0; @@ -35,26 +42,26 @@ Class AmmoFabricator : Inventory abstract return (facta >= factb); } - private int partition_fabammo( Array > a, int l, int h ) + private int partition_fabammo( Array > a, int l, int h ) { - Class pv = a[h]; + Class pv = a[h]; int i = (l-1); for ( int j=l; j<=(h-1); j++ ) { if ( CmpFabAmmo(pv,a[j]) ) { i++; - Class tmp = a[j]; + Class tmp = a[j]; a[j] = a[i]; a[i] = tmp; } } - Class tmp = a[h]; + Class tmp = a[h]; a[h] = a[i+1]; a[i+1] = tmp; return i+1; } - private void qsort_fabammo( Array > a, int l, int h ) + private void qsort_fabammo( Array > a, int l, int h ) { if ( l >= h ) return; int p = partition_fabammo(a,l,h); @@ -62,6 +69,46 @@ Class AmmoFabricator : Inventory abstract qsort_fabammo(a,p+1,h); } + private bool CmpFabAmmo_chance( Class a, Class b ) + { + int cha = GetDefaultByType(a).Accuracy; + int chb = GetDefaultByType(b).Accuracy; + return (cha >= chb); + } + + private int partition_fabammo_chance( Array > a, int l, int h ) + { + Class pv = a[h]; + int i = (l-1); + for ( int j=l; j<=(h-1); j++ ) + { + if ( CmpFabAmmo_chance(pv,a[j]) ) + { + i++; + Class tmp = a[j]; + a[j] = a[i]; + a[i] = tmp; + } + } + Class tmp = a[h]; + a[h] = a[i+1]; + a[i+1] = tmp; + return i+1; + } + private void qsort_fabammo_chance( Array > a, int l, int h ) + { + if ( l >= h ) return; + int p = partition_fabammo_chance(a,l,h); + qsort_fabammo_chance(a,l,p-1); + qsort_fabammo_chance(a,p+1,h); + } + + override String PickupMessage() + { + if ( pickupmsgextra != "" ) return String.Format("\c%c%s\c-\n%s",0x61+txtcol,StringTable.Localize(pickupmsg),pickupmsgextra); + return pickupmsg; + } + bool FabricateAmmo() { // first we must build an array of all valid weapons, this saves time instead of doing recursive loops @@ -78,11 +125,11 @@ Class AmmoFabricator : Inventory abstract if ( !ready || !ready.ValidateSpriteFrame() ) continue; validweapons.Push(type2); } - Array > available; + Array > available; // populate ammo production list for ( int i=0; i)(AllActorClasses[i]); + let a = (Class)(AllActorClasses[i]); // skip over candy gun spares, they're "special ammo" if ( a == 'CandyGunSpares' ) continue; // only direct descendants of swwmammo with a set price below our max unit price @@ -106,21 +153,40 @@ Class AmmoFabricator : Inventory abstract } } if ( !isvalid ) continue; + let f = Owner.FindInventory(a); + // don't include maxed out ammo + if ( f && (f.Amount >= f.MaxAmount) ) continue; available.Push(a); } - // sort by "need weight" (prioritize ammo that the player lacks over ammo that the player has plenty of + // sort by drop chance + qsort_fabammo_chance(available,0,available.Size()-1); + // discard some candidates based on their random drop chance (leaving AT LEAST one) + for ( int i=0; i chance ) continue; + available.Delete(i); + i--; + } + // sort by "need weight" (prioritize ammo that the player lacks over ammo that the player has plenty of) qsort_fabammo(available,0,available.Size()-1); + // crop by "max types" + if ( available.Size() > maxtypes ) available.Resize(maxtypes); // loop through until we fill the inventory or run out of budget bool given = false; int consumed = 0; String fabstr = ""; bool comma = false; int tpertype = pertype; + int ttotal = maxunits; for ( int i=0; i 0 ) { - if ( comma ) fabstr.AppendFormat(", %dx %s",cnt,cur.GetTag()); - else fabstr.AppendFormat("%dx %s",cnt,cur.GetTag()); + String tstr = String.Format("%d %s",cnt,(cnt>1)?StringTable.Localize("$T_"..cur.PickupTag.."S"):StringTable.Localize("$T_"..cur.PickupTag)); + if ( comma ) fabstr = fabstr..", "..tstr; + else fabstr = tstr; comma = true; } + ttotal -= cnt; + if ( ttotal <= 0 ) break; } - if ( given ) PrintPickupMessage(true,fabstr); + if ( given ) pickupmsgextra = fabstr; + else pickupmsgextra = ""; return given; } - override void DoEffect() - { - Super.DoEffect(); - if ( !Owner || !bAUTOACTIVATE ) return; - bool shouldautouse = false; - if ( swwm_enforceautouseammo == 1 ) shouldautouse = true; - else if ( swwm_enforceautouseammo == -1 ) shouldautouse = false; - else shouldautouse = CVar.GetCVar('swwm_autouseammo',Owner.player).GetBool(); - if ( !shouldautouse ) return; - // fabricators of lower tiers, for priority checking - Array others; - for ( Inventory i=Owner.inv; i; i=i.inv ) - { - if ( !(i is 'AmmoFabricator') || (i == self) || !i.bAUTOACTIVATE || (AmmoFabricator(i).maxunitprice >= maxunitprice) ) continue; - others.Push(AmmoFabricator(i)); - } - // check if owner lacks ammo, autouse if we can afford its unit price - bool used = false; - Actor o = Owner; - for ( Inventory i=o.inv; i; i=i.inv ) - { - if ( !(i is 'Ammo') || (i.Amount > (i.MaxAmount/3)) || (i.Stamina <= 0) || (i.Stamina > maxunitprice) ) continue; - // ignore if there's a cheaper fabricator than us that can afford it ("wait our turn", basically) - bool lowprio = false; - for ( int j=0; j others[j].maxunitprice ) continue; - lowprio = true; - break; - } - if ( lowprio ) continue; - // hit it - while ( (Amount > 0) && FabricateAmmo() ) - { - used = true; - Amount--; - } - if ( Amount <= 0 ) - { - DepleteOrDestroy(); - break; - } - } - if ( used && (o.player == players[consoleplayer]) ) o.A_StartSound(UseSound,CHAN_ITEMEXTRA); - } - override bool Use( bool pickup ) { - bool shouldautouse = false; - if ( swwm_enforceautouseammo == 1 ) shouldautouse = true; - else if ( swwm_enforceautouseammo == -1 ) shouldautouse = false; - else shouldautouse = CVar.GetCVar('swwm_autouseammo',Owner.player).GetBool(); - if ( pickup && !shouldautouse ) return false; if ( FabricateAmmo() ) { if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA); @@ -214,13 +234,19 @@ Class AmmoFabricator : Inventory abstract return false; } + override void PostBeginPlay() + { + Super.PostBeginPlay(); + SetZ(floorz); // gee whizz thanks Hexen + } + Default { - +INVENTORY.INVBAR; +INVENTORY.AUTOACTIVATE; +FLOATBOB; Inventory.UseSound "fabricator/use"; Inventory.PickupFlash "SWWMPickupFlash"; + Inventory.MaxAmount 0; FloatBobStrength 0.25; Radius 10; Height 24; @@ -244,14 +270,15 @@ Class FabricatorTier1 : AmmoFabricator //$Sprite graphics/HUD/Icons/I_Fabricator1.png //$Icon ammo Tag "$T_FABRICATOR1"; - Stamina -2500; Inventory.Icon "graphics/HUD/Icons/I_Fabricator1.png"; Inventory.PickupMessage "$T_FABRICATOR1"; - Inventory.MaxAmount 20; - Inventory.InterHubAmount 20; AmmoFabricator.Budget 3000; AmmoFabricator.PerType 1; + AmmoFabricator.MaxUnits 1; + AmmoFabricator.MaxTypes 1; AmmoFabricator.MaxUnitPrice 2500; + AmmoFabricator.ChanceFactor 1; + AmmoFabricator.TextColor Font.CR_BLUE; } } Class FabricatorTier2 : AmmoFabricator @@ -265,14 +292,15 @@ Class FabricatorTier2 : AmmoFabricator //$Sprite graphics/HUD/Icons/I_Fabricator2.png //$Icon ammo Tag "$T_FABRICATOR2"; - Stamina -12000; Inventory.Icon "graphics/HUD/Icons/I_Fabricator2.png"; Inventory.PickupMessage "$T_FABRICATOR2"; - Inventory.MaxAmount 15; - Inventory.InterHubAmount 15; - AmmoFabricator.Budget 15000; - AmmoFabricator.PerType 2; - AmmoFabricator.MaxUnitPrice 12000; + AmmoFabricator.Budget 20000; + AmmoFabricator.PerType 1; + AmmoFabricator.MaxUnits 2; + AmmoFabricator.MaxTypes 2; + AmmoFabricator.MaxUnitPrice 18000; + AmmoFabricator.ChanceFactor 2; + AmmoFabricator.TextColor Font.CR_GREEN; } } Class FabricatorTier3 : AmmoFabricator @@ -286,18 +314,21 @@ Class FabricatorTier3 : AmmoFabricator //$Sprite graphics/HUD/Icons/I_Fabricator3.png //$Icon ammo Tag "$T_FABRICATOR3"; - Stamina -80000; Inventory.Icon "graphics/HUD/Icons/I_Fabricator3.png"; Inventory.PickupMessage "$T_FABRICATOR3"; - Inventory.MaxAmount 10; - Inventory.InterHubAmount 10; AmmoFabricator.Budget 100000; - AmmoFabricator.PerType 4; + AmmoFabricator.PerType 2; + AmmoFabricator.MaxUnits 4; + AmmoFabricator.MaxTypes 3; AmmoFabricator.MaxUnitPrice 80000; + AmmoFabricator.ChanceFactor 4; + AmmoFabricator.TextColor Font.CR_RED; } } Class FabricatorTier4 : AmmoFabricator { + Mixin SWWMAutoUseFix; + Default { //$Title Fabricator (Super Rare) @@ -305,15 +336,15 @@ Class FabricatorTier4 : AmmoFabricator //$Sprite graphics/HUD/Icons/I_Fabricator4.png //$Icon ammo Tag "$T_FABRICATOR4"; - Stamina -1000000; Inventory.Icon "graphics/HUD/Icons/I_Fabricator4.png"; Inventory.PickupMessage "$T_FABRICATOR4"; - Inventory.MaxAmount 5; - Inventory.InterHubAmount 5; AmmoFabricator.Budget int.max; AmmoFabricator.PerType -50; + AmmoFabricator.MaxUnits int.max; + AmmoFabricator.MaxTypes int.max; AmmoFabricator.MaxUnitPrice 1000000; - -INVENTORY.AUTOACTIVATE; + AmmoFabricator.ChanceFactor 0; + AmmoFabricator.TextColor Font.CR_GOLD; } }