From 5401e9560fb6c65986dc539e6de451bbdd2ab73f Mon Sep 17 00:00:00 2001
From: Nev3r <apophycens@gmail.com>
Date: Fri, 19 Apr 2019 14:14:43 +0200
Subject: [PATCH] Dynamic slopes now use thinkers. * Moved dynamic
 slope-related data into its own thinker. * Vertex slopes no longer use the
 mapthings directly.

Signed-off-by: Nev3r <apophycens@gmail.com>
---
 src/lua_maplib.c |  12 --
 src/p_saveg.c    |  84 ++++++++
 src/p_setup.c    |   2 +-
 src/p_slopes.c   | 512 +++++++++++++++++++++--------------------------
 src/p_slopes.h   |  38 +++-
 src/p_tick.c     |  15 --
 src/r_defs.h     |  34 +---
 7 files changed, 358 insertions(+), 339 deletions(-)

diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index 27b97204f..e137b301d 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -292,8 +292,6 @@ enum slope_e {
 	slope_normal,
 	slope_zangle,
 	slope_xydirection,
-	slope_sourceline,
-	slope_refpos,
 	slope_flags
 };
 
@@ -305,8 +303,6 @@ static const char *const slope_opt[] = {
 	"normal",
 	"zangle",
 	"xydirection",
-	"sourceline",
-	"refpos",
 	"flags",
 	NULL};
 
@@ -1831,12 +1827,6 @@ static int slope_get(lua_State *L)
 	case slope_xydirection: // xydirection
 		lua_pushangle(L, slope->xydirection);
 		return 1;
-	case slope_sourceline: // source linedef
-		LUA_PushUserdata(L, slope->sourceline, META_LINE);
-		return 1;
-	case slope_refpos: // refpos
-		lua_pushinteger(L, slope->refpos);
-		return 1;
 	case slope_flags: // flags
 		lua_pushinteger(L, slope->flags);
 		return 1;
@@ -1858,11 +1848,9 @@ static int slope_set(lua_State *L)
 	switch(field) // todo: reorganize this shit
 	{
 	case slope_valid: // valid
-	case slope_sourceline: // sourceline
 	case slope_d: // d
 	case slope_flags: // flags
 	case slope_normal: // normal
-	case slope_refpos: // refpos
 	default:
 		return luaL_error(L, "pslope_t field " LUA_QS " cannot be set.", slope_opt[field]);
 	case slope_o: { // o
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 0d58387b9..10c761753 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -1304,6 +1304,10 @@ typedef enum
 	tc_fade,
 	tc_fadecolormap,
 	tc_planedisplace,
+#ifdef ESLOPE
+	tc_dynslopeline,
+	tc_dynslopevert,
+#endif // ESLOPE
 #ifdef POLYOBJECTS
 	tc_polyrotate, // haleyjd 03/26/06: polyobjects
 	tc_polymove,
@@ -1342,6 +1346,14 @@ static inline UINT32 SavePlayer(const player_t *player)
 	return 0xFFFFFFFF;
 }
 
+#ifdef ESLOPE
+static UINT32 SaveSlope(const pslope_t *slope)
+{
+	if (slope) return (UINT32)(slope->id);
+	return 0xFFFFFFFF;
+}
+#endif // ESLOPE
+
 //
 // SaveMobjThinker
 //
@@ -1979,6 +1991,25 @@ static void SavePlaneDisplaceThinker(const thinker_t *th, const UINT8 type)
 	WRITEFIXED(save_p, ht->speed);
 	WRITEUINT8(save_p, ht->type);
 }
+#ifdef ESLOPE
+/// Save a dynamic slope thinker.
+static inline void SaveDynamicSlopeThinker(const thinker_t *th, const UINT8 type)
+{
+	const dynplanethink_t* ht = (const void*)th;
+
+	CONS_Printf("Number of slopes: %d\n", slopecount);
+
+	WRITEUINT8(save_p, type);
+	WRITEUINT8(save_p, ht->type);
+	WRITEUINT32(save_p, SaveSlope(ht->slope));
+	WRITEUINT32(save_p, SaveLine(ht->sourceline));
+	WRITEFIXED(save_p, ht->extent);
+
+	WRITEMEM(save_p, ht->tags, sizeof(ht->tags));
+    WRITEMEM(save_p, ht->vex, sizeof(ht->vex));
+}
+#endif // ESLOPE
+
 #ifdef POLYOBJECTS
 
 //
@@ -2309,6 +2340,18 @@ static void P_NetArchiveThinkers(void)
 			SavePlaneDisplaceThinker(th, tc_planedisplace);
 			continue;
 		}
+#ifdef ESLOPE
+		else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeLine)
+		{
+			SaveDynamicSlopeThinker(th, tc_dynslopeline);
+			continue;
+		}
+		else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeVert)
+		{
+			SaveDynamicSlopeThinker(th, tc_dynslopevert);
+			continue;
+		}
+#endif // ESLOPE
 #ifdef POLYOBJECTS
 		else if (th->function.acp1 == (actionf_p1)T_PolyObjRotate)
 		{
@@ -2413,6 +2456,20 @@ static inline player_t *LoadPlayer(UINT32 player)
 	return &players[player];
 }
 
+#ifdef ESLOPE
+static inline pslope_t *LoadSlope(UINT32 slopeid)
+{
+	pslope_t *p = slopelist;
+	if (slopeid > slopecount) return NULL;
+	do
+	{
+		if (p->id == slopeid)
+			return p;
+	} while ((p = p->next));
+	return NULL;
+}
+#endif // ESLOPE
+
 //
 // LoadMobjThinker
 //
@@ -3105,6 +3162,7 @@ static inline void LoadPlaneDisplaceThinker(actionf_p1 thinker)
 {
 	planedisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
 	ht->thinker.function.acp1 = thinker;
+
 	ht->affectee = READINT32(save_p);
 	ht->control = READINT32(save_p);
 	ht->last_height = READFIXED(save_p);
@@ -3113,6 +3171,24 @@ static inline void LoadPlaneDisplaceThinker(actionf_p1 thinker)
 	P_AddThinker(&ht->thinker);
 }
 
+#ifdef ESLOPE
+/// Save a dynamic slope thinker.
+static inline void LoadDynamicSlopeThinker(actionf_p1 thinker)
+{
+	dynplanethink_t* ht = Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL);
+	ht->thinker.function.acp1 = thinker;
+
+	ht->type = READUINT8(save_p);
+	ht->slope = LoadSlope(READUINT32(save_p));
+	ht->sourceline = LoadLine(READUINT32(save_p));
+	ht->extent = READFIXED(save_p);
+	READMEM(save_p, ht->tags, sizeof(ht->tags));
+	READMEM(save_p, ht->vex, sizeof(ht->vex));
+
+	P_AddThinker(&ht->thinker);
+}
+#endif // ESLOPE
+
 #ifdef POLYOBJECTS
 
 //
@@ -3446,6 +3522,14 @@ static void P_NetUnArchiveThinkers(void)
 			case tc_planedisplace:
 				LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace);
 				break;
+#ifdef ESLOPE
+			case tc_dynslopeline:
+				LoadDynamicSlopeThinker((actionf_p1)T_DynamicSlopeLine);
+				break;
+			case tc_dynslopevert:
+				LoadDynamicSlopeThinker((actionf_p1)T_DynamicSlopeVert);
+				break;
+#endif // ESLOPE
 #ifdef POLYOBJECTS
 			case tc_polyrotate:
 				LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate);
diff --git a/src/p_setup.c b/src/p_setup.c
index 3dd673906..229ae734d 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -2911,7 +2911,7 @@ boolean P_SetupLevel(boolean skipprecip)
 	P_InitSpecials();
 
 #ifdef ESLOPE
-	P_ResetDynamicSlopes();
+	P_ResetDynamicSlopes(fromnetsave);
 #endif
 
 	P_LoadThings(loademblems);
diff --git a/src/p_slopes.c b/src/p_slopes.c
index 5a6874196..237502400 100644
--- a/src/p_slopes.c
+++ b/src/p_slopes.c
@@ -25,8 +25,8 @@
 
 #ifdef ESLOPE
 
-static pslope_t *slopelist = NULL;
-static UINT16 slopecount = 0;
+pslope_t *slopelist = NULL;
+UINT16 slopecount = 0;
 
 // Calculate line normal
 void P_CalculateSlopeNormal(pslope_t *slope) {
@@ -35,58 +35,57 @@ void P_CalculateSlopeNormal(pslope_t *slope) {
 	slope->normal.y = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.y);
 }
 
-// With a vertex slope that has its vertices set, configure relevant slope info
-static void P_ReconfigureVertexSlope(pslope_t *slope)
+/// Setup slope via 3 vertexes.
+static void ReconfigureViaVertexes (pslope_t *slope, const vector3_t v1, const vector3_t v2, const vector3_t v3)
 {
 	vector3_t vec1, vec2;
 
-	// Set slope normal
-	vec1.x = (slope->vertices[1]->x - slope->vertices[0]->x) << FRACBITS;
-	vec1.y = (slope->vertices[1]->y - slope->vertices[0]->y) << FRACBITS;
-	vec1.z = (slope->vertices[1]->z - slope->vertices[0]->z) << FRACBITS;
-
-	vec2.x = (slope->vertices[2]->x - slope->vertices[0]->x) << FRACBITS;
-	vec2.y = (slope->vertices[2]->y - slope->vertices[0]->y) << FRACBITS;
-	vec2.z = (slope->vertices[2]->z - slope->vertices[0]->z) << FRACBITS;
-
-	// ugggggggh fixed-point maaaaaaath
-	slope->extent = max(
-		max(max(abs(vec1.x), abs(vec1.y)), abs(vec1.z)),
-		max(max(abs(vec2.x), abs(vec2.y)), abs(vec2.z))
-	) >> (FRACBITS+5);
-	vec1.x /= slope->extent;
-	vec1.y /= slope->extent;
-	vec1.z /= slope->extent;
-	vec2.x /= slope->extent;
-	vec2.y /= slope->extent;
-	vec2.z /= slope->extent;
-
-	FV3_Cross(&vec1, &vec2, &slope->normal);
-
-	slope->extent = R_PointToDist2(0, 0, R_PointToDist2(0, 0, slope->normal.x, slope->normal.y), slope->normal.z);
-	if (slope->normal.z < 0)
-		slope->extent = -slope->extent;
-
-	slope->normal.x = FixedDiv(slope->normal.x, slope->extent);
-	slope->normal.y = FixedDiv(slope->normal.y, slope->extent);
-	slope->normal.z = FixedDiv(slope->normal.z, slope->extent);
-
-	// Set origin
-	slope->o.x = slope->vertices[0]->x << FRACBITS;
-	slope->o.y = slope->vertices[0]->y << FRACBITS;
-	slope->o.z = slope->vertices[0]->z << FRACBITS;
-
-	if (slope->normal.x == 0 && slope->normal.y == 0) { // Set some defaults for a non-sloped "slope"
+	// Set origin.
+	FV3_Copy(&slope->o, &v1);
+
+	// Get slope's normal.
+	FV3_SubEx(&v2, &v1, &vec1);
+	FV3_SubEx(&v3, &v1, &vec2);
+
+	// Set some defaults for a non-sloped "slope"
+	if (vec1.z == 0 && vec2.z == 0)
+	{
+		/// \todo Fix fully flat cases.
+		CONS_Printf("Please fix me\n");
+
 		slope->zangle = slope->xydirection = 0;
 		slope->zdelta = slope->d.x = slope->d.y = 0;
-	} else {
+	}
+	else
+	{
+		/// \note Using fixed point for vectorial products easily leads to overflows so we work around by downscaling them.
+		fixed_t m = max(
+			max(max(abs(vec1.x), abs(vec1.y)), abs(vec1.z)),
+			max(max(abs(vec2.x), abs(vec2.y)), abs(vec2.z))
+		) >> 5; // shifting right by 5 is good enough.
+
+		FV3_Cross(
+				FV3_Divide(&vec1, m),
+				FV3_Divide(&vec2, m),
+				&slope->normal
+				);
+
+		// NOTE: FV3_Magnitude() doesn't work properly in some cases, and chaining FixedHypot() seems to give worse results.
+		m = R_PointToDist2(0, 0, R_PointToDist2(0, 0, slope->normal.x, slope->normal.y), slope->normal.z);
+
+		// Invert normal if it's facing down.
+		if (slope->normal.z < 0)
+			m = -m;
+
+		FV3_Divide(&slope->normal, m);
+
 		// Get direction vector
-		slope->extent = R_PointToDist2(0, 0, slope->normal.x, slope->normal.y);
-		slope->d.x = -FixedDiv(slope->normal.x, slope->extent);
-		slope->d.y = -FixedDiv(slope->normal.y, slope->extent);
+		m = FixedHypot(slope->normal.x, slope->normal.y);
+		slope->d.x = -FixedDiv(slope->normal.x, m);
+		slope->d.y = -FixedDiv(slope->normal.y, m);
 
 		// Z delta
-		slope->zdelta = FixedDiv(slope->extent, slope->normal.z);
+		slope->zdelta = FixedDiv(m, slope->normal.z);
 
 		// Get angles
 		slope->xydirection = R_PointToAngle2(0, 0, slope->d.x, slope->d.y)+ANGLE_180;
@@ -94,88 +93,95 @@ static void P_ReconfigureVertexSlope(pslope_t *slope)
 	}
 }
 
-// Recalculate dynamic slopes
-void P_RunDynamicSlopes(void) {
-	pslope_t *slope;
+/// Recalculate dynamic slopes.
+void T_DynamicSlopeLine (dynplanethink_t* th)
+{
+	pslope_t* slope = th->slope;
+	line_t* srcline = th->sourceline;
 
-	for (slope = slopelist; slope; slope = slope->next) {
-		fixed_t zdelta;
+	fixed_t zdelta;
 
-		if (slope->flags & SL_NODYNAMIC)
-			continue;
+	switch(th->type) {
+	case DP_FRONTFLOOR:
+		zdelta = srcline->backsector->floorheight - srcline->frontsector->floorheight;
+		slope->o.z = srcline->frontsector->floorheight;
+		break;
 
-		switch(slope->refpos) {
-		case 1: // front floor
-			zdelta = slope->sourceline->backsector->floorheight - slope->sourceline->frontsector->floorheight;
-			slope->o.z = slope->sourceline->frontsector->floorheight;
-			break;
-		case 2: // front ceiling
-			zdelta = slope->sourceline->backsector->ceilingheight - slope->sourceline->frontsector->ceilingheight;
-			slope->o.z = slope->sourceline->frontsector->ceilingheight;
-			break;
-		case 3: // back floor
-			zdelta = slope->sourceline->frontsector->floorheight - slope->sourceline->backsector->floorheight;
-			slope->o.z = slope->sourceline->backsector->floorheight;
-			break;
-		case 4: // back ceiling
-			zdelta = slope->sourceline->frontsector->ceilingheight - slope->sourceline->backsector->ceilingheight;
-			slope->o.z = slope->sourceline->backsector->ceilingheight;
-			break;
-		case 5: // vertices
-			{
-				mapthing_t *mt;
-				size_t i;
-				INT32 l;
-				line_t *line;
-
-				for (i = 0; i < 3; i++) {
-					mt = slope->vertices[i];
-					l = P_FindSpecialLineFromTag(799, mt->angle, -1);
-					if (l != -1) {
-						line = &lines[l];
-						mt->z = line->frontsector->floorheight >> FRACBITS;
-					}
-				}
-
-				P_ReconfigureVertexSlope(slope);
-			}
-			continue; // TODO
+	case DP_FRONTCEIL:
+		zdelta = srcline->backsector->ceilingheight - srcline->frontsector->ceilingheight;
+		slope->o.z = srcline->frontsector->ceilingheight;
+		break;
 
-		default:
-			I_Error("P_RunDynamicSlopes: slope has invalid type!");
-		}
+	case DP_BACKFLOOR:
+		zdelta = srcline->frontsector->floorheight - srcline->backsector->floorheight;
+		slope->o.z = srcline->backsector->floorheight;
+		break;
+
+	case DP_BACKCEIL:
+		zdelta = srcline->frontsector->ceilingheight - srcline->backsector->ceilingheight;
+		slope->o.z = srcline->backsector->ceilingheight;
+		break;
+
+	default:
+		return;
+	}
+
+	if (slope->zdelta != FixedDiv(zdelta, th->extent)) {
+		slope->zdelta = FixedDiv(zdelta, th->extent);
+		slope->zangle = R_PointToAngle2(0, 0, th->extent, -zdelta);
+		P_CalculateSlopeNormal(slope);
+	}
+}
+
+/// Mapthing-defined
+void T_DynamicSlopeVert (dynplanethink_t* th)
+{
+	pslope_t* slope = th->slope;
+
+	size_t i;
+	INT32 l;
 
-		if (slope->zdelta != FixedDiv(zdelta, slope->extent)) {
-			slope->zdelta = FixedDiv(zdelta, slope->extent);
-			slope->zangle = R_PointToAngle2(0, 0, slope->extent, -zdelta);
-			P_CalculateSlopeNormal(slope);
+	for (i = 0; i < 3; i++) {
+		l = P_FindSpecialLineFromTag(799, th->tags[i], -1);
+		if (l != -1) {
+			th->vex[i].z = lines[l].frontsector->floorheight;
 		}
+		else
+			th->vex[i].z = 0;
 	}
+
+	ReconfigureViaVertexes(slope, th->vex[0], th->vex[1], th->vex[2]);
 }
 
-//
-// P_MakeSlope
-//
-// Alocates and fill the contents of a slope structure.
-//
-static pslope_t *P_MakeSlope(const vector3_t *o, const vector2_t *d,
-                             const fixed_t zdelta, UINT8 flags)
+static inline void P_AddDynSlopeThinker (pslope_t* slope, dynplanetype_t type, line_t* sourceline, fixed_t extent, const INT16 tags[3], const vector3_t vx[3])
 {
-	pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL);
-	memset(ret, 0, sizeof(*ret));
+	dynplanethink_t* th = Z_Calloc(sizeof (*th), PU_LEVSPEC, NULL);
+	switch (type)
+	{
+	case DP_VERTEX:
+		th->thinker.function.acp1 = (actionf_p1)T_DynamicSlopeVert;
+		memcpy(th->tags, tags, sizeof(th->tags));
+		memcpy(th->vex, vx, sizeof(th->vex));
+		break;
+	default:
+		th->thinker.function.acp1 = (actionf_p1)T_DynamicSlopeLine;
+		th->sourceline = sourceline;
+		th->extent = extent;
+	}
 
-	ret->o.x = o->x;
-	ret->o.y = o->y;
-	ret->o.z = o->z;
+	th->slope = slope;
+	th->type = type;
 
-	ret->d.x = d->x;
-	ret->d.y = d->y;
+	P_AddThinker(&th->thinker);
+}
 
-	ret->zdelta = zdelta;
 
+/// Create a new slope and add it to the slope list.
+static inline pslope_t* Slope_Add (const UINT8 flags)
+{
+	pslope_t *ret = Z_Calloc(sizeof(pslope_t), PU_LEVEL, NULL);
 	ret->flags = flags;
 
-	// Add to the slope list
 	ret->next = slopelist;
 	slopelist = ret;
 
@@ -185,13 +191,24 @@ static pslope_t *P_MakeSlope(const vector3_t *o, const vector2_t *d,
 	return ret;
 }
 
-//
-// P_GetExtent
-//
-// Returns the distance to the first line within the sector that
-// is intersected by a line parallel to the plane normal with the point (ox, oy)
-//
-static fixed_t P_GetExtent(sector_t *sector, line_t *line)
+/// Alocates and fill the contents of a slope structure.
+static pslope_t *MakeViaVectors(const vector3_t *o, const vector2_t *d,
+                             const fixed_t zdelta, UINT8 flags)
+{
+	pslope_t *ret = Slope_Add(flags);
+
+	FV3_Copy(&ret->o, o);
+	FV2_Copy(&ret->d, d);
+
+	ret->zdelta = zdelta;
+
+	ret->flags = flags;
+
+	return ret;
+}
+
+/// Get furthest perpendicular distance from all vertexes in a sector for a given line.
+static fixed_t GetExtent(sector_t *sector, line_t *line)
 {
 	// ZDoom code reference: v3float_t = vertex_t
 	fixed_t fardist = -FRACUNIT;
@@ -224,14 +241,8 @@ static fixed_t P_GetExtent(sector_t *sector, line_t *line)
 	return fardist;
 }
 
-
-//
-// P_SpawnSlope_Line
-//
-// Creates one or more slopes based on the given line type and front/back
-// sectors.
-//
-void P_SpawnSlope_Line(int linenum)
+/// Creates one or more slopes based on the given line type and front/back sectors.
+static void line_SpawnViaLine(const int linenum, const boolean spawnthinker)
 {
 	// With dynamic slopes, it's fine to just leave this function as normal,
 	// because checking to see if a slope had changed will waste more memory than
@@ -274,6 +285,7 @@ void P_SpawnSlope_Line(int linenum)
 		ny = -FixedDiv(line->dx, len);
 	}
 
+	// Set origin to line's center.
 	origin.x = line->v1->x + (line->v2->x - line->v1->x)/2;
 	origin.y = line->v1->y + (line->v2->y - line->v1->y)/2;
 
@@ -286,7 +298,7 @@ void P_SpawnSlope_Line(int linenum)
 		direction.x = nx;
 		direction.y = ny;
 
-		extent = P_GetExtent(line->frontsector, line);
+		extent = GetExtent(line->frontsector, line);
 
 		if(extent < 0)
 		{
@@ -312,26 +324,17 @@ void P_SpawnSlope_Line(int linenum)
 			// In P_SpawnSlopeLine the origin is the centerpoint of the sourcelinedef
 
 			fslope = line->frontsector->f_slope =
-            P_MakeSlope(&point, &direction, dz, flags);
-
-            // Set up some shit
-            fslope->extent = extent;
-            fslope->refpos = 1;
+            MakeViaVectors(&point, &direction, dz, flags);
 
 			// Now remember that f_slope IS a vector
 			// fslope->o = origin      3D point 1 of the vector
 			// fslope->d = destination 3D point 2 of the vector
 			// fslope->normal is a 3D line perpendicular to the 3D vector
 
-			// Sync the linedata of the line that started this slope
-			// TODO: Anything special for control sector based slopes later?
-			fslope->sourceline = line;
-
 			// To find the real highz/lowz of a slope, you need to check all the vertexes
 			// in the slope's sector with P_GetZAt to get the REAL lowz & highz
 			// Although these slopes are set by floorheights the ANGLE is what a slope is,
 			// so technically any slope can extend on forever (they are just bound by sectors)
-			// *You can use sourceline as a reference to see if two slopes really are the same
 
 			// Default points for high and low
 			highest = point.z > origin.z ? point.z : origin.z;
@@ -359,6 +362,9 @@ void P_SpawnSlope_Line(int linenum)
 			fslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
 
 			P_CalculateSlopeNormal(fslope);
+
+			if (spawnthinker && !(flags & SL_NODYNAMIC))
+				P_AddDynSlopeThinker(fslope, DP_FRONTFLOOR, line, extent, NULL, NULL);
 		}
 		if(frontceil)
 		{
@@ -369,15 +375,7 @@ void P_SpawnSlope_Line(int linenum)
 			dz = FixedDiv(origin.z - point.z, extent);
 
 			cslope = line->frontsector->c_slope =
-            P_MakeSlope(&point, &direction, dz, flags);
-
-            // Set up some shit
-            cslope->extent = extent;
-            cslope->refpos = 2;
-
-			// Sync the linedata of the line that started this slope
-			// TODO: Anything special for control sector based slopes later?
-			cslope->sourceline = line;
+            MakeViaVectors(&point, &direction, dz, flags);
 
 			// Remember the way the slope is formed
 			highest = point.z > origin.z ? point.z : origin.z;
@@ -402,6 +400,9 @@ void P_SpawnSlope_Line(int linenum)
 			cslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
 
 			P_CalculateSlopeNormal(cslope);
+
+			if (spawnthinker && !(flags & SL_NODYNAMIC))
+				P_AddDynSlopeThinker(cslope, DP_FRONTCEIL, line, extent, NULL, NULL);
 		}
 	}
 	if(backfloor || backceil)
@@ -413,7 +414,7 @@ void P_SpawnSlope_Line(int linenum)
 		direction.x = -nx;
 		direction.y = -ny;
 
-		extent = P_GetExtent(line->backsector, line);
+		extent = GetExtent(line->backsector, line);
 
 		if(extent < 0)
 		{
@@ -435,15 +436,7 @@ void P_SpawnSlope_Line(int linenum)
 			dz = FixedDiv(origin.z - point.z, extent);
 
 			fslope = line->backsector->f_slope =
-            P_MakeSlope(&point, &direction, dz, flags);
-
-            // Set up some shit
-            fslope->extent = extent;
-            fslope->refpos = 3;
-
-			// Sync the linedata of the line that started this slope
-			// TODO: Anything special for control sector based slopes later?
-			fslope->sourceline = line;
+            MakeViaVectors(&point, &direction, dz, flags);
 
 			// Remember the way the slope is formed
 			highest = point.z > origin.z ? point.z : origin.z;
@@ -468,6 +461,9 @@ void P_SpawnSlope_Line(int linenum)
 			fslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
 
 			P_CalculateSlopeNormal(fslope);
+
+			if (spawnthinker && !(flags & SL_NODYNAMIC))
+				P_AddDynSlopeThinker(fslope, DP_BACKFLOOR, line, extent, NULL, NULL);
 		}
 		if(backceil)
 		{
@@ -478,15 +474,7 @@ void P_SpawnSlope_Line(int linenum)
 			dz = FixedDiv(origin.z - point.z, extent);
 
 			cslope = line->backsector->c_slope =
-            P_MakeSlope(&point, &direction, dz, flags);
-
-            // Set up some shit
-            cslope->extent = extent;
-            cslope->refpos = 4;
-
-			// Sync the linedata of the line that started this slope
-			// TODO: Anything special for control sector based slopes later?
-			cslope->sourceline = line;
+            MakeViaVectors(&point, &direction, dz, flags);
 
 			// Remember the way the slope is formed
 			highest = point.z > origin.z ? point.z : origin.z;
@@ -511,6 +499,9 @@ void P_SpawnSlope_Line(int linenum)
 			cslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
 
 			P_CalculateSlopeNormal(cslope);
+
+			if (spawnthinker && !(flags & SL_NODYNAMIC))
+				P_AddDynSlopeThinker(cslope, DP_BACKCEIL, line, extent, NULL, NULL);
 		}
 	}
 
@@ -518,63 +509,99 @@ void P_SpawnSlope_Line(int linenum)
 		return;
 }
 
-//
-// P_NewVertexSlope
-//
-// Creates a new slope from three vertices with the specified IDs
-//
-static pslope_t *P_NewVertexSlope(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flags)
+/// Creates a new slope from three mapthings with the specified IDs
+static pslope_t *MakeViaMapthings(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flags, const boolean spawnthinker)
 {
 	size_t i;
-	mapthing_t *mt = mapthings;
-
-	pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL);
-	memset(ret, 0, sizeof(*ret));
-
-	// Start by setting flags
-	ret->flags = flags;
+	mapthing_t* mt = mapthings;
+	mapthing_t* vertices[3] = {0};
+	INT16 tags[3] = {tag1, tag2, tag3};
 
-	// Now set up the vertex list
-	ret->vertices = Z_Malloc(3*sizeof(mapthing_t), PU_LEVEL, NULL);
-	memset(ret->vertices, 0, 3*sizeof(mapthing_t));
+	vector3_t vx[3];
+	pslope_t* ret = Slope_Add(flags);
 
 	// And... look for the vertices in question.
 	for (i = 0; i < nummapthings; i++, mt++) {
 		if (mt->type != 750) // Haha, I'm hijacking the old Chaos Spawn thingtype for something!
 			continue;
 
-		if (!ret->vertices[0] && mt->angle == tag1)
-			ret->vertices[0] = mt;
-		else if (!ret->vertices[1] && mt->angle == tag2)
-			ret->vertices[1] = mt;
-		else if (!ret->vertices[2] && mt->angle == tag3)
-			ret->vertices[2] = mt;
+		if (!vertices[0] && mt->angle == tag1)
+			vertices[0] = mt;
+		else if (!vertices[1] && mt->angle == tag2)
+			vertices[1] = mt;
+		else if (!vertices[2] && mt->angle == tag3)
+			vertices[2] = mt;
 	}
 
 	// Now set heights for each vertex, because they haven't been set yet
 	for (i = 0; i < 3; i++) {
-		mt = ret->vertices[i];
+		mt = vertices[i];
 		if (!mt) // If a vertex wasn't found, it's game over. There's nothing you can do to recover (except maybe try and kill the slope instead - TODO?)
-			I_Error("P_NewVertexSlope: Slope vertex %s (for linedef tag %d) not found!", sizeu1(i), tag1);
+			I_Error("MakeViaMapthings: Slope vertex %s (for linedef tag %d) not found!", sizeu1(i), tag1);
+		vx[i].x = mt->x << FRACBITS;
+		vx[i].y = mt->y << FRACBITS;
 		if (mt->extrainfo)
-			mt->z = mt->options;
+			vx[i].z = mt->options << FRACBITS;
 		else
-			mt->z = (R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector->floorheight >> FRACBITS) + (mt->options >> ZSHIFT);
+			vx[i].z = (R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector->floorheight) + ((mt->options >> ZSHIFT) << FRACBITS);
 	}
 
-	P_ReconfigureVertexSlope(ret);
-	ret->refpos = 5;
+	ReconfigureViaVertexes(ret, vx[0], vx[1], vx[2]);
 
-	// Add to the slope list
-	ret->next = slopelist;
-	slopelist = ret;
-
-	slopecount++;
-	ret->id = slopecount;
+	if (spawnthinker && !(flags & SL_NODYNAMIC))
+		P_AddDynSlopeThinker(ret, DP_VERTEX, NULL, 0, tags, vx);
 
 	return ret;
 }
 
+/// Create vertex based slopes.
+static void line_SpawnViaVertexes(const int linenum, const boolean spawnthinker)
+{
+	line_t *line = lines + linenum;
+	side_t *side;
+	pslope_t **slopetoset;
+	UINT16 tag1, tag2, tag3;
+
+	UINT8 flags = SL_VERTEXSLOPE;
+	if (line->flags & ML_NOSONIC)
+		flags |= SL_NOPHYSICS;
+	if (!(line->flags & ML_NOTAILS))
+		flags |= SL_NODYNAMIC;
+
+	switch(line->special)
+	{
+	case 704:
+		slopetoset = &line->frontsector->f_slope;
+		side = &sides[line->sidenum[0]];
+		break;
+	case 705:
+		slopetoset = &line->frontsector->c_slope;
+		side = &sides[line->sidenum[0]];
+		break;
+	case 714:
+		slopetoset = &line->backsector->f_slope;
+		side = &sides[line->sidenum[1]];
+		break;
+	case 715:
+		slopetoset = &line->backsector->c_slope;
+		side = &sides[line->sidenum[1]];
+	default:
+		return;
+	}
+
+	if (line->flags & ML_NOKNUX)
+	{
+		tag1 = line->tag;
+		tag2 = side->textureoffset >> FRACBITS;
+		tag3 = side->rowoffset >> FRACBITS;
+	}
+	else
+		tag1 = tag2 = tag3 = line->tag;
+
+	*slopetoset = MakeViaMapthings(tag1, tag2, tag3, flags, spawnthinker);
+
+	side->sector->hasslope = true;
+}
 
 
 //
@@ -615,12 +642,11 @@ pslope_t *P_SlopeById(UINT16 id)
 	return ret;
 }
 
-// Reset the dynamic slopes pointer, and read all of the fancy schmancy slopes
-void P_ResetDynamicSlopes(void) {
+/// Reset slopes and read them from special lines.
+void P_ResetDynamicSlopes(const UINT32 fromsave) {
 	size_t i;
-#ifdef ESLOPE_TYPESHIM // Rewrite old specials to new ones, and give a console warning
-	boolean warned = false;
-#endif
+
+	boolean spawnthinkers = !(boolean)fromsave;
 
 	slopelist = NULL;
 	slopecount = 0;
@@ -631,40 +657,6 @@ void P_ResetDynamicSlopes(void) {
 	{
 		switch (lines[i].special)
 		{
-#ifdef ESLOPE_TYPESHIM // Rewrite old specials to new ones, and give a console warning
-#define WARNME if (!warned) {warned = true; CONS_Alert(CONS_WARNING, "This level uses old slope specials.\nA conversion will be needed before 2.2's release.\n");}
-			case 386:
-			case 387:
-			case 388:
-				lines[i].special += 700-386;
-				WARNME
-				P_SpawnSlope_Line(i);
-				break;
-
-			case 389:
-			case 390:
-			case 391:
-			case 392:
-				lines[i].special += 710-389;
-				WARNME
-				P_SpawnSlope_Line(i);
-				break;
-
-			case 393:
-				lines[i].special = 703;
-				WARNME
-				P_SpawnSlope_Line(i);
-				break;
-
-			case 394:
-			case 395:
-			case 396:
-				lines[i].special += 720-394;
-				WARNME
-				break;
-
-#endif
-
 			case 700:
 			case 701:
 			case 702:
@@ -673,52 +665,14 @@ void P_ResetDynamicSlopes(void) {
 			case 711:
 			case 712:
 			case 713:
-				P_SpawnSlope_Line(i);
+				line_SpawnViaLine(i, spawnthinkers);
 				break;
 
 			case 704:
 			case 705:
 			case 714:
 			case 715:
-				{
-					pslope_t **slopetoset;
-					size_t which = lines[i].special;
-
-					UINT8 flags = SL_VERTEXSLOPE;
-					if (lines[i].flags & ML_NOSONIC)
-						flags |= SL_NOPHYSICS;
-					if (!(lines[i].flags & ML_NOTAILS))
-						flags |= SL_NODYNAMIC;
-
-					if (which == 704)
-					{
-						slopetoset = &lines[i].frontsector->f_slope;
-						which = 0;
-					}
-					else if (which == 705)
-					{
-						slopetoset = &lines[i].frontsector->c_slope;
-						which = 0;
-					}
-					else if (which == 714)
-					{
-						slopetoset = &lines[i].backsector->f_slope;
-						which = 1;
-					}
-					else // 715
-					{
-						slopetoset = &lines[i].backsector->c_slope;
-						which = 1;
-					}
-
-					if (lines[i].flags & ML_NOKNUX)
-						*slopetoset = P_NewVertexSlope(lines[i].tag, sides[lines[i].sidenum[which]].textureoffset >> FRACBITS,
-																			sides[lines[i].sidenum[which]].rowoffset >> FRACBITS, flags);
-					else
-						*slopetoset = P_NewVertexSlope(lines[i].tag, lines[i].tag, lines[i].tag, flags);
-
-					sides[lines[i].sidenum[which]].sector->hasslope = true;
-				}
+				line_SpawnViaVertexes(i, spawnthinkers);
 				break;
 
 			default:
diff --git a/src/p_slopes.h b/src/p_slopes.h
index 56f5d6187..65b5eeb4c 100644
--- a/src/p_slopes.h
+++ b/src/p_slopes.h
@@ -10,14 +10,15 @@
 /// \file  p_slopes.c
 /// \brief ZDoom + Eternity Engine Slopes, ported and enhanced by Kalaron
 
+#include "m_fixed.h" // Vectors
+
 #ifdef ESLOPE
+
+extern pslope_t *slopelist;
+extern UINT16 slopecount;
+
 void P_CalculateSlopeNormal(pslope_t *slope);
-void P_ResetDynamicSlopes(void);
-void P_RunDynamicSlopes(void);
-// P_SpawnSlope_Line
-// Creates one or more slopes based on the given line type and front/back
-// sectors.
-void P_SpawnSlope_Line(int linenum);
+void P_ResetDynamicSlopes(const UINT32 fromsave);
 
 //
 // P_CopySectorSlope
@@ -39,12 +40,33 @@ fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope);
 void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope);
 void P_ButteredSlope(mobj_t *mo);
 
-/// Permit slopes to be dynamically altered.
+
+/// Dynamic plane type enum for the thinker. Will have a different functionality depending on this.
+typedef enum {
+	DP_FRONTFLOOR,
+	DP_FRONTCEIL,
+	DP_BACKFLOOR,
+	DP_BACKCEIL,
+	DP_VERTEX
+} dynplanetype_t;
+
+/// Permit slopes to be dynamically altered through a thinker.
 typedef struct
 {
 	thinker_t thinker;
+
 	pslope_t* slope;
+	dynplanetype_t type;
+
+	// Used by line slopes.
+	line_t* sourceline;
+	fixed_t extent;
+
+	// Used by mapthing vertex slopes.
+	INT16 tags[3];
+	vector3_t vex[3];
 } dynplanethink_t;
 
-void T_DynamicSlope (dynplanethink_t* th);
+void T_DynamicSlopeLine (dynplanethink_t* th);
+void T_DynamicSlopeVert (dynplanethink_t* th);
 #endif // #ifdef ESLOPE
diff --git a/src/p_tick.c b/src/p_tick.c
index a32fa0029..6f7c96ead 100644
--- a/src/p_tick.c
+++ b/src/p_tick.c
@@ -25,11 +25,6 @@
 // Object place
 #include "m_cheat.h"
 
-#ifdef ESLOPE
-// Dynamic slopes
-#include "p_slopes.h"
-#endif
-
 tic_t leveltime;
 
 //
@@ -614,11 +609,6 @@ void P_Ticker(boolean run)
 
 	if (run)
 	{
-		#ifdef ESLOPE
-		// Dynamic slopeness
-		P_RunDynamicSlopes();
-		#endif
-
 		P_RunThinkers();
 
 		// Run any "after all the other thinkers" stuff
@@ -734,11 +724,6 @@ void P_PreTicker(INT32 frames)
 				memcpy(&players[i].cmd, &temptic, sizeof(ticcmd_t));
 			}
 
-#ifdef ESLOPE
-		// Dynamic slopeness
-		P_RunDynamicSlopes();
-#endif
-
 		P_RunThinkers();
 
 		// Run any "after all the other thinkers" stuff
diff --git a/src/r_defs.h b/src/r_defs.h
index e7315b35c..ba569d3a8 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -246,37 +246,23 @@ typedef enum {
 typedef struct pslope_s
 {
 	UINT16 id; // The number of the slope, mostly used for netgame syncing purposes
+	struct pslope_s *next; // Make a linked list of dynamic slopes, for easy reference later
 
-	// --- Information used in clipping/projection ---
-	// Origin vector for the plane
-	vector3_t o;
-
-	// 2-Dimentional vector (x, y) normalized. Used to determine distance from
-	// the origin in 2d mapspace. (Basically a thrust of FRACUNIT in xydirection angle)
-	vector2_t d;
-
-	// The rate at which z changes based on distance from the origin plane.
-	fixed_t zdelta;
-
-	// The normal of the slope; will always point upward, and thus be inverted on ceilings. I think it's only needed for physics? -Red
-	vector3_t normal;
+	// The plane's definition.
+	vector3_t o;		/// Plane origin.
+	vector3_t normal;	/// Plane normal.
 
 	// For comparing when a slope should be rendered
-	fixed_t lowz;
-	fixed_t highz;
+	fixed_t lowz, highz;
 
-	// This values only check and must be updated if the slope itself is modified
-	angle_t zangle; // Angle of the plane going up from the ground (not mesured in degrees)
-	angle_t xydirection; // The direction the slope is facing (north, west, south, etc.)
+	vector2_t d;		/// Precomputed normalized projection of the normal over XY.
+	fixed_t zdelta;		/// Precomputed Z unit increase per XY unit.
 
-	struct line_s *sourceline; // The line that generated the slope
-	fixed_t extent; // Distance value used for recalculating zdelta
-	UINT8 refpos; // 1=front floor 2=front ceiling 3=back floor 4=back ceiling (used for dynamic sloping)
+	// This values only check and must be updated if the slope itself is modified
+	angle_t zangle;		/// Precomputed angle of the plane going up from the ground (not measured in degrees).
+	angle_t xydirection;/// Precomputed angle of the normal's projection on the XY plane.
 
 	UINT8 flags; // Slope options
-	mapthing_t **vertices; // List should be three long for slopes made by vertex things, or one long for slopes using one vertex thing to anchor
-
-	struct pslope_s *next; // Make a linked list of dynamic slopes, for easy reference later
 } pslope_t;
 #endif
 
-- 
GitLab