From 6c619af9ce5d177123ec5a1d7c3ac8127c0231ea Mon Sep 17 00:00:00 2001
From: Monster Iestyn <iestynjealous@ntlworld.com>
Date: Wed, 26 Apr 2017 17:12:57 +0100
Subject: [PATCH 1/4] Use the skybox mobj's actual z position, rather than
 using the spawnpoint angle!

This means setting the skybox view angle is no longer stupid, objectplace no longer breaks skyboxes, and Lua-defined skybox mobjs can actually set a Z position more easily now.
---
 src/p_mobj.c | 1 -
 src/r_main.c | 4 +---
 2 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/p_mobj.c b/src/p_mobj.c
index 17d5d13b3..6b2d1af30 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -9717,7 +9717,6 @@ void P_SpawnMapThing(mapthing_t *mthing)
 	switch(mobj->type)
 	{
 	case MT_SKYBOX:
-		mobj->angle = 0;
 		if (mthing->options & MTF_OBJECTSPECIAL)
 			skyboxmo[1] = mobj;
 		else
diff --git a/src/r_main.c b/src/r_main.c
index f03af9963..c998a7d93 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -798,9 +798,7 @@ void R_SkyboxFrame(player_t *player)
 
 	viewx = viewmobj->x;
 	viewy = viewmobj->y;
-	viewz = 0;
-	if (viewmobj->spawnpoint)
-		viewz = ((fixed_t)viewmobj->spawnpoint->angle)<<FRACBITS;
+	viewz = viewmobj->z; // 26/04/17: use actual Z position instead of spawnpoint angle!
 
 	if (mapheaderinfo[gamemap-1])
 	{

From bdb3c2ea0ee677c9b225e2e6d96950d9909627e8 Mon Sep 17 00:00:00 2001
From: Monster Iestyn <iestynjealous@ntlworld.com>
Date: Wed, 26 Apr 2017 18:16:01 +0100
Subject: [PATCH 2/4] extrainfo now determines "skybox ID", a number between 0
 and 16 to identify the viewpoint or centerpoint

also I made that change skybox linedef exec special I guess (linedef type 448)
---
 src/p_mobj.c  |  4 ++--
 src/p_setup.c |  6 ++++++
 src/p_spec.c  | 36 +++++++++++++++++++++++++++++++++++-
 src/p_spec.h  |  4 +++-
 4 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/src/p_mobj.c b/src/p_mobj.c
index 6b2d1af30..55d10b3bf 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -9718,9 +9718,9 @@ void P_SpawnMapThing(mapthing_t *mthing)
 	{
 	case MT_SKYBOX:
 		if (mthing->options & MTF_OBJECTSPECIAL)
-			skyboxmo[1] = mobj;
+			skyboxcenterpnts[mthing->extrainfo] = mobj;
 		else
-			skyboxmo[0] = mobj;
+			skyboxviewpnts[mthing->extrainfo] = mobj;
 		break;
 	case MT_FAN:
 		if (mthing->options & MTF_OBJECTSPECIAL)
diff --git a/src/p_setup.c b/src/p_setup.c
index a0c745e60..981baf2e2 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -2728,6 +2728,9 @@ boolean P_SetupLevel(boolean skipprecip)
 	for (i = 0; i < 2; i++)
 		skyboxmo[i] = NULL;
 
+	for (i = 0; i < 16; i++)
+		skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL;
+
 	P_MapStart();
 
 	P_PrepareThings(lastloadedmaplumpnum + ML_THINGS);
@@ -2737,6 +2740,9 @@ boolean P_SetupLevel(boolean skipprecip)
 #endif
 
 	P_LoadThings();
+	// skybox mobj defaults
+	skyboxmo[0] = skyboxviewpnts[0];
+	skyboxmo[1] = skyboxcenterpnts[0];
 
 	P_SpawnSecretItems(loademblems);
 
diff --git a/src/p_spec.c b/src/p_spec.c
index db7b852f5..7be9c96ea 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -46,7 +46,9 @@
 #include <errno.h>
 #endif
 
-mobj_t *skyboxmo[2];
+mobj_t *skyboxmo[2]; // current skybox mobjs: 0 = viewpoint, 1 = centerpoint
+mobj_t *skyboxviewpnts[16]; // array of MT_SKYBOX viewpoint mobjs
+mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs
 
 // Amount (dx, dy) vector linedef is shifted right to get scroll amount
 #define SCROLL_SHIFT 5
@@ -3159,6 +3161,38 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 			}
 			break;
 
+		case 448: // Change skybox viewpoint/centerpoint
+			if ((mo && mo->player && P_IsLocalPlayer(mo->player)) || (line->flags & ML_NOCLIMB))
+			{
+				INT32 viewid = sides[line->sidenum[0]].textureoffset>>FRACBITS;
+				INT32 centerid = sides[line->sidenum[0]].rowoffset>>FRACBITS;
+
+				// set viewpoint mobj
+				if (!(line->flags & ML_EFFECT4))
+				{
+					if (viewid >= 0 && viewid < 16)
+						skyboxmo[0] = skyboxviewpnts[viewid];
+					else
+						skyboxmo[0] = NULL;
+				}
+
+				// set centerpoint mobj
+				if (line->flags & ML_BLOCKMONSTERS)
+				{
+					if (centerid >= 0 && centerid < 16)
+						skyboxmo[1] = skyboxcenterpnts[centerid];
+					else
+						skyboxmo[1] = NULL;
+				}
+
+				CONS_Debug(DBG_GAMELOGIC, "Line type 448 Executor: viewid = %d, centerid = %d, viewpoint? = %s, centerpoint? = %s\n",
+						viewid,
+						centerid,
+						((line->flags & ML_EFFECT4) ? "no" : "yes"),
+						((line->flags & ML_BLOCKMONSTERS) ? "yes" : "no"));
+			}
+			break;
+
 		case 450: // Execute Linedef Executor - for recursion
 			P_LinedefExecute(line->tag, mo, NULL);
 			break;
diff --git a/src/p_spec.h b/src/p_spec.h
index e34b0d08e..222df822d 100644
--- a/src/p_spec.h
+++ b/src/p_spec.h
@@ -17,7 +17,9 @@
 #ifndef __P_SPEC__
 #define __P_SPEC__
 
-extern mobj_t *skyboxmo[2];
+extern mobj_t *skyboxmo[2]; // current skybox mobjs: 0 = viewpoint, 1 = centerpoint
+extern mobj_t *skyboxviewpnts[16]; // array of MT_SKYBOX viewpoint mobjs
+extern mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs
 
 // GETSECSPECIAL (specialval, section)
 //

From 21950687edaaae07c88cdeb9776e196650356679 Mon Sep 17 00:00:00 2001
From: Monster Iestyn <iestynjealous@ntlworld.com>
Date: Wed, 26 Apr 2017 21:34:22 +0100
Subject: [PATCH 3/4] Make sure noreload levels don't do anything weird with
 the skybox mobj pointers, especially if Lua was involved

We can assume skyboxviewpnts/skyboxcenterpnts sort themselves out from reloading all the Things at least I guess?
---
 src/p_setup.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/src/p_setup.c b/src/p_setup.c
index 981baf2e2..02a621845 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -2276,6 +2276,17 @@ void P_LoadThingsOnly(void)
 	// Search through all the thinkers.
 	mobj_t *mo;
 	thinker_t *think;
+	INT32 i, viewid = -1, centerid = -1; // for skyboxes
+
+	// check if these are any of the normal viewpoint/centerpoint mobjs in the level or not
+	if (skyboxmo[0] || skyboxmo[1])
+		for (i = 0; i < 16; i++)
+		{
+			if (skyboxmo[0] && skyboxmo[0] == skyboxviewpnts[i])
+				viewid = i; // save id just in case
+			if (skyboxmo[1] && skyboxmo[1] == skyboxcenterpnts[i])
+				centerid = i; // save id just in case
+		}
 
 	for (think = thinkercap.next; think != &thinkercap; think = think->next)
 	{
@@ -2293,6 +2304,10 @@ void P_LoadThingsOnly(void)
 	P_PrepareThings(lastloadedmaplumpnum + ML_THINGS);
 	P_LoadThings();
 
+	// restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that
+	skyboxmo[0] = skyboxviewpnts[(viewid >= 0) ? viewid : 0];
+	skyboxmo[1] = skyboxcenterpnts[(centerid >= 0) ? centerid : 0];
+
 	P_SpawnSecretItems(true);
 }
 

From 7f936d8b57f0e12f8c2be513fcf38ee3fe863b71 Mon Sep 17 00:00:00 2001
From: Monster Iestyn <iestynjealous@ntlworld.com>
Date: Mon, 1 May 2017 19:34:53 +0100
Subject: [PATCH 4/4] Add CONS_Alert warning as toaster suggested

---
 src/p_spec.c | 35 ++++++++++++++++++++++-------------
 1 file changed, 22 insertions(+), 13 deletions(-)

diff --git a/src/p_spec.c b/src/p_spec.c
index 7be9c96ea..29956d160 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3167,22 +3167,31 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 				INT32 viewid = sides[line->sidenum[0]].textureoffset>>FRACBITS;
 				INT32 centerid = sides[line->sidenum[0]].rowoffset>>FRACBITS;
 
-				// set viewpoint mobj
-				if (!(line->flags & ML_EFFECT4))
+				if ((line->flags & (ML_EFFECT4|ML_BLOCKMONSTERS)) == ML_EFFECT4) // Solid Midtexture is on but Block Enemies is off?
 				{
-					if (viewid >= 0 && viewid < 16)
-						skyboxmo[0] = skyboxviewpnts[viewid];
-					else
-						skyboxmo[0] = NULL;
+					CONS_Alert(CONS_WARNING,
+					M_GetText("Skybox switch linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"),
+					line->tag);
 				}
-
-				// set centerpoint mobj
-				if (line->flags & ML_BLOCKMONSTERS)
+				else
 				{
-					if (centerid >= 0 && centerid < 16)
-						skyboxmo[1] = skyboxcenterpnts[centerid];
-					else
-						skyboxmo[1] = NULL;
+					// set viewpoint mobj
+					if (!(line->flags & ML_EFFECT4)) // Solid Midtexture turns off viewpoint setting
+					{
+						if (viewid >= 0 && viewid < 16)
+							skyboxmo[0] = skyboxviewpnts[viewid];
+						else
+							skyboxmo[0] = NULL;
+					}
+
+					// set centerpoint mobj
+					if (line->flags & ML_BLOCKMONSTERS) // Block Enemies turns ON centerpoint setting
+					{
+						if (centerid >= 0 && centerid < 16)
+							skyboxmo[1] = skyboxcenterpnts[centerid];
+						else
+							skyboxmo[1] = NULL;
+					}
 				}
 
 				CONS_Debug(DBG_GAMELOGIC, "Line type 448 Executor: viewid = %d, centerid = %d, viewpoint? = %s, centerpoint? = %s\n",