diff --git a/src/p_floor.c b/src/p_floor.c
index e46b0b4fbbfeb9f379130c2b2c92f7e1e344a467..774606563cac3b6082ab1cefd48564048c1ffcf7 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -1104,181 +1104,167 @@ void T_MarioBlockChecker(levelspecthink_t *block)
 	}
 }
 
+static boolean P_IsPlayerValid(size_t playernum)
+{
+	if (!playeringame[playernum])
+		return false;
+
+	if (!players[playernum].mo)
+		return false;
+
+	if (players[playernum].mo->health <= 0)
+		return false;
+
+	if (players[playernum].spectator)
+		return false;
+
+	return true;
+}
+
 // This is the Thwomp's 'brain'. It looks around for players nearby, and if
 // it finds any, **SMASH**!!! Muahahhaa....
-void T_ThwompSector(levelspecthink_t *thwomp)
+void T_ThwompSector(thwomp_t *thwomp)
 {
-#define speed vars[1]
-#define direction vars[2]
-#define distance vars[3]
-#define floorwasheight vars[4]
-#define ceilingwasheight vars[5]
 	fixed_t thwompx, thwompy;
 	sector_t *actionsector;
 	ffloor_t *rover = NULL;
 	INT32 secnum;
+	fixed_t speed;
 
 	// If you just crashed down, wait a second before coming back up.
-	if (--thwomp->distance > 0)
-	{
-		sides[thwomp->sourceline->sidenum[0]].midtexture = sides[thwomp->sourceline->sidenum[0]].bottomtexture;
+	if (--thwomp->delay > 0)
 		return;
-	}
 
 	// Just find the first sector with the tag.
 	// Doesn't work with multiple sectors that have different floor/ceiling heights.
-	secnum = P_FindSectorFromTag((INT16)thwomp->vars[0], -1);
+	secnum = P_FindSectorFromTag(thwomp->tag, -1);
 
-	if (secnum > 0)
+	if (secnum <= 0)
+		return; // Bad bad bad!
+
+	actionsector = &sectors[secnum];
+
+	// Look for thwomp FOF
+	for (rover = actionsector->ffloors; rover; rover = rover->next)
 	{
-		actionsector = &sectors[secnum];
+		if (rover->master == thwomp->sourceline)
+			break;
+	}
+
+	if (!rover)
+		return; // Didn't find any FOFs, so bail out
+
+	thwompx = actionsector->soundorg.x;
+	thwompy = actionsector->soundorg.y;
 
-		// Look for thwomp FFloor
-		for (rover = actionsector->ffloors; rover; rover = rover->next)
+	if (thwomp->direction == 0) // Not going anywhere, so look for players.
+	{
+		if (rover->flags & FF_EXISTS)
 		{
-			if (rover->master == thwomp->sourceline)
+			UINT8 i;
+			// scan the players to find victims!
+			for (i = 0; i < MAXPLAYERS; i++)
+			{
+				if (!P_IsPlayerValid(i))
+					continue;
+
+				if (players[i].mo->z > thwomp->sector->ceilingheight)
+					continue;
+
+				if (P_AproxDistance(thwompx - players[i].mo->x, thwompy - players[i].mo->y) > 96*FRACUNIT)
+					continue;
+
+				thwomp->direction = -1;
 				break;
+			}
 		}
+
+		thwomp->sector->ceilspeed = 0;
+		thwomp->sector->floorspeed = 0;
 	}
 	else
-		return; // Bad bad bad!
-
-	thwompx = actionsector->soundorg.x;
-	thwompy = actionsector->soundorg.y;
-
-	if (thwomp->direction > 0) // Moving back up..
 	{
 		result_e res = 0;
 
-		// Set the texture from the lower one (normal)
-		sides[thwomp->sourceline->sidenum[0]].midtexture = sides[thwomp->sourceline->sidenum[0]].bottomtexture;
-		/// \note this should only have to be done once, but is already done repeatedly, above
+		if (thwomp->direction > 0) //Moving back up..
+		{
+			// Set the texture from the lower one (normal)
+			sides[thwomp->sourceline->sidenum[0]].midtexture = sides[thwomp->sourceline->sidenum[0]].bottomtexture;
 
-		if (thwomp->sourceline->flags & ML_EFFECT5)
-			thwomp->speed = thwomp->sourceline->dx/8;
-		else
-			thwomp->speed = 2*FRACUNIT;
+			speed = thwomp->retractspeed;
 
-		res = T_MovePlane
-		(
-			thwomp->sector,         // sector
-			thwomp->speed,          // speed
-			thwomp->floorwasheight, // dest
-			false,                      // crush
-			false,                  // ceiling?
-			thwomp->direction       // direction
-		);
-
-		if (res == ok || res == pastdest)
-			T_MovePlane
+			res = T_MovePlane
 			(
 				thwomp->sector,           // sector
-				thwomp->speed,            // speed
-				thwomp->ceilingwasheight, // dest
-				false,                        // crush
-				true,                     // ceiling?
+				speed,                    // speed
+				thwomp->floorstartheight, // dest
+				false,                    // crush
+				false,                    // ceiling?
 				thwomp->direction         // direction
 			);
 
-		if (res == pastdest)
-			thwomp->direction = 0; // stop moving
-
-		thwomp->sector->ceilspeed = 42;
-		thwomp->sector->floorspeed = thwomp->speed*thwomp->direction;
-	}
-	else if (thwomp->direction < 0) // Crashing down!
-	{
-		result_e res = 0;
-
-		// Set the texture from the upper one (angry)
-		sides[thwomp->sourceline->sidenum[0]].midtexture = sides[thwomp->sourceline->sidenum[0]].toptexture;
+			if (res == ok || res == pastdest)
+				T_MovePlane
+				(
+					thwomp->sector,             // sector
+					speed,                      // speed
+					thwomp->ceilingstartheight, // dest
+					false,                      // crush
+					true,                       // ceiling?
+					thwomp->direction           // direction
+				);
 
-		if (thwomp->sourceline->flags & ML_EFFECT5)
-			thwomp->speed = thwomp->sourceline->dy/8;
-		else
-			thwomp->speed = 10*FRACUNIT;
+			if (res == pastdest)
+				thwomp->direction = 0; // stop moving
+			}
+		else // Crashing down!
+		{
+			// Set the texture from the upper one (angry)
+			sides[thwomp->sourceline->sidenum[0]].midtexture = sides[thwomp->sourceline->sidenum[0]].toptexture;
 
-		res = T_MovePlane
-		(
-			thwomp->sector,   // sector
-			thwomp->speed,    // speed
-			P_FloorzAtPos(thwompx, thwompy, thwomp->sector->floorheight,
-				thwomp->sector->ceilingheight - thwomp->sector->floorheight), // dest
-			false,              // crush
-			false,              // ceiling?
-			thwomp->direction // direction
-		);
+			speed = thwomp->crushspeed;
 
-		if (res == ok || res == pastdest)
-			T_MovePlane
+			res = T_MovePlane
 			(
 				thwomp->sector,   // sector
-				thwomp->speed,    // speed
+				speed,            // speed
 				P_FloorzAtPos(thwompx, thwompy, thwomp->sector->floorheight,
-					thwomp->sector->ceilingheight
-					- (thwomp->sector->floorheight + thwomp->speed))
-					+ (thwomp->sector->ceilingheight
-					- (thwomp->sector->floorheight + thwomp->speed/2)), // dest
-				false,             // crush
-				true,              // ceiling?
+					thwomp->sector->ceilingheight - thwomp->sector->floorheight), // dest
+				false,              // crush
+				false,              // ceiling?
 				thwomp->direction // direction
 			);
 
-		if (res == pastdest)
-		{
-			mobj_t *mp = (void *)&actionsector->soundorg;
-
-			if (!rover || (rover->flags & FF_EXISTS))
-			{
-				if (thwomp->sourceline->flags & ML_EFFECT4)
-					S_StartSound(mp, sides[thwomp->sourceline->sidenum[0]].textureoffset>>FRACBITS);
-				else
-					S_StartSound(mp, sfx_thwomp);
-			}
-
-			thwomp->direction = 1; // start heading back up
-			thwomp->distance = TICRATE; // but only after a small delay
-		}
+			if (res == ok || res == pastdest)
+				T_MovePlane
+				(
+					thwomp->sector,   // sector
+					speed,            // speed
+					P_FloorzAtPos(thwompx, thwompy, thwomp->sector->floorheight,
+						thwomp->sector->ceilingheight
+						- (thwomp->sector->floorheight + speed))
+						+ (thwomp->sector->ceilingheight
+						- (thwomp->sector->floorheight + speed/2)), // dest
+					false,             // crush
+					true,              // ceiling?
+					thwomp->direction // direction
+				);
 
-		thwomp->sector->ceilspeed = 42;
-		thwomp->sector->floorspeed = thwomp->speed*thwomp->direction;
-	}
-	else // Not going anywhere, so look for players.
-	{
-		if (!rover || (rover->flags & FF_EXISTS))
-		{
-			UINT8 i;
-			// scan the players to find victims!
-			for (i = 0; i < MAXPLAYERS; i++)
+			if (res == pastdest)
 			{
-				if (!playeringame[i])
-					continue;
-				if (players[i].spectator)
-					continue;
-				if (!players[i].mo)
-					continue;
-				if (!players[i].mo->health)
-					continue;
-				if (players[i].mo->z > thwomp->sector->ceilingheight)
-					continue;
-				if (P_AproxDistance(thwompx - players[i].mo->x, thwompy - players[i].mo->y) > 96 * FRACUNIT)
-					continue;
+				if (rover->flags & FF_EXISTS)
+					S_StartSound((void *)&actionsector->soundorg, thwomp->sound);
 
-				thwomp->direction = -1;
-				break;
+				thwomp->direction = 1; // start heading back up
+				thwomp->delay = TICRATE; // but only after a small delay
 			}
 		}
 
-		thwomp->sector->ceilspeed = 0;
-		thwomp->sector->floorspeed = 0;
+		thwomp->sector->ceilspeed = 42;
+		thwomp->sector->floorspeed = speed*thwomp->direction;
 	}
 
 	P_RecalcPrecipInSector(actionsector);
-#undef speed
-#undef direction
-#undef distance
-#undef floorwasheight
-#undef ceilingwasheight
 }
 
 static boolean T_SectorHasEnemies(sector_t *sec)
@@ -1375,23 +1361,6 @@ static boolean P_IsObjectOnRealGround(mobj_t *mo, sector_t *sec)
 	return false;
 }
 
-static boolean P_IsPlayerValid(size_t playernum)
-{
-	if (!playeringame[playernum])
-		return false;
-
-	if (!players[playernum].mo)
-		return false;
-
-	if (players[playernum].mo->health <= 0)
-		return false;
-
-	if (players[playernum].spectator)
-		return false;
-
-	return true;
-}
-
 static boolean P_IsMobjTouchingSector(mobj_t *mo, sector_t *sec)
 {
 	msecnode_t *node;
diff --git a/src/p_saveg.c b/src/p_saveg.c
index afcd9867e33fcee05495d7bed1283eedd49e0568..888eb96ca3c20880584b8c2203b5b28a00697443 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -1704,6 +1704,27 @@ static void SaveMarioBlockThinker(const thinker_t *th, const UINT8 type)
 	WRITEINT16(save_p, ht->tag);
 }
 
+//
+// SaveThwompThinker
+//
+// Saves a thwomp_t thinker
+//
+static void SaveThwompThinker(const thinker_t *th, const UINT8 type)
+{
+	const thwomp_t *ht  = (const void *)th;
+	WRITEUINT8(save_p, type);
+	WRITEUINT32(save_p, SaveLine(ht->sourceline));
+	WRITEUINT32(save_p, SaveSector(ht->sector));
+	WRITEFIXED(save_p, ht->crushspeed);
+	WRITEFIXED(save_p, ht->retractspeed);
+	WRITEINT32(save_p, ht->direction);
+	WRITEFIXED(save_p, ht->floorstartheight);
+	WRITEFIXED(save_p, ht->ceilingstartheight);
+	WRITEINT32(save_p, ht->delay);
+	WRITEINT16(save_p, ht->tag);
+	WRITEUINT16(save_p, ht->sound);
+}
+
 //
 // SaveFloatThinker
 //
@@ -2317,7 +2338,7 @@ static void P_NetArchiveThinkers(void)
 			}
 			else if (th->function.acp1 == (actionf_p1)T_ThwompSector)
 			{
-				SaveSpecialLevelThinker(th, tc_thwomp);
+				SaveThwompThinker(th, tc_thwomp);
 				continue;
 			}
 			else if (th->function.acp1 == (actionf_p1)T_NoEnemiesSector)
@@ -2906,6 +2927,27 @@ static thinker_t* LoadMarioBlockThinker(actionf_p1 thinker)
 	return &ht->thinker;
 }
 
+// LoadThwompThinker
+//
+// Loads a thwomp_t from a save game
+//
+static thinker_t* LoadThwompThinker(actionf_p1 thinker)
+{
+	thwomp_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
+	ht->thinker.function.acp1 = thinker;
+	ht->sourceline = LoadLine(READUINT32(save_p));
+	ht->sector = LoadSector(READUINT32(save_p));
+	ht->crushspeed = READFIXED(save_p);
+	ht->retractspeed = READFIXED(save_p);
+	ht->direction = READINT32(save_p);
+	ht->floorstartheight = READFIXED(save_p);
+	ht->ceilingstartheight = READFIXED(save_p);
+	ht->delay = READINT32(save_p);
+	ht->tag = READINT16(save_p);
+	ht->sound = READUINT16(save_p);
+	return &ht->thinker;
+}
+
 // LoadFloatThinker
 //
 // Loads a floatthink_t from a save game
@@ -3624,7 +3666,7 @@ static void P_NetUnArchiveThinkers(void)
 					break;
 
 				case tc_thwomp:
-					th = LoadSpecialLevelThinker((actionf_p1)T_ThwompSector, 3);
+					th = LoadThwompThinker((actionf_p1)T_ThwompSector);
 					break;
 
 				case tc_noenemies:
diff --git a/src/p_spec.c b/src/p_spec.c
index 6bcac18f99d6138bb01c2c4207d100c567658747..921bcef26c3a1c35338d2af6ec63649d6437299d 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -6068,12 +6068,7 @@ static void P_AddAirbob(sector_t *sec, line_t *sourceline, fixed_t dist, boolean
   */
 static inline void P_AddThwompThinker(sector_t *sec, sector_t *actionsector, line_t *sourceline)
 {
-#define speed vars[1]
-#define direction vars[2]
-#define distance vars[3]
-#define floorwasheight vars[4]
-#define ceilingwasheight vars[5]
-	levelspecthink_t *thwomp;
+	thwomp_t *thwomp;
 
 	// You *probably* already have a thwomp in this sector. If you've combined it with something
 	// else that uses the floordata/ceilingdata, you must be weird.
@@ -6087,21 +6082,21 @@ static inline void P_AddThwompThinker(sector_t *sec, sector_t *actionsector, lin
 	thwomp->thinker.function.acp1 = (actionf_p1)T_ThwompSector;
 
 	// set up the fields according to the type of elevator action
+	thwomp->sourceline = sourceline;
 	thwomp->sector = sec;
-	thwomp->vars[0] = actionsector->tag;
-	thwomp->floorwasheight = thwomp->sector->floorheight;
-	thwomp->ceilingwasheight = thwomp->sector->ceilingheight;
+	thwomp->crushspeed = (sourceline->flags & ML_EFFECT5) ? sourceline->dy >> 3 : 10*FRACUNIT;
+	thwomp->retractspeed = (sourceline->flags & ML_EFFECT5) ? sourceline->dx >> 3 : 2*FRACUNIT;
 	thwomp->direction = 0;
-	thwomp->distance = 1;
-	thwomp->sourceline = sourceline;
-	thwomp->sector->floordata = thwomp;
-	thwomp->sector->ceilingdata = thwomp;
-	return;
-#undef speed
-#undef direction
-#undef distance
-#undef floorwasheight
-#undef ceilingwasheight
+	thwomp->floorstartheight = sec->floorheight;
+	thwomp->ceilingstartheight = sec->ceilingheight;
+	thwomp->delay = 1;
+	thwomp->tag = actionsector->tag;
+	thwomp->sound = (sourceline->flags & ML_EFFECT4) ? sides[sourceline->sidenum[0]].textureoffset >> FRACBITS : sfx_thwomp;
+
+	sec->floordata = thwomp;
+	sec->ceilingdata = thwomp;
+	// Start with 'resting' texture
+	sides[sourceline->sidenum[0]].midtexture = sides[sourceline->sidenum[0]].bottomtexture;
 }
 
 /** Adds a thinker which checks if any MF_ENEMY objects with health are in the defined area.
diff --git a/src/p_spec.h b/src/p_spec.h
index ef98be5c455e016b382511f45b928b88563ef74d..5e54b568f77bf4758d3f90321eec141d0bd33124 100644
--- a/src/p_spec.h
+++ b/src/p_spec.h
@@ -348,6 +348,21 @@ typedef struct
 	INT16 tag;
 } mariothink_t;
 
+typedef struct
+{
+	thinker_t thinker;
+	line_t *sourceline;
+	sector_t *sector;
+	fixed_t crushspeed;
+	fixed_t retractspeed;
+	INT32 direction;
+	fixed_t floorstartheight;
+	fixed_t ceilingstartheight;
+	INT32 delay;
+	INT16 tag;
+	UINT16 sound;
+} thwomp_t;
+
 typedef struct
 {
 	thinker_t thinker;
@@ -419,7 +434,7 @@ void T_StartCrumble(elevator_t *elevator);
 void T_MarioBlock(mariothink_t *block);
 void T_FloatSector(floatthink_t *floater);
 void T_MarioBlockChecker(levelspecthink_t *block);
-void T_ThwompSector(levelspecthink_t *thwomp);
+void T_ThwompSector(thwomp_t *thwomp);
 void T_NoEnemiesSector(noenemies_t *nobaddies);
 void T_EachTimeThinker(eachtime_t *eachtime);
 void T_CameraScanner(elevator_t *elevator);