diff --git a/extras/conf/udb/Includes/SRB222_linedefs.cfg b/extras/conf/udb/Includes/SRB222_linedefs.cfg
index bc1f43e57b58934513518b5cff3000fb6416ea9a..51332522585a9571f63fe03d9640f1b38b72040c 100644
--- a/extras/conf/udb/Includes/SRB222_linedefs.cfg
+++ b/extras/conf/udb/Includes/SRB222_linedefs.cfg
@@ -1516,6 +1516,50 @@ udmf
 		}
 	}
 
+	polyobject
+	{
+		title = "PolyObject";
+
+		20
+		{
+			title = "First Line";
+			prefix = "(20)";
+			arg0
+			{
+				title = "PolyObject ID";
+				type = 14;
+			}
+			arg1
+			{
+				title = "Parent ID";
+				type = 14;
+			}
+			arg2
+			{
+				title = "Translucency";
+			}
+			arg3
+			{
+				title = "Flags";
+				type = 12;
+				enum
+				{
+					1 = "Don't render insides";
+					2 = "Intangible";
+					4 = "Stopped by pushables";
+					8 = "Don't render planes";
+					16 = "Trigger linedef executor on touch";
+					32 = "Crush player";
+				}
+			}
+			arg4
+			{
+				title = "Trigger linedef tag";
+				type = 15;
+			}
+		}
+	}
+
 	fof
 	{
 		title = "FOF";
diff --git a/src/dehacked.c b/src/dehacked.c
index a6c73e0b45cbe96cdd6ae0de18cf687baec9ef5b..0cbb638c8b941d640310bc236243cbfd915a2443 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -8754,7 +8754,6 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	"MT_ANGLEMAN",
 	"MT_POLYANCHOR",
 	"MT_POLYSPAWN",
-	"MT_POLYSPAWNCRUSH",
 
 	// Skybox objects
 	"MT_SKYBOX",
diff --git a/src/info.c b/src/info.c
index d443e035d004c8437401d89d31a1e6a1186284c5..f65d336aa66901b283ccc66b70ae2c14c88689af 100644
--- a/src/info.c
+++ b/src/info.c
@@ -3361,7 +3361,7 @@ state_t states[NUMSTATES] =
 
 	// CTF Sign
 	{SPR_GFLG, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_GOTFLAG
-	
+
 	// Finish flag
 	{SPR_FNSF,    FF_TRANS30, -1, {NULL}, 0, 0, S_NULL}, // S_FINISHFLAG
 
@@ -18009,7 +18009,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags
 		S_NULL          // raisestate
 	},
-	
+
 	{           // MT_FINISHFLAG
 		-1,             // doomednum
 		S_FINISHFLAG,   // spawnstate
@@ -19854,7 +19854,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
 		S_NULL          // raisestate
 	},
-	
+
 	{           // MT_FLINGNIGHTSSTAR
 		-1,             // doomednum
 		S_NIGHTSSTAR,   // spawnstate
@@ -20857,33 +20857,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
-	{           // MT_POLYSPAWNCRUSH
-		762,            // doomednum
-		S_INVISIBLE,    // spawnstate
-		1,              // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
-		0,              // reactiontime
-		sfx_None,       // attacksound
-		S_NULL,         // painstate
-		3,              // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
-		S_NULL,         // missilestate
-		S_NULL,         // deathstate
-		S_NULL,         // xdeathstate
-		sfx_None,       // deathsound
-		0,              // speed
-		1*FRACUNIT,     // radius
-		1*FRACUNIT,     // height
-		0,              // display offset
-		1000,           // mass
-		8,              // damage
-		sfx_None,       // activesound
-		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY|MF_NOCLIP, // flags
-		S_NULL          // raisestate
-	},
-
 	{           // MT_SKYBOX
 		780,            // doomednum
 		S_INVISIBLE,    // spawnstate
diff --git a/src/info.h b/src/info.h
index 79af9bbbb8ae444fa3e9aee46cc17ca922bf9d68..271a6f3f65d6386d1ac36e30b659d09763b550f0 100644
--- a/src/info.h
+++ b/src/info.h
@@ -3498,7 +3498,7 @@ typedef enum state
 
 	// Got Flag Sign
 	S_GOTFLAG,
-	
+
 	// Finish flag
 	S_FINISHFLAG,
 
@@ -4765,7 +4765,6 @@ typedef enum mobj_type
 	MT_ANGLEMAN,
 	MT_POLYANCHOR,
 	MT_POLYSPAWN,
-	MT_POLYSPAWNCRUSH,
 
 	// Skybox objects
 	MT_SKYBOX,
diff --git a/src/p_mobj.c b/src/p_mobj.c
index a22e655e05c2b7bc521c59292dd003d21b9a4bac..b39f350be116e70c39b50870234344356228a4ec 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -2941,10 +2941,8 @@ static void P_PlayerZMovement(mobj_t *mo)
 
 								if (mo->z == polysec->ceilingheight)
 								{
-									// We're landing on a PO, so check for
-									// a linedef executor.
-									// Trigger tags are 32000 + the PO's ID number.
-									P_LinedefExecute((INT16)(32000 + po->id), mo, NULL);
+									// We're landing on a PO, so check for a linedef executor.
+									P_LinedefExecute(po->triggertag, mo, NULL);
 								}
 
 								po = (polyobj_t *)(po->link.next);
diff --git a/src/p_polyobj.c b/src/p_polyobj.c
index 539ddb741706f2213cac17e3c69b4e17b4bd0107..d745a5749794f1ce1b066d19baa77833a2e036ed 100644
--- a/src/p_polyobj.c
+++ b/src/p_polyobj.c
@@ -204,44 +204,41 @@ boolean P_BBoxInsidePolyobj(polyobj_t *po, fixed_t *bbox)
 	return true;
 }
 
-// Finds the 'polyobject settings' linedef for a polyobject
-// the polyobject's id should be set as its tag
-static void Polyobj_GetInfo(polyobj_t *po)
+// Gets the polyobject's settings from its first line
+// args[0] of the first line should be the polyobject's id
+static void Polyobj_GetInfo(polyobj_t *po, line_t *line)
 {
-	INT32 i = P_FindSpecialLineFromTag(POLYINFO_SPECIALNUM, po->id, -1);
-
-	po->flags = POF_SOLID|POF_TESTHEIGHT|POF_RENDERSIDES;
-
-	if (i == -1)
-		return; // no extra settings to apply, let's leave it
-
-	po->parent = lines[i].frontsector->special;
+	po->parent = line->args[1];
 	if (po->parent == po->id) // do not allow a self-reference
 		po->parent = -1;
 
-	po->translucency = (lines[i].flags & ML_DONTPEGTOP)
-						? (sides[lines[i].sidenum[0]].textureoffset>>FRACBITS)
-						: ((lines[i].frontsector->floorheight>>FRACBITS) / 100);
+	po->translucency = max(min(line->args[2], NUMTRANSMAPS), 0);
 
-	po->translucency = max(min(po->translucency, NUMTRANSMAPS), 0);
+	po->flags = POF_SOLID|POF_TESTHEIGHT|POF_RENDERSIDES|POF_RENDERPLANES;
 
-	if (lines[i].flags & ML_EFFECT1)
+	if (line->args[3] & TMPF_NOINSIDES)
 		po->flags |= POF_ONESIDE;
 
-	if (lines[i].flags & ML_EFFECT2)
+	if (line->args[3] & TMPF_INTANGIBLE)
 		po->flags &= ~POF_SOLID;
 
-	if (lines[i].flags & ML_EFFECT3)
+	if (line->args[3] & TMPF_PUSHABLESTOP)
 		po->flags |= POF_PUSHABLESTOP;
 
-	if (lines[i].flags & ML_EFFECT4)
-		po->flags |= POF_RENDERPLANES;
+	if (line->args[3] & TMPF_INVISIBLEPLANES)
+		po->flags &= ~POF_RENDERPLANES;
 
-	/*if (lines[i].flags & ML_EFFECT5)
+	/*if (line->args[3] & TMPF_DONTCLIPPLANES)
 		po->flags &= ~POF_CLIPPLANES;*/
 
-	if (lines[i].flags & ML_NOCLIMB) // Has a linedef executor
+	if (line->args[3] & TMPF_EXECUTOR) // Has a linedef executor
 		po->flags |= POF_LDEXEC;
+
+	// TODO: support customized damage somehow?
+	if (line->args[3] & TMPF_CRUSH)
+		po->damage = 3;
+
+	po->triggertag = line->args[4];
 }
 
 // Reallocating array maintenance
@@ -480,10 +477,6 @@ static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id)
 
 	po->id = id;
 
-	// TODO: support customized damage somehow?
-	if (spawnSpot->info->doomednum == POLYOBJ_SPAWNCRUSH_DOOMEDNUM)
-		po->damage = 3;
-
 	// set to default thrust; may be modified by attached thinkers
 	// TODO: support customized thrust?
 	po->thrust = FRACUNIT;
@@ -505,10 +498,10 @@ static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id)
 		if (seg->linedef->special != POLYOBJ_START_LINE)
 			continue;
 
-		if (seg->linedef->tag != po->id)
+		if (seg->linedef->args[0] != po->id)
 			continue;
 
-		Polyobj_GetInfo(po); // apply extra settings if they exist!
+		Polyobj_GetInfo(po, seg->linedef); // apply extra settings if they exist!
 
 		// save original flags and translucency to reference later for netgames!
 		po->spawnflags = po->flags;
@@ -1313,8 +1306,7 @@ void Polyobj_InitLevel(void)
 
 		mo = (mobj_t *)th;
 
-		if (mo->info->doomednum == POLYOBJ_SPAWN_DOOMEDNUM ||
-			mo->info->doomednum == POLYOBJ_SPAWNCRUSH_DOOMEDNUM)
+		if (mo->info->doomednum == POLYOBJ_SPAWN_DOOMEDNUM)
 		{
 			++numPolyObjects;
 
diff --git a/src/p_polyobj.h b/src/p_polyobj.h
index 68aff4bf189ec518a5faeb69ecdee3894c403be5..b59e9c2353605119f0ddca1f273fc97951d9eccd 100644
--- a/src/p_polyobj.h
+++ b/src/p_polyobj.h
@@ -26,10 +26,8 @@
 
 #define POLYOBJ_ANCHOR_DOOMEDNUM     760
 #define POLYOBJ_SPAWN_DOOMEDNUM      761
-#define POLYOBJ_SPAWNCRUSH_DOOMEDNUM 762 // todo: REMOVE
 
 #define POLYOBJ_START_LINE    20
-#define POLYINFO_SPECIALNUM   22
 
 typedef enum
 {
@@ -51,6 +49,17 @@ typedef enum
 	POF_NOSPECIALS        = 0x1000,    ///< Don't apply sector specials.
 } polyobjflags_e;
 
+typedef enum
+{
+	TMPF_NOINSIDES       = 1,
+	TMPF_INTANGIBLE      = 1<<1,
+	TMPF_PUSHABLESTOP    = 1<<2,
+	TMPF_INVISIBLEPLANES = 1<<3,
+	TMPF_EXECUTOR        = 1<<4,
+	TMPF_CRUSH           = 1<<5,
+	//TMPF_DONTCLIPPLANES  = 1<<6,
+} textmappolyobjectflags_t;
+
 //
 // Polyobject Structure
 //
@@ -96,6 +105,7 @@ typedef struct polyobj_s
 
 	UINT8 isBad;         // a bad polyobject: should not be rendered/manipulated
 	INT32 translucency; // index to translucency tables
+	INT16 triggertag;   // Tag of linedef executor to trigger on touch
 
 	struct visplane_s *visplane; // polyobject's visplane, for ease of putting into the list later
 
diff --git a/src/p_setup.c b/src/p_setup.c
index b39f4a516c658e84f18f35cbcaeee90eedb2650a..4ff9e61179bd05a0ac998bbfa9ebf8b2f0fceebe 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -2797,6 +2797,30 @@ static void P_LinkMapData(void)
 	}
 }
 
+/** Hashes the sector tags across the sectors and linedefs.
+  *
+  * \sa P_FindSectorFromTag, P_ChangeSectorTag
+  * \author Lee Killough
+  */
+static inline void P_InitTagLists(void)
+{
+	register size_t i;
+
+	for (i = numsectors - 1; i != (size_t)-1; i--)
+	{
+		size_t j = (unsigned)sectors[i].tag % numsectors;
+		sectors[i].nexttag = sectors[j].firsttag;
+		sectors[j].firsttag = (INT32)i;
+	}
+
+	for (i = numlines - 1; i != (size_t)-1; i--)
+	{
+		size_t j = (unsigned)lines[i].tag % numlines;
+		lines[i].nexttag = lines[j].firsttag;
+		lines[j].firsttag = (INT32)i;
+	}
+}
+
 //For maps in binary format, converts setup of specials to UDMF format.
 static void P_ConvertBinaryMap(void)
 {
@@ -2806,6 +2830,45 @@ static void P_ConvertBinaryMap(void)
 	{
 		switch (lines[i].special)
 		{
+		case 20: //PolyObject first line
+		{
+			INT32 paramline = P_FindSpecialLineFromTag(22, lines[i].tag, -1);
+
+			//PolyObject ID
+			lines[i].args[0] = lines[i].tag;
+
+			//Default: Invisible planes
+			lines[i].args[3] |= TMPF_INVISIBLEPLANES;
+
+			//Linedef executor tag
+			lines[i].args[4] = 32000 + lines[i].args[0];
+
+			if (paramline == -1)
+				break; // no extra settings to apply, let's leave it
+
+			//Parent ID
+			lines[i].args[1] = lines[paramline].frontsector->special;
+			//Translucency
+			lines[i].args[2] = (lines[paramline].flags & ML_DONTPEGTOP)
+						? (sides[lines[paramline].sidenum[0]].textureoffset >> FRACBITS)
+						: ((lines[paramline].frontsector->floorheight >> FRACBITS) / 100);
+
+			//Flags
+			if (lines[paramline].flags & ML_EFFECT1)
+				lines[i].args[3] |= TMPF_NOINSIDES;
+			if (lines[paramline].flags & ML_EFFECT2)
+				lines[i].args[3] |= TMPF_INTANGIBLE;
+			if (lines[paramline].flags & ML_EFFECT3)
+				lines[i].args[3] |= TMPF_PUSHABLESTOP;
+			if (lines[paramline].flags & ML_EFFECT4)
+				lines[i].args[3] &= ~TMPF_INVISIBLEPLANES;
+			/*if (lines[paramline].flags & ML_EFFECT5)
+				lines[i].args[3] |= TMPF_DONTCLIPPLANES;*/
+			if (lines[paramline].flags & ML_NOCLIMB)
+				lines[i].args[3] |= TMPF_EXECUTOR;
+
+			break;
+		}
 		case 443: //Call Lua function
 			if (lines[i].text)
 			{
@@ -2956,9 +3019,17 @@ static void P_ConvertBinaryMap(void)
 		case 750:
 		case 760:
 		case 761:
+			mapthings[i].tag = mapthings[i].angle;
+			break;
 		case 762:
+		{
+			INT32 firstline = P_FindSpecialLineFromTag(20, mapthings[i].angle, -1);
+			if (firstline != -1)
+				lines[firstline].args[3] |= TMPF_CRUSH;
 			mapthings[i].tag = mapthings[i].angle;
+			mapthings[i].type = 761;
 			break;
+		}
 		case 780:
 			mapthings[i].tag = mapthings[i].extrainfo;
 			break;
@@ -3043,6 +3114,8 @@ static boolean P_LoadMapFromFile(void)
 
 	P_LinkMapData();
 
+	P_InitTagLists();   // Create xref tables for tags
+
 	if (!udmf)
 		P_ConvertBinaryMap();
 
@@ -3905,8 +3978,7 @@ boolean P_LoadLevel(boolean fromnetsave)
 	if (!P_LoadMapFromFile())
 		return false;
 
-	// init gravity, tag lists,
-	// anything that P_SpawnSlopes/P_LoadThings needs to know
+	// init anything that P_SpawnSlopes/P_LoadThings needs to know
 	P_InitSpecials();
 
 	P_SpawnSlopes(fromnetsave);
diff --git a/src/p_spec.c b/src/p_spec.c
index dae3971fb133a5f3c1ce055fa1c8d119683d9abd..f1d2c13b5c85464e909e1bb37e266b58589ab630 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -1485,30 +1485,6 @@ void P_RunNightsCapsuleTouchExecutors(mobj_t *actor, boolean entering, boolean e
 	}
 }
 
-/** Hashes the sector tags across the sectors and linedefs.
-  *
-  * \sa P_FindSectorFromTag, P_ChangeSectorTag
-  * \author Lee Killough
-  */
-static inline void P_InitTagLists(void)
-{
-	register size_t i;
-
-	for (i = numsectors - 1; i != (size_t)-1; i--)
-	{
-		size_t j = (unsigned)sectors[i].tag % numsectors;
-		sectors[i].nexttag = sectors[j].firsttag;
-		sectors[j].firsttag = (INT32)i;
-	}
-
-	for (i = numlines - 1; i != (size_t)-1; i--)
-	{
-		size_t j = (unsigned)lines[i].tag % numlines;
-		lines[i].nexttag = lines[j].firsttag;
-		lines[j].firsttag = (INT32)i;
-	}
-}
-
 /** Finds minimum light from an adjacent sector.
   *
   * \param sector Sector to start in.
@@ -6264,7 +6240,7 @@ static void P_RunLevelLoadExecutors(void)
   * by P_SpawnSlopes or P_LoadThings. This was split off from
   * P_SpawnSpecials, in case you couldn't tell.
   *
-  * \sa P_SpawnSpecials, P_InitTagLists
+  * \sa P_SpawnSpecials
   * \author Monster Iestyn
   */
 void P_InitSpecials(void)
@@ -6295,8 +6271,6 @@ void P_InitSpecials(void)
 
 	// Set globalweather
 	globalweather = mapheaderinfo[gamemap-1]->weather;
-
-	P_InitTagLists();   // Create xref tables for tags
 }
 
 static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs)