diff --git a/docs/rh-log.txt b/docs/rh-log.txt
index d45604ade..bc7fb6a28 100644
--- a/docs/rh-log.txt
+++ b/docs/rh-log.txt
@@ -1,4 +1,8 @@
 August 3, 2008 (Changes by Graf Zahl)
+- Converted the mace and all related actors to DECORATE and generalized
+  the spawn function that only spawns one mace per level.
+- Moved Mace respawning code into AInventory so that it works properly
+  for replacement actors.
 - Added more DECORATE conversions by Karate Chris.
 - Cleaned up the new bridge code and exported all related actors to
   DECORATE so that the exported code pointers can be used.
diff --git a/src/codepointers.h b/src/codepointers.h
index 7eb5f7e86..32ebbe808 100644
--- a/src/codepointers.h
+++ b/src/codepointers.h
@@ -107,6 +107,7 @@ ACTOR(DamageChildren)
 ACTOR(CheckForReload)
 ACTOR(ResetReloadCounter)
 ACTOR(ClearReFire)
+ACTOR(SpawnSingleItem)
 
 // Heretic stuff
 ACTOR(Feathers)
@@ -151,6 +152,13 @@ ACTOR(FireGoldWandPL2)
 ACTOR(FireCrossbowPL1)
 ACTOR(FireCrossbowPL2)
 ACTOR(GauntletAttack)
+ACTOR(FireMacePL1)
+ACTOR(FireMacePL2)
+ACTOR(MacePL1Check)
+ACTOR(MaceBallImpact)
+ACTOR(MaceBallImpact2)
+ACTOR(DeathBallImpact)
+
 
 WEAPON(CMaceAttack)
 ACTOR(FiredRocks)
diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp
index 21d835808..444c8728a 100644
--- a/src/g_heretic/a_hereticweaps.cpp
+++ b/src/g_heretic/a_hereticweaps.cpp
@@ -14,7 +14,6 @@
 #include "p_enemy.h"
 #include "gi.h"
 #include "r_translate.h"
-#include "a_specialspot.h"
 #include "thingdef/thingdef.h"
 
 static FRandom pr_sap ("StaffAtkPL1");
@@ -22,7 +21,6 @@ static FRandom pr_sap2 ("StaffAtkPL2");
 static FRandom pr_fgw ("FireWandPL1");
 static FRandom pr_fgw2 ("FireWandPL2");
 static FRandom pr_boltspark ("BoltSpark");
-static FRandom pr_spawnmace ("SpawnMace");
 static FRandom pr_macerespawn ("MaceRespawn");
 static FRandom pr_maceatk ("FireMacePL1");
 static FRandom pr_gatk ("GauntletAttack");
@@ -343,212 +341,16 @@ void A_GauntletAttack (AActor *actor)
 
 #define MAGIC_JUNK 1234
 
-void A_FireMacePL1B (AActor *);
-void A_FireMacePL1 (AActor *);
-void A_MacePL1Check (AActor *);
-void A_MaceBallImpact (AActor *);
-void A_MaceBallImpact2 (AActor *);
-void A_FireMacePL2 (AActor *);
-void A_DeathBallImpact (AActor *);
-
-// The mace itself ----------------------------------------------------------
-
-class AMace : public AHereticWeapon
-{
-	DECLARE_ACTOR (AMace, AHereticWeapon)
-protected:
-	bool DoRespawn ();
-};
-
-class AMacePowered : public AMace
-{
-	DECLARE_STATELESS_ACTOR (AMacePowered, AMace)
-};
-
-FState AMace::States[] =
-{
-#define S_WMCE 0
-	S_NORMAL (WMCE, 'A',   -1, NULL 				, NULL),
-
-#define S_MACEREADY (S_WMCE+1)
-	S_NORMAL (MACE, 'A',	1, A_WeaponReady		, &States[S_MACEREADY]),
-
-#define S_MACEDOWN (S_MACEREADY+1)
-	S_NORMAL (MACE, 'A',	1, A_Lower				, &States[S_MACEDOWN]),
-
-#define S_MACEUP (S_MACEDOWN+1)
-	S_NORMAL (MACE, 'A',	1, A_Raise				, &States[S_MACEUP]),
-
-#define S_MACEATK1 (S_MACEUP+1)
-	S_NORMAL (MACE, 'B',	4, NULL 				, &States[S_MACEATK1+1]),
-	S_NORMAL (MACE, 'C',	3, A_FireMacePL1		, &States[S_MACEATK1+2]),
-	S_NORMAL (MACE, 'D',	3, A_FireMacePL1		, &States[S_MACEATK1+3]),
-	S_NORMAL (MACE, 'E',	3, A_FireMacePL1		, &States[S_MACEATK1+4]),
-	S_NORMAL (MACE, 'F',	3, A_FireMacePL1		, &States[S_MACEATK1+5]),
-	S_NORMAL (MACE, 'C',	4, A_ReFire 			, &States[S_MACEATK1+6]),
-	S_NORMAL (MACE, 'D',	4, NULL 				, &States[S_MACEATK1+7]),
-	S_NORMAL (MACE, 'E',	4, NULL 				, &States[S_MACEATK1+8]),
-	S_NORMAL (MACE, 'F',	4, NULL 				, &States[S_MACEATK1+9]),
-	S_NORMAL (MACE, 'B',	4, NULL 				, &States[S_MACEREADY]),
-
-#define S_MACEATK2 (S_MACEATK1+10)
-	S_NORMAL (MACE, 'B',	4, NULL 				, &States[S_MACEATK2+1]),
-	S_NORMAL (MACE, 'D',	4, A_FireMacePL2		, &States[S_MACEATK2+2]),
-	S_NORMAL (MACE, 'B',	4, NULL 				, &States[S_MACEATK2+3]),
-	S_NORMAL (MACE, 'A',	8, A_ReFire 			, &States[S_MACEREADY])
-};
-
-IMPLEMENT_ACTOR (AMace, Heretic, -1, 31)
-	PROP_Flags (MF_SPECIAL)
-	PROP_SpawnState (0)
-
-	PROP_Weapon_SelectionOrder (1400)
-	PROP_Weapon_Flags (WIF_BOT_REACTION_SKILL_THING|WIF_BOT_EXPLOSIVE)
-	PROP_Weapon_AmmoUse1 (USE_MACE_AMMO_1)
-	PROP_Weapon_AmmoGive1 (50)
-	PROP_Weapon_UpState (S_MACEUP)
-	PROP_Weapon_DownState (S_MACEDOWN)
-	PROP_Weapon_ReadyState (S_MACEREADY)
-	PROP_Weapon_AtkState (S_MACEATK1)
-	PROP_Weapon_HoldAtkState (S_MACEATK1+1)
-	PROP_Weapon_YAdjust (15)
-	PROP_Weapon_MoveCombatDist (27000000)
-	PROP_Weapon_AmmoType1 ("MaceAmmo")
-	PROP_Weapon_SisterType ("MacePowered")
-	PROP_Weapon_ProjectileType ("MaceFX2")
-	PROP_Inventory_PickupMessage("$TXT_WPNMACE")
-END_DEFAULTS
-
-IMPLEMENT_STATELESS_ACTOR (AMacePowered, Heretic, -1, 0)
-	PROP_Weapon_Flags (WIF_POWERED_UP|WIF_BOT_REACTION_SKILL_THING|WIF_BOT_EXPLOSIVE)
-	PROP_Weapon_AmmoUse1 (USE_MACE_AMMO_2)
-	PROP_Weapon_AmmoGive1 (0)
-	PROP_Weapon_AtkState (S_MACEATK2)
-	PROP_Weapon_HoldAtkState (S_MACEATK2)
-	PROP_Weapon_SisterType ("Mace")
-	PROP_Weapon_ProjectileType ("MaceFX4")
-END_DEFAULTS
-
-// Mace FX1 -----------------------------------------------------------------
-
-class AMaceFX1 : public AActor
-{
-	DECLARE_ACTOR (AMaceFX1, AActor)
-};
-
-FState AMaceFX1::States[] =
-{
-#define S_MACEFX1 0
-	S_NORMAL (FX02, 'A',	4, A_MacePL1Check		, &States[S_MACEFX1+1]),
-	S_NORMAL (FX02, 'B',	4, A_MacePL1Check		, &States[S_MACEFX1+0]),
-
-#define S_MACEFXI1 (S_MACEFX1+2)
-	S_BRIGHT (FX02, 'F',	4, A_MaceBallImpact 	, &States[S_MACEFXI1+1]),
-	S_BRIGHT (FX02, 'G',	4, NULL 				, &States[S_MACEFXI1+2]),
-	S_BRIGHT (FX02, 'H',	4, NULL 				, &States[S_MACEFXI1+3]),
-	S_BRIGHT (FX02, 'I',	4, NULL 				, &States[S_MACEFXI1+4]),
-	S_BRIGHT (FX02, 'J',	4, NULL 				, NULL)
-};
-
-IMPLEMENT_ACTOR (AMaceFX1, Heretic, -1, 154)
-	PROP_RadiusFixed (8)
-	PROP_HeightFixed (6)
-	PROP_SpeedFixed (20)
-	PROP_Damage (2)
-	PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY)
-	PROP_Flags2 (MF2_HERETICBOUNCE|MF2_THRUGHOST|MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
-	PROP_Flags3 (MF3_WARNBOT)
-
-	PROP_SpawnState (S_MACEFX1)
-	PROP_DeathState (S_MACEFXI1)
-
-	PROP_SeeSound ("weapons/maceshoot")
-END_DEFAULTS
-
-// Mace FX2 -----------------------------------------------------------------
-
-class AMaceFX2 : public AActor
-{
-	DECLARE_ACTOR (AMaceFX2, AActor)
-};
-
-FState AMaceFX2::States[] =
-{
-#define S_MACEFX2 0
-	S_NORMAL (FX02, 'C',	4, NULL 				, &States[S_MACEFX2+1]),
-	S_NORMAL (FX02, 'D',	4, NULL 				, &States[S_MACEFX2+0]),
-
-#define S_MACEFXI2 (S_MACEFX2+2)
-	S_BRIGHT (FX02, 'F',	4, A_MaceBallImpact2	, &AMaceFX1::States[S_MACEFXI1+1])
-};
-
-IMPLEMENT_ACTOR (AMaceFX2, Heretic, -1, 156)
-	PROP_RadiusFixed (8)
-	PROP_HeightFixed (6)
-	PROP_SpeedFixed (10)
-	PROP_Damage (6)
-	PROP_Gravity (FRACUNIT/8)
-	PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF)
-	PROP_Flags2 (MF2_HERETICBOUNCE|MF2_THRUGHOST|MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
-
-	PROP_SpawnState (S_MACEFX2)
-	PROP_DeathState (S_MACEFXI2)
-END_DEFAULTS
-
-// Mace FX3 -----------------------------------------------------------------
-
-class AMaceFX3 : public AMaceFX1
-{
-	DECLARE_ACTOR (AMaceFX3, AMaceFX1)
-};
-
-FState AMaceFX3::States[] =
-{
-#define S_MACEFX3 0
-	S_NORMAL (FX02, 'A',	4, NULL 				, &States[S_MACEFX3+1]),
-	S_NORMAL (FX02, 'B',	4, NULL 				, &States[S_MACEFX3+0])
-};
-
-IMPLEMENT_ACTOR (AMaceFX3, Heretic, -1, 155)
-	PROP_SpeedFixed (7)
-	PROP_Damage (4)
-	PROP_Gravity (FRACUNIT/8)
-	PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF)
-	PROP_Flags2 (MF2_HERETICBOUNCE|MF2_THRUGHOST|MF2_NOTELEPORT|MF2_PCROSS|MF2_IMPACT)
-
-	PROP_SpawnState (S_MACEFX3)
-END_DEFAULTS
-
 // Mace FX4 -----------------------------------------------------------------
 
 class AMaceFX4 : public AActor
 {
-	DECLARE_ACTOR (AMaceFX4, AActor)
+	DECLARE_CLASS (AMaceFX4, AActor)
 public:
 	int DoSpecialDamage (AActor *target, int damage);
 };
 
-FState AMaceFX4::States[] =
-{
-#define S_MACEFX4 0
-	S_NORMAL (FX02, 'E',   99, NULL 				, &States[S_MACEFX4+0]),
-
-#define S_MACEFXI4 (S_MACEFX4+1)
-	S_BRIGHT (FX02, 'C',	4, A_DeathBallImpact	, &AMaceFX1::States[S_MACEFXI1+1])
-};
-
-IMPLEMENT_ACTOR (AMaceFX4, Heretic, -1, 153)
-	PROP_RadiusFixed (8)
-	PROP_HeightFixed (6)
-	PROP_SpeedFixed (7)
-	PROP_Damage (18)
-	PROP_Gravity (FRACUNIT/8)
-	PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF)
-	PROP_Flags2 (MF2_HERETICBOUNCE|MF2_THRUGHOST|MF2_TELESTOMP|MF2_PCROSS|MF2_IMPACT)
-
-	PROP_SpawnState (S_MACEFX4)
-	PROP_DeathState (S_MACEFXI4)
-END_DEFAULTS
+IMPLEMENT_CLASS (AMaceFX4)
 
 int AMaceFX4::DoSpecialDamage (AActor *target, int damage)
 {
@@ -570,79 +372,6 @@ int AMaceFX4::DoSpecialDamage (AActor *target, int damage)
 	return 1000000; // Something's gonna die
 }
 
-// Mace spawn spot ----------------------------------------------------------
-
-void A_SpawnMace (AActor *);
-
-class AMaceSpawner : public ASpecialSpot
-{
-	DECLARE_ACTOR (AMaceSpawner, ASpecialSpot)
-};
-
-FState AMaceSpawner::States[] =
-{
-	S_NORMAL (TNT1, 'A', 1, NULL, &States[1]),
-	S_NORMAL (TNT1, 'A', -1, A_SpawnMace, NULL)
-};
-
-IMPLEMENT_ACTOR (AMaceSpawner, Heretic, 2002, 0)
-	PROP_Flags (MF_NOSECTOR|MF_NOBLOCKMAP)
-	PROP_SpawnState (0)
-END_DEFAULTS
-
-
-// Every mace spawn spot will execute this action. The first one
-// will build a list of all mace spots in the level and spawn a
-// mace. The rest of the spots will do nothing.
-
-void A_SpawnMace (AActor *self)
-{
-	if (self->target != NULL)
-	{ // Another spot already did it
-		return;
-	}
-
-	AActor *spot = NULL;
-	DSpotState *state = DSpotState::GetSpotState();
-
-	if (state != NULL) spot = state->GetRandomSpot(RUNTIME_TYPE(self), true);
-	if (spot == NULL) return;
-
-	if (!deathmatch && pr_spawnmace() < 64)
-	{ // Sometimes doesn't show up if not in deathmatch
-		return;
-	}
-
-	AActor *mace = Spawn<AMace> (self->x, self->y, self->z, ALLOW_REPLACE);
-
-	if (mace)
-	{
-		mace->SetOrigin (spot->x, spot->y, spot->z);
-		mace->z = mace->floorz;
-		// We want this mace to respawn.
-		mace->flags &= ~MF_DROPPED;
-	}
-}
-
-// FIXME: Generalize this so that it doesn't depend on item specific implementation!
-
-// AMace::DoRespawn
-// Moves the mace to a different spot when it respawns
-
-bool AMace::DoRespawn ()
-{
-	AActor *spot = NULL;
-	DSpotState *state = DSpotState::GetSpotState();
-
-	if (state != NULL) spot = state->GetRandomSpot(RUNTIME_CLASS(AMaceSpawner));
-	if (spot != NULL) 
-	{
-		SetOrigin (spot->x, spot->y, spot->z);
-		z = floorz;
-	}
-	return true;
-}
-
 //----------------------------------------------------------------------------
 //
 // PROC A_FireMacePL1B
@@ -666,7 +395,7 @@ void A_FireMacePL1B (AActor *actor)
 		if (!weapon->DepleteAmmo (weapon->bAltFire))
 			return;
 	}
-	ball = Spawn<AMaceFX2> (actor->x, actor->y, actor->z + 28*FRACUNIT 
+	ball = Spawn("MaceFX2", actor->x, actor->y, actor->z + 28*FRACUNIT 
 		- actor->floorclip, ALLOW_REPLACE);
 	ball->momz = 2*FRACUNIT+/*((player->lookdir)<<(FRACBITS-5))*/
 		finetangent[FINEANGLES/4-(actor->pitch>>ANGLETOFINESHIFT)];
@@ -710,7 +439,7 @@ void A_FireMacePL1 (AActor *actor)
 	}
 	player->psprites[ps_weapon].sx = ((pr_maceatk()&3)-2)*FRACUNIT;
 	player->psprites[ps_weapon].sy = WEAPONTOP+(pr_maceatk()&3)*FRACUNIT;
-	ball = P_SpawnPlayerMissile (actor, RUNTIME_CLASS(AMaceFX1),
+	ball = P_SpawnPlayerMissile (actor, PClass::FindClass("MaceFX1"),
 		actor->angle+(((pr_maceatk()&7)-4)<<24));
 	if (ball)
 	{
@@ -812,7 +541,7 @@ void A_MaceBallImpact2 (AActor *ball)
 		ball->momz = (ball->momz * 192) >> 8;
 		ball->SetState (ball->SpawnState);
 
-		tiny = Spawn<AMaceFX3> (ball->x, ball->y, ball->z, ALLOW_REPLACE);
+		tiny = Spawn("MaceFX3", ball->x, ball->y, ball->z, ALLOW_REPLACE);
 		angle = ball->angle+ANG90;
 		tiny->target = ball->target;
 		tiny->angle = angle;
@@ -824,7 +553,7 @@ void A_MaceBallImpact2 (AActor *ball)
 		tiny->momz = ball->momz;
 		P_CheckMissileSpawn (tiny);
 
-		tiny = Spawn<AMaceFX3> (ball->x, ball->y, ball->z, ALLOW_REPLACE);
+		tiny = Spawn("MaceFX3", ball->x, ball->y, ball->z, ALLOW_REPLACE);
 		angle = ball->angle-ANG90;
 		tiny->target = ball->target;
 		tiny->angle = angle;
diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp
index 3e00bde64..46494ad8d 100644
--- a/src/g_shared/a_pickups.cpp
+++ b/src/g_shared/a_pickups.cpp
@@ -14,6 +14,7 @@
 #include "templates.h"
 #include "a_strifeglobal.h"
 #include "a_morph.h"
+#include "a_specialspot.h"
 
 static FRandom pr_restore ("RestorePos");
 
@@ -489,7 +490,7 @@ void AInventory::Tick ()
 void AInventory::Serialize (FArchive &arc)
 {
 	Super::Serialize (arc);
-	arc << Owner << Amount << MaxAmount << RespawnTics << ItemFlags << Icon << PickupSound;
+	arc << Owner << Amount << MaxAmount << RespawnTics << ItemFlags << Icon << PickupSound << SpawnPointClass;
 }
 
 //===========================================================================
@@ -1168,6 +1169,18 @@ END_DEFAULTS
 
 bool AInventory::DoRespawn ()
 {
+	if (SpawnPointClass != NULL)
+	{
+		AActor *spot = NULL;
+		DSpotState *state = DSpotState::GetSpotState();
+
+		if (state != NULL) spot = state->GetRandomSpot(SpawnPointClass);
+		if (spot != NULL) 
+		{
+			SetOrigin (spot->x, spot->y, spot->z);
+			z = floorz;
+		}
+	}
 	return true;
 }
 
diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h
index 152821a28..cc063715b 100644
--- a/src/g_shared/a_pickups.h
+++ b/src/g_shared/a_pickups.h
@@ -117,7 +117,6 @@ public:
 	virtual bool ShouldRespawn ();
 	virtual bool ShouldStay ();
 	virtual void Hide ();
-	virtual bool DoRespawn ();
 	virtual bool TryPickup (AActor *toucher);
 	virtual void DoPickupSpecial (AActor *toucher);
 	virtual bool SpecialDropAction (AActor *dropper);
@@ -127,6 +126,7 @@ public:
 	virtual const char *PickupMessage ();
 	virtual void PlayPickupSound (AActor *toucher);
 
+	bool DoRespawn ();
 	AInventory *PrevItem();		// Returns the item preceding this one in the list.
 	AInventory *PrevInv();		// Returns the previous item with IF_INVBAR set.
 	AInventory *NextInv();		// Returns the next item with IF_INVBAR set.
@@ -137,6 +137,7 @@ public:
 	int RespawnTics;			// Tics from pickup time to respawn time
 	FTextureID Icon;					// Icon to show on status bar or HUD
 	int DropTime;				// Countdown after dropping
+	const PClass *SpawnPointClass;	// For respawning like Heretic's mace
 
 	DWORD ItemFlags;
 	const PClass *PickupFlash;	// actor to spawn as pickup flash
diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp
index e8c91b6ce..65d08059f 100644
--- a/src/g_shared/a_specialspot.cpp
+++ b/src/g_shared/a_specialspot.cpp
@@ -37,12 +37,14 @@
 #include "p_local.h"
 #include "statnums.h"
 #include "i_system.h"
+#include "thingdef/thingdef.h"
 
 static FRandom pr_spot ("SpecialSpot");
+static FRandom pr_spawnmace ("SpawnMace");
 
 
 IMPLEMENT_CLASS(DSpotState)
-IMPLEMENT_ABSTRACT_ACTOR (ASpecialSpot)
+IMPLEMENT_CLASS (ASpecialSpot)
 TObjPtr<DSpotState> DSpotState::SpotState;
 
 //----------------------------------------------------------------------------
@@ -371,3 +373,65 @@ void ASpecialSpot::Destroy()
 	if (state != NULL) state->RemoveSpot(this);
 	Super::Destroy();
 }
+
+// Mace spawn spot ----------------------------------------------------------
+
+
+// Every mace spawn spot will execute this action. The first one
+// will build a list of all mace spots in the level and spawn a
+// mace. The rest of the spots will do nothing.
+
+void A_SpawnSingleItem (AActor *self)
+{
+	AActor *spot = NULL;
+	DSpotState *state = DSpotState::GetSpotState();
+
+	if (state != NULL) spot = state->GetRandomSpot(RUNTIME_TYPE(self), true);
+	if (spot == NULL) return;
+
+	int index=CheckIndex(4);
+	if (index<0) return;
+
+	ENamedName SpawnType = (ENamedName)StateParameters[index];
+	int fail_sp = EvalExpressionI (StateParameters[index+1], self);
+	int fail_co = EvalExpressionI (StateParameters[index+2], self);
+	int fail_dm = EvalExpressionI (StateParameters[index+3], self);
+
+	if (!multiplayer && pr_spawnmace() < fail_sp)
+	{ // Sometimes doesn't show up if not in deathmatch
+		return;
+	}
+
+	if (multiplayer && !deathmatch && pr_spawnmace() < fail_co)
+	{
+		return;
+	}
+
+	if (deathmatch && pr_spawnmace() < fail_dm)
+	{
+		return;
+	}
+	const PClass *cls = PClass::FindClass(SpawnType);
+	if (cls == NULL)
+	{
+		return;
+	}
+
+	AActor *spawned = Spawn(cls, self->x, self->y, self->z, ALLOW_REPLACE);
+
+	if (spawned)
+	{
+		spawned->SetOrigin (spot->x, spot->y, spot->z);
+		spawned->z = spawned->floorz;
+		// We want this to respawn.
+		if (!(self->flags & MF_DROPPED)) 
+		{
+			spawned->flags &= ~MF_DROPPED;
+		}
+		if (spawned->IsKindOf(RUNTIME_CLASS(AInventory)))
+		{
+			static_cast<AInventory*>(spawned)->SpawnPointClass = RUNTIME_TYPE(self);
+		}
+	}
+}
+
diff --git a/src/g_shared/a_specialspot.h b/src/g_shared/a_specialspot.h
index 8efb35cfa..ffc083978 100644
--- a/src/g_shared/a_specialspot.h
+++ b/src/g_shared/a_specialspot.h
@@ -6,7 +6,7 @@
 
 class ASpecialSpot : public AActor
 {
-	DECLARE_STATELESS_ACTOR (ASpecialSpot, AActor)
+	DECLARE_CLASS (ASpecialSpot, AActor)
 
 public:
 
diff --git a/src/version.h b/src/version.h
index 8878e17f5..6cb203d9e 100644
--- a/src/version.h
+++ b/src/version.h
@@ -75,7 +75,7 @@
 // SAVESIG should match SAVEVER.
 
 // MINSAVEVER is the minimum level snapshot version that can be loaded.
-#define MINSAVEVER 1075
+#define MINSAVEVER 1107
 
 #if SVN_REVISION_NUMBER < MINSAVEVER
 // Never write a savegame with a version lower than what we need
diff --git a/wadsrc/static/actors/heretic/hereticweaps.txt b/wadsrc/static/actors/heretic/hereticweaps.txt
index f6317fbde..f3c7056fa 100644
--- a/wadsrc/static/actors/heretic/hereticweaps.txt
+++ b/wadsrc/static/actors/heretic/hereticweaps.txt
@@ -474,3 +474,187 @@ ACTOR GauntletPuff2 : GauntletPuff1
 }
 
 
+// The mace itself ----------------------------------------------------------
+
+ACTOR Mace : HereticWeapon
+{
+	Game Heretic
+	SpawnID 31
+	Weapon.SelectionOrder 1400
+	Weapon.AmmoUse 1
+	Weapon.AmmoGive1 50
+	Weapon.YAdjust 15
+	Weapon.AmmoType "MaceAmmo"
+	Weapon.SisterWeapon "MacePowered"
+	Inventory.PickupMessage "$TxT_WPNMACE"
+	
+	action native A_FireMacePL1();
+	
+	States
+	{
+	Spawn:
+		WMCE A -1
+		Stop
+	Ready:
+		MACE A 1 A_WeaponReady
+		Loop
+	Deselect:
+		MACE A 1 A_Lower
+		Loop
+	Select:
+		MACE A 1 A_Raise
+		Loop
+	Fire:
+		MACE B 4
+	Hold:
+		MACE CDEF 3 A_FireMacePL1
+		MACE C 4 A_ReFire
+		MACE DEFB 4
+		Goto Ready
+	}
+}
+
+ACTOR MacePowered : Mace
+{
+	+WEAPON.POWERED_UP
+	Weapon.AmmoUse 5
+	Weapon.AmmoGive 0
+	Weapon.SisterWeapon "Mace"
+	
+	action native A_FireMacePL2();
+	
+	States
+	{
+	Fire:
+	Hold:	
+		MACE B 4
+		MACE D 4 A_FireMacePL2
+		MACE B 4
+		MACE A 8 A_ReFire
+		Goto Ready
+	}
+}
+
+// Mace FX1 -----------------------------------------------------------------
+
+ACTOR MaceFX1
+{
+	Game Heretic
+	SpawnID 154
+	Radius 8
+	Height 6
+	Speed 20
+	Damage 2
+	Projectile
+	+THRUGHOST
+	+HERETICBOUNCE
+	SeeSound "weapons/maceshoot"
+
+	action native A_MacePL1Check();
+	action native A_MaceBallImpact();
+
+	States
+	{
+	Spawn:
+		FX02 AB 4 A_MacePL1Check
+		Loop
+	Death:
+		FX02 F 4 BRIGHT A_MaceBallImpact
+		FX02 GHIJ 4 BRIGHT
+		Stop
+	}
+}
+
+// Mace FX2 -----------------------------------------------------------------
+
+ACTOR MaceFX2 : MaceFX1
+{
+	Game Heretic
+	SpawnID 156
+	Speed 10
+	Damage 6
+	Gravity 0.125
+	-NOGRAVITY
+	SeeSound ""
+
+	action native A_MaceBallImpact2();
+
+	States
+	{
+	Spawn:
+		FX02 CD 4
+		Loop
+	Death:
+		FX02 F 4 A_MaceBallImpact2
+		goto Super::Death+1
+	}
+}
+
+// Mace FX3 -----------------------------------------------------------------
+
+ACTOR MaceFX3 : MaceFX1
+{
+	Game Heretic
+	SpawnID 155
+	Speed 7
+	Damage 4
+	-NOGRAVITY
+	Gravity 0.125
+	States
+	{
+	Spawn:
+		FX02 AB 4
+		Loop
+	}
+}
+
+
+// Mace FX4 -----------------------------------------------------------------
+
+ACTOR MaceFX4 native
+{
+	Game Heretic
+	SpawnID 153
+	Radius 8
+	Height 6
+	Speed 7
+	Damage 18
+	Gravity 0.125
+	Projectile
+	-NOGRAVITY
+	+TELESTOMP
+	+THRUGHOST
+	+HERETICBOUNCE
+	SeeSound ""
+
+	action native A_DeathBallImpact();
+
+	States
+	{
+	Spawn:
+		FX02 E 99
+		Loop
+	Death:
+		FX02 C 4 A_DeathBallImpact
+		FX02 GHIJ 4 BRIGHT
+		Stop
+	}
+}
+
+
+// Mace spawn spot ----------------------------------------------------------
+
+ACTOR MaceSpawner : SpecialSpot 2002
+{
+	Game Heretic
+	+NOSECTOR
+	+NOBLOCKMAP
+	States
+	{
+	Spawn:
+		TNT1 A 1
+		TNT1 A -1 A_SpawnSingleItem("Mace", 64, 64, 0)
+		Stop
+	}
+}
+
diff --git a/wadsrc/static/actors/shared/specialspot.txt b/wadsrc/static/actors/shared/specialspot.txt
new file mode 100644
index 000000000..12803e597
--- /dev/null
+++ b/wadsrc/static/actors/shared/specialspot.txt
@@ -0,0 +1,5 @@
+
+ACTOR SpecialSpot native
+{
+	action native A_SpawnSingleItem(class<Actor> type, optional eval int fail_sp, optional eval int fail_co, optional eval int fail_dm);
+}
diff --git a/wadsrc/static/decorate.txt b/wadsrc/static/decorate.txt
index cd53a92b6..57c3a0b88 100644
--- a/wadsrc/static/decorate.txt
+++ b/wadsrc/static/decorate.txt
@@ -10,6 +10,7 @@
 #include "actors/shared/fountain.txt"
 #include "actors/shared/soundsequence.txt"
 #include "actors/shared/bridge.txt"
+#include "actors/shared/specialspot.txt"
 
 #include "actors/doom/doomplayer.txt"
 #include "actors/doom/possessed.txt"