diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp
index 68309d8cc..c8220af5a 100644
--- a/src/g_shared/a_morph.cpp
+++ b/src/g_shared/a_morph.cpp
@@ -157,13 +157,13 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp
 DEFINE_ACTION_FUNCTION(_PlayerInfo, MorphPlayer)
 {
 	PARAM_SELF_STRUCT_PROLOGUE(player_t);
-	PARAM_POINTER(victim, player_t);
+	PARAM_POINTER(activator, 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));
+	ACTION_RETURN_BOOL(P_MorphPlayer(activator, self, spawntype, duration, style, enter_flash, exit_flash));
 }
 
 //----------------------------------------------------------------------------
@@ -396,7 +396,7 @@ bool P_MorphMonster (AActor *actor, PClassActor *spawntype, int duration, int st
 	if (actor == NULL || actor->player || spawntype == NULL ||
 		actor->flags3 & MF3_DONTMORPH ||
 		!(actor->flags3 & MF3_ISMONSTER) ||
-		!spawntype->IsDescendantOf (RUNTIME_CLASS(AMorphedMonster)))
+		!spawntype->IsDescendantOf (PClass::FindActor(NAME_MorphedMonster)))
 	{
 		return false;
 	}
@@ -440,6 +440,17 @@ bool P_MorphMonster (AActor *actor, PClassActor *spawntype, int duration, int st
 	return true;
 }
 
+DEFINE_ACTION_FUNCTION(AActor, MorphMonster)
+{
+	PARAM_SELF_PROLOGUE(AActor);
+	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_MorphMonster(self, spawntype, duration, style, enter_flash, exit_flash));
+}
+
 //----------------------------------------------------------------------------
 //
 // FUNC P_UndoMonsterMorph
@@ -635,50 +646,6 @@ void InitAllPowerupEffects(AInventory *item)
 	}
 }
 
-// Base class for morphing projectiles --------------------------------------
-
-IMPLEMENT_CLASS(AMorphProjectile, false, true)
-
-IMPLEMENT_POINTERS_START(AMorphProjectile)
-	IMPLEMENT_POINTER(PlayerClass)
-	IMPLEMENT_POINTER(MonsterClass)
-	IMPLEMENT_POINTER(MorphFlash)
-	IMPLEMENT_POINTER(UnMorphFlash)
-IMPLEMENT_POINTERS_END
-
-DEFINE_FIELD(AMorphProjectile, PlayerClass)
-DEFINE_FIELD(AMorphProjectile, MonsterClass)
-DEFINE_FIELD(AMorphProjectile, MorphFlash)
-DEFINE_FIELD(AMorphProjectile, UnMorphFlash)
-DEFINE_FIELD(AMorphProjectile, Duration)
-DEFINE_FIELD(AMorphProjectile, MorphStyle)
-
-int AMorphProjectile::DoSpecialDamage (AActor *target, int damage, FName damagetype)
-{
-	if (target->player)
-	{
-		P_MorphPlayer (NULL, target->player, PlayerClass, Duration, MorphStyle, MorphFlash, UnMorphFlash);
-	}
-	else
-	{
-		P_MorphMonster (target, MonsterClass, Duration, MorphStyle, MorphFlash, UnMorphFlash);
-	}
-	return -1;
-}
-
-void AMorphProjectile::Serialize(FSerializer &arc)
-{
-	Super::Serialize (arc);
-	auto def = (AMorphProjectile*)GetDefault();
-	arc("playerclass", PlayerClass, def->PlayerClass)
-		("monsterclass", MonsterClass, def->MonsterClass)
-		("duration", Duration, def->Duration)
-		("morphstyle", MorphStyle, def->MorphStyle)
-		("morphflash", MorphFlash, def->MorphFlash)
-		("unmorphflash", UnMorphFlash, def->UnMorphFlash);
-}
-
-
 // Morphed Monster (you must subclass this to do something useful) ---------
 
 IMPLEMENT_CLASS(AMorphedMonster, false, true)
diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h
index bee819dd0..c9d0d86ce 100644
--- a/src/g_shared/a_sharedglobal.h
+++ b/src/g_shared/a_sharedglobal.h
@@ -76,31 +76,6 @@ private:
 	DImpactDecal();
 };
 
-class ASkyViewpoint : public AActor
-{
-	DECLARE_CLASS (ASkyViewpoint, AActor)
-public:
-	void BeginPlay ();
-	void OnDestroy() override;
-};
-
-// For an EE compatible linedef based definition.
-class ASkyCamCompat : public ASkyViewpoint
-{
-	DECLARE_CLASS (ASkyCamCompat, ASkyViewpoint)
-
-public:
-	void BeginPlay();
-};
-
-
-class AStackPoint : public ASkyViewpoint
-{
-	DECLARE_CLASS (AStackPoint, ASkyViewpoint)
-public:
-	void BeginPlay ();
-};
-
 class DFlashFader : public DThinker
 {
 	DECLARE_CLASS (DFlashFader, DThinker)
@@ -177,20 +152,6 @@ private:
 	DEarthquake ();
 };
 
-class AMorphProjectile : public AActor
-{
-	DECLARE_CLASS (AMorphProjectile, AActor)
-	HAS_OBJECT_POINTERS;
-public:
-	int DoSpecialDamage (AActor *target, int damage, FName damagetype);
-	
-	void Serialize(FSerializer &arc);
-
-	PClassPlayerPawn *PlayerClass;
-	PClassActor *MonsterClass, *MorphFlash, *UnMorphFlash;
-	int Duration, MorphStyle;
-};
-
 class AMorphedMonster : public AActor
 {
 	DECLARE_CLASS (AMorphedMonster, AActor)
diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp
index 198dfea6e..92416f88b 100644
--- a/src/gl/scene/gl_sprite.cpp
+++ b/src/gl/scene/gl_sprite.cpp
@@ -779,8 +779,10 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal)
 
 		vt = gltexture->GetSpriteVT();
 		vb = gltexture->GetSpriteVB();
+		if (thing->renderflags & RF_YFLIP) std::swap(vt, vb);
+
 		gltexture->GetSpriteRect(&r);
-		if (mirror)
+		if (mirror ^ !!(thing->renderflags & RF_XFLIP))
 		{
 			r.left = -r.width - r.left;	// mirror the sprite's x-offset
 			ul = gltexture->GetSpriteUL();
diff --git a/src/namedef.h b/src/namedef.h
index cc393ffaf..731947da7 100644
--- a/src/namedef.h
+++ b/src/namedef.h
@@ -726,8 +726,11 @@ xx(MoveBob)
 xx(StillBob)
 xx(WBobSpeed)
 xx(PlayerClass)
+xx(MonsterClass)
+xx(MorphedMonster)
 xx(Wi_NoAutostartMap)
 
+xx(Duration)
 xx(MorphStyle)
 xx(MorphFlash)
 xx(UnMorphFlash)
diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp
index 3a1943fc8..3d1e77d6d 100644
--- a/src/p_buildmap.cpp
+++ b/src/p_buildmap.cpp
@@ -854,45 +854,3 @@ static void Decrypt (void *to_, const void *from_, int len, int key)
 }
 
 #endif
-//==========================================================================
-//
-// Just an actor to make the Build sprites show up. It doesn't do anything
-// with them other than display them.
-//
-//==========================================================================
-
-class ACustomSprite : public AActor
-{
-	DECLARE_CLASS (ACustomSprite, AActor);
-public:
-	void BeginPlay ();
-};
-
-IMPLEMENT_CLASS(ACustomSprite, false, false)
-
-void ACustomSprite::BeginPlay ()
-{
-	char name[9];
-	Super::BeginPlay ();
-
-	mysnprintf (name, countof(name), "BTIL%04d", args[0] & 0xffff);
-	picnum = TexMan.GetTexture (name, FTexture::TEX_Build);
-
-	Scale.X = args[2] / 64.;
-	Scale.Y = args[3] / 64.;
-
-	int cstat = args[4];
-	if (cstat & 2)
-	{
-		RenderStyle = STYLE_Translucent;
-		Alpha = (cstat & 512) ? 0.6666 : 0.3333;
-	}
-	if (cstat & 4)
-		renderflags |= RF_XFLIP;
-	if (cstat & 8)
-		renderflags |= RF_YFLIP;
-
-	// set face/wall/floor flags
-	renderflags |= ActorRenderFlags::FromInt (((cstat >> 4) & 3) << 12);
-}
-
diff --git a/src/r_defs.h b/src/r_defs.h
index a6e8358ee..3c38f285d 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -278,20 +278,6 @@ enum
 	SECSPAC_HitFakeFloor= 1024,	// Trigger when player hits fake floor
 };
 
-class ASectorAction : public AActor
-{
-	DECLARE_CLASS (ASectorAction, AActor)
-public:
-	void OnDestroy() override;
-	void BeginPlay ();
-	void Activate (AActor *source);
-	void Deactivate (AActor *source);
-	bool CanTrigger (AActor *triggerer) const;
-	virtual bool DoTriggerAction(AActor *triggerer, int activationType);
-protected:
-	bool CheckTrigger(AActor *triggerer) const;
-};
-
 struct secplane_t
 {
 	// the plane is defined as a*x + b*y + c*z + d = 0
diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp
index 56209e114..21e4f46d9 100644
--- a/src/scripting/thingdef_data.cpp
+++ b/src/scripting/thingdef_data.cpp
@@ -324,6 +324,8 @@ static FFlagDef ActorFlagDefs[]=
 	DEFINE_FLAG(RF, MASKROTATION, AActor, renderflags),
 	DEFINE_FLAG(RF, ABSMASKANGLE, AActor, renderflags),
 	DEFINE_FLAG(RF, ABSMASKPITCH, AActor, renderflags),
+	DEFINE_FLAG(RF, XFLIP, AActor, renderflags),
+	DEFINE_FLAG(RF, YFLIP, AActor, renderflags),
 
 	// Bounce flags
 	DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),
diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp
index 11e5dc96d..807bd2a93 100644
--- a/src/scripting/thingdef_properties.cpp
+++ b/src/scripting/thingdef_properties.cpp
@@ -2780,55 +2780,55 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, viewbob, F, PlayerPawn)
 //==========================================================================
 // (non-fatal with non-existent types only in DECORATE)
 //==========================================================================
-DEFINE_CLASS_PROPERTY(playerclass, S, MorphProjectile)
+DEFINE_SCRIPTED_PROPERTY(playerclass, S, MorphProjectile)
 {
 	PROP_STRING_PARM(str, 0);
-	defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate);
+	defaults->PointerVar<PClassActor>(NAME_PlayerClass) = FindClassTentativePlayerPawn(str, bag.fromDecorate);
 }
 
 //==========================================================================
 // (non-fatal with non-existent types only in DECORATE)
 //==========================================================================
-DEFINE_CLASS_PROPERTY(monsterclass, S, MorphProjectile)
+DEFINE_SCRIPTED_PROPERTY(monsterclass, S, MorphProjectile)
 {
 	PROP_STRING_PARM(str, 0);
-	defaults->MonsterClass = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
+	defaults->PointerVar<PClassActor>(NAME_MonsterClass) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
 }
 
 //==========================================================================
 //
 //==========================================================================
-DEFINE_CLASS_PROPERTY(duration, I, MorphProjectile)
+DEFINE_SCRIPTED_PROPERTY(duration, I, MorphProjectile)
 {
 	PROP_INT_PARM(i, 0);
-	defaults->Duration = i >= 0 ? i : -i*TICRATE;
+	defaults->IntVar(NAME_Duration) = i >= 0 ? i : -i*TICRATE;
 }
 
 //==========================================================================
 //
 //==========================================================================
-DEFINE_CLASS_PROPERTY(morphstyle, M, MorphProjectile)
+DEFINE_SCRIPTED_PROPERTY(morphstyle, M, MorphProjectile)
 {
 	PROP_INT_PARM(i, 0);
-	defaults->MorphStyle = i;
+	defaults->IntVar(NAME_MorphStyle) = i;
 }
 
 //==========================================================================
 // (non-fatal with non-existent types only in DECORATE)
 //==========================================================================
-DEFINE_CLASS_PROPERTY(morphflash, S, MorphProjectile)
+DEFINE_SCRIPTED_PROPERTY(morphflash, S, MorphProjectile)
 {
 	PROP_STRING_PARM(str, 0);
-	defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
+	defaults->PointerVar<PClassActor>(NAME_MorphFlash) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
 }
 
 //==========================================================================
 //
 //==========================================================================
-DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile)
+DEFINE_SCRIPTED_PROPERTY(unmorphflash, S, MorphProjectile)
 {
 	PROP_STRING_PARM(str, 0);
-	defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
+	defaults->PointerVar<PClassActor>(NAME_UnMorphFlash) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
 }
 
 //==========================================================================
diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt
index 9ae0126eb..7df019fc3 100644
--- a/wadsrc/static/zscript/actor.txt
+++ b/wadsrc/static/zscript/actor.txt
@@ -497,6 +497,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);
 
 	// DECORATE compatible functions
 	native int	CountInv(class<Inventory> itemtype, int ptr_select = AAPTR_DEFAULT);
diff --git a/wadsrc/static/zscript/inventory/inventory.txt b/wadsrc/static/zscript/inventory/inventory.txt
index 0a193978c..da915f170 100644
--- a/wadsrc/static/zscript/inventory/inventory.txt
+++ b/wadsrc/static/zscript/inventory/inventory.txt
@@ -65,6 +65,7 @@ class Inventory : Actor native
 		Stop;
 	}
 	
+
 	//===========================================================================
 	//
 	// AInventory :: BeginPlay
diff --git a/wadsrc/static/zscript/shared/morph.txt b/wadsrc/static/zscript/shared/morph.txt
index c5c2cbe0a..149cf3cea 100644
--- a/wadsrc/static/zscript/shared/morph.txt
+++ b/wadsrc/static/zscript/shared/morph.txt
@@ -1,9 +1,9 @@
-class MorphProjectile : Actor native
+class MorphProjectile : Actor
 {
 
-	native Class<PlayerPawn> PlayerClass;
-	native Class<Actor> MonsterClass, MorphFlash, UnMorphFlash;
-	native int Duration, MorphStyle;
+	Class<PlayerPawn> PlayerClass;
+	Class<Actor> MonsterClass, MorphFlash, UnMorphFlash;
+	int Duration, MorphStyle;
 
 	Default
 	{
@@ -12,6 +12,21 @@ class MorphProjectile : Actor native
 		-ACTIVATEIMPACT
 		-ACTIVATEPCROSS
 	}
+	
+	override int DoSpecialDamage (Actor target, int damage, Name damagetype)
+	{
+		if (target.player)
+		{
+			target.player.MorphPlayer (NULL, PlayerClass, Duration, MorphStyle, MorphFlash, UnMorphFlash);
+		}
+		else
+		{
+			target.MorphMonster (MonsterClass, Duration, MorphStyle, MorphFlash, UnMorphFlash);
+		}
+		return -1;
+	}
+
+	
 }
 
 class MorphedMonster : Actor native
diff --git a/wadsrc/static/zscript/shared/sharedmisc.txt b/wadsrc/static/zscript/shared/sharedmisc.txt
index 812718d30..bc410e3f0 100644
--- a/wadsrc/static/zscript/shared/sharedmisc.txt
+++ b/wadsrc/static/zscript/shared/sharedmisc.txt
@@ -140,7 +140,7 @@ class Gibs : RealGibs
 
 // Needed for loading Build maps -------------------------------------------
 
-class CustomSprite : Actor native
+class CustomSprite : Actor
 {
 	Default
 	{
@@ -153,6 +153,33 @@ class CustomSprite : Actor native
 		TNT1 A -1;
 		Stop;
 	}
+	
+	override void BeginPlay ()
+	{
+		String name;
+		Super.BeginPlay ();
+
+		format(name, "BTIL%04d", args[0] & 0xffff);
+		picnum = TexMan.CheckForTexture (name, TexMan.TYPE_Build);
+		if (!picnum.Exists())
+		{
+			Destroy();
+			return;
+		}
+
+		Scale.X = args[2] / 64.;
+		Scale.Y = args[3] / 64.;
+
+		int cstat = args[4];
+		if (cstat & 2)
+		{
+			A_SetRenderStyle((cstat & 512) ? 0.6666 : 0.3333, STYLE_Translucent);
+		}
+		if (cstat & 4) bXFlip = true;
+		if (cstat & 8) bYFlip = true;
+		if (cstat & 16) bWallSprite = true;
+		if (cstat & 32) bFlatSprite = true;
+	}
 }
 
 // SwitchableDecoration: Activate and Deactivate change state --------------