From 12dc5c1506673cce53a065f0d08016462a220074 Mon Sep 17 00:00:00 2001 From: Boondorl Date: Mon, 1 Jan 2024 11:50:01 -0500 Subject: [PATCH] Further morphing clean up Players will now use their Alternative field to check if they're morphed instead of their MorphTics. This makes the current state of morphing more reliable, otherwise setting this to 0 manually without unmorphing could have very odd results. Both monsters and players consider 0 morph time to mean infinite now (previously this only applied to monsters). Player unmorphs no longer die in the case of a failed unmorph on death. Removed inventory swapping on player pointer substitution as it's too messy to do here. --- src/g_statusbar/sbar_mugshot.cpp | 2 +- src/namedef_custom.h | 1 - src/p_saveg.cpp | 2 +- src/playsim/a_morph.cpp | 2 +- src/playsim/p_enemy.cpp | 2 +- src/playsim/p_interaction.cpp | 16 +++++++++------- src/playsim/p_mobj.cpp | 17 ++++------------- src/playsim/p_user.cpp | 4 ++-- wadsrc/static/zscript/actors/actor.zs | 2 +- .../static/zscript/actors/heretic/chicken.zs | 2 +- wadsrc/static/zscript/actors/hexen/pig.zs | 2 +- .../zscript/actors/inventory/powerups.zs | 2 +- .../static/zscript/actors/inventory/weapons.zs | 2 +- wadsrc/static/zscript/actors/morph.zs | 2 +- wadsrc/static/zscript/actors/player/player.zs | 18 +++++++++--------- .../zscript/actors/player/player_cheat.zs | 4 ++-- .../zscript/actors/player/player_morph.zs | 2 +- 17 files changed, 37 insertions(+), 45 deletions(-) diff --git a/src/g_statusbar/sbar_mugshot.cpp b/src/g_statusbar/sbar_mugshot.cpp index f1d43af28..493124389 100644 --- a/src/g_statusbar/sbar_mugshot.cpp +++ b/src/g_statusbar/sbar_mugshot.cpp @@ -479,7 +479,7 @@ FGameTexture *FMugShot::GetFace(player_t *player, const char *default_face, int if (CurrentState != NULL) { int skin = player->userinfo.GetSkin(); - const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->morphTics ? (GetDefaultByType(player->MorphedPlayerClass))->NameVar(NAME_Face).GetChars() : Skins[skin].Face.GetChars()); + const char *skin_face = (stateflags & FMugShot::CUSTOM) ? nullptr : (player->mo->alternative != nullptr ? (GetDefaultByType(player->MorphedPlayerClass))->NameVar(NAME_Face).GetChars() : Skins[skin].Face.GetChars()); return CurrentState->GetCurrentFrameTexture(default_face, skin_face, level, angle); } return NULL; diff --git a/src/namedef_custom.h b/src/namedef_custom.h index f0cb451c6..0727a4a44 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -145,7 +145,6 @@ xx(Reflection) xx(CustomInventory) xx(Inventory) xx(StateProvider) -xx(ObtainInventory) xx(CallTryPickup) xx(QuestItem25) xx(QuestItem28) diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 733239df2..865810cdc 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -1149,7 +1149,7 @@ void FLevelLocals::UnSnapshotLevel(bool hubLoad) // If this isn't the unmorphed original copy of a player, destroy it, because it's extra. for (i = 0; i < MAXPLAYERS; ++i) { - if (PlayerInGame(i) && Players[i]->morphTics && Players[i]->mo->alternative == pawn) + if (PlayerInGame(i) && Players[i]->mo->alternative == pawn) { break; } diff --git a/src/playsim/a_morph.cpp b/src/playsim/a_morph.cpp index 80e6807af..5f6c38b91 100644 --- a/src/playsim/a_morph.cpp +++ b/src/playsim/a_morph.cpp @@ -37,7 +37,7 @@ bool P_MorphActor(AActor *activator, AActor *victim, PClassActor *ptype, PClassA bool P_UnmorphActor(AActor *activator, AActor *morphed, int flags, bool force) { - IFVIRTUALPTR(morphed, AActor, UnMorph) + IFVIRTUALPTR(morphed, AActor, Unmorph) { VMValue params[] = { morphed, activator, flags, force }; int retval; diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index 6111a6019..b5bf36133 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -3115,7 +3115,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Pain) PARAM_SELF_PROLOGUE(AActor); // [RH] Vary player pain sounds depending on health (ala Quake2) - if (self->player && self->player->morphTics == 0) + if (self->player && self->alternative == nullptr) { const char *pain_amount; FSoundID sfx_id = NO_SOUND; diff --git a/src/playsim/p_interaction.cpp b/src/playsim/p_interaction.cpp index 00ef947b6..db19107b7 100644 --- a/src/playsim/p_interaction.cpp +++ b/src/playsim/p_interaction.cpp @@ -329,8 +329,10 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf VMValue params[] = { this }; VMCall(func, params, 1, nullptr, 0); - // Always kill the dummy Actor if it didn't unmorph, otherwise checking the morph flags. - if (realMo != nullptr && (!(morphStyle & MORPH_UNDOBYDEATH) || !(morphStyle & MORPH_UNDOBYDEATHSAVES))) + // 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 + && ((alternative != nullptr && player == nullptr) || (alternative == nullptr && !(morphStyle & MORPH_UNDOBYDEATHSAVES)))) { if (wasgibbed) { @@ -460,7 +462,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf ++source->player->spreecount; } - if (source->player->morphTics) + if (source->alternative != nullptr) { // Make a super chicken source->GiveInventoryType (PClass::FindActor(NAME_PowerWeaponLevel2)); } @@ -1331,7 +1333,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da if (damage >= player->health && !telefragDamage && (G_SkillProperty(SKILLP_AutoUseHealth) || deathmatch) - && !player->morphTics) + && target->alternative == nullptr) { // Try to use some inventory health P_AutoUseHealth (player, damage - player->health + 1); } @@ -1465,7 +1467,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da // check for special fire damage or ice damage deaths if (mod == NAME_Fire) { - if (player && !player->morphTics) + if (player && target->alternative == nullptr) { // Check for flame death if (!inflictor || ((target->health > -50) && (damage > 25)) || @@ -1799,7 +1801,7 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPain } if (damage >= player->health && (G_SkillProperty(SKILLP_AutoUseHealth) || deathmatch) - && !player->morphTics) + && target->alternative == nullptr) { // Try to use some inventory health P_AutoUseHealth(player, damage - player->health+1); } @@ -1829,7 +1831,7 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPain else { target->special1 = damage; - if (player && !player->morphTics) + if (player && target->alternative == nullptr) { // Check for flame death if ((player->poisontype == NAME_Fire) && (target->health > -50) && (damage > 25)) { diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index f980c9a8d..c3f4a82d5 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -835,7 +835,7 @@ int P_GetRealMaxHealth(AActor *actor, int max) { max = actor->GetMaxHealth(true); // [MH] First step in predictable generic morph effects - if (player->morphTics) + if (actor->alternative != nullptr) { if (player->MorphStyle & MORPH_FULLHEALTH) { @@ -857,7 +857,7 @@ int P_GetRealMaxHealth(AActor *actor, int max) else { // Bonus health should be added on top of the item's limit. - if (player->morphTics == 0 || (player->MorphStyle & MORPH_ADDSTAMINA)) + if (actor->alternative == nullptr || (player->MorphStyle & MORPH_ADDSTAMINA)) { max += actor->IntVar(NAME_BonusHealth); } @@ -5225,14 +5225,6 @@ void PlayerPointerSubstitution(AActor* oldPlayer, AActor* newPlayer) return; } - // Swap over the inventory. - auto func = dyn_cast(newPlayer->GetClass()->FindSymbol(NAME_ObtainInventory, true)); - if (func) - { - VMValue params[] = { newPlayer, oldPlayer }; - VMCall(func->Variants[0].Implementation, params, 2, nullptr, 0); - } - // Go through player infos. for (int i = 0; i < MAXPLAYERS; ++i) { @@ -5314,11 +5306,10 @@ int MorphPointerSubstitution(AActor* from, AActor* to) // Since the check is good, move the inventory items over. This should always be done when // morphing to emulate Heretic/Hexen's behavior since those stored the inventory in their // player structs. - auto func = dyn_cast(to->GetClass()->FindSymbol(NAME_ObtainInventory, true)); - if (func) + IFVM(Actor, ObtainInventory) { VMValue params[] = { to, from }; - VMCall(func->Variants[0].Implementation, params, 2, nullptr, 0); + VMCall(func, params, 2, nullptr, 0); } // Only change some gameplay-related pointers that we know we can safely swap to whatever diff --git a/src/playsim/p_user.cpp b/src/playsim/p_user.cpp index 49353dcf2..a1888d5c1 100644 --- a/src/playsim/p_user.cpp +++ b/src/playsim/p_user.cpp @@ -693,7 +693,7 @@ bool player_t::Resurrect() P_BringUpWeapon(this); } - if (morphTics) + if (mo->alternative != nullptr) { P_UnmorphActor(mo, mo); } @@ -1172,7 +1172,7 @@ void P_CheckEnvironment(player_t *player) P_PlayerOnSpecialFlat(player, P_GetThingFloorType(player->mo)); } if (player->mo->Vel.Z <= -player->mo->FloatVar(NAME_FallingScreamMinSpeed) && - player->mo->Vel.Z >= -player->mo->FloatVar(NAME_FallingScreamMaxSpeed) && !player->morphTics && + player->mo->Vel.Z >= -player->mo->FloatVar(NAME_FallingScreamMaxSpeed) && player->mo->alternative == nullptr && player->mo->waterlevel == 0) { auto id = S_FindSkinnedSound(player->mo, S_FindSound("*falling")); diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 5326a6184..b35c8cd8e 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -1406,7 +1406,7 @@ class Actor : Thinker native bool grunted; // [RH] only make noise if alive - if (self.health > 0 && self.player.morphTics == 0) + if (self.health > 0 && !Alternative) { grunted = false; // Why should this number vary by gravity? diff --git a/wadsrc/static/zscript/actors/heretic/chicken.zs b/wadsrc/static/zscript/actors/heretic/chicken.zs index 4bc2e20de..a49418ca3 100644 --- a/wadsrc/static/zscript/actors/heretic/chicken.zs +++ b/wadsrc/static/zscript/actors/heretic/chicken.zs @@ -221,7 +221,7 @@ class ChickenPlayer : PlayerPawn pspr.y = WEAPONTOP + player.chickenPeck / 2; } } - if (player.morphTics & 15) + if ((player.MorphTics ? player.MorphTics : Random[ChickenPlayerThink]()) & 15) { return; } diff --git a/wadsrc/static/zscript/actors/hexen/pig.zs b/wadsrc/static/zscript/actors/hexen/pig.zs index 45c601c4e..95e90722e 100644 --- a/wadsrc/static/zscript/actors/hexen/pig.zs +++ b/wadsrc/static/zscript/actors/hexen/pig.zs @@ -145,7 +145,7 @@ class PigPlayer : PlayerPawn override void MorphPlayerThink () { - if (player.morphTics & 15) + if ((player.MorphTics ? player.MorphTics : Random[PigPlayerThink]()) & 15) { return; } diff --git a/wadsrc/static/zscript/actors/inventory/powerups.zs b/wadsrc/static/zscript/actors/inventory/powerups.zs index 381f26af0..da436dcdc 100644 --- a/wadsrc/static/zscript/actors/inventory/powerups.zs +++ b/wadsrc/static/zscript/actors/inventory/powerups.zs @@ -1933,7 +1933,7 @@ class PowerMorph : Powerup EMorphFlags mStyle = MorphedPlayer ? MorphedPlayer.MorphStyle : MorphStyle; - Owner.Unmorph(Owner, 0, mStyle & MRF_UNDOALWAYS); + Owner.Unmorph(Owner, force: mStyle & MRF_UNDOALWAYS); MorphedPlayer = null; } } diff --git a/wadsrc/static/zscript/actors/inventory/weapons.zs b/wadsrc/static/zscript/actors/inventory/weapons.zs index 49e32f3a2..66a7f8964 100644 --- a/wadsrc/static/zscript/actors/inventory/weapons.zs +++ b/wadsrc/static/zscript/actors/inventory/weapons.zs @@ -262,7 +262,7 @@ class Weapon : StateProvider } let psp = player.GetPSprite(PSP_WEAPON); if (!psp) return; - if (player.morphTics || player.cheats & CF_INSTANTWEAPSWITCH) + if (Alternative || player.cheats & CF_INSTANTWEAPSWITCH) { psp.y = WEAPONBOTTOM; } diff --git a/wadsrc/static/zscript/actors/morph.zs b/wadsrc/static/zscript/actors/morph.zs index 6a418714a..21b2767a9 100644 --- a/wadsrc/static/zscript/actors/morph.zs +++ b/wadsrc/static/zscript/actors/morph.zs @@ -94,7 +94,7 @@ extend class Actor virtual bool CheckUnmorph() { - return UnmorphTime <= Level.Time && Unmorph(self); + return UnmorphTime && UnmorphTime <= Level.Time && Unmorph(self, MRF_UNDOBYTIMEOUT); } //--------------------------------------------------------------------------- diff --git a/wadsrc/static/zscript/actors/player/player.zs b/wadsrc/static/zscript/actors/player/player.zs index ec020d2f3..d87fc1706 100644 --- a/wadsrc/static/zscript/actors/player/player.zs +++ b/wadsrc/static/zscript/actors/player/player.zs @@ -477,7 +477,7 @@ class PlayerPawn : Actor let player = self.player; if (!player) return; if ((player.WeaponState & WF_DISABLESWITCH) || // Weapon changing has been disabled. - player.morphTics != 0) // Morphed classes cannot change weapons. + Alternative) // Morphed classes cannot change weapons. { // ...so throw away any pending weapon requests. player.PendingWeapon = WP_NOCHANGE; } @@ -651,7 +651,7 @@ class PlayerPawn : Actor } } - if (player.morphTics) + if (Alternative) { bob = 0; } @@ -1072,7 +1072,7 @@ class PlayerPawn : Actor virtual bool CanCrouch() const { - return player.morphTics == 0 || bCrouchableMorph; + return !Alternative || bCrouchableMorph; } //---------------------------------------------------------------------------- @@ -1238,7 +1238,7 @@ class PlayerPawn : Actor side *= SideMove2; } - if (!player.morphTics) + if (!Alternative) { double factor = 1.; for(let it = Inv; it != null; it = it.Inv) @@ -1528,13 +1528,13 @@ class PlayerPawn : Actor { let player = self.player; // Morph counter - if (player.morphTics) + if (Alternative) { if (player.chickenPeck) { // Chicken attack counter player.chickenPeck -= 3; } - if (!--player.morphTics) + if (player.MorphTics && !--player.MorphTics) { // Attempt to undo the chicken/pig Unmorph(self, MRF_UNDOBYTIMEOUT); } @@ -1661,7 +1661,7 @@ class PlayerPawn : Actor player.jumpTics = 0; } } - if (player.morphTics && !(player.cheats & CF_PREDICTING)) + if (Alternative && !(player.cheats & CF_PREDICTING)) { MorphPlayerThink (); } @@ -2042,9 +2042,9 @@ class PlayerPawn : Actor Inventory item, next; let p = player; - if (p.morphTics != 0) + if (Alternative) { // Undo morph - Unmorph(self, 0, true); + Unmorph(self, force: true); } // 'self' will be no longer valid from here on in case of an unmorph let me = p.mo; diff --git a/wadsrc/static/zscript/actors/player/player_cheat.zs b/wadsrc/static/zscript/actors/player/player_cheat.zs index c2d2581d9..40693fbce 100644 --- a/wadsrc/static/zscript/actors/player/player_cheat.zs +++ b/wadsrc/static/zscript/actors/player/player_cheat.zs @@ -434,7 +434,7 @@ extend class PlayerPawn int style = MRF_UNDOBYTOMEOFPOWER; if (gameinfo.gametype == GAME_Hexen) style |= MRF_UNDOBYCHAOSDEVICE; - if (player.morphTics) + if (Alternative) { if (Unmorph (self)) { @@ -454,7 +454,7 @@ extend class PlayerPawn virtual void CheatTakeWeaps() { - if (player.morphTics || health <= 0) + if (Alternative || health <= 0) { return; } diff --git a/wadsrc/static/zscript/actors/player/player_morph.zs b/wadsrc/static/zscript/actors/player/player_morph.zs index 6d28306ed..594ddebfc 100644 --- a/wadsrc/static/zscript/actors/player/player_morph.zs +++ b/wadsrc/static/zscript/actors/player/player_morph.zs @@ -106,7 +106,7 @@ extend class PlayerPawn if (!duration) duration = DEFMORPHTICS; - if (player.MorphTics) + if (Alternative) { // Player is already a beast. if (bCanSuperMorph && spawnType == GetClass()