- scriptified P_MorphMonster.

This commit is contained in:
Christoph Oelckers 2018-11-24 09:33:03 +01:00
parent 3ed7f4066d
commit ac1bffc51b
8 changed files with 115 additions and 201 deletions

View file

@ -39,12 +39,11 @@
static FRandom pr_morphmonst ("MorphMonster");
bool P_MorphPlayer(player_t *activator, player_t *p, PClassActor *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash)
bool P_MorphActor(AActor *activator, AActor *victim, PClassActor *ptype, PClassActor *mtype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash)
{
if (!p->mo) return false;
IFVIRTUALPTR(p->mo, APlayerPawn, MorphPlayer)
IFVIRTUALPTR(victim, AActor, Morph)
{
VMValue params[] = { p->mo, activator, spawntype, duration, style, enter_flash, exit_flash };
VMValue params[] = { victim, activator, ptype, mtype, duration, style, enter_flash, exit_flash };
int retval;
VMReturn ret(&retval);
VMCall(func, params, countof(params), &ret, 1);
@ -56,7 +55,7 @@ bool P_MorphPlayer(player_t *activator, player_t *p, PClassActor *spawntype, int
bool P_UndoPlayerMorph(player_t *activator, player_t *player, int unmorphflag, bool force)
{
if (!player->mo) return false;
IFVIRTUALPTR(player->mo, APlayerPawn, MorphPlayer)
IFVIRTUALPTR(player->mo, APlayerPawn, UndoPlayerMorph)
{
VMValue params[] = { player->mo, activator, unmorphflag, force };
int retval;
@ -67,76 +66,6 @@ bool P_UndoPlayerMorph(player_t *activator, player_t *player, int unmorphflag, b
return false;
}
//---------------------------------------------------------------------------
//
// FUNC P_MorphMonster
//
// Returns true if the monster gets turned into a chicken/pig.
//
//---------------------------------------------------------------------------
bool P_MorphMonster (AActor *actor, PClassActor *spawntype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash)
{
AMorphedMonster *morphed;
if (actor == NULL || actor->player || spawntype == NULL ||
actor->flags3 & MF3_DONTMORPH ||
!(actor->flags3 & MF3_ISMONSTER) ||
!spawntype->IsDescendantOf (PClass::FindActor(NAME_MorphedMonster)))
{
return false;
}
morphed = static_cast<AMorphedMonster *>(Spawn (spawntype, actor->Pos(), NO_REPLACE));
DObject::StaticPointerSubstitution (actor, morphed);
if ((style & MORPH_TRANSFERTRANSLATION) && !(morphed->flags2 & MF2_DONTTRANSLATE))
{
morphed->Translation = actor->Translation;
}
morphed->tid = actor->tid;
morphed->Angles.Yaw = actor->Angles.Yaw;
morphed->UnmorphedMe = actor;
morphed->Alpha = actor->Alpha;
morphed->RenderStyle = actor->RenderStyle;
morphed->Score = actor->Score;
morphed->UnmorphTime = level.time + ((duration) ? duration : MORPHTICS) + pr_morphmonst();
morphed->MorphStyle = style;
morphed->MorphExitFlash = (exit_flash) ? exit_flash : PClass::FindActor("TeleportFog");
morphed->FlagsSave = actor->flags & ~MF_JUSTHIT;
morphed->special = actor->special;
memcpy (morphed->args, actor->args, sizeof(actor->args));
morphed->CopyFriendliness (actor, true);
morphed->flags |= actor->flags & MF_SHADOW;
morphed->flags3 |= actor->flags3 & MF3_GHOST;
if (actor->renderflags & RF_INVISIBLE)
{
morphed->FlagsSave |= MF_JUSTHIT;
}
morphed->AddToHash ();
actor->RemoveFromHash ();
actor->special = 0;
actor->tid = 0;
actor->flags &= ~(MF_SOLID|MF_SHOOTABLE);
actor->flags |= MF_UNMORPHED;
actor->renderflags |= RF_INVISIBLE;
AActor *eflash = Spawn(((enter_flash) ? enter_flash : PClass::FindActor("TeleportFog")), actor->PosPlusZ(TELEFOGHEIGHT), ALLOW_REPLACE);
if (eflash)
eflash->target = morphed;
return true;
}
DEFINE_ACTION_FUNCTION(AActor, MorphMonster)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_CLASS(spawntype, AActor);
PARAM_INT(duration);
PARAM_INT(style);
PARAM_CLASS(enter_flash, AActor);
PARAM_CLASS(exit_flash, AActor);
ACTION_RETURN_BOOL(P_MorphMonster(self, spawntype, duration, style, enter_flash, exit_flash));
}
//----------------------------------------------------------------------------
//
// FUNC P_UndoMonsterMorph
@ -197,23 +126,6 @@ bool P_UndoMonsterMorph (AMorphedMonster *beast, bool force)
return true;
}
//----------------------------------------------------------------------------
//
// FUNC P_UpdateMorphedMonster
//
// Returns true if the monster unmorphs.
//
//----------------------------------------------------------------------------
bool P_UpdateMorphedMonster (AMorphedMonster *beast)
{
if (beast->UnmorphTime > level.time)
{
return false;
}
return P_UndoMonsterMorph (beast);
}
//----------------------------------------------------------------------------
//
// FUNC P_MorphedDeath
@ -280,55 +192,6 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor
return false;
}
//===========================================================================
//
// EndAllPowerupEffects
//
// Calls EndEffect() on every Powerup in the inventory list.
//
//===========================================================================
void EndAllPowerupEffects(AInventory *item)
{
auto ptype = PClass::FindActor(NAME_Powerup);
while (item != NULL)
{
if (item->IsKindOf(ptype))
{
IFVIRTUALPTRNAME(item, NAME_Powerup, EndEffect)
{
VMValue params[1] = { item };
VMCall(func, params, 1, nullptr, 0);
}
}
item = item->Inventory;
}
}
//===========================================================================
//
// InitAllPowerupEffects
//
// Calls InitEffect() on every Powerup in the inventory list.
//
//===========================================================================
void InitAllPowerupEffects(AInventory *item)
{
auto ptype = PClass::FindActor(NAME_Powerup);
while (item != NULL)
{
if (item->IsKindOf(ptype))
{
IFVIRTUALPTRNAME(item, NAME_Powerup, InitEffect)
{
VMValue params[1] = { item };
VMCall(func, params, 1, nullptr, 0);
}
}
item = item->Inventory;
}
}
// Morphed Monster (you must subclass this to do something useful) ---------
@ -380,35 +243,9 @@ void AMorphedMonster::Die (AActor *source, AActor *inflictor, int dmgflags, FNam
void AMorphedMonster::Tick ()
{
if (!P_UpdateMorphedMonster (this))
if (UnmorphTime > level.time || !P_UndoMonsterMorph(this))
{
Super::Tick ();
Super::Tick();
}
}
DEFINE_ACTION_FUNCTION(AActor, A_Morph)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_CLASS(type, AActor);
PARAM_INT(duration);
PARAM_INT(flags);
PARAM_CLASS(enter_flash, AActor);
PARAM_CLASS(exit_flash, AActor);
bool res = false;
if (self->player)
{
if (type->IsDescendantOf(RUNTIME_CLASS(APlayerPawn)))
{
res = P_MorphPlayer(self->player, self->player, type, duration, flags, enter_flash, exit_flash);
}
}
else
{
if (type->IsDescendantOf(RUNTIME_CLASS(AMorphedMonster)))
{
res = P_MorphMonster(self, type, duration, flags, enter_flash, exit_flash);
}
}
ACTION_RETURN_BOOL(res);
}

View file

@ -35,13 +35,10 @@ class AActor;
class player_t;
class AMorphedMonster;
bool P_MorphPlayer (player_t *activator, player_t *player, PClassActor *morphclass, int duration = 0, int style = 0,
PClassActor *enter_flash = NULL, PClassActor *exit_flash = NULL);
bool P_MorphActor(AActor *activator, AActor *victim, PClassActor *ptype, PClassActor *mtype, int duration, int style, PClassActor *enter_flash, PClassActor *exit_flash);
bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag = 0, bool force = false);
bool P_MorphMonster (AActor *actor, PClassActor *morphclass, int duration = 0, int style = 0,
PClassActor *enter_flash = NULL, PClassActor *exit_flash = NULL);
bool P_UndoMonsterMorph (AMorphedMonster *beast, bool force = false);
bool P_UpdateMorphedMonster (AActor *actor);
bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *morphedhealth);
#endif //__A_MORPH__

View file

@ -10305,14 +10305,7 @@ scriptwait:
if (tag == 0)
{
if (activator != NULL && activator->player)
{
changes += P_MorphPlayer(activator->player, activator->player, playerclass, duration, style, morphflash, unmorphflash);
}
else
{
changes += P_MorphMonster(activator, monsterclass, duration, style, morphflash, unmorphflash);
}
changes = P_MorphActor(activator, activator, playerclass, monsterclass, duration, style, morphflash, unmorphflash);
}
else
{
@ -10321,15 +10314,7 @@ scriptwait:
while ( (actor = iterator.Next ()) )
{
if (actor->player)
{
changes += P_MorphPlayer(activator == NULL ? NULL : activator->player,
actor->player, playerclass, duration, style, morphflash, unmorphflash);
}
else
{
changes += P_MorphMonster(actor, monsterclass, duration, style, morphflash, unmorphflash);
}
changes += P_MorphActor(activator, actor, playerclass, monsterclass, duration, style, morphflash, unmorphflash);
}
}

View file

@ -293,10 +293,10 @@ CCMD (playerclasses)
}
}
DEFINE_ACTION_FUNCTION(APlayerPawn, Substitute)
DEFINE_ACTION_FUNCTION(AActor, Substitute)
{
PARAM_SELF_PROLOGUE(APlayerPawn);
PARAM_OBJECT(replace, APlayerPawn);
PARAM_SELF_PROLOGUE(AActor);
PARAM_OBJECT(replace, AActor);
DObject::StaticPointerSubstitution(self, replace);
return 0;
}

View file

@ -75,6 +75,7 @@ class Actor : Thinker native
const LARGE_MASS = 10000000; // not INT_MAX on purpose
const ORIG_FRICTION = (0xE800/65536.); // original value
const ORIG_FRICTION_FACTOR = (2048/65536.); // original value
const DEFMORPHTICS = 40 * TICRATE;
// flags are not defined here, the native fields for those get synthesized from the internal tables.
@ -329,6 +330,7 @@ class Actor : Thinker native
// need some definition work first
//FRenderStyle RenderStyle;
native private int RenderStyle; // This is kept private until its real type has been implemented into the VM. But some code needs to copy this.
//int ConversationRoot; // THe root of the current dialogue
// deprecated things.
@ -438,6 +440,7 @@ class Actor : Thinker native
virtual native bool Slam(Actor victim);
virtual native void Touch(Actor toucher);
virtual native void MarkPrecacheSounds();
native void Substitute(Actor replacement);
// Called by PIT_CheckThing to check if two actors actually can collide.
virtual bool CanCollideWith(Actor other, bool passive)
@ -735,7 +738,7 @@ class Actor : Thinker native
native bool GiveAmmo (Class<Ammo> type, int amount);
native bool UsePuzzleItem(int PuzzleItemType);
native float AccuracyFactor();
native bool MorphMonster (Class<Actor> spawntype, int duration, int style, Class<Actor> enter_flash, Class<Actor> exit_flash);
action native void SetCamera(Actor cam, bool revert = false);
native bool Warp(Actor dest, double xofs = 0, double yofs = 0, double zofs = 0, double angle = 0, int flags = 0, double heightoffset = 0, double radiusoffset = 0, double pitch = 0);
@ -1097,8 +1100,6 @@ class Actor : Thinker native
native void Revive();
action native bool, Actor A_ThrowGrenade(class<Actor> itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true);
native void A_Weave(int xspeed, int yspeed, double xdist, double ydist);
native bool A_Morph(class<Actor> type, int duration = 0, int flags = 0, class<Actor> enter_flash = null, class<Actor> exit_flash = null);
action native state, bool A_Teleport(statelabel teleportstate = null, class<SpecialSpot> targettype = "BossSpot", class<Actor> fogtype = "TeleportFog", int flags = 0, double mindist = 128, double maxdist = 0, int ptr = AAPTR_DEFAULT);
action native state, bool A_Warp(int ptr_destination, double xofs = 0, double yofs = 0, double zofs = 0, double angle = 0, int flags = 0, statelabel success_state = null, double heightoffset = 0, double radiusoffset = 0, double pitch = 0);
@ -1218,6 +1219,7 @@ class Actor : Thinker native
return ACS_ExecuteWithResult(-int(script), arg1, arg2, arg3, arg4);
}
States(Actor, Overlay, Weapon, Item)
{
Spawn:

View file

@ -71,7 +71,7 @@ Class ArtiTomeOfPower : PowerupGiver
Playerinfo p = Owner.player;
if (p && p.morphTics && (p.MorphStyle & MRF_UNDOBYTOMEOFPOWER))
{ // Attempt to undo chicken
if (!p.UndoPlayerMorph (p, MRF_UNDOBYTOMEOFPOWER))
if (!p.mo.UndoPlayerMorph (p, MRF_UNDOBYTOMEOFPOWER))
{ // Failed
if (!(p.MorphStyle & MRF_FAILNOTELEFRAG))
{

View file

@ -1,3 +1,99 @@
extend class Actor
{
//===========================================================================
//
// Main entry point
//
//===========================================================================
bool Morph(Actor activator, class<PlayerPawn> playerclass, class<MorphedMonster> monsterclass, int duration = 0, int style = 0, class<Actor> morphflash = null, class<Actor>unmorphflash = null)
{
if (player != null && player.mo != null && playerclass != null)
{
return player.mo.MorphPlayer(activator.player, playerclass, duration, style, morphflash, unmorphflash);
}
else
{
return MorphMonster(monsterclass, duration, style, morphflash, unmorphflash);
}
}
//===========================================================================
//
// Action function variant whose arguments differ from the generic one.
//
//===========================================================================
bool A_Morph(class<Actor> type, int duration = 0, int style = 0, class<Actor> morphflash = null, class<Actor>unmorphflash = null)
{
if (self.player != null)
{
let playerclass = (class<PlayerPawn>)(type);
if (playerclass && self.player.mo != null) return player.mo.MorphPlayer(self.player, playerclass, duration, style, morphflash, unmorphflash);
}
else
{
return MorphMonster(type, duration, style, morphflash, unmorphflash);
}
return false;
}
//---------------------------------------------------------------------------
//
// FUNC P_MorphMonster
//
// Returns true if the monster gets turned into a chicken/pig.
//
//---------------------------------------------------------------------------
virtual bool MorphMonster (Class<Actor> spawntype, int duration, int style, Class<Actor> enter_flash, Class<Actor> exit_flash)
{
if (player || spawntype == NULL || bDontMorph || !bIsMonster || !(spawntype is 'MorphedMonster'))
{
return false;
}
let morphed = MorphedMonster(Spawn (spawntype, Pos, NO_REPLACE));
Substitute (morphed);
if ((style & MRF_TRANSFERTRANSLATION) && !morphed.bDontTranslate)
{
morphed.Translation = Translation;
}
morphed.ChangeTid(tid);
ChangeTid(0);
morphed.Angle = Angle;
morphed.UnmorphedMe = self;
morphed.Alpha = Alpha;
morphed.RenderStyle = RenderStyle;
morphed.Score = Score;
morphed.UnmorphTime = level.time + ((duration) ? duration : DEFMORPHTICS) + random[morphmonst]();
morphed.MorphStyle = style;
morphed.MorphExitFlash = (exit_flash) ? exit_flash : (class<Actor>)("TeleportFog");
//morphed.FlagsSave = bSolid * 2 + bShootable * 4 + bInvisible * 0x40; // The factors are for savegame compatibility
morphed.special = special;
morphed.args[0] = args[0];
morphed.args[1] = args[1];
morphed.args[2] = args[2];
morphed.args[3] = args[3];
morphed.args[4] = args[4];
morphed.CopyFriendliness (self, true);
morphed.bShadow |= bShadow;
morphed.bGhost |= bGhost;
special = 0;
bSolid = false;
bShootable = false;
bUnmorphed = true;
bInvisible = true;
let eflash = Spawn(enter_flash ? enter_flash : (class<Actor>)("TeleportFog"), Pos + (0, 0, gameinfo.TELEFOGHEIGHT), ALLOW_REPLACE);
if (eflash)
eflash.target = morphed;
return true;
}
}
extend class PlayerPawn
{
//===========================================================================

View file

@ -15,7 +15,6 @@ class PlayerPawn : Actor native
const CROUCHSPEED = (1./12);
// [RH] # of ticks to complete a turn180
const TURN180_TICKS = ((TICRATE / 4) + 1);
const DEFMORPHTICS = 40 * TICRATE;
native int crouchsprite;
native int MaxHealth;
@ -1280,8 +1279,6 @@ class PlayerPawn : Actor native
native void CheckWeaponButtons();
native Weapon BestWeapon(class<Ammo> ammotype);
native Weapon PickNewWeapon(class<Ammo> ammotype);
native void Substitute(PlayerPawn replacement);
}
class PlayerChunk : PlayerPawn