From 06f04f134bc6252b68f641a6bb054f7a21a90cbc Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Thu, 8 May 2025 16:42:18 -0700 Subject: [PATCH 01/14] initial planning for blaster --- zscript/rweapons/w2blaster.zs | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 zscript/rweapons/w2blaster.zs diff --git a/zscript/rweapons/w2blaster.zs b/zscript/rweapons/w2blaster.zs new file mode 100644 index 0000000..9e914b3 --- /dev/null +++ b/zscript/rweapons/w2blaster.zs @@ -0,0 +1,6 @@ +class RwBlaster : RandomizedWeapon { + // A pistol alternative that runs off an internal battery. + // Instead of ammo, its firerate drops off dramatically as it heats up. + // The idea is that this is a weapon you want to use in between other weapons; it works best in short bursts and 'cools down' while in your pocket. + // Partly inspired by the Treasure Tech pistol's altfire--again, high burst damage, but it's at its best when you have other weapons on hand. +} \ No newline at end of file From 4780754d8c047115cefc696377fa83e94628c1d3 Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Sat, 10 May 2025 18:18:41 -0700 Subject: [PATCH 02/14] assets for blaster --- TEXTURES.txt | 30 ++++++++++++++++++ credits.txt | 2 ++ sprites/weapons/blaster/BOLTA0 | Bin 0 -> 1212 bytes sprites/weapons/blaster/BOLTB0 | Bin 0 -> 1223 bytes sprites/weapons/blaster/BOLTC0 | Bin 0 -> 1272 bytes sprites/weapons/blaster/BOLTD0 | Bin 0 -> 1289 bytes sprites/weapons/blaster/BOLTE0 | Bin 0 -> 1247 bytes sprites/weapons/blaster/BOLTF0 | Bin 0 -> 1194 bytes .../blaster/breadbagfly-scrapyard-pistols.png | Bin 0 -> 49098 bytes 9 files changed, 32 insertions(+) create mode 100644 TEXTURES.txt create mode 100644 sprites/weapons/blaster/BOLTA0 create mode 100644 sprites/weapons/blaster/BOLTB0 create mode 100644 sprites/weapons/blaster/BOLTC0 create mode 100644 sprites/weapons/blaster/BOLTD0 create mode 100644 sprites/weapons/blaster/BOLTE0 create mode 100644 sprites/weapons/blaster/BOLTF0 create mode 100644 sprites/weapons/blaster/breadbagfly-scrapyard-pistols.png diff --git a/TEXTURES.txt b/TEXTURES.txt new file mode 100644 index 0000000..822af98 --- /dev/null +++ b/TEXTURES.txt @@ -0,0 +1,30 @@ +// Texture definitions generated by SLADE3 +// on Sat May 10 17:08:32 2025 + +Sprite "BLSGA0", 79, 73 +{ + Offset -136, -95 + Patch "sprites/weapons/blaster/breadbagfly-scrapyard-pistols.png", -196, -71 +} + +Sprite "BLSGB0", 79, 82 +{ + Offset -136, -86 + Patch "PLSEA0", 13, 0 + Patch "sprites/weapons/blaster/breadbagfly-scrapyard-pistols.png", -196, -62 +} + +Sprite "BLSGC0", 79, 82 +{ + Offset -136, -86 + Patch "PLSED0", 9, 0 + Patch "sprites/weapons/blaster/breadbagfly-scrapyard-pistols.png", -196, -62 +} + +Sprite "BLASA0", 18, 13 +{ + Offset 9, 13 + Patch "sprites/weapons/blaster/breadbagfly-scrapyard-pistols.png", -212, -36 +} + +// End of texture definitions diff --git a/credits.txt b/credits.txt index 547d888..0199609 100644 --- a/credits.txt +++ b/credits.txt @@ -14,6 +14,8 @@ Resources: Uses ZForms by Gutawer Additional graphics and mods's base: Id Software, Raven Software Armor and backpack sprites: cybermonday https://forum.zdoom.org/viewtopic.php?t=78536 + Blaster graphics from Breadbagfly's Scrapyard https://forum.zdoom.org/viewtopic.php?p=921224 + Blaster projectile graphics from Realm667, "Plasma Bolter" (Sprites from id Software and 3D Realms, edited by Daniel) https://www.realm667.com/component/docman/?task=doc_download&gid=313&Itemid= Other sprites: Realm667 - per-resource credits are inside credits folder diff --git a/sprites/weapons/blaster/BOLTA0 b/sprites/weapons/blaster/BOLTA0 new file mode 100644 index 0000000000000000000000000000000000000000..da02f29467f22a3d4c869ec823b8ba70edc50df8 GIT binary patch literal 1212 zcmd^8!HeTm82^TK$?V469wJ7K5HN?b1dR|dXbxdFGiJuhWZjGgH;0H3BLszBIrLE04Cc^7k;3*6uwsQCM(Cl3A{7c2>0x*2p$k3CVGl0*`8xg?KHm2}-h=P= z``-Kg-gh^Tj4PL4xeNeT4iENjkxXx6_X1geywiArq+S2c^-oE@xQ%z-dhs5>1-SYC z@jlt}EX`J^TCIkN9LF&XL(?=xQIf(7Vuj_Y3Jazx8nU2?91aFgdcCtwXWeeEvTWIC zEaG?;MUx;Hd)~-#hPGXrX5TQnn$}U(T$bCCl!;m^5#uvnp%^@9L2RVGJ2uj z3AEf(GgoQYa$-q!Qw)r%s|%LK*Az~ZSXpF5p|aU*R;$%=xm+w3v)ODinT*Hd(P%Un z49c?X^?KcIw-8`UgCOuc&v6{vwoTJC3`5s-RaF&5ktC^F ztqOur$1vRZ{?c`)wlgxVzELYQy`^ZWq(q|R2~~^Zb(WPYj6l;YHR@)AqS0?B-K<_T z!aNCDvDb{8G_YgOth=?))_qHJYl^MQmL?Ucm({H_sMTG~w`9i65Kvi-nx zJj1e8!<02cRJ1B$v|iZrp?;c6{g}@krlC`j2t;dKEO0o)JjXaj*F{Z3o=1QUzyp9e zzyx3fPy%!Ta)2g40uTZC01g0=jOevm;dqR_9%dOv5n2{13ULvEA(Oxm3<5x^Q-A=# z+VZX!I3MCT$1=u_gPDp6cNVehu(I?kbC;gj)Ts#r1N!=TpEyS>5i`U9(LfXsp{qfm zKudy#K+IXyB~B3-iK7X{xs_A^2|xf~x4(gq7CNqK7?V<*!nA-qgrFM)kI%}#0CwQ( zTSw=;ZTtJ5jsM=5Tw3|{AyEu2eRc3LQJH48u>(JxyhILf9PV8|-o5wX_a9t^H=oo0 z#$)Eu>D{OIfBx*{OW(YH?WZ?Ru04Lf`P<3WyT1I#pSKS#e);IN_g?*de}{ke3r6og c`)9cG#Ydm}Pr0`r5;Qp6Kia#0-4i$PR(nG->dRU={SuHx?cv(JQ$3Mfz``-872jB1a zz4!ax{aeTSjs55M0pP~bVf{Ao^me~{jjV^ldway~Ha<9bm-uIhUGJ$n4{!}`y>@bw zoH>SODwJUuh{&>RwOXZVnxZIC=6IpPa8!i>QxSBDR|OV_!^?jEqSrg`cGqdTYPFV8 zG!Mh6?@v5$>^LLaE=_Zw>xHWJ6eW|St|+F0(B}Ds<6@R=GE7*l`jtw9rd^71D9WNJ z6F>*h0PuW;kLI|X;CzI$5+?SLPN&^&CrJ{=akJSBg24BE&+{C|v2EKlO3YVxvF(!H4)`d5Iw$Tv7E**Ql-k%G((MxbeOjW-MC1bc`L|b zzY}@w&`Eqd^30}d1h&?&RM(JgO|n!mPrS5gCBD&g)rKWGx?n22Cb3cM1)<&WO~=zM zThUEP)dg9tA%^Emdoj|^GI0=bnNw|PR44$^8kb8PjWEkFiqLgYRgvQmU<2?7U;!`% z7z3051waPS28aPdfChjAKqMo2t=Bl2V84%PieZSBg|bY#h`^9ZUWWvm7x8oM{4*S8=3|EW ze&28A_nY_E*VLuOCl>)=Y4yy?ITDYO!5le6=F!5#HVH?HmrlMy;{GAp{^hm~a0u4V zo(l9EE9CI~UlS2(Ve%S9|3FpQtgx|vLorfrI{ zD9WHH!bb&A0B~oD_eVHMan!?M2h%3@6YN#7Q`&2V^M*f5+-cPrSFB;l7({wM)H=S} z@|1=vCyo@`V%aQ2h7jnytLANmGvu5mva-Mw_$<$5=JWY%Hk(eTlgVT>8Vv@6G)?>c zez)80bULk8tJ!SU>-Ac#R;^Yml}f2pilQh80?+eY*L57nvMkdybzN6gRZ$d4l0;Dy z1RN4^0u{60!u!I_33NyQ-y>yUWhHeL6@ zZs#X}1$g7!+5xwHe*d%f-y4%li(mdq6oW@Do_UF=OlSAU0$l&(7}-ywV;h%$ zkRIDQ{^;TL#Xq8_tP6|j=H)v-KfQYG?7T{VDM~?%D+4Ae?^q z>>}AGS(;5y*=!aOIgVo(hNfwXqC_dl3kfz!C0Nihf|}-Kfx~8Vx6#cBC*1h-y%uiA*om+mVyl92akt@3>h36Xh84SCHn)p<*Vo!!Hg?rU zUa32BXlDXTDj8{C7Ymx;s3}X~bvc=pI9X)V0weH=$z(DbjfTVFU@++Qdfjff)9JL^ z?PjwX$8n?4h@z-gt5vJjN~KaRmy5-s@B4*9A)n7Xj$_-lX_|&%Xqu*~s-h^FOh%F< zQ4~|D6wmVo%;zV$+|aVN4YRH3TWYo@D-}sDijpgcHlNbDq{6c41jExbOSPk*Su1T- z{U|8ZO8L-tDxO_-&7xy?wpOsRc|*zRvXzw#C9TV1t!M`Yz35~MmYmbmrYdL|UP*JF zZ|7Yj=V+#_>PAM@(y}T@athHM4~%|Gxe|(7UNSV9l0vxx5Up`Az*Y;x5Iqkq3uPIT zNdzF?xCYP%=mN9>Vt@!B1SkXe04_idzyu(Y5xqtu>~yfvz#u@^MO{ZpA}%5@WD*#H zK>$c~5x@b^_xg?p*l%Gc#Mr~Si9rT^ZpUTE`NS}n=v#Expsr}pRAEcm=ZSs97%@O} z5LHAT5h59C5>!Me@x+`dMdT!&5jmQ)*tb#!Km_2)Hz0=JL#Zh^%A!X~aT~U45az*& z9Ot*4_(y;P@YI==eQtaF{%7OAHzt>sKKX?x2GdV0tr3-JW-kuFTW{Y+4uj=|`LlPw ze(8<**{|-HTKp70c=P64zZ{*sI(y>d%h%`ZrJwGxp1=5bw-Eh4``Of-zj=`PgWbIU z^XSji^!X3p-;g$@FWi`W^uE>Bv85M(JzhPRonh7=Y@XY=>+;g#@t2RjclFr!k6k!* z%i$A8=Wjpx>`Ut8(!Jm4KY#tsspy%(uK&uBxu=DVNB)X#Twnd}3-{u4>uZ0%HvVVz RRYDDx7grWOdg%NM{{rEeqN4x+ literal 0 HcmV?d00001 diff --git a/sprites/weapons/blaster/BOLTE0 b/sprites/weapons/blaster/BOLTE0 new file mode 100644 index 0000000000000000000000000000000000000000..ffe2a40c0abadd7a59f981d5421080f331a9f4cd GIT binary patch literal 1247 zcmd^7(W~2382>K2l6#kJb+->0%f;%AP$WWxAbE%o?s7+V>A1NplQ5%X7^O%Y5hE1L zL%<+q^dU;!3TBXpKJ=lo`w&LesvYd1Vh4TbL&55*Oemw1K3rj_$mi+x&+u@*@8cZ! ze!uUW-|zbVo_6y1+2a6ka`(c{B~ni>W9=BpC$i4>q^yc;yVy@K3$STnEMv$X`pn$RP0P8lO%F`!o(>%i4%DMLag3ND#)vMWhR7j8 zOMz5^x&T#IPijtJ3ATnH&VmPo=(U1jAxhxMPDHFw>Af(M^!t))Di&!>bm^Mv&6y;KsO;Hwr z0iXlmZiAOgT+eVh#YKg)66+kNeXPUS2NbPxI)v;Mc#wgT>ftLGf z<|$oAPHd@TiGk7bbivk|row9yCyT5oF#G*}yWMU!oAr9VTrTJH`D`|;>v}SoR8=(^ zjmoktiefMr^!xo@ua~B2k|do@Ck(?N2z=jnUDt6O%d!l^&~;r^RYg%GNouuPf*^D- z4EOE!#`6}ATU++nFbhrZD_SZkktq2>%jTOp$H@#U&@@NYWi~0g<3UnpouV7&Nzjk| zUgV~M6Z=-jGebvj+nQ%8jxO7pRHS~^vD3ipcv{<*T|=}~L6`YB@x#bz2bSv_wxb%B ztQn%BwGgA-+F4EYr@1tao4Lz&bt)2pXpQSNPN$gX7{};&sA<@2BETNtk{AbI4nTZT z0h9naKo1}RhydCEE&!2?=(XMAY=)x|W*J5i+BPZ*aS@>*o6ryrLO{?dKmcGL`tH`a zn&K?SD#oFUnTiR26>+>s(uH!0bf42xSs7W z-~Vj=_s8VX$}fKq#o*TCvk!^NG<%2}@ZI;Xk;~)rlRFO^-`@N6r&r*(@zQ(Gy?dX& z@zL9-KmUCRXPXUchdG_qhC&zz1`r-3<`cHCHH}3w{&*q;IES#TSocwtA(O3Th Des*>8 literal 0 HcmV?d00001 diff --git a/sprites/weapons/blaster/breadbagfly-scrapyard-pistols.png b/sprites/weapons/blaster/breadbagfly-scrapyard-pistols.png new file mode 100644 index 0000000000000000000000000000000000000000..f953af47b83bd957d99a3c63f89fbbbcc0734f92 GIT binary patch literal 49098 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 literal 0 HcmV?d00001 From 3e14232925d9e8f13d8fce404447f1e2b62e1aeb Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Sat, 10 May 2025 18:19:17 -0700 Subject: [PATCH 03/14] actual blaster implementation --- zscript.zsc | 2 + zscript/rweapons/projectiles/rwblasterball.zs | 24 ++++ zscript/rweapons/w2blaster.zs | 121 ++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 zscript/rweapons/projectiles/rwblasterball.zs diff --git a/zscript.zsc b/zscript.zsc index 43ed1f5..37e9102 100644 --- a/zscript.zsc +++ b/zscript.zsc @@ -129,6 +129,7 @@ version "4.10.0" #include "zscript/rweapons/w1fist.zs" #include "zscript/rweapons/w1chainsaw.zs" #include "zscript/rweapons/w2pistol.zs" +#include "zscript/rweapons/w2blaster.zs" #include "zscript/rweapons/w3shotgun.zs" #include "zscript/rweapons/w3ssg.zs" #include "zscript/rweapons/w4chaingun.zs" @@ -143,6 +144,7 @@ version "4.10.0" #include "zscript/rweapons/projectiles/rwbfgball.zs" #include "zscript/rweapons/projectiles/rwflechette.zs" #include "zscript/rweapons/projectiles/rwplasmaball.zs" +#include "zscript/rweapons/projectiles/rwblasterball.zs" #include "zscript/rweapons/projectiles/rwminirocket.zs" #include "zscript/rweapons/projectiles/rwrocket.zs" diff --git a/zscript/rweapons/projectiles/rwblasterball.zs b/zscript/rweapons/projectiles/rwblasterball.zs new file mode 100644 index 0000000..a581dc0 --- /dev/null +++ b/zscript/rweapons/projectiles/rwblasterball.zs @@ -0,0 +1,24 @@ +class RwBlasterBall : RwProjectile { + Default { + Radius 8; + Height 6; + Speed 30; + Projectile; + +RANDOMIZE; + +ZDOOMTRANS; + RenderStyle "Add"; + Alpha 0.6; + SeeSound "weapons/plasmaf"; + DeathSound "weapons/plasmax"; + Obituary "$OB_MPBLASTER"; + } + + states { + Spawn: + BOLT A 4 Bright RWA_SeekerMissile(); + Loop; + Death: + BOLT BCDEF 3 Bright; + Stop; + } +} \ No newline at end of file diff --git a/zscript/rweapons/w2blaster.zs b/zscript/rweapons/w2blaster.zs index 9e914b3..539b736 100644 --- a/zscript/rweapons/w2blaster.zs +++ b/zscript/rweapons/w2blaster.zs @@ -3,4 +3,125 @@ class RwBlaster : RandomizedWeapon { // Instead of ammo, its firerate drops off dramatically as it heats up. // The idea is that this is a weapon you want to use in between other weapons; it works best in short bursts and 'cools down' while in your pocket. // Partly inspired by the Treasure Tech pistol's altfire--again, high burst damage, but it's at its best when you have other weapons on hand. + + int chargeAcc; + int chargeTimer; + + default { + Weapon.SlotNumber 2; + Weapon.SelectionOrder 3600; // Backup weapon + + Inventory.PickupMessage "$GOTBLASTER"; + Obituary "$OB_MPBLASTER"; + Tag "$TAG_BLASTER"; + // I'd like to set this thing up so that it doesn't autoswitch away + // when the clip is depleted (since the clip recharges over time), + // but it looks like I can't do that without making the recharge completely irrelevant, + // esp. if this thing gets firerate affixes. + } + + override void DoEffect() { + super.DoEffect(); + chargeTimer++; + chargeAcc += stats.reloadSpeedModifier; + // Charge speed up from reload speed. + while (chargeAcc > 100) { + chargeTimer++; + chargeAcc -= 100; + } + // Charge speed down from reload speed penalties. + if (chargeAcc < -100) { + chargeTimer--; // can only happen once a frame--you can't go backwards! + chargeAcc += 100; + } + if (chargeTimer >= 3 && currentClipAmmo < stats.clipSize) { + currentClipAmmo++; // Reloads slowly over time. + // Base clip size takes ~9 seconds to recharge from empty. + chargeTimer = 0; + } + } + + action state PickBlasterStage() { + double magfill = double(invoker.CurrentClipAmmo) / double(invoker.stats.clipSize); + if (magfill > 0.7) { + return ResolveState("Stage1"); + } else if (magfill > 0.4) { + return ResolveState("Stage2"); + } else { + return ResolveState("Stage3"); + } + } + + states { + Spawn: + BLAS A -1; + + Select: + BLSG A 1 A_Raise; + Loop; + DeSelect: + BLSG A 1 A_Lower; + Loop; + + Ready: + BLSG A 1 A_WeaponReady; // Does not manually reload! + Loop; + + Fire: + BLSG A 0 PickBlasterStage; + + Stage1: + BLSG B 1 Bright { + RWA_ApplyRateOfFire(); + RWA_DoFire(); + } + BLSG C 1 Bright RWA_ApplyRateOfFire; + Goto Ready; + Stage2: + BLSG B 2 Bright { + RWA_ApplyRateOfFire(); + RWA_DoFire(); + } + BLSG C 2 Bright RWA_ApplyRateOfFire; + Goto Ready; + Stage3: + BLSG B 2 Bright { + RWA_ApplyRateOfFire(); + RWA_DoFire(); + } + BLSG C 2 Bright RWA_ApplyRateOfFire; + BLSG A 2 RWA_ApplyRateOfFire; + Goto Ready; + } + + override void setBaseStats() { + stats = RWStatsClass.NewWeaponStats( + 10, 20, + 1, + 5, + 5.0, + 1.0 + ); + stats.clipSize = 100; + stats.firesProjectiles = true; + stats.projClass = 'RwBlasterBall'; + rwBaseName = "Blaster"; + } + + override string GetRandomFluffName() { + static const string specialNames[] = + { + "Reserve Shooter", + "Taser", + "Zapper", + "Zapgun", + "Bolt Thrower", + "Backup Plan", + "Phaser", + "Beamer", + "Sprayer", + "Cricket" + }; + return specialNames[rnd.randn(specialNames.Size())]; + } } \ No newline at end of file From deb7f0ca519d4012011aa39fe94f87a90ac8c2dc Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Sat, 10 May 2025 18:19:27 -0700 Subject: [PATCH 04/14] add blaster to drop pool under pistols --- zscript/drops/map_placed_items_replacements_handler.zs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/zscript/drops/map_placed_items_replacements_handler.zs b/zscript/drops/map_placed_items_replacements_handler.zs index 6b4871a..1727947 100644 --- a/zscript/drops/map_placed_items_replacements_handler.zs +++ b/zscript/drops/map_placed_items_replacements_handler.zs @@ -15,7 +15,11 @@ class MapPlacedItemsToRWCounterpartsReplacementHandler : EventHandler e.Replacement = 'rwChainsaw'; break; case 'Pistol': - e.Replacement = 'rwPistol'; + if (rnd.OneChanceFrom(2)) { + e.Replacement = "rwBlaster"; + } else { + e.Replacement = 'rwPistol'; + } break; case 'Shotgun': e.Replacement = 'rwShotgun'; From 13f152b78b276d60c6c15bce938f12a067060ead Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Sun, 11 May 2025 11:15:26 -0700 Subject: [PATCH 05/14] blaster ammo usage increased --- zscript/rweapons/w2blaster.zs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zscript/rweapons/w2blaster.zs b/zscript/rweapons/w2blaster.zs index 539b736..50e40a1 100644 --- a/zscript/rweapons/w2blaster.zs +++ b/zscript/rweapons/w2blaster.zs @@ -98,7 +98,7 @@ class RwBlaster : RandomizedWeapon { stats = RWStatsClass.NewWeaponStats( 10, 20, 1, - 5, + 10, 5.0, 1.0 ); From b655174c5d256c88a4fa6e340164202f5759df0c Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Sat, 10 May 2025 20:52:38 -0700 Subject: [PATCH 06/14] start DropDatabase, impl new WeightedRand functions in it --- zscript/drops/drops_database.zs | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 zscript/drops/drops_database.zs diff --git a/zscript/drops/drops_database.zs b/zscript/drops/drops_database.zs new file mode 100644 index 0000000..29f35a4 --- /dev/null +++ b/zscript/drops/drops_database.zs @@ -0,0 +1,53 @@ +class DropDatabase : StaticEventHandler { // Good thing this isn't SQL, lmao + // This class has two jobs: + // 1. At startup, iterate the whole class list looking for categories of items. + Map OneTimeItems; // Consumables such as Bonuses, Stimpacks, Scrolls, Spheres + Map AmmoItems; // Ammunition drops. + Map WeaponItems; // Types of weapons that can be dropped. + Map ArmorItems; // As above, for armor. + Map EquipItems; // Non-armor equipment. + + // 2. When something asks for a random drop, give it to them. + + int WeightedRand(Array weights) { + int sum = 0; + for (w : weights) { + sum += w; + } + if (sum <= 0) { debug.panic("Bad weights sent."); } + + int selected = random(0,sum-1); + + for (int i = 0; i < weights.Size(); i++) { + if (weights[i] > 0 && selected < weights[i]) { + return i; + } + + selected -= weights[i]; + } + + debug.panic("Weighted random failed to select an item."); + return 0; + } + + String PickFromWeightList(Map items) { + MapIterator it; + Array weights; + Array results; + if (it.init(items);) { + while (it.Valid() && it.Next()) { + weights.push(it.GetKey()); + results.push(it.GetValue()); + } + } + + // Now we have a list of weights, so we can just do WeightedRand. + int selected = WeightedRand(weights); + if (selected < 0 || selected > results.Size()) { + String err = String.format("Invalid result %d from WeightedRand",selected); + debug.panic(err); + } + + return results[selected]; + } +} \ No newline at end of file From 5edd0221fce16a978e59a6244cc4b5c9cd649a5b Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Tue, 13 May 2025 05:09:31 -0700 Subject: [PATCH 07/14] add weight property to items that need it --- zscript/rarmor/randomized_armor.zs | 6 +++++- zscript/rbackpacks/randomized_backpack.zs | 3 +++ zscript/rflasks/base_rw_flask.zs | 6 +++++- zscript/rweapons/randomized_weapon.zs | 6 +++++- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/zscript/rarmor/randomized_armor.zs b/zscript/rarmor/randomized_armor.zs index 77969c0..5eb48dc 100644 --- a/zscript/rarmor/randomized_armor.zs +++ b/zscript/rarmor/randomized_armor.zs @@ -1,4 +1,4 @@ -class RandomizedArmor : Armor { +class RandomizedArmor : Armor abstract { mixin Affixable; @@ -9,10 +9,14 @@ class RandomizedArmor : Armor { int lastDamageTick; int cumulativeRepair; + int rweight; // Random drop weight. + Property Weight : rweight; + Default { Radius 20; Height 16; + RandomizedArmor.Weight 10; // Same as green and blue armor. } virtual void setBaseStats() { diff --git a/zscript/rbackpacks/randomized_backpack.zs b/zscript/rbackpacks/randomized_backpack.zs index 4c788fc..63b2a75 100644 --- a/zscript/rbackpacks/randomized_backpack.zs +++ b/zscript/rbackpacks/randomized_backpack.zs @@ -4,6 +4,9 @@ class RwBackpack : Inventory { string rwbaseName; RwBackpackStats stats; + int rweight; // Just like in the others, this is the weight for random drops + Property Weight: rweight; + Default { Height 26; // Inventory.PickupMessage "$GOTBACKPACK"; diff --git a/zscript/rflasks/base_rw_flask.zs b/zscript/rflasks/base_rw_flask.zs index d181d11..ab66221 100644 --- a/zscript/rflasks/base_rw_flask.zs +++ b/zscript/rflasks/base_rw_flask.zs @@ -1,4 +1,4 @@ -class RwFlask : Inventory { +class RwFlask : Inventory abstract { mixin Affixable; RwFlaskStats stats; string rwbaseName; @@ -6,8 +6,12 @@ class RwFlask : Inventory { // Current vars int currentCharges, cooldownTicksRemaining; + int rweight; + Property Weight: rweight; + Default { Height 26; + RwFlask.Weight 10; } States { Spawn: diff --git a/zscript/rweapons/randomized_weapon.zs b/zscript/rweapons/randomized_weapon.zs index 285c081..0f75acf 100644 --- a/zscript/rweapons/randomized_weapon.zs +++ b/zscript/rweapons/randomized_weapon.zs @@ -1,13 +1,17 @@ -class RandomizedWeapon : DoomWeapon { +class RandomizedWeapon : DoomWeapon abstract { mixin Affixable; string rwbaseName; RWStatsClass stats; + int rweight; // Weight for randomization. + Property Weight : rweight; // + Default { Weapon.AmmoUse 1; // We use custom ammo usage routine anyway Weapon.AmmoGive 0; // Ammo is dropped separately so that the player doesn't have to "press use to pick it up" + RandomizedWeapon.Weight 20; // A sane default--about as common as the Chaingun and SMG. } virtual void setBaseStats() { From 0426cc603db1e61c9067fa901e2dbe458fd03116 Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Tue, 13 May 2025 05:12:06 -0700 Subject: [PATCH 08/14] add weights to everything that doesn't use default weight --- zscript/rarmor/aenergy.zs | 1 + zscript/rbackpacks/randomized_backpack.zs | 4 ++-- zscript/rweapons/w1chainsaw.zs | 1 + zscript/rweapons/w2pistol.zs | 1 + zscript/rweapons/w3shotgun.zs | 1 + zscript/rweapons/w3ssg.zs | 1 + zscript/rweapons/w4chaingun.zs | 1 + zscript/rweapons/w4smg.zs | 1 + zscript/rweapons/w5rocketlauncher.zs | 1 + zscript/rweapons/w6plasmarifle.zs | 1 + zscript/rweapons/w7bfg.zs | 1 + zscript/rweapons/w7bfg2704.zs | 1 + 12 files changed, 13 insertions(+), 2 deletions(-) diff --git a/zscript/rarmor/aenergy.zs b/zscript/rarmor/aenergy.zs index 3754e19..92867f9 100644 --- a/zscript/rarmor/aenergy.zs +++ b/zscript/rarmor/aenergy.zs @@ -4,6 +4,7 @@ class RwEnergyArmor : RandomizedArmor { Inventory.Pickupmessage "Energy Armor"; Inventory.Icon "EARMA0"; + RandomizedArmor.Weight 5; } States { diff --git a/zscript/rbackpacks/randomized_backpack.zs b/zscript/rbackpacks/randomized_backpack.zs index 63b2a75..2690478 100644 --- a/zscript/rbackpacks/randomized_backpack.zs +++ b/zscript/rbackpacks/randomized_backpack.zs @@ -9,8 +9,8 @@ class RwBackpack : Inventory { Default { Height 26; - // Inventory.PickupMessage "$GOTBACKPACK"; - } + RwBackpack.Weight 10; + // Inventory.PickupMessage "$GOTBACKPACK"; } States { Spawn: BPAK A -1; diff --git a/zscript/rweapons/w1chainsaw.zs b/zscript/rweapons/w1chainsaw.zs index 2b30fc0..fb03179 100644 --- a/zscript/rweapons/w1chainsaw.zs +++ b/zscript/rweapons/w1chainsaw.zs @@ -17,6 +17,7 @@ class RwChainsaw : RandomizedWeapon Tag "$TAG_CHAINSAW"; +WEAPON.MELEEWEAPON +WEAPON.NOAUTOSWITCHTO + RandomizedWeapon.Weight 5; } States { diff --git a/zscript/rweapons/w2pistol.zs b/zscript/rweapons/w2pistol.zs index bceb54f..eaa2f1f 100644 --- a/zscript/rweapons/w2pistol.zs +++ b/zscript/rweapons/w2pistol.zs @@ -10,6 +10,7 @@ class rwPistol : RandomizedWeapon Obituary "$OB_MPPISTOL"; Inventory.PickupMessage "$GOTPISTOL"; Tag "$TAG_PISTOL"; + RandomizedWeapon.Weight 25; } States { diff --git a/zscript/rweapons/w3shotgun.zs b/zscript/rweapons/w3shotgun.zs index abda1ce..9d6d39f 100644 --- a/zscript/rweapons/w3shotgun.zs +++ b/zscript/rweapons/w3shotgun.zs @@ -10,6 +10,7 @@ class rwShotgun : RandomizedWeapon Inventory.PickupMessage "$GOTSHOTGUN"; Obituary "$OB_MPSHOTGUN"; Tag "$TAG_SHOTGUN"; + RandomizedWeapon.Weight 25; } States { diff --git a/zscript/rweapons/w3ssg.zs b/zscript/rweapons/w3ssg.zs index c734ecd..23255b9 100644 --- a/zscript/rweapons/w3ssg.zs +++ b/zscript/rweapons/w3ssg.zs @@ -10,6 +10,7 @@ class RwSuperShotgun : RandomizedWeapon Inventory.PickupMessage "$GOTSHOTGUN2"; Obituary "$OB_MPSSHOTGUN"; Tag "$TAG_SUPERSHOTGUN"; + RandomizedWeapon.Weight 15; } States { diff --git a/zscript/rweapons/w4chaingun.zs b/zscript/rweapons/w4chaingun.zs index c9ffe9e..3c29f5e 100644 --- a/zscript/rweapons/w4chaingun.zs +++ b/zscript/rweapons/w4chaingun.zs @@ -36,6 +36,7 @@ class RwChaingun : RandomizedWeapon Inventory.PickupMessage "$GOTCHAINGUN"; Obituary "$OB_MPCHAINGUN"; Tag "$TAG_CHAINGUN"; + RandomizedWeapon.Weight 20; } States { diff --git a/zscript/rweapons/w4smg.zs b/zscript/rweapons/w4smg.zs index 31a543b..59d1abe 100644 --- a/zscript/rweapons/w4smg.zs +++ b/zscript/rweapons/w4smg.zs @@ -10,6 +10,7 @@ class RwSmg : RandomizedWeapon Inventory.PickupMessage "$GOTSMG"; Obituary "$OB_MPSMG"; Tag "$TAG_SMG"; + RandomizedWeapon.Weight 20; } States { diff --git a/zscript/rweapons/w5rocketlauncher.zs b/zscript/rweapons/w5rocketlauncher.zs index 8885863..5845cc2 100644 --- a/zscript/rweapons/w5rocketlauncher.zs +++ b/zscript/rweapons/w5rocketlauncher.zs @@ -10,6 +10,7 @@ class RwRocketLauncher : RandomizedWeapon +WEAPON.NOAUTOFIRE Inventory.PickupMessage "$GOTLAUNCHER"; Tag "$TAG_ROCKETLAUNCHER"; + RandomizedWeapon.Weight 10; } States { diff --git a/zscript/rweapons/w6plasmarifle.zs b/zscript/rweapons/w6plasmarifle.zs index 03b8276..1cce6cd 100644 --- a/zscript/rweapons/w6plasmarifle.zs +++ b/zscript/rweapons/w6plasmarifle.zs @@ -9,6 +9,7 @@ class RwPlasmaRifle : RandomizedWeapon Weapon.AmmoType "Cell"; Inventory.PickupMessage "$GOTPLASMA"; Tag "$TAG_PLASMARIFLE"; + RandomizedWeapon.Weight 10; } States { diff --git a/zscript/rweapons/w7bfg.zs b/zscript/rweapons/w7bfg.zs index 211fa24..fdfcaab 100644 --- a/zscript/rweapons/w7bfg.zs +++ b/zscript/rweapons/w7bfg.zs @@ -9,6 +9,7 @@ class RwBFG : RandomizedWeapon +WEAPON.NOAUTOFIRE; Inventory.PickupMessage "$GOTBFG9000"; Tag "$TAG_BFG9000"; + RandomizedWeapon.Weight 1; } States { diff --git a/zscript/rweapons/w7bfg2704.zs b/zscript/rweapons/w7bfg2704.zs index 15797fe..08157fd 100644 --- a/zscript/rweapons/w7bfg2704.zs +++ b/zscript/rweapons/w7bfg2704.zs @@ -9,6 +9,7 @@ class RwBFG2704 : RandomizedWeapon +WEAPON.NOAUTOFIRE; Inventory.PickupMessage "$GOTBFG9000"; Tag "$TAG_BFG9000"; + RandomizedWeapon.Weight 1; } States { From b266c2038777942dccfb38dbf69b4976d615c725 Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Tue, 13 May 2025 05:12:28 -0700 Subject: [PATCH 09/14] implement drop registry --- mapinfo.txt | 1 + zscript.zsc | 1 + zscript/drops/drops_database.zs | 84 ++++++++++++++++++++++++++++----- 3 files changed, 75 insertions(+), 11 deletions(-) diff --git a/mapinfo.txt b/mapinfo.txt index 709197c..7dab408 100644 --- a/mapinfo.txt +++ b/mapinfo.txt @@ -11,6 +11,7 @@ gameinfo // AddEventHandlers = "MonstersCacheHandler" - UNUSED for now AddEventHandlers = "AmmoDropsHandler" AddEventHandlers = "DropsHandler" + AddEventHandlers = "DropDatabase" AddEventHandlers = "ExperienceGivingHandler" AddEventHandlers = "DroppedItemsUnclumpHandler" AddEventHandlers = "MonstersAffixingHandler" diff --git a/zscript.zsc b/zscript.zsc index 37e9102..e3f1734 100644 --- a/zscript.zsc +++ b/zscript.zsc @@ -56,6 +56,7 @@ version "4.10.0" #include "zscript/affixable/stats_scaling.zs" #include "zscript/drops/ammo_drops_handler.zs" +#include "zscript/drops/drops_database.zs" #include "zscript/drops/drops_decider.zs" #include "zscript/drops/drops_handler.zs" #include "zscript/drops/drops_handler_progression.zs" diff --git a/zscript/drops/drops_database.zs b/zscript/drops/drops_database.zs index 29f35a4..919aa9d 100644 --- a/zscript/drops/drops_database.zs +++ b/zscript/drops/drops_database.zs @@ -1,17 +1,79 @@ class DropDatabase : StaticEventHandler { // Good thing this isn't SQL, lmao // This class has two jobs: // 1. At startup, iterate the whole class list looking for categories of items. - Map OneTimeItems; // Consumables such as Bonuses, Stimpacks, Scrolls, Spheres - Map AmmoItems; // Ammunition drops. - Map WeaponItems; // Types of weapons that can be dropped. - Map ArmorItems; // As above, for armor. - Map EquipItems; // Non-armor equipment. + Map OneTimeItems; // Consumables such as Bonuses, Stimpacks, Scrolls, Spheres + Map AmmoItems; // Ammunition drops. + Map WeaponItems; // Types of weapons that can be dropped. + Map ArmorItems; // As above, for armor. + Map EquipItems; // Non-armor equipment. + + override void OnRegister() { + // Start by pushing all the known OneTimeItems. + // TODO: Better way of doing this. + OneTimeItems.insert("RwArmorBonus",400); + OneTimeItems.insert("HealthBonus",400); + OneTimeItems.insert("Stimpack",100); + OneTimeItems.insert("Blursphere",10); + OneTimeItems.insert("Soulsphere",7); + OneTimeItems.insert("Berserk",5); + OneTimeItems.insert("MegaSphere",3); + OneTimeItems.insert("InvulnerabilitySphere",1); + OneTimeItems.insert("StatScroll",10); + OneTimeItems.insert("RwFlaskRefill",200); + // Also, ammo items. + // No plans to add new ammo, AFAIK. + AmmoItems.insert("Clip",5); + AmmoItems.insert("Shell",5); + AmmoItems.insert("RocketAmmo",1); + AmmoItems.insert("Cell",2); + + // And now, iterate the whole class list... + // I might be able to make this even more flexible later. + // There's a way to check if a class has a function, + // which would mean that I could have each of these implement a "GetRandWeight()" function + // and then check for the presence of that function + // to insert items into the drop tables. + // This would necessarily mean unifying all of the item drops into one table, though. + foreach (c : AllClasses) { + // Don't include abstract classes. + if (c.isAbstract()) { + continue; + } + // Sort items into their proper lists. + if (c is "RandomizedWeapon") { + Class rwc = c.GetClassName(); + let rw = RandomizedWeapon(GetDefaultByType(rwc)); + WeaponItems.Insert(rw.GetClassName(),rw.rweight); + console.printf("Weapon - %s (%d)",rw.GetClassName(),rw.rweight); + } + if (c is "RandomizedArmor") { + Class rac = c.GetClassName(); + let ra = RandomizedArmor(GetDefaultByType(rac)); + ArmorItems.Insert(ra.GetClassName(),ra.rweight); + console.printf("Armor - %s (%d)",ra.GetClassName(),ra.rweight); + } + if (c is "RwBackpack") { + Class bpc = c.GetClassName(); + let bp = RwBackpack(GetDefaultByType(bpc)); + EquipItems.Insert(bp.GetClassName(),bp.rweight); + console.printf("Backpack - %s (%d)",bp.GetClassName(),bp.rweight); + } + if (c is "RwFlask") { + Class flc = c.GetClassName(); + let fl = RwFlask(GetDefaultByType(flc)); + EquipItems.Insert(fl.GetClassName(),fl.rweight); + console.printf("Flask - %s (%d)",fl.GetClassName(),fl.rweight); + } + } + + } // 2. When something asks for a random drop, give it to them. + int WeightedRand(Array weights) { int sum = 0; - for (w : weights) { + foreach (w : weights) { sum += w; } if (sum <= 0) { debug.panic("Bad weights sent."); } @@ -30,14 +92,14 @@ class DropDatabase : StaticEventHandler { // Good thing this isn't SQL, lmao return 0; } - String PickFromWeightList(Map items) { - MapIterator it; + String PickFromWeightList(Map items) { + MapIterator it; Array weights; Array results; - if (it.init(items);) { + if (it.init(items)) { while (it.Valid() && it.Next()) { - weights.push(it.GetKey()); - results.push(it.GetValue()); + weights.push(it.GetValue()); + results.push(it.GetKey()); } } From e8d384af5bb5491b1c5156550d63875ae02a32d6 Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Fri, 23 May 2025 14:42:18 -0700 Subject: [PATCH 10/14] line was inexplicably commented out, better fix that --- zscript/rbackpacks/randomized_backpack.zs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zscript/rbackpacks/randomized_backpack.zs b/zscript/rbackpacks/randomized_backpack.zs index 2690478..e869eab 100644 --- a/zscript/rbackpacks/randomized_backpack.zs +++ b/zscript/rbackpacks/randomized_backpack.zs @@ -10,7 +10,8 @@ class RwBackpack : Inventory { Default { Height 26; RwBackpack.Weight 10; - // Inventory.PickupMessage "$GOTBACKPACK"; } + Inventory.PickupMessage "$GOTBACKPACK"; + } States { Spawn: BPAK A -1; From e54721dbaef15015a42fc9ac6f848f75c129d197 Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Fri, 23 May 2025 15:23:20 -0700 Subject: [PATCH 11/14] bugfixes for weighted rand, dead-simple shortcut functions for item categories --- zscript/drops/drops_database.zs | 40 +++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/zscript/drops/drops_database.zs b/zscript/drops/drops_database.zs index 919aa9d..8cdd46e 100644 --- a/zscript/drops/drops_database.zs +++ b/zscript/drops/drops_database.zs @@ -7,6 +7,10 @@ class DropDatabase : StaticEventHandler { // Good thing this isn't SQL, lmao Map ArmorItems; // As above, for armor. Map EquipItems; // Non-armor equipment. + static DropDatabase Get() { + return DropDatabase(StaticEventHandler.Find("DropDatabase")); + } + override void OnRegister() { // Start by pushing all the known OneTimeItems. // TODO: Better way of doing this. @@ -73,7 +77,8 @@ class DropDatabase : StaticEventHandler { // Good thing this isn't SQL, lmao int WeightedRand(Array weights) { int sum = 0; - foreach (w : weights) { + for (int i = 0; i < weights.size(); i++) { + int w = weights[i]; sum += w; } if (sum <= 0) { debug.panic("Bad weights sent."); } @@ -96,11 +101,10 @@ class DropDatabase : StaticEventHandler { // Good thing this isn't SQL, lmao MapIterator it; Array weights; Array results; - if (it.init(items)) { - while (it.Valid() && it.Next()) { - weights.push(it.GetValue()); - results.push(it.GetKey()); - } + it.init(items); + foreach (k, v : it) { + weights.push(v); + results.push(k); } // Now we have a list of weights, so we can just do WeightedRand. @@ -110,6 +114,28 @@ class DropDatabase : StaticEventHandler { // Good thing this isn't SQL, lmao debug.panic(err); } - return results[selected]; + string result = results[selected]; + + return result; + } + + String PickWeapon() { + return PickFromWeightList(WeaponItems); + } + + String PickArmor() { + return PickFromWeightList(ArmorItems); + } + + String PickEquip() { + return PickFromWeightList(EquipItems); + } + + String PickAmmo() { + return PickFromWeightList(AmmoItems); + } + + String PickOneTimeItem() { + return PickFromWeightList(OneTimeItems); } } \ No newline at end of file From 205a1ab1524d14b79d451ab371b81ac43a730373 Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Fri, 23 May 2025 15:24:39 -0700 Subject: [PATCH 12/14] DropsSpawner now uses DropDatabase for picking items from each category. TODO: Come up with a good way to handle the categories themselves. --- zscript/drops/drops_spawner.zs | 179 ++++++++++----------------------- 1 file changed, 52 insertions(+), 127 deletions(-) diff --git a/zscript/drops/drops_spawner.zs b/zscript/drops/drops_spawner.zs index 741c808..2ccd683 100644 --- a/zscript/drops/drops_spawner.zs +++ b/zscript/drops/drops_spawner.zs @@ -8,53 +8,19 @@ class DropsSpawner { } static play Actor SpawnRandomOneTimeItemDrop(Actor dropper) { - int dropType = rnd.weightedRand(400, 400, 100, 10, 7, 5, 3, 1, 10, 200); - switch (dropType) { - case 0: - return createDropByClass(dropper, 'RwArmorBonus'); - case 1: - return createDropByClass(dropper, 'HealthBonus'); - case 2: - return createDropByClass(dropper, 'Stimpack'); - case 3: - return createDropByClass(dropper, 'BlurSphere'); - case 4: - return createDropByClass(dropper, 'SoulSphere'); - case 5: - return createDropByClass(dropper, 'Berserk'); - case 6: - return createDropByClass(dropper, 'MegaSphere'); - case 7: - return createDropByClass(dropper, 'InvulnerabilitySphere'); - case 8: - return createDropByClass(dropper, 'StatScroll'); - case 9: - return createDropByClass(dropper, 'RwFlaskRefill'); - default: - debug.panic("Random one-time item drop spawner crashed"); - } - return null; + Actor itemDrop; + DropDatabase db = DropDatabase.Get(); + String spawnedClass = db.PickOneTimeItem(); + itemDrop = createDropByClass(dropper,spawnedClass); + return itemDrop; } static play Actor SpawnRandomAmmoDrop(Actor dropper, int maxAmmoPercentage = 200) { - int dropType = rnd.weightedRand(5, 5, 1, 2); Actor ammoDrop; - switch (dropType) { - case 0: - ammoDrop = createDropByClass(dropper, 'Clip'); - break; - case 1: - ammoDrop = createDropByClass(dropper, 'Shell'); - break; - case 2: - ammoDrop = createDropByClass(dropper, 'RocketAmmo'); - break; - case 3: - ammoDrop = createDropByClass(dropper, 'Cell'); - break; - default: - debug.panic("Ammo random drop spawner crashed"); - } + DropDatabase db = DropDatabase.Get(); + String spawnedClass = db.PickAmmo(); + ammoDrop = createDropByClass(dropper,spawnedClass); + // Randomly increase dropped ammo amount let invItem = Inventory(ammoDrop); if (invItem) { @@ -64,16 +30,17 @@ class DropsSpawner { } static play Actor SpawnRandomRWArtifactItemDrop(Actor dropper) { - int dropType = rnd.weightedRand(6, 4, 1, 1); + int dropType = rnd.weightedRand(6, 4, 2); switch (dropType) { case 0: return SpawnRWeaponDrop(dropper); case 1: return SpawnRArmorDrop(dropper); case 2: - return SpawnRBackpackDrop(dropper); - case 3: - return SpawnRFlaskDrop(dropper); + return SpawnREquipDrop(dropper); + // Backpacks and Flasks are currently merged into the same drop pool, + // which doesn't matter for now because they have equal weights. + // May become an issue if new equip slots are added. default: debug.panic("SpawnRandomRWArtifactItemDrop crashed"); } @@ -82,96 +49,54 @@ class DropsSpawner { private static play Actor SpawnRWeaponDrop(Actor dropper) { Actor spawnedItem; - int dropType = rnd.weightedRand( - 5, // Chainsaw - 25, // Pistol - 25, // Shotgun - 15, // SSG (it is supported in Doom 1 too) - 20, // Chaingun - 20, // SMG - 10, // Rocket Launcher - 10, // Plasma Rifle - 1, // BFG - 1 // BFG-2704 - ); - switch (dropType) { - case 0: - spawnedItem = createDropByClass(dropper, 'RwChainsaw'); - break; - case 1: - spawnedItem = createDropByClass(dropper, 'RwPistol'); - break; - case 2: - spawnedItem = createDropByClass(dropper, 'RwShotgun'); - break; - case 3: - spawnedItem = createDropByClass(dropper, 'RwSuperShotgun'); - break; - case 4: - spawnedItem = createDropByClass(dropper, 'RwChaingun'); - break; - case 5: - spawnedItem = createDropByClass(dropper, 'RwSmg'); - break; - case 6: - spawnedItem = createDropByClass(dropper, 'RwRocketLauncher'); - break; - case 7: - spawnedItem = createDropByClass(dropper, 'RwPlasmarifle'); - break; - case 8: - spawnedItem = createDropByClass(dropper, 'RwBFG'); - break; - case 9: - spawnedItem = createDropByClass(dropper, 'RwBFG2704'); - break; - default: - debug.panic("RWeapon drop spawner crashed"); - } + DropDatabase db = DropDatabase.Get(); + String spawnedClass = db.PickWeapon(); + spawnedItem = createDropByClass(dropper,spawnedClass); return spawnedItem; } private static play Actor SpawnRArmorDrop(Actor dropper) { - bool unused; Actor spawnedItem; - let dropType = rnd.weightedRand(10, 10, 5); - switch (dropType) { - case 0: - [unused, spawnedItem] = dropper.A_SpawnItemEx('RwGreenArmor'); - break; - case 1: - [unused, spawnedItem] = dropper.A_SpawnItemEx('RwBlueArmor'); - break; - case 2: - [unused, spawnedItem] = dropper.A_SpawnItemEx('RwEnergyArmor'); - break; - default: - debug.panic("Drop spawner crashed"); - } + DropDatabase db = DropDatabase.Get(); + String spawnedClass = db.PickArmor(); + spawnedItem = createDropByClass(dropper,spawnedClass); return spawnedItem; } - private static play Actor SpawnRBackpackDrop(Actor dropper) { - return createDropByClass(dropper, RwBackpack.GetRandomVariantClass()); - } + // private static play Actor SpawnRBackpackDrop(Actor dropper) { + // return createDropByClass(dropper, RwBackpack.GetRandomVariantClass()); + // } + // TODO: GetRandomVariantClass is no longer necessary + // because subclasses of RwBackpack are added to the equipment pool + // and have the same weights as normal backpacks. + // It should probably be removed, maybe replaced with a more generic + // 'item skins' system that can also be used for weapons and the like. - private static play Actor SpawnRFlaskDrop(Actor dropper) { - let dropType = rnd.weightedRand(10, 10, 10); - bool unused; + // private static play Actor SpawnRFlaskDrop(Actor dropper) { + // let dropType = rnd.weightedRand(10, 10, 10); + // bool unused; + // Actor spawnedItem; + // switch (dropType) { + // case 0: + // [unused, spawnedItem] = dropper.A_SpawnItemEx('RwSmallFlask'); + // break; + // case 1: + // [unused, spawnedItem] = dropper.A_SpawnItemEx('RwMediumFlask'); + // break; + // case 2: + // [unused, spawnedItem] = dropper.A_SpawnItemEx('RwBigFlask'); + // break; + // default: + // debug.panic("Drop spawner crashed"); + // } + // return spawnedItem; + // } + + private static play Actor SpawnREquipDrop(Actor dropper) { Actor spawnedItem; - switch (dropType) { - case 0: - [unused, spawnedItem] = dropper.A_SpawnItemEx('RwSmallFlask'); - break; - case 1: - [unused, spawnedItem] = dropper.A_SpawnItemEx('RwMediumFlask'); - break; - case 2: - [unused, spawnedItem] = dropper.A_SpawnItemEx('RwBigFlask'); - break; - default: - debug.panic("Drop spawner crashed"); - } + DropDatabase db = DropDatabase.Get(); + String spawnedClass = db.PickEquip(); + spawnedItem = createDropByClass(dropper,spawnedClass); return spawnedItem; } } \ No newline at end of file From f2993c9ffd43376955cd1e110d7d6b1ef86a2da2 Mon Sep 17 00:00:00 2001 From: sidav Date: Sun, 11 May 2025 16:25:31 +0200 Subject: [PATCH 13/14] Code style fix. Add DE locale lines. Fix typos in README. --- LANGUAGE.de | 8 +++--- README.md | 9 ++++--- zscript/rweapons/w4chaingun.zs | 48 +++++++++++++++++----------------- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/LANGUAGE.de b/LANGUAGE.de index eb024d1..c3a945c 100644 --- a/LANGUAGE.de +++ b/LANGUAGE.de @@ -4,9 +4,9 @@ RAREMONSTERSPAWNED = "Du spürst eine starke Präsenz an diesem Ort."; // Weapons -TAG_SMG = "PLACEHOLDER_DE: Sub-Machine Gun"; -GOTSMG = "PLACEHOLDER_DE: You got a Sub-Machine Gun!"; -OB_MPSMG = "PLACEHOLDER_DE: %o was rattled by %k's little friend."; +TAG_SMG = "Machinenpistole"; +GOTSMG = "Machinenpistole genommen."; +OB_MPSMG = "%o wurde mit Blei aus %ks Machinenpistole vollgepumpt."; // Menu RWMENU_DOOMABLOSETTINGS = "DOOMablo anpassen"; @@ -45,4 +45,4 @@ RWSETTINGS_CHARACTERSCREENBTN = "Charakter-Bildschirm öffnen"; // Generic YES = "Ja"; -NO = "Nein"; \ No newline at end of file +NO = "Nein"; diff --git a/README.md b/README.md index bbd85b1..c88aa4b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Doomablo: a looter-shooter Doom mod **DOOM and Diablo are two of the most well-known games about fighting demon hordes. Let's merge them, will we?** + DOOMablo (the title is not final, though) is a mod inspired by BorderDoom and Doom: Infinite which transforms DOOM into a looter-shooter in the vein of Diablo. Kill demons, grab randomly generated weapons and armor with various affixes, so that you could kill more demons and find even better loot! ## What's included: @@ -18,15 +19,15 @@ DOOMablo (the title is not final, though) is a mod inspired by BorderDoom and Do ## Prerequisites and running: - You will need GZDoom v.4.10.0 or later and DOOM.WAD or DOOM2.WAD. The mod should work with Freedom, although it was not tested. - Just run this mod like you usually run GZDoom mods. Doomablo usually should be after your monster packs in the mods order. +- First of all, visit DOOMablo settings to configure the needed keys. - **Use the fullscreen HUD** to see Doomablo UI elements. **Statusbar (default DOOM UI) won't work!** Just press "+" key when you e.g can't see item stats. - Enable the mouselook! -- Visit DOOMablo settings to configure the needed keys. -- If monster's health bars look strange or unreadable, you can configure them in DOOMablo settings. +- If monster's health bars look strange or unreadable, try configuring them in DOOMablo settings. ## Compatibility: - The mod works both with Doom 1 and Doom 2. -- This mod should (but not guaranteed to) be compatible with any non-heavily scripted map packs. Compatibility with map packs is a high priority for me, so please report any incompatibilities and/or mappack-related bugs. -- This mod should (but not guaranteed to) be compatible with most non-heavily scripted monster packs. Monster pack ccompatibility is somewhat of a lower priority. +- This mod should (but not guaranteed to) be compatible with any map packs, unless they are scripted with custom gameplay logic. Compatibility with map packs is a high priority for me, so please report any incompatibilities and/or mappack-related bugs. +- This mod should (but not guaranteed to) be compatible with most non-heavily scripted monster packs. Monster pack compatibility is somewhat of a lower priority, but please report any incompatibilities nonetheless. - This mod is compatible with Nashgore. In fact, I'm testing it without ever disabling Nashgore. - **This mod is NOT compatible with any mods that alter weapons and/or armor.** Sadly, universal compatibility is not quite possible at this stage, as there is too much custom logic involved. To compensate for that, I'm targeting to implement more weapons inside this mod itself in the future to ensure enough variety even without third party weapon mods. diff --git a/zscript/rweapons/w4chaingun.zs b/zscript/rweapons/w4chaingun.zs index 3c29f5e..16ba425 100644 --- a/zscript/rweapons/w4chaingun.zs +++ b/zscript/rweapons/w4chaingun.zs @@ -3,28 +3,6 @@ class RwChaingun : RandomizedWeapon int currentFireFrame; - // A couple simple wrapper functions to make the animation read a little more cleanly. - // - dbrz - - action void ShootAndApplyROF() { - RWA_ApplyRateOfFire(); - if (invoker.currentClipAmmo >= invoker.stats.ammoUsage) { - RWA_DoFire(); - RWA_ChaingunFlash(); - } - // The gun now shoots during spinup. This should make the chaingun feel way, way more responsive, - // since the old behavior meant that swapping to another weapon was basically mandatory if you had a threat to deal with right away. - // - dbrz - } - - action void SpinDown() { - RWA_ApplyRateOfFire(); - RWA_Refire(); - // You can start firing again during spindown, but swapping weapons or reloading requires full spindown. - // Firing from spindown jumps right to full speed, as long as you're still in spindown when you hit the button again, - // so you no longer have to wait for the whole spindown and spinup if your finger slips. - // - dbrz - } Default { @@ -126,7 +104,29 @@ class RwChaingun : RandomizedWeapon } } - override void setBaseStats() { + // A couple simple wrapper functions to make the animation read a little more cleanly. + // - dbrz + action void ShootAndApplyROF() { + RWA_ApplyRateOfFire(); + if (invoker.currentClipAmmo >= invoker.stats.ammoUsage) { + RWA_DoFire(); + RWA_ChaingunFlash(); + } + // The gun now shoots during spinup. This should make the chaingun feel way, way more responsive, + // since the old behavior meant that swapping to another weapon was basically mandatory if you had a threat to deal with right away. + // - dbrz + } + + action void SpinDown() { + RWA_ApplyRateOfFire(); + RWA_Refire(); + // You can start firing again during spindown, but swapping weapons or reloading requires full spindown. + // Firing from spindown jumps right to full speed, as long as you're still in spindown when you hit the button again, + // so you no longer have to wait for the whole spindown and spinup if your finger slips. + // - dbrz + } + + override void setBaseStats() { stats = RWStatsClass.NewWeaponStats( 4, 8, 1, @@ -136,7 +136,7 @@ class RwChaingun : RandomizedWeapon ); stats.clipSize = 100; rwBaseName = "Chaingun"; - } + } override string GetRandomFluffName() { static const string specialNames[] = From e5974b4c2eeb1c971a4efb4707c8f058eb83edac Mon Sep 17 00:00:00 2001 From: Chris Scott Date: Fri, 23 May 2025 23:35:29 -0700 Subject: [PATCH 14/14] add blaster lang entries --- LANGUAGE.de | 4 ++++ LANGUAGE.default | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/LANGUAGE.de b/LANGUAGE.de index c3a945c..27d47f1 100644 --- a/LANGUAGE.de +++ b/LANGUAGE.de @@ -8,6 +8,10 @@ TAG_SMG = "Machinenpistole"; GOTSMG = "Machinenpistole genommen."; OB_MPSMG = "%o wurde mit Blei aus %ks Machinenpistole vollgepumpt."; +TAG_BLASTER = "Blaster"; +GOTBLASTER = "You got a Blaster!"; +OB_MPBLASTER = "%o got tased by %k's blaster."; + // Menu RWMENU_DOOMABLOSETTINGS = "DOOMablo anpassen"; RWMENU_CUSTOMIZEDOOMABLO = "DOOMablo Einstellungen"; diff --git a/LANGUAGE.default b/LANGUAGE.default index ee38bcc..36c9c10 100644 --- a/LANGUAGE.default +++ b/LANGUAGE.default @@ -8,6 +8,10 @@ TAG_SMG = "Sub-Machine Gun"; GOTSMG = "You got a Sub-Machine Gun!"; OB_MPSMG = "%o was rattled by %k's little friend."; +TAG_BLASTER = "Blaster"; +GOTBLASTER = "You got a Blaster!"; +OB_MPBLASTER = "%o got tased by %k's blaster."; + // Menu RWMENU_DOOMABLOSETTINGS = "DOOMablo settings"; RWMENU_CUSTOMIZEDOOMABLO = "Customize DOOMablo";