diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 2ed4ddf62..7834f92d4 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -626,10 +626,13 @@ public: double plyrdmgfact = Pawn->DamageFactor; Pawn->DamageFactor = 1.; P_DamageMobj (Pawn, Pawn, Pawn, TELEFRAG_DAMAGE, NAME_Suicide); - Pawn->DamageFactor = plyrdmgfact; - if (Pawn->health <= 0) + if (Pawn != nullptr) { - Pawn->flags &= ~MF_SHOOTABLE; + Pawn->DamageFactor = plyrdmgfact; + if (Pawn->health <= 0) + { + Pawn->flags &= ~MF_SHOOTABLE; + } } Destroy(); } diff --git a/src/namedef_custom.h b/src/namedef_custom.h index 0727a4a44..2da881531 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -465,7 +465,6 @@ xx(MonsterClass) xx(MorphedMonster) xx(Wi_NoAutostartMap) -xx(MorphFlags) xx(Duration) xx(MorphStyle) xx(MorphFlash) diff --git a/src/playsim/a_morph.h b/src/playsim/a_morph.h index 00303533c..762cd01bb 100644 --- a/src/playsim/a_morph.h +++ b/src/playsim/a_morph.h @@ -26,6 +26,8 @@ enum MORPH_UNDOBYTIMEOUT = 0x00001000, // Player unmorphs once countdown expires MORPH_UNDOALWAYS = 0x00002000, // Powerups must always unmorph, no matter what. MORPH_TRANSFERTRANSLATION = 0x00004000, // Transfer translation from the original actor to the morphed one + MORPH_KEEPARMOR = 0x00008000, // Don't lose current armor value when morphing. + MORPH_IGNOREINVULN = 0x00010000, // Completely ignore invulnerability status on players. MORPH_STANDARDUNDOING = MORPH_UNDOBYTOMEOFPOWER | MORPH_UNDOBYCHAOSDEVICE | MORPH_UNDOBYTIMEOUT, }; diff --git a/src/playsim/p_interaction.cpp b/src/playsim/p_interaction.cpp index db19107b7..86416f0c3 100644 --- a/src/playsim/p_interaction.cpp +++ b/src/playsim/p_interaction.cpp @@ -324,14 +324,23 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf { // Return values are no longer used to ensure things stay properly managed. AActor* const realMo = alternative; - const int morphStyle = player != nullptr ? player->MorphStyle : IntVar(NAME_MorphFlags); + int morphStyle = 0; VMValue params[] = { this }; + + { + IFVM(Actor, GetMorphStyle) + { + VMReturn ret[] = { &morphStyle }; + VMCall(func, params, 1, ret, 1); + } + } + VMCall(func, params, 1, nullptr, 0); // Kill the dummy Actor if it didn't unmorph, otherwise checking the morph flags. Player pawns need // to stay, otherwise they won't respawn correctly. - if (realMo != nullptr + if (realMo != nullptr && !(realMo->flags6 & MF6_KILLED) && ((alternative != nullptr && player == nullptr) || (alternative == nullptr && !(morphStyle & MORPH_UNDOBYDEATHSAVES)))) { if (wasgibbed) @@ -345,6 +354,11 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf realMo->health = 0; } + // Pass appropriate damage information along when it's confirmed to die. + realMo->DamageTypeReceived = DamageTypeReceived; + realMo->DamageType = DamageType; + realMo->special1 = special1; + realMo->CallDie(source, inflictor, dmgflags, MeansOfDeath); } } diff --git a/wadsrc/static/zscript/actors/morph.zs b/wadsrc/static/zscript/actors/morph.zs index 187471b96..b9fdbb101 100644 --- a/wadsrc/static/zscript/actors/morph.zs +++ b/wadsrc/static/zscript/actors/morph.zs @@ -91,7 +91,7 @@ extend class Actor // when a morphed Actor dies. virtual Actor, int, int MorphedDeath() { - EMorphFlags mStyle = player ? player.MorphStyle : MorphFlags; + EMorphFlags mStyle = GetMorphStyle(); if (mStyle & MRF_UNDOBYDEATH) Unmorph(self, force: mStyle & MRF_UNDOBYDEATHFORCED); diff --git a/wadsrc/static/zscript/actors/player/player_cheat.zs b/wadsrc/static/zscript/actors/player/player_cheat.zs index 40693fbce..c89832dca 100644 --- a/wadsrc/static/zscript/actors/player/player_cheat.zs +++ b/wadsrc/static/zscript/actors/player/player_cheat.zs @@ -426,29 +426,34 @@ extend class PlayerPawn } - virtual String CheatMorph(class morphClass, bool quickundo) + virtual String CheatMorph(class morphClass, bool undo) { - let oldclass = GetClass(); - // Set the standard morph style for the current game - int style = MRF_UNDOBYTOMEOFPOWER; - if (gameinfo.gametype == GAME_Hexen) style |= MRF_UNDOBYCHAOSDEVICE; + EMorphFlags style = MRF_UNDOBYTOMEOFPOWER; + if (GameInfo.GameType == GAME_Hexen) + style |= MRF_UNDOBYCHAOSDEVICE; if (Alternative) { - if (Unmorph (self)) + class cls = GetClass(); + Actor mo = Alternative; + if (!undo || Unmorph(self)) { - if (!quickundo && oldclass != morphclass && Morph(self, morphclass, null, 0, style)) + if ((!undo && Morph(self, morphClass, null, 0, style)) + || (undo && morphClass != cls && mo.Morph(mo, morphClass, null, 0, style))) { return StringTable.Localize("$TXT_STRANGER"); } - return StringTable.Localize("$TXT_NOTSTRANGE"); + + if (undo) + return StringTable.Localize("$TXT_NOTSTRANGE"); } } - else if (Morph (self, morphclass, null, 0, style)) + else if (Morph(self, morphClass, null, 0, style)) { return StringTable.Localize("$TXT_STRANGE"); } + return ""; } diff --git a/wadsrc/static/zscript/actors/player/player_morph.zs b/wadsrc/static/zscript/actors/player/player_morph.zs index 581bd1536..ff84246a1 100644 --- a/wadsrc/static/zscript/actors/player/player_morph.zs +++ b/wadsrc/static/zscript/actors/player/player_morph.zs @@ -98,7 +98,7 @@ extend class PlayerPawn virtual bool MorphPlayer(PlayerInfo activator, class spawnType, int duration, EMorphFlags style, class enterFlash = "TeleportFog", class exitFlash = "TeleportFog") { if (!player || !spawnType || bDontMorph || player.Health <= 0 - || (bInvulnerable && (player != activator || !(style & MRF_WHENINVULNERABLE)))) + || (!(style & MRF_IGNOREINVULN) && bInvulnerable && (player != activator || !(style & MRF_WHENINVULNERABLE)))) { return false; } @@ -106,10 +106,10 @@ extend class PlayerPawn if (!duration) duration = DEFMORPHTICS; - if (Alternative) + if (spawnType == GetClass()) { // Player is already a beast. - if (bCanSuperMorph && spawnType == GetClass() + if (Alternative && bCanSuperMorph && GetMorphTics() < duration - TICRATE && !FindInventory("PowerWeaponLevel2", true)) { @@ -120,9 +120,6 @@ extend class PlayerPawn return false; } - if (spawnType == GetClass()) - return false; - let morphed = PlayerPawn(Spawn(spawnType, Pos, NO_REPLACE)); if (!MorphInto(morphed)) { @@ -228,7 +225,7 @@ extend class PlayerPawn if (!Alternative || bStayMorphed || Alternative.bStayMorphed) return false; - if (bInvulnerable + if (!(unmorphFlags & MRF_IGNOREINVULN) && bInvulnerable && (player != activator || (!(player.MorphStyle & MRF_WHENINVULNERABLE) && !(unmorphFlags & MRF_STANDARDUNDOING)))) { return false; diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index e2178de50..7afacf208 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -233,6 +233,7 @@ enum EMorphFlags MRF_UNDOALWAYS = 0x00002000, MRF_TRANSFERTRANSLATION = 0x00004000, MRF_KEEPARMOR = 0x00008000, + MRF_IGNOREINVULN = 0x00010000, MRF_STANDARDUNDOING = MRF_UNDOBYTOMEOFPOWER | MRF_UNDOBYCHAOSDEVICE | MRF_UNDOBYTIMEOUT, };