From 9f54ec6f62cf978fc2e380141211d757960b16fa Mon Sep 17 00:00:00 2001 From: Marisa Kirisame Date: Wed, 22 Sep 2021 19:39:44 +0200 Subject: [PATCH] More changes from master. --- README.md | 4 +- language.def_lore | 2 +- language.es_lore | 2 +- language.version | 4 +- lore/default/candygun.txt | 2 +- lore/es/candygun.txt | 2 +- readme.txt | 2 +- zscript/compat/swwm_compat.zsc | 79 ++++++- zscript/handler/swwm_handler_damage.zsc | 10 +- zscript/handler/swwm_handler_vanillaboss.zsc | 21 ++ zscript/handler/swwm_handler_worldload.zsc | 2 + zscript/handler/swwm_handler_worldthings.zsc | 2 +- zscript/handler/swwm_handler_worldtick.zsc | 7 +- zscript/items/swwm_ammoextra.zsc | 199 ++++++++++-------- zscript/items/swwm_powerups.zsc | 15 +- zscript/swwm_player.zsc | 2 +- zscript/swwm_thinkers_hud.zsc | 25 ++- .../weapons/swwm_deathlydeathcannon_fx.zsc | 6 +- zscript/weapons/swwm_deepdarkimpact_fx.zsc | 2 +- zscript/weapons/swwm_jackhammer.zsc | 19 +- zscript/weapons/swwm_shot_fx.zsc | 2 +- zscript/weapons/swwm_tastytreat.zsc | 69 ++++-- 22 files changed, 335 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index dd4649158..952865e85 100644 --- a/README.md +++ b/README.md @@ -254,7 +254,7 @@ Coming from an old unreleased weapon mini-mod, the **Candy Gun** is like an **Ex **Reload:** Does what you'd expect. -Holding primary fire during the first few moments of alt fire will throw the weapon itself, armed and ready to explode if it hits anyone or anything. The blast area for this is pretty ridiculous. You can hold spare guns, by the way (up to four). +Holding secondary fire and primary fire (in that order) will throw the weapon itself, armed and ready to explode if it hits anyone or anything. The blast area for this is pretty ridiculous. You can hold spare guns, by the way (up to four). ### Candy Gun Bullets ~ Replaces Cells, Runes ![](docimg/candybullet.png) @@ -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.def_lore b/language.def_lore index 013e76a38..2322310c2 100644 --- a/language.def_lore +++ b/language.def_lore @@ -408,7 +408,7 @@ SWWM_LORETXT_CANDYGUN = "\n" "\cfSecondary Fire:\c- Perform an \"explosive reload\", just like with a standard Explodium Gun. Note that unlike its weaker counterpart, the yield is much more extreme. It is best practice to always have one spare magazine at the ready for the reload, so you aren't left with an unusable weapon should your throw miss the target.\n" "\n" -"\cfCombo Fire:\c- During the first moments of preparing an explosive reload, you can opt to, instead, leave the magazine in the gun, armed and ready, then throw the whole weapon as a grenade, for the ultimate destruction. As always, make sure you have a fully loaded spare around, or you'll be left with nothing. Due to this disposable nature, you're allowed to carry up to 4 spares in your inventory. Use them well.\n" +"\cfCombo Fire:\c- By holding secondary and primary fire (in that order) you can opt to, instead of performing the usual explosive reload, leave the magazine in the gun, armed and ready, then throw the whole weapon as a grenade, for the ultimate destruction. As always, make sure you at least have a spare and more ammo, or you'll be left with nothing. Due to this disposable nature, you're allowed to carry up to 4 spares in your inventory. Use them well.\n" "\n" "\cxSaya's Notes:\c-\n" "\cfI don't get it, really don't. How is it that mixing that exploding shit with candy does this? Oh, whatever, I still love every second of it, but the pretty fireworks make me really nostalgic, for some reason...\c-\n" diff --git a/language.es_lore b/language.es_lore index 55f9427cb..9c8db896f 100644 --- a/language.es_lore +++ b/language.es_lore @@ -381,7 +381,7 @@ SWWM_LORETXT_CANDYGUN = "\n" "\cfFuego Secundario:\c- Realiza una \"recarga explosiva\", al igual que la Pistola de Explodium estándar. Ten en cuenta que a diferencia de su débil homóloga, la carga explosiva es mucho más extrema. Se recomienda tener siempre un cargador de repuesto listo para la recarga, para no acabar con un arma inútil si el que has lanzado no alcanza su objetivo.\n" "\n" -"\cfFuego Combinado:\c- Durante los primeros momentos de preparar una recarga explosiva, también puedes, en su lugar, dejar el cargador dentro de la pistola, armado y listo, y entonces lanzar el arma entera como una granada, para una destrucción total. Como siempre, asegúrate de tener una de repuesto cargada, o acabarás con las manos vacías. Dada esta naturaleza desechable, se te permite llevar hasta 4 repuestos en tu inventario. Úsalos bien.\n" +"\cfFuego Combinado:\c- Manteniendo el fuego secundario y primario pulsados (en ese orden) puedes optar por, en lugar de realizar la típica recarga explosiva, dejar el cargador dentro de la pistola, armado y listo, y entonces lanzar el arma entera como una granada, para una destrucción total. Como siempre, asegúrate de tener al menos un repuesto y más munición, o acabarás con las manos vacías. Dada esta naturaleza desechable, se te permite llevar hasta 4 repuestos en tu inventario. Úsalos bien.\n" "\n" "\cxNotas de Saya:\c-\n" "\cfNo lo pillo, en serio que no. ¿Como es que mezclando toda esa mierda explosiva con caramelo hace esto? Oh, es igual, me sigue molando mucho cada momento, pero los bonitos fuegos artificiales me dan como nostalgia, no sé por qué...\c-\n" diff --git a/language.version b/language.version index 0166492cc..108efb752 100644 --- a/language.version +++ b/language.version @@ -1,3 +1,3 @@ [default] -SWWM_MODVER="\chSWWM \czGZ\c- \cw1.2pre r1 \cu(Mon 20 Sep 23:36:13 CEST 2021)\c-"; -SWWM_SHORTVER="\cw1.2pre r1 \cu(2021-09-20 23:36:13)\c-"; +SWWM_MODVER="\chSWWM \czGZ\c- \cw1.2pre r2 \cu(Wed 22 Sep 19:39:44 CEST 2021)\c-"; +SWWM_SHORTVER="\cw1.2pre r2 \cu(2021-09-22 19:39:44)\c-"; diff --git a/lore/default/candygun.txt b/lore/default/candygun.txt index 6db792ab6..7a3d564e8 100644 --- a/lore/default/candygun.txt +++ b/lore/default/candygun.txt @@ -18,7 +18,7 @@ A highly boosted variant of the standard **Explodium Gun**. Its magenta tint com \cfSecondary Fire:\c- Perform an "explosive reload", just like with a standard Explodium Gun. Note that unlike its weaker counterpart, the yield is much more extreme. It is best practice to always have one spare magazine at the ready for the reload, so you aren't left with an unusable weapon should your throw miss the target. -\cfCombo Fire:\c- During the first moments of preparing an explosive reload, you can opt to, instead, leave the magazine in the gun, armed and ready, then throw the whole weapon as a grenade, for the ultimate destruction. As always, make sure you have a fully loaded spare around, or you'll be left with nothing. Due to this disposable nature, you're allowed to carry up to 4 spares in your inventory. Use them well. +\cfCombo Fire:\c- By holding secondary and primary fire (in that order) you can opt to, instead of performing the usual explosive reload, leave the magazine in the gun, armed and ready, then throw the whole weapon as a grenade, for the ultimate destruction. As always, make sure you at least have a spare and more ammo, or you'll be left with nothing. Due to this disposable nature, you're allowed to carry up to 4 spares in your inventory. Use them well. \cxSaya's Notes:\c- \cfI don't get it, really don't. How is it that mixing that exploding shit with candy does this? Oh, whatever, I still love every second of it, but the pretty fireworks make me really nostalgic, for some reason...\c- diff --git a/lore/es/candygun.txt b/lore/es/candygun.txt index df7565031..a12ba60b3 100644 --- a/lore/es/candygun.txt +++ b/lore/es/candygun.txt @@ -14,7 +14,7 @@ Una variante altamente potenciada de la **Pistola de Explodium** estándar. Su c \cfFuego Secundario:\c- Realiza una "recarga explosiva", al igual que la Pistola de Explodium estándar. Ten en cuenta que a diferencia de su débil homóloga, la carga explosiva es mucho más extrema. Se recomienda tener siempre un cargador de repuesto listo para la recarga, para no acabar con un arma inútil si el que has lanzado no alcanza su objetivo. -\cfFuego Combinado:\c- Durante los primeros momentos de preparar una recarga explosiva, también puedes, en su lugar, dejar el cargador dentro de la pistola, armado y listo, y entonces lanzar el arma entera como una granada, para una destrucción total. Como siempre, asegúrate de tener una de repuesto cargada, o acabarás con las manos vacías. Dada esta naturaleza desechable, se te permite llevar hasta 4 repuestos en tu inventario. Úsalos bien. +\cfFuego Combinado:\c- Manteniendo el fuego secundario y primario pulsados (en ese orden) puedes optar por, en lugar de realizar la típica recarga explosiva, dejar el cargador dentro de la pistola, armado y listo, y entonces lanzar el arma entera como una granada, para una destrucción total. Como siempre, asegúrate de tener al menos un repuesto y más munición, o acabarás con las manos vacías. Dada esta naturaleza desechable, se te permite llevar hasta 4 repuestos en tu inventario. Úsalos bien. \cxNotas de Saya:\c- \cfNo lo pillo, en serio que no. ¿Como es que mezclando toda esa mierda explosiva con caramelo hace esto? Oh, es igual, me sigue molando mucho cada momento, pero los bonitos fuegos artificiales me dan como nostalgia, no sé por qué...\c- diff --git a/readme.txt b/readme.txt index 41181da79..f474d41f1 100644 --- a/readme.txt +++ b/readme.txt @@ -196,7 +196,7 @@ Slot 9. Pistol (but very strong). A tasty treat of sweetness and DEATH. From the lost forever™ Weirdweapons pack. Primary fire does the thing. Secondary fire does also the same thing as its slot 2 counterpart. -Holding primary fire after pressing secondary fire will switch to yeeting the +Holding secondary and primary fire (in that order) will switch to yeeting the entire damn gun, for some absurd reason. It's very effective, though. Considering that you can dispose of it like that, you can hold some spares. diff --git a/zscript/compat/swwm_compat.zsc b/zscript/compat/swwm_compat.zsc index 5d3af824d..47e2a8ae8 100644 --- a/zscript/compat/swwm_compat.zsc +++ b/zscript/compat/swwm_compat.zsc @@ -251,16 +251,91 @@ Class SWWMLevelCompatibility : LevelPostProcessor SetThingEdNum(0,4206992); SetThingAngle(0,0); break; + // Hexen MAP06 + case '1B6DF1FD51FDC3D882009D287B5A28C6': + case '65EFFD49449AD3FD32A6EB347C6D923B': + // replace an Icon of the Defender with a Chancebox + SetThingEdNum(193,4206920); + SetThingSkills(193,SKILLS_ALL); + SetThingFlags(193,MTF_SINGLE|MTF_COOPERATIVE); + // replace a Mystic Ambit Incant with a Chancebox + SetThingEdNum(377,4206920); + SetThingSkills(193,SKILLS_ALL); + SetThingFlags(377,MTF_SINGLE|MTF_COOPERATIVE); + SetThingAngle(377,90); // should face north + break; + case 'A3D86F121B41320BFD1EB747D9133EF2': + // replace an Icon of the Defender with a Chancebox + SetThingEdNum(193,4206921); + SetThingSkills(193,SKILLS_ALL); + SetThingFlags(193,MTF_SINGLE|MTF_COOPERATIVE); + // this version doesn't have a Mystic Ambit Incant placed + AddThing(4206921,(-32,-3072,-456),90,SKILLS_ALL,MTF_SINGLE|MTF_COOPERATIVE); + break; + // Hexen MAP11 + case 'F8DFDCBAA677F83E2CD2409F5C00505F': + case 'CC90EAF7131A1CA59F8322735C92899C': + case 'B2A1B321E56494081085E51931EB3158': + // replace Mystic Urns with Chanceboxes + SetThingEdNum(62,4206920); + SetThingEdNum(63,4206920); + SetThingEdNum(64,4206920); + SetThingSkills(62,SKILLS_ALL); + SetThingSkills(63,SKILLS_ALL); + SetThingSkills(64,SKILLS_ALL); + SetThingFlags(62,MTF_SINGLE|MTF_COOPERATIVE); + SetThingFlags(63,MTF_SINGLE|MTF_COOPERATIVE); + SetThingFlags(64,MTF_SINGLE|MTF_COOPERATIVE); + SetThingAngle(62,0); + SetThingAngle(63,270); + SetThingAngle(64,180); + break; + // Hexen MAP31 + case '4A4436544EBFA930AE3C4C8C2409FD6E': + case 'D48508B92843539B4464235C2B355CC3': + case 'BF9DFE95D9351AA3A65666185BFC921C': + // place 2 Chanceboxes at the final room + AddThing(4206920,(416,-352,0),180,SKILLS_ALL,MTF_SINGLE|MTF_COOPERATIVE); + AddThing(4206920,(544,-352,0),0,SKILLS_ALL,MTF_SINGLE|MTF_COOPERATIVE); + break; + // Hexen MAP26 + case '339B4B50B615BE6E1D8454F6C605A97C': + case 'BFDC70A9D445EA5B9010ABB133253D6F': + case '2CF971EECD6B790782DB44B0E917B5B2': + // place 2 Chanceboxes in the central square + AddThing(4206920,(-224,416,-128),270,SKILLS_ALL,MTF_SINGLE|MTF_COOPERATIVE); + AddThing(4206920,(-224,-672,-128),90,SKILLS_ALL,MTF_SINGLE|MTF_COOPERATIVE); + break; + // Hexen MAP39 + case '2639C89B8B7052E2CE4CB9CFC63F4C53': + case 'EC5A1B294CC7FB822A6C913F811797C4': + case 'FEA83EE6BCFC899F06CBE394DFBE6707': + // replace Porkalator with a Chancebox + SetThingEdNum(179,4206920); + SetThingSkills(179,SKILLS_ALL); + SetThingFlags(179,MTF_SINGLE|MTF_COOPERATIVE); + SetThingAngle(179,270); + // add two more Chanceboxes near it + AddThing(4206920,(-32,2848,128),270,SKILLS_ALL,MTF_SINGLE|MTF_COOPERATIVE); + AddThing(4206920,(160,2848,128),270,SKILLS_ALL,MTF_SINGLE|MTF_COOPERATIVE); + break; + // Hexen MAP40 + case '2A6C4235B942467D25FD50D5B313E67A': + case '1C5DE5A921DEE405E98E7E09D9829387': + case 'EFAFE59092DE5E613562ACF52B86C37F': + // place a final Chancebox behind the player start + AddThing(4206920,(2912,256,-112),180,SKILLS_ALL,MTF_SINGLE|MTF_COOPERATIVE); + break; // Kinsie's Test Map case '0EADB2F82732A968B8513E4DC6138439': case 'D70250F93C6B6072DA39D9672B37F236': case '959A613006CC3AA912C4A22908B7566A': // add collectibles for ( int i=0; i<12; i++ ) - AddThing(4206900+i,(1472+64*i,640,0)); + AddThing(4206900+i,(1472+64*i,640,0),SKILLS_ALL,MTF_SINGLE|MTF_COOPERATIVE); // add some chance boxes for ( int i=0; i<3; i++ ) - AddThing(4206920,(3616,1824-64*i,0),180); + AddThing(4206920,(3616,1824-64*i,0),180,SKILLS_ALL,MTF_SINGLE|MTF_COOPERATIVE); break; } switch ( checksum ) diff --git a/zscript/handler/swwm_handler_damage.zsc b/zscript/handler/swwm_handler_damage.zsc index 25cfb8d1e..75ccb3265 100644 --- a/zscript/handler/swwm_handler_damage.zsc +++ b/zscript/handler/swwm_handler_damage.zsc @@ -112,7 +112,7 @@ extend Class SWWMHandler if ( e.Damage > s.topdealt ) s.topdealt = e.Damage; } SWWMFlyTracker.Track(e.Thing,e.DamageSource); - if ( e.Thing.bBOSS ) + if ( e.Thing.bBOSS || e.Thing.FindInventory("BossMarker") ) { let tk = e.Thing.FindInventory("DeepImpactOnlyToken"); if ( !tk ) @@ -141,7 +141,7 @@ extend Class SWWMHandler { if ( e.Thing.IsFriend(e.DamageSource) ) lastcombat = AddOneliner("friendhit",1,10); - else if ( (!lastcombat || (gametic > lastcombat+100)) && !Random[DemoLines](0,e.DamageSource.bBOSS?2:4) && !SWWMHDoomHandler.IsCuteGirl(e.DamageSource) ) // [HDoom] don't shout at the girls + else if ( (!lastcombat || (gametic > lastcombat+100)) && !Random[DemoLines](0,(e.DamageSource.bBOSS||e.DamageSource.FindInventory("BossMarker"))?2:4) && !SWWMHDoomHandler.IsCuteGirl(e.DamageSource) ) // [HDoom] don't shout at the girls lastcombat = AddOneliner("gethit",1,15); } highesttic = gametic; @@ -180,7 +180,7 @@ extend Class SWWMHandler { if ( e.Thing.IsFriend(src) ) lastcombat = AddOneliner("friendkill",1,5); - else if ( (!lastcombat || (gametic > lastcombat+100)) && !Random[DemoLines](0,e.Thing.bBOSS?2:5) && !SWWMHDoomHandler.IsCuteGirl(e.Thing) ) // [HDoom] don't shout at the girls + else if ( (!lastcombat || (gametic > lastcombat+100)) && !Random[DemoLines](0,(e.Thing.bBOSS||e.Thing.FindInventory("BossMarker"))?2:5) && !SWWMHDoomHandler.IsCuteGirl(e.Thing) ) // [HDoom] don't shout at the girls lastcombat = AddOneliner("scorekill",1,15); } } @@ -188,7 +188,7 @@ extend Class SWWMHandler // achievement stuff if ( e.Thing.IsHostile(src) ) { - if ( e.Thing.bBOSS && ((e.DamageType == 'Dash') || (e.DamageType == 'Buttslam')) ) + if ( (e.Thing.bBOSS||e.Thing.FindInventory("BossMarker")) && ((e.DamageType == 'Dash') || (e.DamageType == 'Buttslam')) ) SWWMUtility.AchievementProgressInc("bossdash",1,src.player); if ( e.DamageType == 'Push' ) SWWMUtility.AchievementProgressInc("sneeze",1,src.player); @@ -334,7 +334,7 @@ extend Class SWWMHandler scr.xcnt = ++ofs; } } - if ( e.Thing.bBOSS ) + if ( e.Thing.bBOSS || e.Thing.FindInventory("BossMarker") ) { score += 2000; if ( scr ) diff --git a/zscript/handler/swwm_handler_vanillaboss.zsc b/zscript/handler/swwm_handler_vanillaboss.zsc index aaab3c2a6..05c0d06e5 100644 --- a/zscript/handler/swwm_handler_vanillaboss.zsc +++ b/zscript/handler/swwm_handler_vanillaboss.zsc @@ -1,6 +1,7 @@ // vanilla boss stuff Class EndgameBossMarker : Inventory {} +Class BossMarker : Inventory {} extend Class SWWMHandler { @@ -116,6 +117,7 @@ extend Class SWWMHandler bossactors.Push(e.Thing); if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 3; if ( trk ) trk.bBOSS = true; + e.Thing.GiveInventory('BossMarker',1); } bosstag = "$BT_BRUISERS"; } @@ -126,6 +128,7 @@ extend Class SWWMHandler bossactors.Push(e.Thing); if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 5; if ( trk ) trk.bBOSS = true; + e.Thing.GiveInventory('BossMarker',1); } bosstag = "$BT_CYBIE"; } @@ -136,6 +139,7 @@ extend Class SWWMHandler bossactors.Push(e.Thing); if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 6; if ( trk ) trk.bBOSS = true; + e.Thing.GiveInventory('BossMarker',1); e.Thing.GiveInventory('EndgameBossMarker',1); } bosstag = "$BT_SPIDER"; @@ -147,6 +151,7 @@ extend Class SWWMHandler bossactors.Push(e.Thing); if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 4; if ( trk ) trk.bBOSS = true; + e.Thing.GiveInventory('BossMarker',1); } bosstag = "$BT_SPIDER2"; } @@ -157,6 +162,7 @@ extend Class SWWMHandler bossactors.Push(e.Thing); if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 2; if ( trk ) trk.bBOSS = true; + e.Thing.GiveInventory('BossMarker',1); } bosstag = "$BT_DIMPLE"; } @@ -168,6 +174,7 @@ extend Class SWWMHandler bossactors.Push(e.Thing); if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 40; // goodbye, instakills if ( trk ) trk.bBOSS = true; + e.Thing.GiveInventory('BossMarker',1); e.Thing.GiveInventory('EndgameBossMarker',1); } if ( e.Thing is 'BossEye' ) @@ -181,6 +188,7 @@ extend Class SWWMHandler bossactors.Push(e.Thing); if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 4; if ( trk ) trk.bBOSS = true; + e.Thing.GiveInventory('BossMarker',1); } bosstag = "$BT_CYBIE2"; } @@ -191,6 +199,7 @@ extend Class SWWMHandler bossactors.Push(e.Thing); if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 4; if ( trk ) trk.bBOSS = true; + e.Thing.GiveInventory('BossMarker',1); } bosstag = "$BT_LICHES"; } @@ -201,6 +210,7 @@ extend Class SWWMHandler bossactors.Push(e.Thing); if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 3; if ( trk ) trk.bBOSS = true; + e.Thing.GiveInventory('BossMarker',1); } bosstag = "$BT_MINOTAUR"; } @@ -212,6 +222,7 @@ extend Class SWWMHandler if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 2; if ( trk ) trk.bBOSS = true; bosstag = "$BT_DSPARIL"; + e.Thing.GiveInventory('BossMarker',1); e.Thing.GiveInventory('EndgameBossMarker',1); } else if ( e.Thing is 'Sorcerer2' ) @@ -223,6 +234,7 @@ extend Class SWWMHandler if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 8; if ( trk ) trk.bBOSS = true; bosstag = "$BT_DSPARIL2"; + e.Thing.GiveInventory('BossMarker',1); e.Thing.GiveInventory('EndgameBossMarker',1); } } @@ -234,6 +246,7 @@ extend Class SWWMHandler if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 2; if ( trk ) trk.bBOSS = true; bosstag = "$BT_CLERIC"; + e.Thing.GiveInventory('BossMarker',1); } } else if ( bossmap == MAP_HMAP36 ) @@ -244,6 +257,7 @@ extend Class SWWMHandler if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 2; if ( trk ) trk.bBOSS = true; bosstag = "$BT_FIGHTER"; + e.Thing.GiveInventory('BossMarker',1); } } else if ( bossmap == MAP_HMAP37 ) @@ -254,6 +268,7 @@ extend Class SWWMHandler if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 2; if ( trk ) trk.bBOSS = true; bosstag = "$BT_MAGE"; + e.Thing.GiveInventory('BossMarker',1); } } else if ( bossmap == MAP_HMAP12 ) @@ -264,6 +279,7 @@ extend Class SWWMHandler if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 4; if ( trk ) trk.bBOSS = true; bosstag = "$BT_DRAGON"; + e.Thing.GiveInventory('BossMarker',1); } } else if ( bossmap == MAP_HMAP23_HMAP27_HMAP48_HMAP55 ) @@ -274,6 +290,7 @@ extend Class SWWMHandler if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 8; if ( trk ) trk.bBOSS = true; bosstag = "$BT_HERESIARCH"; + e.Thing.GiveInventory('BossMarker',1); } } else if ( bossmap == MAP_HMAP40 ) @@ -284,6 +301,7 @@ extend Class SWWMHandler if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 10; if ( trk ) trk.bBOSS = true; bosstag = "$BT_KORAX"; + e.Thing.GiveInventory('BossMarker',1); e.Thing.GiveInventory('EndgameBossMarker',1); } } @@ -296,6 +314,7 @@ extend Class SWWMHandler if ( trk ) trk.bBOSS = true; bosstag = "$BT_DEATHKINGS"; initialized = true; // healthbar shows from the start + e.Thing.GiveInventory('BossMarker',1); e.Thing.GiveInventory('EndgameBossMarker',1); } } @@ -307,6 +326,7 @@ extend Class SWWMHandler if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 5; if ( trk ) trk.bBOSS = true; bosstag = "$BT_ARCHANGELUS"; + e.Thing.GiveInventory('BossMarker',1); e.Thing.GiveInventory('EndgameBossMarker',1); } else if ( e.Thing.GetClassName() == "ArchangelusB" ) @@ -318,6 +338,7 @@ extend Class SWWMHandler if ( upgrademe ) e.Thing.StartHealth = e.Thing.Health *= 5; if ( trk ) trk.bBOSS = true; bosstag = "$BT_ARCHANGELUS"; + e.Thing.GiveInventory('BossMarker',1); e.Thing.GiveInventory('EndgameBossMarker',1); doextramsg = true; } diff --git a/zscript/handler/swwm_handler_worldload.zsc b/zscript/handler/swwm_handler_worldload.zsc index 12ebfe993..b31be9ca4 100644 --- a/zscript/handler/swwm_handler_worldload.zsc +++ b/zscript/handler/swwm_handler_worldload.zsc @@ -65,10 +65,12 @@ extend Class SWWMHandler int csiz = s.clustervisit.Size(); if ( csiz == 0 ) { + s.clustervisit.Push(clust); s.secretdone.Push(secret); } else if ( s.clustervisit[csiz-1] != clust ) { + s.clustervisit.Push(clust); s.secretdone.Push(secret|s.secretdone[csiz-1]); } s.AddLevelStats(); diff --git a/zscript/handler/swwm_handler_worldthings.zsc b/zscript/handler/swwm_handler_worldthings.zsc index 0d832b960..4b4973b7d 100644 --- a/zscript/handler/swwm_handler_worldthings.zsc +++ b/zscript/handler/swwm_handler_worldthings.zsc @@ -77,7 +77,7 @@ extend Class SWWMHandler override void WorldThingDied( WorldEvent e ) { if ( profiling ) curms = MSTime(); - if ( e.Thing.default.bISMONSTER && ((e.Thing.default.bBOSS) || (e.Thing.GetSpawnHealth() >= 1000)) && (alreadygold.Find(e.Thing) == alreadygold.Size()) ) + if ( e.Thing.default.bISMONSTER && ((e.Thing.default.bBOSS) || (e.Thing.GetSpawnHealth() >= 1000) || e.Thing.FindInventory("BossMarker")) && (alreadygold.Find(e.Thing) == alreadygold.Size()) ) { // make sure we can't farm drops from revivable enemies // (or cause some things to spam-spawn gold shells) diff --git a/zscript/handler/swwm_handler_worldtick.zsc b/zscript/handler/swwm_handler_worldtick.zsc index f8c331636..61f5d20b1 100644 --- a/zscript/handler/swwm_handler_worldtick.zsc +++ b/zscript/handler/swwm_handler_worldtick.zsc @@ -251,7 +251,7 @@ extend Class SWWMHandler continue; if ( !thesight && !(deathmatch && (a is 'Inventory') && !a.bDROPPED) && !(a.IsFriend(players[consoleplayer].mo) && !(a.player && (a.player.mo != a))) && !players[consoleplayer].Camera.CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; - if ( a.bKILLED || (a.Health <= 0) ) + if ( a.bKILLED || (a.Health <= 0) || a.bUnmorphed ) continue; if ( (a is 'Inventory') && (!a.bSPECIAL || Inventory(a).Owner) ) continue; @@ -307,7 +307,7 @@ extend Class SWWMHandler continue; if ( !thesight && !(deathmatch && (a is 'Inventory') && !a.bDROPPED) && !a.IsFriend(players[consoleplayer].mo) && !players[consoleplayer].Camera.CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; - if ( a.bKILLED || (a.Health <= 0) ) + if ( a.bKILLED || (a.Health <= 0) || a.bUnmorphed ) continue; if ( (a is 'Inventory') && (!a.bSPECIAL || Inventory(a).Owner) ) continue; @@ -353,7 +353,8 @@ extend Class SWWMHandler if ( (trk.target.bKILLED || (trk.target.Health <= 0)) || ((trk.target is 'Inventory') && (!trk.target.bSPECIAL || Inventory(trk.target).Owner)) || ((trk.target is 'Chancebox') && (trk.target.CurState != trk.target.SpawnState)) - || (trk.target.default.bMISSILE && !trk.target.bMISSILE) ) + || (trk.target.default.bMISSILE && !trk.target.bMISSILE) + || trk.target.bUnmorphed ) trk.Update(); } // prune expired trackers 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; } } diff --git a/zscript/items/swwm_powerups.zsc b/zscript/items/swwm_powerups.zsc index 2360fb0f0..9b2208abe 100644 --- a/zscript/items/swwm_powerups.zsc +++ b/zscript/items/swwm_powerups.zsc @@ -2345,7 +2345,7 @@ Class MykradvoTendril : Actor { if ( t.hitlist[i].hitactor.IsFriend(target) ) continue; if ( (t.hitlist[i].hitactor == tracer) && bMISSILEMORE ) bMISSILEEVENMORE = true; // we split - int dmg = t.hitlist[i].hitactor.bBOSS?(GetMissileDamage(0,0)*4):max(t.hitlist[i].hitactor.Health,GetMissileDamage(0,0)); + int dmg = (t.hitlist[i].hitactor.bBOSS||t.hitlist[i].hitactor.FindInventory("BossMarker"))?(GetMissileDamage(0,0)*4):max(t.hitlist[i].hitactor.Health,GetMissileDamage(0,0)); SWWMUtility.DoKnockback(t.hitlist[i].hitactor,-t.hitlist[i].x+(0,0,.5),((t.hitlist[i].hitactor.Health-dmg)<=0)?60000:8000); t.hitlist[i].hitactor.DamageMobj(self,target,dmg,'Plasma',DMG_THRUSTLESS); if ( t.hitlist[i].hitactor && t.hitlist[i].hitactor.bISMONSTER && !Random[Mykradvo](0,3) ) @@ -2353,7 +2353,7 @@ Class MykradvoTendril : Actor } } invoker.nextpos = level.Vec3Offset(pos,x*speed); - if ( !bSTANDSTILL && (!tracer || !tracer.bSHOOTABLE || (tracer.Health <= 0) || (tracer.bBOSS && !bMISSILEMORE)) ) + if ( !bSTANDSTILL && (!tracer || !tracer.bSHOOTABLE || (tracer.Health <= 0) || ((tracer.bBOSS || tracer.FindInventory("BossMarker")) && !bMISSILEMORE)) ) { ReactionTime--; if ( ReactionTime <= 0 ) @@ -2396,7 +2396,7 @@ Class MykradvoTendril : Actor r.pitch = asin(-sdir.z); r.target = target; r.tracer = tracer; - if ( tracer && tracer.bBOSS ) r.ReactionTime -= Random[ExploS](5,15); + if ( tracer && (tracer.bBOSS || tracer.FindInventory("BossMarker")) ) r.ReactionTime -= Random[ExploS](5,15); else r.ReactionTime += Random[ExploS](0,20); } return; @@ -2850,7 +2850,7 @@ Class Mykradvo : Inventory Amount++; return true; } - if ( (targets.Size() == 1) && targets[0] && !targets[0].bBOSS ) + if ( (targets.Size() == 1) && targets[0] && !targets[0].bBOSS && !targets[0].FindInventory("BossMarker") ) SWWMUtility.MarkAchievement("anone",Owner.player); let p = Spawn("MykradvoBurst",spawnpos); p.target = Owner; @@ -3500,7 +3500,6 @@ Class DivineSpriteEffect : Inventory { Inventory.Icon "graphics/HUD/Icons/I_Divine.png"; DivineSpriteEffect.HealTimer 1750; - Inventory.InterHubAmount 0; +INVENTORY.UNDROPPABLE; +INVENTORY.UNTOSSABLE; } @@ -3518,6 +3517,12 @@ Class DivineSpriteEffect : Inventory return Color(int(64*alph),255,255,255); } + override void Travelled() + { + Super.Travelled(); + bHealDone = true; + } + override void DoEffect() { Super.DoEffect(); diff --git a/zscript/swwm_player.zsc b/zscript/swwm_player.zsc index dbf88c83d..1ae0118da 100644 --- a/zscript/swwm_player.zsc +++ b/zscript/swwm_player.zsc @@ -896,7 +896,7 @@ Class Demolitionist : PlayerPawn if ( player.onground && (player.jumptics < -18) ) player.jumptics = 0; } - if ( player.playerstate != PST_DEAD ) + if ( (player.playerstate != PST_DEAD) && !ReactionTime ) { // quick grenade if ( player.cmd.buttons&BT_USER4 ) diff --git a/zscript/swwm_thinkers_hud.zsc b/zscript/swwm_thinkers_hud.zsc index cb11aac64..bd78a35c9 100644 --- a/zscript/swwm_thinkers_hud.zsc +++ b/zscript/swwm_thinkers_hud.zsc @@ -285,6 +285,8 @@ Class SWWMCombatTracker : Thinker int mxdist, dbar; bool bBOSS, bFRIENDLY; bool firsthit; + bool bUpdateMorph; + String unmorphedtag; void UpdateTag() { @@ -405,6 +407,12 @@ Class SWWMCombatTracker : Thinker pos = level.Vec3Offset(mytarget.pos,(0,0,height)); prevpos = level.Vec3Offset(mytarget.prev,(0,0,height)); } + if ( bUpdateMorph && !(mytarget is 'MorphedMonster') ) + { + // reset our tag + mytag = unmorphedtag; + bUpdateMorph = false; + } tcnt++; if ( (tcnt == 1) && !mytarget.player ) { @@ -414,6 +422,21 @@ Class SWWMCombatTracker : Thinker maxhealth = lasthealth; intp.Reset(lasthealth); } + // post-spawn morph check + if ( (mytarget is 'MorphedMonster') && MorphedMonster(mytarget).UnmorphedMe ) + { + // look for a previous tracker that has the same target as us + for ( SWWMCombatTracker t=next; t; t=t.next ) + { + if ( t.mytarget != mytarget ) continue; + // change its tag and destroy ourselves (such is life) + t.bUpdateMorph = true; + t.unmorphedtag = t.mytag; + t.mytag = String.Format("%s (%s)",mytag,t.unmorphedtag); + Destroy(); + return; + } + } } if ( (tcnt == 6) && !mytarget.player ) { @@ -547,7 +570,7 @@ Class SWWMSimpleTracker : Thinker } else if ( ismonster ) { - expired = target.bKILLED; + expired = target.bKILLED||target.bUnmorphed; if ( !expired ) { lastupdate += 35; diff --git a/zscript/weapons/swwm_deathlydeathcannon_fx.zsc b/zscript/weapons/swwm_deathlydeathcannon_fx.zsc index 409ff3dd4..00891eef7 100644 --- a/zscript/weapons/swwm_deathlydeathcannon_fx.zsc +++ b/zscript/weapons/swwm_deathlydeathcannon_fx.zsc @@ -518,7 +518,7 @@ Class YnykronImpact : Actor if ( t && YnykronShot(master) ) { YnykronShot(master).hitlist.Push(t); - if ( t.bBOSS ) YnykronShot(master).hitboss = true; + if ( t.bBOSS || t.FindInventory("BossMarker") ) YnykronShot(master).hitboss = true; } // spawn blast that will propagate let b = Spawn("YnykronDelayedImpact",t.pos); @@ -705,7 +705,7 @@ Class YnykronBeam : Actor if ( t.hitlist[i].hitactor && YnykronShot(master) ) { YnykronShot(master).hitlist.Push(t.hitlist[i].hitactor); - if ( t.hitlist[i].hitactor.bBOSS ) YnykronShot(master).hitboss = true; + if ( t.hitlist[i].hitactor.bBOSS || t.hitlist[i].hitactor.FindInventory("BossMarker") ) YnykronShot(master).hitboss = true; } // spawn blast that will propagate let b = Spawn("YnykronImpact",t.hitlist[i].hitlocation); @@ -805,7 +805,7 @@ Class YnykronBeam : Actor if ( it.hitlist[i].hitactor && YnykronShot(master) ) { YnykronShot(master).hitlist.Push(it.hitlist[i].hitactor); - if ( it.hitlist[i].hitactor.bBOSS ) YnykronShot(master).hitboss = true; + if ( it.hitlist[i].hitactor.bBOSS || it.hitlist[i].hitactor.FindInventory("BossMarker") ) YnykronShot(master).hitboss = true; } // spawn blast that will propagate let b = Spawn("YnykronImpact",it.hitlist[i].hitlocation); diff --git a/zscript/weapons/swwm_deepdarkimpact_fx.zsc b/zscript/weapons/swwm_deepdarkimpact_fx.zsc index 0f493504f..4f56910ae 100644 --- a/zscript/weapons/swwm_deepdarkimpact_fx.zsc +++ b/zscript/weapons/swwm_deepdarkimpact_fx.zsc @@ -24,7 +24,7 @@ Class AirBullet : FastProjectile } override int DoSpecialDamage( Actor target, int damage, Name damagetype ) { - if ( target.bBOSS ) damage = int(damage*.4); + if ( target.bBOSS || target.FindInventory("BossMarker") ) damage = int(damage*.4); if ( !bAMBUSH ) { if ( target == lasthit ) return 0; diff --git a/zscript/weapons/swwm_jackhammer.zsc b/zscript/weapons/swwm_jackhammer.zsc index 6754070a6..5d18234d8 100644 --- a/zscript/weapons/swwm_jackhammer.zsc +++ b/zscript/weapons/swwm_jackhammer.zsc @@ -185,6 +185,7 @@ Class PusherWeapon : SWWMWeapon { // didn't hit anything, randomly slip off player.SetPSprite(PSP_WEAPON,ResolveState("AltMiss")); + invoker.bNODEATHDESELECT = true; // prevent any glitching that could happen if the sequence is interrupted A_StopSound(CHAN_WEAPON); A_StopSound(CHAN_WEAPONEXTRA); A_StartSound("pusher/miss",CHAN_WEAPON,CHANF_OVERLAP); @@ -357,18 +358,16 @@ Class PusherWeapon : SWWMWeapon XZW3 QRSTUVW 1; TNT1 A -1 { - if ( player.PendingWeapon != WP_NOCHANGE ) + invoker.bNODEATHDESELECT = false; + let nw = player.mo.PickNextWeapon(); + // gross hack (don't prioritize Deep Impact if we have something better than it) + if ( nw is 'DeepImpact' ) { - let nw = player.mo.PickNextWeapon(); - // gross hack (don't prioritize Deep Impact if we have something better than it) - if ( nw is 'DeepImpact' ) - { - player.ReadyWeapon = nw; - nw = player.mo.PickNextWeapon(); - player.ReadyWeapon = invoker; - } - if ( nw != invoker ) player.PendingWeapon = nw; + player.ReadyWeapon = nw; + nw = player.mo.PickNextWeapon(); + player.ReadyWeapon = invoker; } + if ( nw != invoker ) player.PendingWeapon = nw; RemoveInventory(invoker); invoker.Destroy(); } diff --git a/zscript/weapons/swwm_shot_fx.zsc b/zscript/weapons/swwm_shot_fx.zsc index f662ed9bc..3d2e0e048 100644 --- a/zscript/weapons/swwm_shot_fx.zsc +++ b/zscript/weapons/swwm_shot_fx.zsc @@ -1220,7 +1220,7 @@ Class TheBall : Actor } if ( crit ) SWWMUtility.DoExplosion(self,dmg/2,25000,150,80,ignoreme:target); - if ( crit && victim && (victim.Health <= 0) && victim.bBOSS && target ) + if ( crit && victim && (victim.Health <= 0) && (victim.bBOSS || victim.FindInventory("BossMarker")) && target ) SWWMUtility.MarkAchievement("clonk",target.player); // only rip shootables if ( (slamforce > girth) && is_schutt ) diff --git a/zscript/weapons/swwm_tastytreat.zsc b/zscript/weapons/swwm_tastytreat.zsc index 61e541531..ff30e5d38 100644 --- a/zscript/weapons/swwm_tastytreat.zsc +++ b/zscript/weapons/swwm_tastytreat.zsc @@ -85,6 +85,7 @@ Class CandyGun : SWWMWeapon override void DrawWeapon( double TicFrac, double bx, double by, Vector2 hs, Vector2 ss ) { + if ( Amount <= 0 ) return; if ( !WeaponBox ) WeaponBox = TexMan.CheckForTexture("graphics/HUD/CandygunDisplay.png",TexMan.Type_Any); if ( !TewiFont ) TewiFont = Font.GetFont('TewiShaded'); Screen.DrawTexture(WeaponBox,false,bx-51,by-44,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); @@ -215,8 +216,12 @@ Class CandyGun : SWWMWeapon { let weap = Weapon(invoker); if ( !weap ) return; + invoker.bNODEATHDESELECT = true; // prevent any glitching that could happen if the sequence is interrupted if ( !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) ) + { + if ( weap.Ammo2.Amount <= 0 ) weap.Amount = 0; weap.Ammo2.Amount = max(0,weap.Ammo2.Amount-1); + } Vector3 x, y, z, x2, y2, z2; [x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll); Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x-2*y-3*z); @@ -287,6 +292,7 @@ Class CandyGun : SWWMWeapon override bool CheckAmmo( int fireMode, bool autoSwitch, bool requireAmmo, int ammocount ) { if ( sv_infiniteammo || Owner.FindInventory('PowerInfiniteAmmo',true) ) return true; + if ( Amount <= 0 ) return false; if ( fireMode == PrimaryFire ) return (chambered || (clipcount > 0) || (Ammo1.Amount > 0) || (Owner.CountInv("CandyGunBullets") > 0)); if ( fireMode == AltFire ) return ((Ammo1.Amount > 0) || (Owner.CountInv("CandyGunBullets") > 0)); return Super.CheckAmmo(firemode,autoswitch,requireammo,ammocount); @@ -294,6 +300,7 @@ Class CandyGun : SWWMWeapon override bool ReportHUDAmmo() { + if ( Amount <= 0 ) return false; if ( chambered || (clipcount > 0) || (Owner.CountInv("CandyGunBullets") > 0) ) return true; if ( Ammo1.Amount <= 0 ) return false; return Super.ReportHUDAmmo(); @@ -388,9 +395,14 @@ Class CandyGun : SWWMWeapon int flg = WRF_ALLOWZOOM|WRF_ALLOWUSER1; if ( sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) || (invoker.Ammo1.Amount > 0) || invoker.chambered ) flg |= WRF_ALLOWRELOAD; if ( (invoker.Ammo1.Amount <= 0) && (CountInv("CandyGunBullets") <= 0) && !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) ) flg |= WRF_NOSECONDARY; - A_WeaponReady(flg); - if ( player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK) ) - invoker.CheckAmmo(EitherFire,true); + if ( (flg&WRF_NOSECONDARY) && (player.cmd.buttons&BT_ATTACK) && (player.cmd.buttons&BT_ALTATTACK) ) + player.SetPSprite(PSP_WEAPON,ResolveState("SpecialFirePre")); + else + { + A_WeaponReady(flg); + if ( player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK) ) + invoker.CheckAmmo(EitherFire,true); + } } } Wait; @@ -500,7 +512,7 @@ Class CandyGun : SWWMWeapon XZW5 Q 1; XZW5 R 1 { - if ( player.cmd.buttons&BT_ATTACK && ((((invoker.Ammo1.Amount > 0) || (CountInv("CandyGunBullets") > 0)) && (invoker.Ammo2.Amount > 0)) || sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true)) ) + if ( player.cmd.buttons&BT_ATTACK ) player.SetPSprite(PSP_WEAPON,ResolveState("SpecialFire")); } XZW5 STUVWXYZ 1; @@ -527,6 +539,12 @@ Class CandyGun : SWWMWeapon XZW6 XY 2; XZW6 Z 4; Goto ReloadEnd; + SpecialFirePre: + XZW2 A 2 A_PlayerReload(); + XZW5 NO 2; + XZW5 P 1 A_StartSound("explodium/magpin",CHAN_WEAPON,CHANF_OVERLAP); + XZW5 QR 1; + Goto SpecialFire+1; SpecialFire: #### # 1; XZWA Z 1; @@ -539,25 +557,42 @@ Class CandyGun : SWWMWeapon XZWB EFGHIJKLMNOPQR 1; XZWB S 1 A_ThrowGun(); XZWB TUVWXYZ 2; - XZW1 B 0 + XZW1 B -1 { - invoker.PlayUpSound(self); - if ( sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) ) - invoker.clipcount = invoker.default.clipcount; - else if ( invoker.Ammo1.Amount <= 0 ) + invoker.bNODEATHDESELECT = false; + if ( (invoker.Amount > 0) && (invoker.Ammo2.Amount >= 0) ) { - MagAmmo sb = MagAmmo(FindInventory("CandyGunBullets")); - int takeamt = min(sb.Amount,sb.ClipSize); - invoker.clipcount = takeamt; - sb.Amount -= takeamt; + if ( sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) ) + invoker.clipcount = invoker.default.clipcount; + else if ( invoker.Ammo1.Amount <= 0 ) + { + MagAmmo sb = MagAmmo(FindInventory("CandyGunBullets")); + int takeamt = min(sb.Amount,sb.ClipSize); + invoker.clipcount = takeamt; + sb.Amount -= takeamt; + } + else + { + invoker.Ammo1.Amount = max(0,invoker.Ammo1.Amount-1); + invoker.clipcount = invoker.default.clipcount; + } } - else + if ( invoker.clipcount > 0 ) { - invoker.Ammo1.Amount = max(0,invoker.Ammo1.Amount-1); - invoker.clipcount = invoker.default.clipcount; + invoker.PlayUpSound(self); + return ResolveState("Select"); } + let nw = player.mo.PickPrevWeapon(); + if ( nw != invoker ) player.PendingWeapon = nw; + if ( invoker.Amount <= 0 ) + { + RemoveInventory(invoker); + invoker.Destroy(); + } + else A_FullLower(); // this works + return ResolveState(null); } - Goto Select; + Stop; Reload: XZW2 A 1 {