From 30730647fecf342086b9165e5678e23ea1cfb252 Mon Sep 17 00:00:00 2001 From: Boondorl Date: Mon, 1 Jan 2024 01:31:25 -0500 Subject: [PATCH] Fixed inconsistencies between player and monster morphing The Tome of Power and Chaos Device will now work on non-players. The STAYMORPHED flag will now work on players. --- src/playsim/p_interaction.cpp | 2 +- .../actors/heretic/hereticartifacts.zs | 32 +++--- wadsrc/static/zscript/actors/morph.zs | 103 ++++++++++++------ .../zscript/actors/player/player_morph.zs | 13 ++- .../static/zscript/actors/raven/artitele.zs | 43 ++++---- 5 files changed, 116 insertions(+), 77 deletions(-) diff --git a/src/playsim/p_interaction.cpp b/src/playsim/p_interaction.cpp index ee35e71d2..00ef947b6 100644 --- a/src/playsim/p_interaction.cpp +++ b/src/playsim/p_interaction.cpp @@ -330,7 +330,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf VMCall(func, params, 1, nullptr, 0); // Always kill the dummy Actor if it didn't unmorph, otherwise checking the morph flags. - if (realMo != nullptr && (alternative != nullptr || !(morphStyle & MORPH_UNDOBYDEATHSAVES))) + if (realMo != nullptr && (!(morphStyle & MORPH_UNDOBYDEATH) || !(morphStyle & MORPH_UNDOBYDEATHSAVES))) { if (wasgibbed) { diff --git a/wadsrc/static/zscript/actors/heretic/hereticartifacts.zs b/wadsrc/static/zscript/actors/heretic/hereticartifacts.zs index 3ea8c7a48..e52ca5041 100644 --- a/wadsrc/static/zscript/actors/heretic/hereticartifacts.zs +++ b/wadsrc/static/zscript/actors/heretic/hereticartifacts.zs @@ -66,28 +66,26 @@ Class ArtiTomeOfPower : PowerupGiver Loop; } - override bool Use (bool pickup) + override bool Use(bool pickup) { - Playerinfo p = Owner.player; - if (p && p.morphTics && (p.MorphStyle & MRF_UNDOBYTOMEOFPOWER)) - { // Attempt to undo chicken - if (!p.mo.Unmorph (p.mo, MRF_UNDOBYTOMEOFPOWER)) - { // Failed - if (!(p.MorphStyle & MRF_FAILNOTELEFRAG)) - { - Owner.DamageMobj (null, null, TELEFRAG_DAMAGE, 'Telefrag'); - } + EMorphFlags mStyle = Owner.player ? Owner.player.MorphStyle : Owner.MorphFlags; + if (Owner.Alternative && (mStyle & MRF_UNDOBYTOMEOFPOWER)) + { + // Attempt to undo chicken. + if (!Owner.Unmorph(Owner, MRF_UNDOBYTOMEOFPOWER)) + { + if (!(mStyle & MRF_FAILNOTELEFRAG)) + Owner.DamageMobj(null, null, TELEFRAG_DAMAGE, 'Telefrag'); } - else - { // Succeeded - Owner.A_StartSound ("*evillaugh", CHAN_VOICE); + else if (Owner.player) + { + Owner.A_StartSound("*evillaugh", CHAN_VOICE); } + return true; } - else - { - return Super.Use (pickup); - } + + return Super.Use(pickup); } } diff --git a/wadsrc/static/zscript/actors/morph.zs b/wadsrc/static/zscript/actors/morph.zs index b3a6c4086..6a418714a 100644 --- a/wadsrc/static/zscript/actors/morph.zs +++ b/wadsrc/static/zscript/actors/morph.zs @@ -40,8 +40,9 @@ extend class Actor // when a morphed Actor dies. virtual Actor, int, int MorphedDeath() { - if (MorphFlags & MRF_UNDOBYDEATH) - Unmorph(self, force: MorphFlags & MRF_UNDOBYDEATHFORCED); + EMorphFlags mStyle = player ? player.MorphStyle : MorphFlags; + if (mStyle & MRF_UNDOBYDEATH) + Unmorph(self, force: mStyle & MRF_UNDOBYDEATHFORCED); return null, 0, 0; } @@ -106,7 +107,7 @@ extend class Actor virtual bool MorphMonster(class spawnType, int duration, EMorphFlags style, class enterFlash = "TeleportFog", class exitFlash = "TeleportFog") { - if (player || !spawnType || bDontMorph || !bIsMonster) + if (player || !bIsMonster || !spawnType || bDontMorph || Health <= 0 || spawnType == GetClass()) return false; Actor morphed = Spawn(spawnType, Pos, ALLOW_REPLACE); @@ -130,13 +131,30 @@ extend class Actor morphed.bShadow |= bShadow; morphed.bGhost |= bGhost; morphed.Score = Score; - morphed.ChangeTID(TID); morphed.Special = Special; for (int i; i < 5; ++i) morphed.Args[i] = Args[i]; + if (TID && (style & MRF_NEWTIDBEHAVIOUR)) + { + morphed.ChangeTID(TID); + ChangeTID(0); + } + + morphed.Tracer = Tracer; + morphed.Master = Master; morphed.CopyFriendliness(self, true); + // Remove all armor. + for (Inventory item = morphed.Inv; item;) + { + Inventory next = item.Inv; + if (item is "Armor") + item.DepleteOrDestroy(); + + item = next; + } + morphed.UnmorphTime = Level.Time + (duration ? duration : DEFMORPHTICS) + Random[morphmonst](); morphed.MorphFlags = style; morphed.MorphExitFlash = exitFlash; @@ -147,10 +165,10 @@ extend class Actor if (morphMon) { morphMon.UnmorphedMe = morphMon.Alternative; + morphMon.MorphStyle = morphMon.MorphFlags; morphMon.FlagsSave = morphMon.PremorphProperties; } - ChangeTID(0); Special = 0; bInvisible = true; bSolid = bShootable = false; @@ -178,22 +196,23 @@ extend class Actor virtual bool UndoMonsterMorph(bool force = false) { - if (!UnmorphTime || !Alternative || bStayMorphed || Alternative.bStayMorphed) + if (!Alternative || bStayMorphed || Alternative.bStayMorphed) return false; - Alternative.SetOrigin(Pos, false); + Actor alt = Alternative; + alt.SetOrigin(Pos, false); if (!force && (PremorphProperties & MPROP_SOLID)) { - bool altSolid = Alternative.bSolid; + bool altSolid = alt.bSolid; bool isSolid = bSolid; bool isTouchy = bTouchy; - Alternative.bSolid = true; + alt.bSolid = true; bSolid = bTouchy = false; - bool res = Alternative.TestMobjLocation(); + bool res = alt.TestMobjLocation(); - Alternative.bSolid = altSolid; + alt.bSolid = altSolid; bSolid = isSolid; bTouchy = isTouchy; @@ -205,44 +224,64 @@ extend class Actor } } - Actor unmorphed = Alternative; - if (!MorphInto(unmorphed)) + if (!MorphInto(alt)) return false; - PreUnmorph(unmorphed, false); - unmorphed.PreUnmorph(self, true); + PreUnmorph(alt, false); + alt.PreUnmorph(self, true); - unmorphed.Angle = Angle; - unmorphed.bShadow = bShadow; - unmorphed.bGhost = bGhost; - unmorphed.bSolid = (PremorphProperties & MPROP_SOLID); - unmorphed.bShootable = (PremorphProperties & MPROP_SHOOTABLE); - unmorphed.bInvisible = (PremorphProperties & MPROP_INVIS); - unmorphed.Vel = Vel; - unmorphed.Score = Score; + // Check to see if it had a powerup that caused it to morph. + for (Inventory item = alt.Inv; item;) + { + Inventory next = item.Inv; + if (item is "PowerMorph") + item.Destroy(); - unmorphed.ChangeTID(TID); - unmorphed.Special = Special; + item = next; + } + + alt.Angle = Angle; + alt.bShadow = bShadow; + alt.bGhost = bGhost; + alt.bSolid = (PremorphProperties & MPROP_SOLID); + alt.bShootable = (PremorphProperties & MPROP_SHOOTABLE); + alt.bInvisible = (PremorphProperties & MPROP_INVIS); + alt.Vel = Vel; + alt.Score = Score; + + if (TID && (MorphFlags & MRF_NEWTIDBEHAVIOUR)) + { + alt.ChangeTID(TID); + ChangeTID(0); + } + + alt.Special = Special; for (int i; i < 5; ++i) - unmorphed.Args[i] = Args[i]; + alt.Args[i] = Args[i]; - unmorphed.CopyFriendliness(self, true); + alt.Tracer = Tracer; + alt.Master = Master; + alt.CopyFriendliness(self, true, false); + if (Health > 0 || (MorphFlags & MRF_UNDOBYDEATHSAVES)) + alt.Health = alt.SpawnHealth(); + else + alt.Health = Health; - ChangeTID(0); Special = 0; bInvisible = true; bSolid = bShootable = false; - PostUnmorph(unmorphed, false); // From is false here: Leaving the caller's body. - unmorphed.PostUnmorph(self, true); // True here: Entering this body from here. + PostUnmorph(alt, false); // From is false here: Leaving the caller's body. + alt.PostUnmorph(self, true); // True here: Entering this body from here. if (MorphExitFlash) { - Actor fog = Spawn(MorphExitFlash, unmorphed.Pos.PlusZ(GameInfo.TELEFOGHEIGHT), ALLOW_REPLACE); + Actor fog = Spawn(MorphExitFlash, alt.Pos.PlusZ(GameInfo.TELEFOGHEIGHT), ALLOW_REPLACE); if (fog) - fog.Target = unmorphed; + fog.Target = alt; } + ClearCounters(); Destroy(); return true; } diff --git a/wadsrc/static/zscript/actors/player/player_morph.zs b/wadsrc/static/zscript/actors/player/player_morph.zs index a11878fff..6d28306ed 100644 --- a/wadsrc/static/zscript/actors/player/player_morph.zs +++ b/wadsrc/static/zscript/actors/player/player_morph.zs @@ -97,8 +97,11 @@ extend class PlayerPawn virtual bool MorphPlayer(PlayerInfo activator, class spawnType, int duration, EMorphFlags style, class enterFlash = "TeleportFog", class exitFlash = "TeleportFog") { - if (!spawnType || bDontMorph || player.Health <= 0 || (bInvulnerable && (player != activator || !(style & MRF_WHENINVULNERABLE)))) + if (!player || !spawnType || bDontMorph || player.Health <= 0 + || (bInvulnerable && (player != activator || !(style & MRF_WHENINVULNERABLE)))) + { return false; + } if (!duration) duration = DEFMORPHTICS; @@ -210,7 +213,7 @@ extend class PlayerPawn virtual bool UndoPlayerMorph(PlayerInfo activator, EMorphFlags unmorphFlags = 0, bool force = false) { - if (!Alternative) + if (!Alternative || bStayMorphed || Alternative.bStayMorphed) return false; if (bInvulnerable @@ -222,18 +225,20 @@ extend class PlayerPawn let alt = PlayerPawn(Alternative); alt.SetOrigin(Pos, false); // Test if there's room to unmorph. - if (!force && (special2 & MPROP_SOLID)) + if (!force && (PremorphProperties & MPROP_SOLID)) { bool altSolid = alt.bSolid; bool isSolid = bSolid; + bool isTouchy = bTouchy; alt.bSolid = true; - bSolid = false; + bSolid = bTouchy = false; bool res = alt.TestMobjLocation(); alt.bSolid = altSolid; bSolid = isSolid; + bTouchy = isTouchy; if (!res) { diff --git a/wadsrc/static/zscript/actors/raven/artitele.zs b/wadsrc/static/zscript/actors/raven/artitele.zs index 38ead5837..fcbb499c8 100644 --- a/wadsrc/static/zscript/actors/raven/artitele.zs +++ b/wadsrc/static/zscript/actors/raven/artitele.zs @@ -23,35 +23,32 @@ class ArtiTeleport : Inventory Loop; } - override bool Use (bool pickup) + override bool Use(bool pickup) { Vector3 dest; - int destAngle; - + double destAngle; if (deathmatch) - { - [dest, destAngle] = level.PickDeathmatchStart(); - } + [dest, destAngle] = Level.PickDeathmatchStart(); else - { - [dest, destAngle] = level.PickPlayerStart(Owner.PlayerNumber()); - } - if (!level.useplayerstartz) + [dest, destAngle] = Level.PickPlayerStart(Owner.PlayerNumber()); + + if (!Level.UsePlayerStartZ) dest.Z = ONFLOORZ; - Owner.Teleport (dest, destAngle, TELF_SOURCEFOG | TELF_DESTFOG); - bool canlaugh = true; - Playerinfo p = Owner.player; - if (p && p.morphTics && (p.MorphStyle & MRF_UNDOBYCHAOSDEVICE)) - { // Teleporting away will undo any morph effects (pig) - if (!p.mo.Unmorph(p.mo, MRF_UNDOBYCHAOSDEVICE) && (p.MorphStyle & MRF_FAILNOLAUGH)) - { - canlaugh = false; - } - } - if (canlaugh) - { // Full volume laugh - Owner.A_StartSound ("*evillaugh", CHAN_VOICE, CHANF_DEFAULT, 1., ATTN_NONE); + + Owner.Teleport(dest, destAngle, TELF_SOURCEFOG | TELF_DESTFOG); + + bool canLaugh = Owner.player != null; + EMorphFlags mStyle = Owner.player ? Owner.player.MorphStyle : Owner.MorphFlags; + if (Owner.Alternative && (mStyle & MRF_UNDOBYCHAOSDEVICE)) + { + // Teleporting away will undo any morph effects (pig). + if (!Owner.Unmorph(Owner, MRF_UNDOBYCHAOSDEVICE) && (mStyle & MRF_FAILNOLAUGH)) + canLaugh = false; } + + if (canLaugh) + Owner.A_StartSound("*evillaugh", CHAN_VOICE, attenuation: ATTN_NONE); + return true; }