diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d4edae81e..434d0c520 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -858,7 +858,6 @@ set( NOT_COMPILED_SOURCE_FILES
 	sc_man_scanner.h
 	sc_man_scanner.re
 	g_heretic/a_hereticartifacts.cpp
-	g_heretic/a_hereticweaps.cpp
 	g_hexen/a_blastradius.cpp
 	g_hexen/a_boostarmor.cpp
 	g_hexen/a_clericflame.cpp
diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp
index 5929c1d86..af9d10ba5 100644
--- a/src/g_heretic/a_hereticmisc.cpp
+++ b/src/g_heretic/a_hereticmisc.cpp
@@ -20,4 +20,3 @@
 
 // Include all the other Heretic stuff here to reduce compile time
 #include "a_hereticartifacts.cpp"
-#include "a_hereticweaps.cpp"
diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp
deleted file mode 100644
index 7ec036413..000000000
--- a/src/g_heretic/a_hereticweaps.cpp
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
-#include "templates.h"
-#include "actor.h"
-#include "info.h"
-#include "s_sound.h"
-#include "m_random.h"
-#include "a_pickups.h"
-#include "d_player.h"
-#include "p_pspr.h"
-#include "p_local.h"
-#include "gstrings.h"
-#include "gi.h"
-#include "r_data/r_translate.h"
-#include "vm.h"
-#include "doomstat.h"
-*/
-
-static FRandom pr_boltspark ("BoltSpark");
-static FRandom pr_macerespawn ("MaceRespawn");
-static FRandom pr_maceatk ("FireMacePL1");
-static FRandom pr_bfx1 ("BlasterFX1");
-static FRandom pr_ripd ("RipperD");
-static FRandom pr_fb1 ("FireBlasterPL1");
-static FRandom pr_bfx1t ("BlasterFX1Tick");
-static FRandom pr_rp ("RainPillar");
-static FRandom pr_fsr1 ("FireSkullRodPL1");
-static FRandom pr_storm ("SkullRodStorm");
-static FRandom pr_impact ("RainImpact");
-static FRandom pr_pfx1 ("PhoenixFX1");
-static FRandom pr_pfx2 ("PhoenixFX2");
-static FRandom pr_fp2 ("FirePhoenixPL2");
-
-#define FLAME_THROWER_TICS (10*TICRATE)
-
-void P_DSparilTeleport (AActor *actor);
-
-#define USE_BLSR_AMMO_1 1
-#define USE_BLSR_AMMO_2 5
-#define USE_SKRD_AMMO_1 1
-#define USE_SKRD_AMMO_2 5
-#define USE_PHRD_AMMO_1 1
-#define USE_PHRD_AMMO_2 1
-#define USE_MACE_AMMO_1 1
-#define USE_MACE_AMMO_2 5
-
-extern bool P_AutoUseChaosDevice (player_t *player);
-
-
-// --- Phoenix Rod ----------------------------------------------------------
-
-class APhoenixRod : public AWeapon
-{
-	DECLARE_CLASS (APhoenixRod, AWeapon)
-public:
-	
-	void Serialize(FSerializer &arc)
-	{
-		Super::Serialize (arc);
-		arc("flamecount", FlameCount);
-	}
-	int FlameCount;		// for flamethrower duration
-};
-
-class APhoenixRodPowered : public APhoenixRod
-{
-	DECLARE_CLASS (APhoenixRodPowered, APhoenixRod)
-public:
-	void EndPowerup ();
-};
-
-IMPLEMENT_CLASS(APhoenixRod, false, false)
-IMPLEMENT_CLASS(APhoenixRodPowered, false, false)
-
-void APhoenixRodPowered::EndPowerup ()
-{
-	DepleteAmmo (bAltFire);
-	Owner->player->refire = 0;
-	S_StopSound (Owner, CHAN_WEAPON);
-	Owner->player->ReadyWeapon = SisterWeapon;
-	P_SetPsprite(Owner->player, PSP_WEAPON, SisterWeapon->GetReadyState());
-}
-
-// Phoenix FX 2 -------------------------------------------------------------
-
-class APhoenixFX2 : public AActor
-{
-	DECLARE_CLASS (APhoenixFX2, AActor)
-public:
-	int DoSpecialDamage (AActor *target, int damage, FName damagetype);
-};
-
-IMPLEMENT_CLASS(APhoenixFX2, false, false)
-
-int APhoenixFX2::DoSpecialDamage (AActor *target, int damage, FName damagetype)
-{
-	if (target->player && pr_pfx2 () < 128)
-	{ // Freeze player for a bit
-		target->reactiontime += 4;
-	}
-	return damage;
-}
-
-//----------------------------------------------------------------------------
-//
-// PROC A_FirePhoenixPL1
-//
-//----------------------------------------------------------------------------
-
-DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL1)
-{
-	PARAM_ACTION_PROLOGUE(AActor);
-
-	player_t *player;
-
-	if (NULL == (player = self->player))
-	{
-		return 0;
-	}
-
-	AWeapon *weapon = self->player->ReadyWeapon;
-	if (weapon != NULL)
-	{
-		if (!weapon->DepleteAmmo (weapon->bAltFire))
-			return 0;
-	}
-	P_SpawnPlayerMissile (self, PClass::FindActor("PhoenixFX1"));
-	self->Thrust(self->Angles.Yaw + 180, 4);
-	return 0;
-}
-
-//----------------------------------------------------------------------------
-//
-// PROC A_PhoenixPuff
-//
-//----------------------------------------------------------------------------
-
-DEFINE_ACTION_FUNCTION(AActor, A_PhoenixPuff)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	AActor *puff;
-	DAngle ang;
-
-	//[RH] Heretic never sets the target for seeking
-	//P_SeekerMissile (self, 5, 10);
-	puff = Spawn("PhoenixPuff", self->Pos(), ALLOW_REPLACE);
-	ang = self->Angles.Yaw + 90;
-	puff->Vel = DVector3(ang.ToVector(1.3), 0);
-
-	puff = Spawn("PhoenixPuff", self->Pos(), ALLOW_REPLACE);
-	ang = self->Angles.Yaw - 90;
-	puff->Vel = DVector3(ang.ToVector(1.3), 0);
-	return 0;
-}
-
-//----------------------------------------------------------------------------
-//
-// PROC A_InitPhoenixPL2
-//
-//----------------------------------------------------------------------------
-
-DEFINE_ACTION_FUNCTION(AActor, A_InitPhoenixPL2)
-{
-	PARAM_ACTION_PROLOGUE(AActor);
-
-	if (self->player != NULL)
-	{
-		APhoenixRod *flamethrower = static_cast<APhoenixRod *> (self->player->ReadyWeapon);
-		if (flamethrower != NULL)
-		{
-			flamethrower->FlameCount = FLAME_THROWER_TICS;
-		}
-	}
-	return 0;
-}
-
-//----------------------------------------------------------------------------
-//
-// PROC A_FirePhoenixPL2
-//
-// Flame thrower effect.
-//
-//----------------------------------------------------------------------------
-
-DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2)
-{
-	PARAM_ACTION_PROLOGUE(AActor);
-
-	AActor *mo;
-
-	double slope;
-	FSoundID soundid;
-	player_t *player;
-	APhoenixRod *flamethrower;
-
-	if (nullptr == (player = self->player))
-	{
-		return 0;
-	}
-
-	soundid = "weapons/phoenixpowshoot";
-
-	flamethrower = static_cast<APhoenixRod *> (player->ReadyWeapon);
-	if (flamethrower == nullptr || --flamethrower->FlameCount == 0)
-	{ // Out of flame
-		P_SetPsprite(player, PSP_WEAPON, flamethrower->FindState("Powerdown"));
-		player->refire = 0;
-		S_StopSound (self, CHAN_WEAPON);
-		return 0;
-	}
-
-	slope = -self->Angles.Pitch.TanClamped();
-	double xo = pr_fp2.Random2() / 128.;
-	double yo = pr_fp2.Random2() / 128.;
-	DVector3 pos = self->Vec3Offset(xo, yo, 26 + slope - self->Floorclip);
-
-	slope += 0.1;
-	mo = Spawn("PhoenixFX2", pos, ALLOW_REPLACE);
-	mo->target = self;
-	mo->Angles.Yaw = self->Angles.Yaw;
-	mo->VelFromAngle();
-	mo->Vel += self->Vel.XY();
-	mo->Vel.Z = mo->Speed * slope;
-	if (!player->refire || !S_IsActorPlayingSomething (self, CHAN_WEAPON, -1))
-	{
-		S_Sound (self, CHAN_WEAPON|CHAN_LOOP, soundid, 1, ATTN_NORM);
-	}	
-	P_CheckMissileSpawn (mo, self->radius);
-	return 0;
-}
-
-//----------------------------------------------------------------------------
-//
-// PROC A_ShutdownPhoenixPL2
-//
-//----------------------------------------------------------------------------
-
-DEFINE_ACTION_FUNCTION(AActor, A_ShutdownPhoenixPL2)
-{
-	PARAM_ACTION_PROLOGUE(AActor);
-
-	player_t *player;
-
-	if (NULL == (player = self->player))
-	{
-		return 0;
-	}
-	S_StopSound (self, CHAN_WEAPON);
-	AWeapon *weapon = player->ReadyWeapon;
-	if (weapon != NULL)
-	{
-		if (!weapon->DepleteAmmo (weapon->bAltFire))
-			return 0;
-	}
-	return 0;
-}
-
-//----------------------------------------------------------------------------
-//
-// PROC A_FlameEnd
-//
-//----------------------------------------------------------------------------
-
-DEFINE_ACTION_FUNCTION(AActor, A_FlameEnd)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	self->Vel.Z += 1.5;
-	return 0;
-}
-
-//----------------------------------------------------------------------------
-//
-// PROC A_FloatPuff
-//
-//----------------------------------------------------------------------------
-
-DEFINE_ACTION_FUNCTION(AActor, A_FloatPuff)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	self->Vel.Z += 1.8;
-	return 0;
-}
-
diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp
index 73b71e2ff..854881647 100644
--- a/src/g_shared/a_artifacts.cpp
+++ b/src/g_shared/a_artifacts.cpp
@@ -1185,7 +1185,7 @@ void APowerWeaponLevel2::EndEffect ()
 		if (player->ReadyWeapon != NULL &&
 			player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP)
 		{
-			player->ReadyWeapon->EndPowerup ();
+			player->ReadyWeapon->CallEndPowerup ();
 		}
 		if (player->PendingWeapon != NULL && player->PendingWeapon != WP_NOCHANGE &&
 			player->PendingWeapon->WeaponFlags & WIF_POWERED_UP &&
diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h
index bf4af5a63..0cfd04147 100644
--- a/src/g_shared/a_pickups.h
+++ b/src/g_shared/a_pickups.h
@@ -342,6 +342,7 @@ public:
 
 	virtual void PostMorphWeapon ();
 	virtual void EndPowerup ();
+	void CallEndPowerup();
 
 	enum
 	{
diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp
index b94a4770c..02cd19fa6 100644
--- a/src/g_shared/a_weapons.cpp
+++ b/src/g_shared/a_weapons.cpp
@@ -18,6 +18,7 @@
 #include "d_net.h"
 #include "serializer.h"
 #include "thingdef.h"
+#include "virtual.h"
 
 #define BONUSADD 6
 
@@ -789,6 +790,26 @@ void AWeapon::EndPowerup ()
 	}
 }
 
+DEFINE_ACTION_FUNCTION(AWeapon, EndPowerup)
+{
+	PARAM_SELF_PROLOGUE(AWeapon);
+	self->EndPowerup();
+	return 0;
+}
+
+void AWeapon::CallEndPowerup()
+{
+	IFVIRTUAL(AWeapon, EndPowerup)
+	{
+		// Without the type cast this picks the 'void *' assignment...
+		VMValue params[1] = { (DObject*)this };
+		VMFrameStack stack;
+		stack.Call(func, params, 1, nullptr, 0, nullptr);
+	}
+	else EndPowerup();
+}
+
+
 //===========================================================================
 //
 // AWeapon :: GetUpState
diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt
index 7144c64e5..fa0cebd96 100644
--- a/wadsrc/static/zscript.txt
+++ b/wadsrc/static/zscript.txt
@@ -85,7 +85,6 @@ zscript/heretic/hereticartifacts.txt
 zscript/heretic/heretickeys.txt
 zscript/heretic/hereticdecorations.txt
 zscript/heretic/hereticmisc.txt
-zscript/heretic/hereticweaps.txt
 zscript/heretic/mummy.txt
 zscript/heretic/clink.txt
 zscript/heretic/beast.txt
@@ -103,6 +102,7 @@ zscript/heretic/weapongauntlets.txt
 zscript/heretic/weaponmace.txt
 zscript/heretic/weaponblaster.txt
 zscript/heretic/weaponskullrod.txt
+zscript/heretic/weaponphoenix.txt
 
 zscript/hexen/baseweapons.txt
 zscript/hexen/korax.txt
diff --git a/wadsrc/static/zscript/heretic/hereticweaps.txt b/wadsrc/static/zscript/heretic/hereticweaps.txt
deleted file mode 100644
index 1b84d13fe..000000000
--- a/wadsrc/static/zscript/heretic/hereticweaps.txt
+++ /dev/null
@@ -1,184 +0,0 @@
-
-class HereticWeapon : Weapon
-{
-	Default
-	{
-		Weapon.Kickback 150;
-	}
-}
-
-
-// Phoenix Rod --------------------------------------------------------------
-
-class PhoenixRod : Weapon native
-{
-	Default
-	{
-		+WEAPON.NOAUTOFIRE
-		Weapon.SelectionOrder 2600;
-		Weapon.Kickback 150;
-		Weapon.YAdjust 15;
-		Weapon.AmmoUse 1;
-		Weapon.AmmoGive 2;
-		Weapon.AmmoType "PhoenixRodAmmo";
-		Weapon.Sisterweapon "PhoenixRodPowered";
-		Inventory.PickupMessage "$TXT_WPNPHOENIXROD";
-		Tag "$TAG_PHOENIXROD";
-	}
-
-	action native void A_FirePhoenixPL1();
-
-	States
-	{
-	Spawn:
-		WPHX A -1;
-		Stop;
-	Ready:
-		PHNX A 1 A_WeaponReady;
-		Loop;
-	Deselect:
-		PHNX A 1 A_Lower;
-		Loop;
-	Select:
-		PHNX A 1 A_Raise;
-		Loop;
-	Fire:
-		PHNX B 5;
-		PHNX C 7 A_FirePhoenixPL1;
-		PHNX DB 4;
-		PHNX B 0 A_ReFire;
-		Goto Ready;
-	}
-}
-
-class PhoenixRodPowered : PhoenixRod native
-{
-	Default
-	{
-		+WEAPON.POWERED_UP
-		+WEAPON.MELEEWEAPON
-		Weapon.SisterWeapon "PhoenixRod";
-		Weapon.AmmoGive 0;
-		Tag "$TAG_PHOENIXRODP";
-	}
-
-	action native void A_InitPhoenixPL2();
-	action native void A_FirePhoenixPL2();
-	action native void A_ShutdownPhoenixPL2();
-
-	States
-	{
-	Fire:
-		PHNX B 3 A_InitPhoenixPL2;
-	Hold:
-		PHNX C 1 A_FirePhoenixPL2;
-		PHNX B 4 A_ReFire;
-	Powerdown:
-		PHNX B 4 A_ShutdownPhoenixPL2;
-		Goto Ready;
-	}
-}
-
-// Phoenix FX 1 -------------------------------------------------------------
-
-class PhoenixFX1 : Actor
-{
-	Default
-	{
-		Radius 11;
-		Height 8;
-		Speed 20;
-		Damage 20;
-		DamageType "Fire";
-		Projectile;
-		+THRUGHOST
-		+SPECIALFIREDAMAGE
-		SeeSound "weapons/phoenixshoot";
-		DeathSound "weapons/phoenixhit";
-		Obituary "$OB_MPPHOENIXROD";
-	}
-
-	native void A_PhoenixPuff();
-
-	States
-	{
-	Spawn:
-		FX04 A 4 BRIGHT A_PhoenixPuff;
-		Loop;
-	Death:
-		FX08 A 6 BRIGHT A_Explode;
-		FX08 BC 5 BRIGHT;
-		FX08 DEFGH 4 BRIGHT;
-		Stop;
-	}
-	
-	override int DoSpecialDamage (Actor target, int damage, Name damagetype)
-	{
-		Sorcerer2 s2 = Sorcerer2(target);
-		if (s2 != null && random[HornRodFX2]() < 96)
-		{ // D'Sparil teleports away
-			s2.DSparilTeleport ();
-			return -1;
-		}
-		return damage;
-	}
-	
-}
-
-// Phoenix puff -------------------------------------------------------------
-
-class PhoenixPuff : Actor
-{
-	Default
-	{
-		+NOBLOCKMAP
-		+NOGRAVITY
-		+NOTELEPORT
-		+CANNOTPUSH
-		RenderStyle "Translucent";
-		Alpha 0.4;
-	}
-
-	States
-	{
-	Spawn:
-		FX04 BCDEF 4;
-		Stop;
-	}
-}
-
-// Phoenix FX 2 -------------------------------------------------------------
-
-class PhoenixFX2 : Actor native
-{
-	Default
-	{
-		Radius 6;
-		Height 8;
-		Speed 10;
-		Damage 2;
-		DamageType "Fire";
-		Projectile;
-		RenderStyle "Add";
-		Obituary "$OB_MPPPHOENIXROD";
-	}
-
-	native void A_FlameEnd();
-	native void A_FloatPuff();
-
-	States
-	{
-	Spawn:
-		FX09 ABABA 2 BRIGHT;
-		FX09 B 2 BRIGHT A_FlameEnd;
-		FX09 CDEF 2 BRIGHT;
-		Stop;
-	Death:
-		FX09 G 3 BRIGHT;
-		FX09 H 3 BRIGHT A_FloatPuff;
-		FX09 I 4 BRIGHT;
-		FX09 JK 5 BRIGHT;
-		Stop;
-	}
-}
-
diff --git a/wadsrc/static/zscript/heretic/weaponphoenix.txt b/wadsrc/static/zscript/heretic/weaponphoenix.txt
new file mode 100644
index 000000000..554d52d21
--- /dev/null
+++ b/wadsrc/static/zscript/heretic/weaponphoenix.txt
@@ -0,0 +1,347 @@
+
+class HereticWeapon : Weapon
+{
+	Default
+	{
+		Weapon.Kickback 150;
+	}
+}
+
+
+// Phoenix Rod --------------------------------------------------------------
+
+class PhoenixRod : Weapon
+{
+	Default
+	{
+		+WEAPON.NOAUTOFIRE
+		Weapon.SelectionOrder 2600;
+		Weapon.Kickback 150;
+		Weapon.YAdjust 15;
+		Weapon.AmmoUse 1;
+		Weapon.AmmoGive 2;
+		Weapon.AmmoType "PhoenixRodAmmo";
+		Weapon.Sisterweapon "PhoenixRodPowered";
+		Inventory.PickupMessage "$TXT_WPNPHOENIXROD";
+		Tag "$TAG_PHOENIXROD";
+	}
+
+	States
+	{
+	Spawn:
+		WPHX A -1;
+		Stop;
+	Ready:
+		PHNX A 1 A_WeaponReady;
+		Loop;
+	Deselect:
+		PHNX A 1 A_Lower;
+		Loop;
+	Select:
+		PHNX A 1 A_Raise;
+		Loop;
+	Fire:
+		PHNX B 5;
+		PHNX C 7 A_FirePhoenixPL1;
+		PHNX DB 4;
+		PHNX B 0 A_ReFire;
+		Goto Ready;
+	}
+	
+	//----------------------------------------------------------------------------
+	//
+	// PROC A_FirePhoenixPL1
+	//
+	//----------------------------------------------------------------------------
+
+	action void A_FirePhoenixPL1()
+	{
+		if (player == null)
+		{
+			return;
+		}
+
+		Weapon weapon = player.ReadyWeapon;
+		if (weapon != null)
+		{
+			if (!weapon.DepleteAmmo (weapon.bAltFire))
+				return;
+		}
+		SpawnPlayerMissile ("PhoenixFX1");
+		Thrust(4, angle + 180);
+	}
+
+	
+}
+
+class PhoenixRodPowered : PhoenixRod
+{
+	const FLAME_THROWER_TICS = (10*TICRATE);
+	
+	private int FlameCount;		// for flamethrower duration
+	
+	Default
+	{
+		+WEAPON.POWERED_UP
+		+WEAPON.MELEEWEAPON
+		Weapon.SisterWeapon "PhoenixRod";
+		Weapon.AmmoGive 0;
+		Tag "$TAG_PHOENIXRODP";
+	}
+
+	States
+	{
+	Fire:
+		PHNX B 3 A_InitPhoenixPL2;
+	Hold:
+		PHNX C 1 A_FirePhoenixPL2;
+		PHNX B 4 A_ReFire;
+	Powerdown:
+		PHNX B 4 A_ShutdownPhoenixPL2;
+		Goto Ready;
+	}
+	
+
+	override void EndPowerup ()
+	{
+		DepleteAmmo (bAltFire);
+		Owner.player.refire = 0;
+		Owner.A_StopSound (CHAN_WEAPON);
+		Owner.player.ReadyWeapon = SisterWeapon;
+		Owner.player.SetPsprite(PSP_WEAPON, SisterWeapon.GetReadyState());
+	}
+
+	//----------------------------------------------------------------------------
+	//
+	// PROC A_InitPhoenixPL2
+	//
+	//----------------------------------------------------------------------------
+
+	action void A_InitPhoenixPL2()
+	{
+		if (player != null)
+		{
+			PhoenixRodPowered flamethrower = PhoenixRodPowered(player.ReadyWeapon);
+			if (flamethrower != null)
+			{
+				flamethrower.FlameCount = FLAME_THROWER_TICS;
+			}
+		}
+	}
+
+	//----------------------------------------------------------------------------
+	//
+	// PROC A_FirePhoenixPL2
+	//
+	// Flame thrower effect.
+	//
+	//----------------------------------------------------------------------------
+
+	action void A_FirePhoenixPL2()
+	{
+		if (player == null)
+		{
+			return;
+		}
+
+		PhoenixRodPowered flamethrower = PhoenixRodPowered(player.ReadyWeapon);
+		
+		if (flamethrower == null || --flamethrower.FlameCount == 0)
+		{ // Out of flame
+			player.SetPsprite(PSP_WEAPON, flamethrower.FindState("Powerdown"));
+			player.refire = 0;
+			A_StopSound (CHAN_WEAPON);
+			return;
+		}
+
+		double slope = -clamp(tan(pitch), -5, 5);
+		double xo = Random2[FirePhoenixPL2]() / 128.;
+		double yo = Random2[FirePhoenixPL2]() / 128.;
+		Vector3 spawnpos = Vec3Offset(xo, yo, 26 + slope - Floorclip);
+
+		slope += 0.1;
+		Actor mo = Spawn("PhoenixFX2", spawnpos, ALLOW_REPLACE);
+		mo.target = self;
+		mo.Angle = Angle;
+		mo.VelFromAngle();
+		mo.Vel.XY += Vel.XY;
+		mo.Vel.Z = mo.Speed * slope;
+		if (!player.refire)
+		{
+			A_PlaySound("weapons/phoenixpowshoot", CHAN_WEAPON, 1, true);
+		}	
+		mo.CheckMissileSpawn (radius);
+	}
+
+	//----------------------------------------------------------------------------
+	//
+	// PROC A_ShutdownPhoenixPL2
+	//
+	//----------------------------------------------------------------------------
+
+	action void A_ShutdownPhoenixPL2()
+	{
+		if (player == null)
+		{
+			return;
+		}
+		A_StopSound (CHAN_WEAPON);
+		Weapon weapon = player.ReadyWeapon;
+		if (weapon != null)
+		{
+			weapon.DepleteAmmo (weapon.bAltFire);
+		}
+	}
+
+	
+}
+
+// Phoenix FX 1 -------------------------------------------------------------
+
+class PhoenixFX1 : Actor
+{
+	Default
+	{
+		Radius 11;
+		Height 8;
+		Speed 20;
+		Damage 20;
+		DamageType "Fire";
+		Projectile;
+		+THRUGHOST
+		+SPECIALFIREDAMAGE
+		SeeSound "weapons/phoenixshoot";
+		DeathSound "weapons/phoenixhit";
+		Obituary "$OB_MPPHOENIXROD";
+	}
+
+	States
+	{
+	Spawn:
+		FX04 A 4 BRIGHT A_PhoenixPuff;
+		Loop;
+	Death:
+		FX08 A 6 BRIGHT A_Explode;
+		FX08 BC 5 BRIGHT;
+		FX08 DEFGH 4 BRIGHT;
+		Stop;
+	}
+	
+	override int DoSpecialDamage (Actor target, int damage, Name damagetype)
+	{
+		Sorcerer2 s2 = Sorcerer2(target);
+		if (s2 != null && random[HornRodFX2]() < 96)
+		{ // D'Sparil teleports away
+			s2.DSparilTeleport ();
+			return -1;
+		}
+		return damage;
+	}
+
+	//----------------------------------------------------------------------------
+	//
+	// PROC A_PhoenixPuff
+	//
+	//----------------------------------------------------------------------------
+
+	void A_PhoenixPuff()
+	{
+		//[RH] Heretic never sets the target for seeking
+		//P_SeekerMissile (self, 5, 10);
+		Actor puff = Spawn("PhoenixPuff", Pos, ALLOW_REPLACE);
+		puff.Vel.XY = AngleToVector(Angle + 90, 1.3);
+
+		puff = Spawn("PhoenixPuff", Pos, ALLOW_REPLACE);
+		puff.Vel.XY = AngleToVector(Angle - 90, 1.3);
+	}
+
+	
+}
+
+// Phoenix puff -------------------------------------------------------------
+
+class PhoenixPuff : Actor
+{
+	Default
+	{
+		+NOBLOCKMAP
+		+NOGRAVITY
+		+NOTELEPORT
+		+CANNOTPUSH
+		RenderStyle "Translucent";
+		Alpha 0.4;
+	}
+
+	States
+	{
+	Spawn:
+		FX04 BCDEF 4;
+		Stop;
+	}
+}
+
+// Phoenix FX 2 -------------------------------------------------------------
+
+class PhoenixFX2 : Actor
+{
+	Default
+	{
+		Radius 6;
+		Height 8;
+		Speed 10;
+		Damage 2;
+		DamageType "Fire";
+		Projectile;
+		RenderStyle "Add";
+		Obituary "$OB_MPPPHOENIXROD";
+	}
+
+	States
+	{
+	Spawn:
+		FX09 ABABA 2 BRIGHT;
+		FX09 B 2 BRIGHT A_FlameEnd;
+		FX09 CDEF 2 BRIGHT;
+		Stop;
+	Death:
+		FX09 G 3 BRIGHT;
+		FX09 H 3 BRIGHT A_FloatPuff;
+		FX09 I 4 BRIGHT;
+		FX09 JK 5 BRIGHT;
+		Stop;
+	}
+	
+
+	int DoSpecialDamage (Actor target, int damage, Name damagetype)
+	{
+		if (target.player && Random[PhoenixFX2]() < 128)
+		{ // Freeze player for a bit
+			target.reactiontime += 4;
+		}
+		return damage;
+	}
+	
+	//----------------------------------------------------------------------------
+	//
+	// PROC A_FlameEnd
+	//
+	//----------------------------------------------------------------------------
+
+	void A_FlameEnd()
+	{
+		Vel.Z += 1.5;
+	}
+
+	//----------------------------------------------------------------------------
+	//
+	// PROC A_FloatPuff
+	//
+	//----------------------------------------------------------------------------
+
+	void A_FloatPuff()
+	{
+		Vel.Z += 1.8;
+	}
+
+	
+}
diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt
index 12e521d53..52a346ce1 100644
--- a/wadsrc/static/zscript/shared/inventory.txt
+++ b/wadsrc/static/zscript/shared/inventory.txt
@@ -569,6 +569,7 @@ class Weapon : StateProvider native
 	}
 	
 	native bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1);
+	native virtual void EndPowerup();
 	
 	virtual State GetReadyState ()
 	{