mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 06:42:08 +00:00
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.
This commit is contained in:
parent
2c09a443b4
commit
30730647fe
5 changed files with 116 additions and 77 deletions
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Actor> spawnType, int duration, EMorphFlags style, class<Actor> enterFlash = "TeleportFog", class<Actor> 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;
|
||||
}
|
||||
|
|
|
@ -97,8 +97,11 @@ extend class PlayerPawn
|
|||
|
||||
virtual bool MorphPlayer(PlayerInfo activator, class<PlayerPawn> spawnType, int duration, EMorphFlags style, class<Actor> enterFlash = "TeleportFog", class<Actor> 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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue