From 66cc68606f7c337aaa9c729d70c8f63256bffa29 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 1 Jan 2017 19:23:43 +0100 Subject: [PATCH] - scriptified the methods of APowerMorph. - made some changes to PowerMorph to better deal with recursive calls from UndoPlayerMorph. The flag hackery was only needed because the 'alternative' pointers were cleared far too late. --- src/g_inventory/a_artifacts.cpp | 75 ----------------------- src/g_inventory/a_artifacts.h | 6 -- src/g_shared/a_morph.cpp | 19 ++++-- wadsrc/static/zscript/shared/player.txt | 1 + wadsrc/static/zscript/shared/powerups.txt | 73 +++++++++++++++++++++- 5 files changed, 88 insertions(+), 86 deletions(-) diff --git a/src/g_inventory/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp index 00efa0579..f78c6875e 100644 --- a/src/g_inventory/a_artifacts.cpp +++ b/src/g_inventory/a_artifacts.cpp @@ -1759,7 +1759,6 @@ DEFINE_FIELD(APowerMorph, MorphFlash) DEFINE_FIELD(APowerMorph, UnMorphFlash) DEFINE_FIELD(APowerMorph, MorphStyle) DEFINE_FIELD(APowerMorph, MorphedPlayer) -DEFINE_FIELD(APowerMorph, bInUndoMorph) //=========================================================================== // @@ -1777,77 +1776,3 @@ void APowerMorph::Serialize(FSerializer &arc) ("morphedplayer", MorphedPlayer); } -//=========================================================================== -// -// APowerMorph :: InitEffect -// -//=========================================================================== - -void APowerMorph::InitEffect( ) -{ - Super::InitEffect(); - - if (Owner != nullptr && Owner->player != nullptr && PlayerClass != nullptr) - { - player_t *realplayer = Owner->player; // Remember the identity of the player - if (P_MorphPlayer(realplayer, realplayer, PlayerClass, INT_MAX/*INDEFINITELY*/, MorphStyle, MorphFlash, UnMorphFlash)) - { - Owner = realplayer->mo; // Replace the new owner in our owner; safe because we are not attached to anything yet - ItemFlags |= IF_CREATECOPYMOVED; // Let the caller know the "real" owner has changed (to the morphed actor) - MorphedPlayer = realplayer; // Store the player identity (morphing clears the unmorphed actor's "player" field) - } - else // morph failed - give the caller an opportunity to fail the pickup completely - { - ItemFlags |= IF_INITEFFECTFAILED; // Let the caller know that the activation failed (can fail the pickup if appropriate) - } - } -} - -//=========================================================================== -// -// APowerMorph :: EndEffect -// -//=========================================================================== - -void APowerMorph::EndEffect( ) -{ - Super::EndEffect(); - - // Abort if owner already destroyed or unmorphed - if (Owner == nullptr || MorphedPlayer == nullptr) - { - return; - } - - // Abort if owner is dead; their Die() method will - // take care of any required unmorphing on death. - if (MorphedPlayer->health <= 0) - { - return; - } - - // Unmorph if possible - if (!bInUndoMorph) - { - int savedMorphTics = MorphedPlayer->morphTics; - P_UndoPlayerMorph (MorphedPlayer, MorphedPlayer, 0, !!(MorphedPlayer->MorphStyle & MORPH_UNDOALWAYS)); - - // Abort if unmorph failed; in that case, - // set the usual retry timer and return. - if (MorphedPlayer != NULL && MorphedPlayer->morphTics) - { - // Transfer retry timeout - // to the powerup's timer. - EffectTics = MorphedPlayer->morphTics; - // Reload negative morph tics; - // use actual value; it may - // be in use for animation. - MorphedPlayer->morphTics = savedMorphTics; - // Try again some time later - return; - } - } - // Unmorph suceeded - MorphedPlayer = NULL; -} - diff --git a/src/g_inventory/a_artifacts.h b/src/g_inventory/a_artifacts.h index f68516de7..90670abb5 100644 --- a/src/g_inventory/a_artifacts.h +++ b/src/g_inventory/a_artifacts.h @@ -228,18 +228,12 @@ class APowerMorph : public APowerup public: virtual void Serialize(FSerializer &arc) override; - void SetNoCallUndoMorph() { bInUndoMorph = true; } // Variables PClassPlayerPawn *PlayerClass; PClassActor *MorphFlash, *UnMorphFlash; int MorphStyle; player_t *MorphedPlayer; - bool bInUndoMorph; // Because P_UndoPlayerMorph() can call EndEffect recursively - -protected: - virtual void InitEffect () override; - virtual void EndEffect () override; }; #endif //__A_ARTIFACTS_H__ diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 7550ff0da..935efa2db 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -154,6 +154,18 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp return true; } +DEFINE_ACTION_FUNCTION(_PlayerInfo, MorphPlayer) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_POINTER(victim, player_t); + PARAM_CLASS(spawntype, APlayerPawn); + PARAM_INT(duration); + PARAM_INT(style); + PARAM_CLASS_DEF(enter_flash, AActor); + PARAM_CLASS_DEF(exit_flash, AActor); + ACTION_RETURN_BOOL(P_MorphPlayer(self, victim, spawntype, duration, style, enter_flash, exit_flash)); +} + //---------------------------------------------------------------------------- // // FUNC P_UndoPlayerMorph @@ -204,14 +216,15 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, mo->target = pmo->target; mo->tracer = pmo->tracer; pmo->player = nullptr; + mo->alternative = pmo->alternative = nullptr; // Remove the morph power if the morph is being undone prematurely. + auto pmtype = PClass::FindActor("PowerMorph"); for (AInventory *item = pmo->Inventory, *next = nullptr; item != nullptr; item = next) { next = item->Inventory; - if (item->IsKindOf(RUNTIME_CLASS(APowerMorph))) + if (item->IsKindOf(pmtype)) { - static_cast(item)->SetNoCallUndoMorph(); item->Destroy(); } } @@ -348,8 +361,6 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, beastweap->Destroy (); } } - mo->alternative = nullptr; - pmo->alternative = nullptr; pmo->Destroy (); // Restore playerclass armor to its normal amount. AHexenArmor *hxarmor = mo->FindInventory(); diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 2f6dc4bc1..953b9d971 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -251,6 +251,7 @@ FWeaponSlots weapons; */ + native bool MorphPlayer(playerinfo p, Class spawntype, int duration, int style, Class enter_flash = null, Class exit_flash = null); native bool UndoPlayerMorph(playerinfo player, int unmorphflag = 0, bool force = false); native bool PoisonPlayer(Actor poisoner, Actor source, int poison); native void PoisonDamage(Actor source, int damage, bool playPainSound); diff --git a/wadsrc/static/zscript/shared/powerups.txt b/wadsrc/static/zscript/shared/powerups.txt index 868951166..c6064d676 100644 --- a/wadsrc/static/zscript/shared/powerups.txt +++ b/wadsrc/static/zscript/shared/powerups.txt @@ -430,11 +430,82 @@ class PowerMorph : Powerup native native Class MorphFlash, UnMorphFlash; native int MorphStyle; native PlayerInfo MorphedPlayer; - native bool bInUndoMorph; Default { Powerup.Duration -40; } + + //=========================================================================== + // + // InitEffect + // + //=========================================================================== + + override void InitEffect() + { + Super.InitEffect(); + + if (Owner != null && Owner.player != null && PlayerClass != null) + { + let realplayer = Owner.player; // Remember the identity of the player + if (realplayer.MorphPlayer(realplayer, PlayerClass, 0x7fffffff/*INDEFINITELY*/, MorphStyle, MorphFlash, UnMorphFlash)) + { + Owner = realplayer.mo; // Replace the new owner in our owner; safe because we are not attached to anything yet + bCreateCopyMoved = true; // Let the caller know the "real" owner has changed (to the morphed actor) + MorphedPlayer = realplayer; // Store the player identity (morphing clears the unmorphed actor's "player" field) + } + else // morph failed - give the caller an opportunity to fail the pickup completely + { + bInitEffectFailed = true; // Let the caller know that the activation failed (can fail the pickup if appropriate) + } + } + } + + //=========================================================================== + // + // EndEffect + // + //=========================================================================== + + override void EndEffect() + { + Super.EndEffect(); + + // Abort if owner already destroyed or unmorphed + if (Owner == null || MorphedPlayer == null || Owner.alternative == null) + { + return; + } + + // Abort if owner is dead; their Die() method will + // take care of any required unmorphing on death. + if (MorphedPlayer.health <= 0) + { + return; + } + + int savedMorphTics = MorphedPlayer.morphTics; + MorphedPlayer.UndoPlayerMorph (MorphedPlayer, 0, !!(MorphedPlayer.MorphStyle & MRF_UNDOALWAYS)); + + // Abort if unmorph failed; in that case, + // set the usual retry timer and return. + if (MorphedPlayer != null && MorphedPlayer.morphTics) + { + // Transfer retry timeout + // to the powerup's timer. + EffectTics = MorphedPlayer.morphTics; + // Reload negative morph tics; + // use actual value; it may + // be in use for animation. + MorphedPlayer.morphTics = savedMorphTics; + // Try again some time later + return; + } + // Unmorph suceeded + MorphedPlayer = null; + } + + }