From 89478a7ba46eaa4932dc45bbfdaf520343e1e46d Mon Sep 17 00:00:00 2001
From: Monster Iestyn <iestynjealous@ntlworld.com>
Date: Thu, 14 Jun 2018 21:51:21 +0100
Subject: [PATCH 01/20] Added linedef 447 as the change colormap linedef exec
 special.

IMPORTANT NOTE: UNTESTED
---
 src/p_setup.c | 1 +
 src/p_spec.c  | 9 +++++++++
 2 files changed, 10 insertions(+)

diff --git a/src/p_setup.c b/src/p_setup.c
index a5544c26b..052006a35 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -1428,6 +1428,7 @@ static void P_LoadRawSideDefs2(void *data)
 		{
 			case 63: // variable colormap via 242 linedef
 			case 606: //SoM: 4/4/2000: Just colormap transfer
+			case 447: // Change colormap of tagged sectors! -- Monster Iestyn 14/06/18
 				// SoM: R_CreateColormap will only create a colormap in software mode...
 				// Perhaps we should just call it instead of doing the calculations here.
 				if (rendermode == render_soft || rendermode == render_none)
diff --git a/src/p_spec.c b/src/p_spec.c
index 93b5c89ca..9d1e85366 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3033,6 +3033,15 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 			}
 			break;
 
+		case 447: // Change colormap of tagged sectors!
+			// Basically this special applies a colormap to the tagged sectors, just like 606 (the colormap linedef)
+			// Except it is activated by linedef executor, not level load
+			// This could even override existing colormaps I believe
+			// -- Monster Iestyn 14/06/18
+			for (secnum = -1; (secnum = P_FindSectorFromLineTag(line, secnum)) >= 0 ;)
+				sectors[secnum].midmap = line->frontsector->midmap;
+			break;
+
 		case 448: // Change skybox viewpoint/centerpoint
 			if ((mo && mo->player && P_IsLocalPlayer(mo->player)) || (line->flags & ML_NOCLIMB))
 			{

From 002f1bad8fe8741590b362f62a3a092ce77e0e49 Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Sun, 9 Sep 2018 12:01:50 -0400
Subject: [PATCH 02/20] Savegame netsync for sector colormaps; add spawn_midmap
 and co for comparison

---
 src/p_saveg.c | 74 ++++++++++++++++++++++++++++++++++++++-------------
 src/p_setup.c |  5 ++--
 src/p_spec.c  |  2 +-
 src/r_defs.h  |  1 +
 4 files changed, 60 insertions(+), 22 deletions(-)

diff --git a/src/p_saveg.c b/src/p_saveg.c
index 22d43f358..1c9589e8f 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -487,10 +487,16 @@ static void P_NetUnArchivePlayers(void)
 #define SD_FYOFFS    0x02
 #define SD_CXOFFS    0x04
 #define SD_CYOFFS    0x08
-#define SD_TAG       0x10
-#define SD_FLOORANG  0x20
-#define SD_CEILANG   0x40
-#define SD_TAGLIST   0x80
+#define SD_FLOORANG  0x10
+#define SD_CEILANG   0x20
+#define SD_TAG       0x40
+#define SD_DIFF3     0x80
+
+// diff3 flags
+#define SD_TAGLIST   0x01
+#define SD_BOTTOMMAP 0x02
+#define SD_MIDMAP    0x04
+#define SD_TOPMAP    0x08
 
 #define LD_FLAG     0x01
 #define LD_SPECIAL  0x02
@@ -523,7 +529,7 @@ static void P_NetArchiveWorld(void)
 	mapsidedef_t *msd;
 	maplinedef_t *mld;
 	const sector_t *ss = sectors;
-	UINT8 diff, diff2;
+	UINT8 diff, diff2, diff3;
 
 	WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD);
 	put = save_p;
@@ -550,7 +556,7 @@ static void P_NetArchiveWorld(void)
 
 	for (i = 0; i < numsectors; i++, ss++, ms++)
 	{
-		diff = diff2 = 0;
+		diff = diff2 = diff3 = 0;
 		if (ss->floorheight != SHORT(ms->floorheight)<<FRACBITS)
 			diff |= SD_FLOORHT;
 		if (ss->ceilingheight != SHORT(ms->ceilingheight)<<FRACBITS)
@@ -584,7 +590,13 @@ static void P_NetArchiveWorld(void)
 		if (ss->tag != SHORT(ms->tag))
 			diff2 |= SD_TAG;
 		if (ss->nexttag != ss->spawn_nexttag || ss->firsttag != ss->spawn_firsttag)
-			diff2 |= SD_TAGLIST;
+			diff3 |= SD_TAGLIST;
+		if (ss->bottommap != ss->spawn_bottommap)
+			diff3 |= SD_BOTTOMMAP;
+		if (ss->midmap != ss->spawn_midmap)
+			diff3 |= SD_MIDMAP;
+		if (ss->topmap != ss->spawn_topmap)
+			diff3 |= SD_TOPMAP;
 
 		// Check if any of the sector's FOFs differ from how they spawned
 		if (ss->ffloors)
@@ -601,6 +613,9 @@ static void P_NetArchiveWorld(void)
 			}
 		}
 
+		if (diff3)
+			diff2 |= SD_DIFF3;
+
 		if (diff2)
 			diff |= SD_DIFF2;
 
@@ -612,6 +627,8 @@ static void P_NetArchiveWorld(void)
 			WRITEUINT8(put, diff);
 			if (diff & SD_DIFF2)
 				WRITEUINT8(put, diff2);
+			if (diff2 & SD_DIFF3)
+				WRITEUINT8(put, diff3);
 			if (diff & SD_FLOORHT)
 				WRITEFIXED(put, ss->floorheight);
 			if (diff & SD_CEILHT)
@@ -632,17 +649,23 @@ static void P_NetArchiveWorld(void)
 				WRITEFIXED(put, ss->ceiling_xoffs);
 			if (diff2 & SD_CYOFFS)
 				WRITEFIXED(put, ss->ceiling_yoffs);
-			if (diff2 & SD_TAG) // save only the tag
-				WRITEINT16(put, ss->tag);
 			if (diff2 & SD_FLOORANG)
 				WRITEANGLE(put, ss->floorpic_angle);
 			if (diff2 & SD_CEILANG)
 				WRITEANGLE(put, ss->ceilingpic_angle);
-			if (diff2 & SD_TAGLIST) // save both firsttag and nexttag
+			if (diff2 & SD_TAG) // save only the tag
+				WRITEINT16(put, ss->tag);
+			if (diff3 & SD_TAGLIST) // save both firsttag and nexttag
 			{ // either of these could be changed even if tag isn't
 				WRITEINT32(put, ss->firsttag);
 				WRITEINT32(put, ss->nexttag);
 			}
+			if (diff3 & SD_BOTTOMMAP)
+				WRITEINT32(put, ss->bottommap);
+			if (diff3 & SD_MIDMAP)
+				WRITEINT32(put, ss->midmap);
+			if (diff3 & SD_TOPMAP)
+				WRITEINT32(put, ss->topmap);
 
 			// Special case: save the stats of all modified ffloors along with their ffloor "number"s
 			// we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed
@@ -680,7 +703,7 @@ static void P_NetArchiveWorld(void)
 	// do lines
 	for (i = 0; i < numlines; i++, mld++, li++)
 	{
-		diff = diff2 = 0;
+		diff = diff2 = diff3 = 0;
 
 		if (li->special != SHORT(mld->special))
 			diff |= LD_SPECIAL;
@@ -772,7 +795,7 @@ static void P_NetUnArchiveWorld(void)
 	line_t *li;
 	side_t *si;
 	UINT8 *get;
-	UINT8 diff, diff2;
+	UINT8 diff, diff2, diff3;
 
 	if (READUINT32(save_p) != ARCHIVEBLOCK_WORLD)
 		I_Error("Bad $$$.sav at archive block World");
@@ -794,6 +817,10 @@ static void P_NetUnArchiveWorld(void)
 			diff2 = READUINT8(get);
 		else
 			diff2 = 0;
+		if (diff2 & SD_DIFF3)
+			diff3 = READUINT8(get);
+		else
+			diff3 = 0;
 
 		if (diff & SD_FLOORHT)
 			sectors[i].floorheight = READFIXED(get);
@@ -822,17 +849,23 @@ static void P_NetUnArchiveWorld(void)
 			sectors[i].ceiling_xoffs = READFIXED(get);
 		if (diff2 & SD_CYOFFS)
 			sectors[i].ceiling_yoffs = READFIXED(get);
-		if (diff2 & SD_TAG)
-			sectors[i].tag = READINT16(get); // DON'T use P_ChangeSectorTag
-		if (diff2 & SD_TAGLIST)
-		{
-			sectors[i].firsttag = READINT32(get);
-			sectors[i].nexttag = READINT32(get);
-		}
 		if (diff2 & SD_FLOORANG)
 			sectors[i].floorpic_angle  = READANGLE(get);
 		if (diff2 & SD_CEILANG)
 			sectors[i].ceilingpic_angle = READANGLE(get);
+		if (diff2 & SD_TAG)
+			sectors[i].tag = READINT16(get); // DON'T use P_ChangeSectorTag
+		if (diff3 & SD_TAGLIST)
+		{
+			sectors[i].firsttag = READINT32(get);
+			sectors[i].nexttag = READINT32(get);
+		}
+		if (diff3 & SD_BOTTOMMAP)
+			sectors[i].bottommap = READINT32(get);
+		if (diff3 & SD_MIDMAP)
+			sectors[i].midmap = READINT32(get);
+		if (diff3 & SD_TOPMAP)
+			sectors[i].topmap = READINT32(get);
 
 		if (diff & SD_FFLOORS)
 		{
@@ -891,6 +924,9 @@ static void P_NetUnArchiveWorld(void)
 			diff2 = READUINT8(get);
 		else
 			diff2 = 0;
+
+		diff3 = 0;
+
 		if (diff & LD_FLAG)
 			li->flags = READINT16(get);
 		if (diff & LD_SPECIAL)
diff --git a/src/p_setup.c b/src/p_setup.c
index 92a618b98..50b2e8eda 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -719,6 +719,7 @@ static void P_LoadRawSectors(UINT8 *data, size_t i)
 		ss->floorpic_angle = ss->ceilingpic_angle = 0;
 		ss->spawn_flrpic_angle = ss->spawn_ceilpic_angle = 0;
 		ss->bottommap = ss->midmap = ss->topmap = -1;
+		ss->spawn_bottommap = ss->spawn_midmap = ss->spawn_topmap = -1;
 		ss->gravity = NULL;
 		ss->cullheight = NULL;
 		ss->verticalflip = false;
@@ -1477,7 +1478,7 @@ static void P_LoadRawSideDefs2(void *data)
 				{
 					if (msd->toptexture[0] == '#' || msd->bottomtexture[0] == '#')
 					{
-						sec->midmap = R_CreateColormap(msd->toptexture, msd->midtexture,
+						sec->midmap = sec->spawn_midmap = R_CreateColormap(msd->toptexture, msd->midtexture,
 							msd->bottomtexture);
 						sd->toptexture = sd->bottomtexture = 0;
 					}
@@ -1507,7 +1508,7 @@ static void P_LoadRawSideDefs2(void *data)
 					{
 						char *col;
 
-						sec->midmap = R_CreateColormap(msd->toptexture, msd->midtexture,
+						sec->midmap = sec->spawn_midmap = R_CreateColormap(msd->toptexture, msd->midtexture,
 							msd->bottomtexture);
 						sd->toptexture = sd->bottomtexture = 0;
 #define HEX2INT(x) (x >= '0' && x <= '9' ? x - '0' : x >= 'a' && x <= 'f' ? x - 'a' + 10 : x >= 'A' && x <= 'F' ? x - 'A' + 10 : 0)
diff --git a/src/p_spec.c b/src/p_spec.c
index 87a0bae9c..40be3c7fb 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -6769,7 +6769,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
 
 			case 606: // HACK! Copy colormaps. Just plain colormaps.
 				for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
-					sectors[s].midmap = lines[i].frontsector->midmap;
+					sectors[s].midmap = sectors[s].spawn_midmap = lines[i].frontsector->midmap;
 				break;
 
 #ifdef ESLOPE // Slope copy specials. Handled here for sanity.
diff --git a/src/r_defs.h b/src/r_defs.h
index 7c8f2a73f..f219f0f9e 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -385,6 +385,7 @@ typedef struct sector_s
 
 	// these are saved for netgames, so do not let Lua touch these!
 	INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed
+	INT32 spawn_bottommap, spawn_midmap, spawn_topmap;
 
 	// offsets sector spawned with (via linedef type 7)
 	fixed_t spawn_flr_xoffs, spawn_flr_yoffs;

From e171e565ceb794ac50109f8687b77a5609c1c5fb Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Mon, 10 Sep 2018 09:03:58 -0400
Subject: [PATCH 03/20] Remove bottommap and topmap from savegame because
 unused

---
 src/p_saveg.c | 16 +---------------
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/src/p_saveg.c b/src/p_saveg.c
index 1c9589e8f..42757faf2 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -494,9 +494,7 @@ static void P_NetUnArchivePlayers(void)
 
 // diff3 flags
 #define SD_TAGLIST   0x01
-#define SD_BOTTOMMAP 0x02
-#define SD_MIDMAP    0x04
-#define SD_TOPMAP    0x08
+#define SD_MIDMAP    0x02
 
 #define LD_FLAG     0x01
 #define LD_SPECIAL  0x02
@@ -591,12 +589,8 @@ static void P_NetArchiveWorld(void)
 			diff2 |= SD_TAG;
 		if (ss->nexttag != ss->spawn_nexttag || ss->firsttag != ss->spawn_firsttag)
 			diff3 |= SD_TAGLIST;
-		if (ss->bottommap != ss->spawn_bottommap)
-			diff3 |= SD_BOTTOMMAP;
 		if (ss->midmap != ss->spawn_midmap)
 			diff3 |= SD_MIDMAP;
-		if (ss->topmap != ss->spawn_topmap)
-			diff3 |= SD_TOPMAP;
 
 		// Check if any of the sector's FOFs differ from how they spawned
 		if (ss->ffloors)
@@ -660,12 +654,8 @@ static void P_NetArchiveWorld(void)
 				WRITEINT32(put, ss->firsttag);
 				WRITEINT32(put, ss->nexttag);
 			}
-			if (diff3 & SD_BOTTOMMAP)
-				WRITEINT32(put, ss->bottommap);
 			if (diff3 & SD_MIDMAP)
 				WRITEINT32(put, ss->midmap);
-			if (diff3 & SD_TOPMAP)
-				WRITEINT32(put, ss->topmap);
 
 			// Special case: save the stats of all modified ffloors along with their ffloor "number"s
 			// we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed
@@ -860,12 +850,8 @@ static void P_NetUnArchiveWorld(void)
 			sectors[i].firsttag = READINT32(get);
 			sectors[i].nexttag = READINT32(get);
 		}
-		if (diff3 & SD_BOTTOMMAP)
-			sectors[i].bottommap = READINT32(get);
 		if (diff3 & SD_MIDMAP)
 			sectors[i].midmap = READINT32(get);
-		if (diff3 & SD_TOPMAP)
-			sectors[i].topmap = READINT32(get);
 
 		if (diff & SD_FFLOORS)
 		{

From c007dfacecb8b392e2c063f1f73373d78a29322b Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Mon, 10 Sep 2018 21:12:56 -0400
Subject: [PATCH 04/20] Savegame fixes

---
 src/p_saveg.c | 18 +++++++++---------
 src/r_defs.h  |  1 -
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/src/p_saveg.c b/src/p_saveg.c
index eb49e9730..33923551d 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -655,8 +655,6 @@ static void P_NetArchiveWorld(void)
 				WRITEINT32(put, ss->firsttag);
 				WRITEINT32(put, ss->nexttag);
 			}
-			if (diff3 & SD_MIDMAP)
-				WRITEINT32(put, ss->midmap);
 
 			if (diff3 & SD_COLORMAP)
 			{
@@ -938,8 +936,8 @@ static void P_NetUnArchiveWorld(void)
 					&& fadeend == exc->fadeend
 					&& fog == exc->fog)
 				{
-					CONS_Debug(DBG_RENDER, "P_NetUnArchiveWorld: Found map %d: rgba(%d,%d,%d,%d) fadergba(%d,%d,%d,%d)\n",
-						dbg_i, cr, cg, cb, ca, cfr, cfg, cfb, cfa);
+					// CONS_Debug(DBG_RENDER, "P_NetUnArchiveWorld: Found map %d: rgba(%d,%d,%d,%d) fadergba(%d,%d,%d,%d)\n",
+					// 	dbg_i, cr, cg, cb, ca, cfr, cfg, cfb, cfa);
 					break;
 				}
 				dbg_i++;
@@ -947,8 +945,8 @@ static void P_NetUnArchiveWorld(void)
 
 			if (!exc)
 			{
-				CONS_Debug(DBG_RENDER, "P_NetUnArchiveWorld: Creating map %d: rgba(%d,%d,%d,%d) fadergba(%d,%d,%d,%d)\n",
-					dbg_i, cr, cg, cb, ca, cfr, cfg, cfb, cfa);
+				// CONS_Debug(DBG_RENDER, "P_NetUnArchiveWorld: Creating map %d: rgba(%d,%d,%d,%d) fadergba(%d,%d,%d,%d)\n",
+				// 	dbg_i, cr, cg, cb, ca, cfr, cfg, cfb, cfa);
 
 				exc = Z_Calloc(sizeof (*exc), PU_LEVEL, NULL);
 
@@ -973,14 +971,16 @@ static void P_NetUnArchiveWorld(void)
 
 				R_AddColormapToList(exc);
 
-				sectors[i].extra_colormap = exc;
-
 #ifdef EXTRACOLORMAPLUMPS
 				exc->lump = LUMPERROR;
 				exc->lumpname[0] = 0;
-			} // if (!exc) // if (!lumpname[0] || !R_ColormapForName(lumpname))
 #endif
 			}
+
+			sectors[i].extra_colormap = exc;
+#ifdef EXTRACOLORMAPLUMPS
+			}
+#endif
 		}
 
 		if (diff & SD_FFLOORS)
diff --git a/src/r_defs.h b/src/r_defs.h
index 77b56bd30..8dd34cd15 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -393,7 +393,6 @@ typedef struct sector_s
 
 	// these are saved for netgames, so do not let Lua touch these!
 	INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed
-	INT32 spawn_bottommap, spawn_midmap, spawn_topmap;
 
 	// offsets sector spawned with (via linedef type 7)
 	fixed_t spawn_flr_xoffs, spawn_flr_yoffs;

From 17e101a24b81f8baaa8382b4ae26f28842330d2f Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Mon, 10 Sep 2018 22:35:03 -0400
Subject: [PATCH 05/20] Add COLORMAPREVERSELIST ifdef to toggle Newest ->
 Oldest extra_colormaps order

---
 src/r_data.c | 7 +++++++
 src/r_data.h | 3 +++
 2 files changed, 10 insertions(+)

diff --git a/src/r_data.c b/src/r_data.c
index f1f04b2d2..160539437 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -1369,11 +1369,18 @@ void R_AddColormapToList(extracolormap_t *extra_colormap)
 		return;
 	}
 
+#ifdef COLORMAPREVERSELIST
+	extra_colormaps->prev = extra_colormap;
+	extra_colormap->next = extra_colormaps;
+	extra_colormaps = extra_colormap;
+	extra_colormap->prev = 0;
+#else
 	for (exc = extra_colormaps; exc->next; exc = exc->next);
 
 	exc->next = extra_colormap;
 	extra_colormap->prev = exc;
 	extra_colormap->next = 0;
+#endif
 }
 
 #ifdef EXTRACOLORMAPLUMPS
diff --git a/src/r_data.h b/src/r_data.h
index 5600d36dc..e6eec41b4 100644
--- a/src/r_data.h
+++ b/src/r_data.h
@@ -100,6 +100,9 @@ INT32 R_CheckTextureNumForName(const char *name);
 // Uncomment to enable
 //#define EXTRACOLORMAPLUMPS
 
+// Uncomment to make extra_colormaps order Newest -> Oldest
+//#define COLORMAPREVERSELIST
+
 void R_ReInitColormaps(UINT16 num);
 void R_ClearColormaps(void);
 void R_AddColormapToList(extracolormap_t *extra_colormap);

From fb7ac4ccae6a345da7f716cbddde1eea737b06d1 Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Tue, 11 Sep 2018 15:59:13 -0400
Subject: [PATCH 06/20] Ifdef typo

---
 src/r_data.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/r_data.c b/src/r_data.c
index e679f27ba..e08600cae 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -1496,7 +1496,7 @@ extracolormap_t *R_GetColormapFromList(extracolormap_t *extra_colormap)
 {
 #ifdef EXTRACOLORMAPLUMPS
 	return R_GetColormapFromListByValues(extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->fog, extra_colormap->lump);
-else
+#else
 	return R_GetColormapFromListByValues(extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->fog);
 #endif
 }

From bb6cf6a807f6946de1a8cfcc6b848fcec2daf351 Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Tue, 11 Sep 2018 16:50:35 -0400
Subject: [PATCH 07/20] Added alpha-only, relative calc, and offset params to
 447 Change Colormap

---
 src/p_spec.c | 38 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/src/p_spec.c b/src/p_spec.c
index 21380584b..8d17c6de3 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3256,7 +3256,43 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 			// This could even override existing colormaps I believe
 			// -- Monster Iestyn 14/06/18
 			for (secnum = -1; (secnum = P_FindSectorFromLineTag(line, secnum)) >= 0 ;)
-				sectors[secnum].extra_colormap = line->frontsector->extra_colormap;
+			{
+				if (line->flags & ML_NOCLIMB) // set alpha only
+				{
+					if (sectors[secnum].extra_colormap) // does nothing without an existing colormap
+					{
+						extracolormap_t *dest_colormap = R_CopyColormap(sectors[secnum].extra_colormap, false);
+						INT16 alpha;
+
+						// base rgba
+						alpha = (line->flags & ML_DONTPEGBOTTOM && line->sidenum[1] != 0xFFFF) ?
+							(sides[line->sidenum[1]].textureoffset >> FRACBITS)
+							: R_GetRgbaA(line->frontsector->extra_colormap->rgba);
+						if (line->flags & ML_EFFECT3) // relative calc
+							alpha = max(min(R_GetRgbaA(sectors[secnum].extra_colormap->rgba) + alpha, 25), 0);
+						dest_colormap->rgba = (dest_colormap->rgba & 0xFFFFFF) + (alpha << 24);
+
+						// fade rgba
+						alpha = (line->flags & ML_DONTPEGBOTTOM && line->sidenum[1] != 0xFFFF) ?
+							(sides[line->sidenum[1]].rowoffset >> FRACBITS)
+							: R_GetRgbaA(line->frontsector->extra_colormap->fadergba);
+						if (line->flags & ML_EFFECT3) // relative calc
+							alpha = max(min(R_GetRgbaA(sectors[secnum].extra_colormap->fadergba) + alpha, 25), 0);
+						dest_colormap->fadergba = (dest_colormap->fadergba & 0xFFFFFF) + (alpha << 24);
+
+						if (!(sectors[secnum].extra_colormap = R_GetColormapFromList(dest_colormap)))
+						{
+							dest_colormap->colormap = R_CreateLightTable(dest_colormap);
+							R_AddColormapToList(dest_colormap);
+							sectors[secnum].extra_colormap = dest_colormap;
+						}
+						else
+							memset(dest_colormap, 0, sizeof(*dest_colormap));
+					}
+				}
+				else
+					sectors[secnum].extra_colormap = line->frontsector->extra_colormap;
+			}
 			break;
 
 		case 448: // Change skybox viewpoint/centerpoint

From f703c195027c4c5c6b798ffb043ba5a50c591998 Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Tue, 11 Sep 2018 17:06:44 -0400
Subject: [PATCH 08/20] Don't set sector's extra_colormap if we just made a
 default clone

* Allow colormap parsing to proceed in p_setup always
* Add R_CheckDefaultColormap
* Add R_GetRgbaR/G/B/A macros
---
 src/p_setup.c | 30 +++--------------------
 src/r_data.c  | 68 ++++++++++++++++++++++++++++++++++-----------------
 src/r_data.h  | 13 +++++++++-
 3 files changed, 61 insertions(+), 50 deletions(-)

diff --git a/src/p_setup.c b/src/p_setup.c
index 0f4a267ad..498b9cb61 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -1438,7 +1438,6 @@ static inline void P_LoadSideDefs(lumpnum_t lumpnum)
 static void P_LoadRawSideDefs2(void *data)
 {
 	UINT16 i;
-	INT32 num;
 
 	for (i = 0; i < numsides; i++)
 	{
@@ -1473,32 +1472,9 @@ static void P_LoadRawSideDefs2(void *data)
 			case 447: // Change colormap of tagged sectors! -- Monster Iestyn 14/06/18
 				// SoM: R_CreateColormap will only create a colormap in software mode...
 				// Perhaps we should just call it instead of doing the calculations here.
-				if (msd->toptexture[0] == '#' || msd->bottomtexture[0] == '#'
-					|| (msd->toptexture[0] >= 'a' && msd->toptexture[0] <= 'z' && !msd->toptexture[1])
-					|| (msd->toptexture[0] >= 'A' && msd->toptexture[0] <= 'Z' && !msd->toptexture[1])
-					|| (msd->bottomtexture[0] >= 'a' && msd->bottomtexture[0] <= 'z' && !msd->bottomtexture[1])
-					|| (msd->bottomtexture[0] >= 'A' && msd->bottomtexture[0] <= 'Z' && !msd->bottomtexture[1])
-				)
-				{
-					sec->extra_colormap = sec->spawn_extra_colormap = R_CreateColormap(msd->toptexture, msd->midtexture,
-						msd->bottomtexture);
-					sd->toptexture = sd->bottomtexture = 0;
-				}
-				else
-				{
-					if ((num = R_CheckTextureNumForName(msd->toptexture)) == -1)
-						sd->toptexture = 0;
-					else
-						sd->toptexture = num;
-					if ((num = R_CheckTextureNumForName(msd->midtexture)) == -1)
-						sd->midtexture = 0;
-					else
-						sd->midtexture = num;
-					if ((num = R_CheckTextureNumForName(msd->bottomtexture)) == -1)
-						sd->bottomtexture = 0;
-					else
-						sd->bottomtexture = num;
-				}
+				sec->extra_colormap = sec->spawn_extra_colormap = R_CreateColormap(msd->toptexture, msd->midtexture,
+					msd->bottomtexture);
+				sd->toptexture = sd->midtexture = sd->bottomtexture = 0;
 				break;
 
 			case 413: // Change music
diff --git a/src/r_data.c b/src/r_data.c
index e08600cae..529507e9a 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -1435,26 +1435,41 @@ void R_AddColormapToList(extracolormap_t *extra_colormap)
 }
 
 //
-// R_CheckDefaultColormap()
+// R_CheckDefaultColormapByValues()
 //
-boolean R_CheckDefaultColormapValues(extracolormap_t *extra_colormap, boolean checkrgba, boolean checkfadergba, boolean checkparams)
+#ifdef EXTRACOLORMAPLUMPS
+boolean R_CheckDefaultColormapByValues(boolean checkrgba, boolean checkfadergba, boolean checkparams,
+	INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, boolean fog, lumpnum_t lump)
+#else
+boolean R_CheckDefaultColormapByValues(boolean checkrgba, boolean checkfadergba, boolean checkparams,
+	INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, boolean fog)
+#endif
+{
+	return (
+		(!checkparams ? true :
+			(fadestart == 0
+				&& fadeend == 31
+				&& !fog)
+			)
+		&& (!checkrgba ? true : rgba == 0)
+		&& (!checkfadergba ? true : fadergba == 0x19000000)
+#ifdef EXTRACOLORMAPLUMPS
+		&& lump == LUMPERROR
+		&& extra_colormap->lumpname[0] == 0
+#endif
+		);
+}
+
+boolean R_CheckDefaultColormap(extracolormap_t *extra_colormap, boolean checkrgba, boolean checkfadergba, boolean checkparams)
 {
 	if (!extra_colormap)
 		return true;
-	else
-		return (
-			(!checkparams ? true :
-				(extra_colormap->fadestart == 0
-					&& extra_colormap->fadeend == 31
-					&& !extra_colormap->fog)
-				)
-			&& (!checkrgba ? true : extra_colormap->rgba == 0)
-			&& (!checkfadergba ? true : extra_colormap->fadergba == 0x19000000)
+
 #ifdef EXTRACOLORMAPLUMPS
-			&& extra_colormap->lump == LUMPERROR
-			&& extra_colormap->lumpname[0] == 0
+	return R_CheckDefaultColormapByValues(checkrgba, checkfadergba, checkparams, extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->fog, extra_colormap->lump);
+#else
+	return R_CheckDefaultColormapByValues(checkrgba, checkfadergba, checkparams, extra_colormap->rgba, extra_colormap->fadergba, extra_colormap->fadestart, extra_colormap->fadeend, extra_colormap->fog);
 #endif
-			);
 }
 
 //
@@ -1557,14 +1572,14 @@ lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap)
 	double cmaskr, cmaskg, cmaskb, cdestr, cdestg, cdestb;
 	double maskamt = 0, othermask = 0;
 
-	UINT8 cr = (extra_colormap->rgba) & 0xFF,
-		cg = (extra_colormap->rgba >> 8) & 0xFF,
-		cb = (extra_colormap->rgba >> 16) & 0xFF,
-		ca = (extra_colormap->rgba >> 24) & 0xFF,
-		cfr = (extra_colormap->fadergba) & 0xFF,
-		cfg = (extra_colormap->fadergba >> 8) & 0xFF,
-		cfb = (extra_colormap->fadergba >> 16) & 0xFF;
-//		cfa = (extra_colormap->fadergba >> 24) & 0xFF; // unused in software
+	UINT8 cr = R_GetRgbaR(extra_colormap->rgba),
+		cg = R_GetRgbaG(extra_colormap->rgba),
+		cb = R_GetRgbaB(extra_colormap->rgba),
+		ca = R_GetRgbaA(extra_colormap->rgba),
+		cfr = R_GetRgbaR(extra_colormap->fadergba),
+		cfg = R_GetRgbaG(extra_colormap->fadergba),
+		cfb = R_GetRgbaB(extra_colormap->fadergba);
+//		cfa = R_GetRgbaA(extra_colormap->fadergba); // unused in software
 
 	UINT8 fadestart = extra_colormap->fadestart,
 		fadedist = extra_colormap->fadeend - extra_colormap->fadestart;
@@ -1807,6 +1822,15 @@ extracolormap_t *R_CreateColormap(char *p1, char *p2, char *p3)
 	rgba = cr + (cg << 8) + (cb << 16) + (ca << 24);
 	fadergba = cfr + (cfg << 8) + (cfb << 16) + (cfa << 24);
 
+	// Did we just make a default colormap?
+#ifdef EXTRACOLORMAPLUMPS
+	if (R_CheckDefaultColormapByValues(true, true, true, rgba, fadergba, fadestart, fadeend, fog, LUMPERROR))
+		return NULL;
+#else
+	if (R_CheckDefaultColormapByValues(true, true, true, rgba, fadergba, fadestart, fadeend, fog))
+		return NULL;
+#endif
+
 	// Look for existing colormaps
 #ifdef EXTRACOLORMAPLUMPS
 	exc = R_GetColormapFromListByValues(rgba, fadergba, fadestart, fadeend, fog, LUMPERROR);
diff --git a/src/r_data.h b/src/r_data.h
index 17d85fd8b..ee497d155 100644
--- a/src/r_data.h
+++ b/src/r_data.h
@@ -109,13 +109,19 @@ extracolormap_t *R_CreateDefaultColormap(boolean lighttable);
 extracolormap_t *R_GetDefaultColormap(void);
 extracolormap_t *R_CopyColormap(extracolormap_t *extra_colormap, boolean lighttable);
 void R_AddColormapToList(extracolormap_t *extra_colormap);
-boolean R_CheckDefaultColormapValues(extracolormap_t *extra_colormap, boolean checkrgba, boolean checkfadergba, boolean checkparams);
+
 #ifdef EXTRACOLORMAPLUMPS
+boolean R_CheckDefaultColormapByValues(boolean checkrgba, boolean checkfadergba, boolean checkparams,
+	INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, boolean fog, lumpnum_t lump);
 extracolormap_t *R_GetColormapFromListByValues(INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, boolean fog, lumpnum_t lump);
 #else
+boolean R_CheckDefaultColormapByValues(boolean checkrgba, boolean checkfadergba, boolean checkparams,
+	INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, boolean fog);
 extracolormap_t *R_GetColormapFromListByValues(INT32 rgba, INT32 fadergba, UINT8 fadestart, UINT8 fadeend, boolean fog);
 #endif
+boolean R_CheckDefaultColormap(extracolormap_t *extra_colormap, boolean checkrgba, boolean checkfadergba, boolean checkparams);
 extracolormap_t *R_GetColormapFromList(extracolormap_t *extra_colormap);
+
 lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap);
 extracolormap_t *R_CreateColormap(char *p1, char *p2, char *p3);
 #ifdef EXTRACOLORMAPLUMPS
@@ -123,6 +129,11 @@ extracolormap_t *R_ColormapForName(char *name);
 const char *R_NameForColormap(extracolormap_t *extra_colormap);
 #endif
 
+#define R_GetRgbaR(rgba) (rgba & 0xFF)
+#define R_GetRgbaG(rgba) ((rgba >> 8) & 0xFF)
+#define R_GetRgbaB(rgba) ((rgba >> 16) & 0xFF)
+#define R_GetRgbaA(rgba) ((rgba >> 24) & 0xFF)
+
 extern INT32 numtextures;
 
 #endif

From 5523fc3a8d43e69dcc77f55b4d762c3c738c6931 Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Tue, 11 Sep 2018 17:07:50 -0400
Subject: [PATCH 09/20] Account for NULL colormaps in alpha-only code 447

---
 src/p_spec.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/p_spec.c b/src/p_spec.c
index 8d17c6de3..adcd46462 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3267,7 +3267,9 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 						// base rgba
 						alpha = (line->flags & ML_DONTPEGBOTTOM && line->sidenum[1] != 0xFFFF) ?
 							(sides[line->sidenum[1]].textureoffset >> FRACBITS)
-							: R_GetRgbaA(line->frontsector->extra_colormap->rgba);
+							: line->frontsector->extra_colormap ?
+								R_GetRgbaA(line->frontsector->extra_colormap->rgba)
+								: 0;
 						if (line->flags & ML_EFFECT3) // relative calc
 							alpha = max(min(R_GetRgbaA(sectors[secnum].extra_colormap->rgba) + alpha, 25), 0);
 						dest_colormap->rgba = (dest_colormap->rgba & 0xFFFFFF) + (alpha << 24);
@@ -3275,7 +3277,9 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 						// fade rgba
 						alpha = (line->flags & ML_DONTPEGBOTTOM && line->sidenum[1] != 0xFFFF) ?
 							(sides[line->sidenum[1]].rowoffset >> FRACBITS)
-							: R_GetRgbaA(line->frontsector->extra_colormap->fadergba);
+							: line->frontsector->extra_colormap ?
+								R_GetRgbaA(line->frontsector->extra_colormap->fadergba)
+								: 0;
 						if (line->flags & ML_EFFECT3) // relative calc
 							alpha = max(min(R_GetRgbaA(sectors[secnum].extra_colormap->fadergba) + alpha, 25), 0);
 						dest_colormap->fadergba = (dest_colormap->fadergba & 0xFFFFFF) + (alpha << 24);

From b9e4cd40ca45936428467dcf7eaa7eb31679d946 Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Tue, 11 Sep 2018 17:32:43 -0400
Subject: [PATCH 10/20] Use RGB/RGBA macros in 447 code

---
 src/p_spec.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/p_spec.c b/src/p_spec.c
index adcd46462..f119c3e2f 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3272,7 +3272,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 								: 0;
 						if (line->flags & ML_EFFECT3) // relative calc
 							alpha = max(min(R_GetRgbaA(sectors[secnum].extra_colormap->rgba) + alpha, 25), 0);
-						dest_colormap->rgba = (dest_colormap->rgba & 0xFFFFFF) + (alpha << 24);
+						dest_colormap->rgba = R_GetRgbaRGB(dest_colormap->rgba) + R_PutRgbaA(alpha);
 
 						// fade rgba
 						alpha = (line->flags & ML_DONTPEGBOTTOM && line->sidenum[1] != 0xFFFF) ?
@@ -3282,7 +3282,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 								: 0;
 						if (line->flags & ML_EFFECT3) // relative calc
 							alpha = max(min(R_GetRgbaA(sectors[secnum].extra_colormap->fadergba) + alpha, 25), 0);
-						dest_colormap->fadergba = (dest_colormap->fadergba & 0xFFFFFF) + (alpha << 24);
+						dest_colormap->fadergba = R_GetRgbaRGB(dest_colormap->fadergba) + R_PutRgbaA(alpha);
 
 						if (!(sectors[secnum].extra_colormap = R_GetColormapFromList(dest_colormap)))
 						{

From a1a05c99721eb65da73ec822f3e32de97dd23112 Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Tue, 11 Sep 2018 19:11:50 -0400
Subject: [PATCH 11/20] Add relative color change to 447

---
 src/p_spec.c | 85 +++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 61 insertions(+), 24 deletions(-)

diff --git a/src/p_spec.c b/src/p_spec.c
index f119c3e2f..4a23902c7 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3257,41 +3257,78 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 			// -- Monster Iestyn 14/06/18
 			for (secnum = -1; (secnum = P_FindSectorFromLineTag(line, secnum)) >= 0 ;)
 			{
-				if (line->flags & ML_NOCLIMB) // set alpha only
+				if (line->flags & ML_EFFECT3) // relative calc
 				{
 					if (sectors[secnum].extra_colormap) // does nothing without an existing colormap
 					{
-						extracolormap_t *dest_colormap = R_CopyColormap(sectors[secnum].extra_colormap, false);
-						INT16 alpha;
+						extracolormap_t *target_colormap = R_CopyColormap(sectors[secnum].extra_colormap, false);
+						extracolormap_t *source_colormap = line->frontsector->extra_colormap ? line->frontsector->extra_colormap
+							: R_GetDefaultColormap();
+
+						INT16 red, green, blue, alpha;
 
 						// base rgba
-						alpha = (line->flags & ML_DONTPEGBOTTOM && line->sidenum[1] != 0xFFFF) ?
-							(sides[line->sidenum[1]].textureoffset >> FRACBITS)
-							: line->frontsector->extra_colormap ?
-								R_GetRgbaA(line->frontsector->extra_colormap->rgba)
-								: 0;
-						if (line->flags & ML_EFFECT3) // relative calc
-							alpha = max(min(R_GetRgbaA(sectors[secnum].extra_colormap->rgba) + alpha, 25), 0);
-						dest_colormap->rgba = R_GetRgbaRGB(dest_colormap->rgba) + R_PutRgbaA(alpha);
+						red = max(min(
+							R_GetRgbaR(target_colormap->rgba)
+								+ ((line->flags & ML_EFFECT1) ? -1 : 1) // subtract R
+								* R_GetRgbaR(source_colormap->rgba)
+							, 255), 0);
+
+						green = max(min(
+							R_GetRgbaG(target_colormap->rgba)
+								+ ((line->flags & ML_NOCLIMB) ? -1 : 1) // subtract G
+								* R_GetRgbaG(source_colormap->rgba)
+							, 255), 0);
+
+						blue = max(min(
+							R_GetRgbaB(target_colormap->rgba)
+								+ ((line->flags & ML_EFFECT2) ? -1 : 1) // subtract B
+								* R_GetRgbaB(source_colormap->rgba)
+							, 255), 0);
+
+						alpha = (line->flags & ML_DONTPEGBOTTOM) ? // front (or back!) X offset; needed to subtract A
+							(sides[line->sidenum[line->sidenum[1] != 0xFFFF ? 1 : 0]].textureoffset >> FRACBITS)
+							: R_GetRgbaA(source_colormap->rgba);
+						alpha = max(min(R_GetRgbaA(target_colormap->rgba) + alpha, 25), 0);
+
+						target_colormap->rgba = R_PutRgbaRGBA(red, green, blue, alpha);
 
 						// fade rgba
-						alpha = (line->flags & ML_DONTPEGBOTTOM && line->sidenum[1] != 0xFFFF) ?
-							(sides[line->sidenum[1]].rowoffset >> FRACBITS)
-							: line->frontsector->extra_colormap ?
-								R_GetRgbaA(line->frontsector->extra_colormap->fadergba)
-								: 0;
-						if (line->flags & ML_EFFECT3) // relative calc
-							alpha = max(min(R_GetRgbaA(sectors[secnum].extra_colormap->fadergba) + alpha, 25), 0);
-						dest_colormap->fadergba = R_GetRgbaRGB(dest_colormap->fadergba) + R_PutRgbaA(alpha);
+						red = max(min(
+							R_GetRgbaR(target_colormap->fadergba)
+								+ ((line->flags & ML_EFFECT1) ? -1 : 1) // subtract R
+								* R_GetRgbaR(source_colormap->fadergba)
+							, 255), 0);
 
-						if (!(sectors[secnum].extra_colormap = R_GetColormapFromList(dest_colormap)))
+						green = max(min(
+							R_GetRgbaG(target_colormap->fadergba)
+								+ ((line->flags & ML_NOCLIMB) ? -1 : 1) // subtract G
+								* R_GetRgbaG(source_colormap->fadergba)
+							, 255), 0);
+
+						blue = max(min(
+							R_GetRgbaB(target_colormap->fadergba)
+								+ ((line->flags & ML_EFFECT2) ? -1 : 1) // subtract B
+								* R_GetRgbaB(source_colormap->fadergba)
+							, 255), 0);
+
+						alpha = (line->flags & ML_DONTPEGBOTTOM) ? // front (or back!) Y offset; needed to subtract A
+							(sides[line->sidenum[line->sidenum[1] != 0xFFFF ? 1 : 0]].rowoffset >> FRACBITS)
+							: R_GetRgbaA(source_colormap->fadergba);
+						if (alpha == 25)
+							alpha = 0; // HACK: fadergba A defaults at 25, so don't add anything in this case
+						alpha = max(min(R_GetRgbaA(target_colormap->fadergba) + alpha, 25), 0);
+
+						target_colormap->fadergba = R_PutRgbaRGBA(red, green, blue, alpha);
+
+						if (!(sectors[secnum].extra_colormap = R_GetColormapFromList(target_colormap)))
 						{
-							dest_colormap->colormap = R_CreateLightTable(dest_colormap);
-							R_AddColormapToList(dest_colormap);
-							sectors[secnum].extra_colormap = dest_colormap;
+							target_colormap->colormap = R_CreateLightTable(target_colormap);
+							R_AddColormapToList(target_colormap);
+							sectors[secnum].extra_colormap = target_colormap;
 						}
 						else
-							memset(dest_colormap, 0, sizeof(*dest_colormap));
+							memset(target_colormap, 0, sizeof(*target_colormap));
 					}
 				}
 				else

From 0fb594ad5829274ddff998cb393d2c1af07bd403 Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Tue, 11 Sep 2018 21:02:58 -0400
Subject: [PATCH 12/20] R_AddColormaps method

---
 src/r_data.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/r_data.h |  5 +++
 2 files changed, 91 insertions(+)

diff --git a/src/r_data.c b/src/r_data.c
index 949a842cc..03de15d85 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -1876,6 +1876,92 @@ extracolormap_t *R_CreateColormap(char *p1, char *p2, char *p3)
 	return extra_colormap;
 }
 
+//
+// R_AddColormaps()
+// NOTE: The result colormap DOES get added to the extra_colormaps chain!
+//
+extracolormap_t *R_AddColormaps(extracolormap_t *exc_augend, extracolormap_t *exc_addend,
+	boolean subR, boolean subG, boolean subB, boolean subA,
+	boolean subFadeR, boolean subFadeG, boolean subFadeB, boolean subFadeA,
+	boolean useAltAlpha, INT16 altAlpha, INT16 altFadeAlpha,
+	boolean lighttable)
+{
+	extracolormap_t *exc;
+
+	// exc_augend is added (or subtracted) onto by exc_addend
+	// In Rennaisance times, the first number was considered the augend, the second number the addend
+	// But since the commutative property was discovered, today they're both called addends!
+	// So let's be Olde English for a hot second.
+
+	exc_augend = R_CopyColormap(exc_augend, false);
+	if(!exc_addend)
+		exc_addend = R_GetDefaultColormap();
+
+	INT16 red, green, blue, alpha;
+
+	// base rgba
+	red = max(min(
+		R_GetRgbaR(exc_augend->rgba)
+			+ (subR ? -1 : 1) // subtract R
+			* R_GetRgbaR(exc_addend->rgba)
+		, 255), 0);
+
+	green = max(min(
+		R_GetRgbaG(exc_augend->rgba)
+			+ (subG ? -1 : 1) // subtract G
+			* R_GetRgbaG(exc_addend->rgba)
+		, 255), 0);
+
+	blue = max(min(
+		R_GetRgbaB(exc_augend->rgba)
+			+ (subB ? -1 : 1) // subtract B
+			* R_GetRgbaB(exc_addend->rgba)
+		, 255), 0);
+
+	alpha = useAltAlpha ? altAlpha : R_GetRgbaA(exc_addend->rgba);
+	alpha = max(min(R_GetRgbaA(exc_augend->rgba) + (subA ? -1 : 1) * alpha, 25), 0);
+
+	exc_augend->rgba = R_PutRgbaRGBA(red, green, blue, alpha);
+
+	// fade rgba
+	red = max(min(
+		R_GetRgbaR(exc_augend->fadergba)
+			+ (subFadeR ? -1 : 1) // subtract R
+			* R_GetRgbaR(exc_addend->fadergba)
+		, 255), 0);
+
+	green = max(min(
+		R_GetRgbaG(exc_augend->fadergba)
+			+ (subFadeG ? -1 : 1) // subtract G
+			* R_GetRgbaG(exc_addend->fadergba)
+		, 255), 0);
+
+	blue = max(min(
+		R_GetRgbaB(exc_augend->fadergba)
+			+ (subFadeB ? -1 : 1) // subtract B
+			* R_GetRgbaB(exc_addend->fadergba)
+		, 255), 0);
+
+	alpha = useAltAlpha ? altFadeAlpha : R_GetRgbaA(exc_addend->fadergba);
+	if (alpha == 25)
+		alpha = 0; // HACK: fadergba A defaults at 25, so don't add anything in this case
+	alpha = max(min(R_GetRgbaA(exc_augend->fadergba) + (subFadeA ? -1 : 1) * alpha, 25), 0);
+
+	exc_augend->fadergba = R_PutRgbaRGBA(red, green, blue, alpha);
+
+	if (!(exc = R_GetColormapFromList(exc_augend)))
+	{
+		exc_augend->colormap = lighttable ? R_CreateLightTable(exc_augend) : NULL;
+		R_AddColormapToList(exc_augend);
+		return exc_augend;
+	}
+	else
+	{
+		Z_Free(exc_augend);
+		return exc;
+	}
+}
+
 // Thanks to quake2 source!
 // utils3/qdata/images.c
 static UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b)
diff --git a/src/r_data.h b/src/r_data.h
index d980e9c56..6f8d08120 100644
--- a/src/r_data.h
+++ b/src/r_data.h
@@ -124,6 +124,11 @@ extracolormap_t *R_GetColormapFromList(extracolormap_t *extra_colormap);
 
 lighttable_t *R_CreateLightTable(extracolormap_t *extra_colormap);
 extracolormap_t *R_CreateColormap(char *p1, char *p2, char *p3);
+extracolormap_t *R_AddColormaps(extracolormap_t *exc_augend, extracolormap_t *exc_addend,
+	boolean subR, boolean subG, boolean subB, boolean subA,
+	boolean subFadeR, boolean subFadeG, boolean subFadeB, boolean subFadeA,
+	boolean useAltAlpha, INT16 altAlpha, INT16 altFadeAlpha,
+	boolean lighttable);
 #ifdef EXTRACOLORMAPLUMPS
 extracolormap_t *R_ColormapForName(char *name);
 const char *R_NameForColormap(extracolormap_t *extra_colormap);

From 54669a6cc83fca0b8793e867113cc16e3bb8ee40 Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Tue, 11 Sep 2018 21:03:13 -0400
Subject: [PATCH 13/20] Use R_AddColormaps method in 447 relative calc

---
 src/p_spec.c | 87 +++++++++-------------------------------------------
 1 file changed, 14 insertions(+), 73 deletions(-)

diff --git a/src/p_spec.c b/src/p_spec.c
index 4a23902c7..2c607f74e 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3258,79 +3258,20 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 			for (secnum = -1; (secnum = P_FindSectorFromLineTag(line, secnum)) >= 0 ;)
 			{
 				if (line->flags & ML_EFFECT3) // relative calc
-				{
-					if (sectors[secnum].extra_colormap) // does nothing without an existing colormap
-					{
-						extracolormap_t *target_colormap = R_CopyColormap(sectors[secnum].extra_colormap, false);
-						extracolormap_t *source_colormap = line->frontsector->extra_colormap ? line->frontsector->extra_colormap
-							: R_GetDefaultColormap();
-
-						INT16 red, green, blue, alpha;
-
-						// base rgba
-						red = max(min(
-							R_GetRgbaR(target_colormap->rgba)
-								+ ((line->flags & ML_EFFECT1) ? -1 : 1) // subtract R
-								* R_GetRgbaR(source_colormap->rgba)
-							, 255), 0);
-
-						green = max(min(
-							R_GetRgbaG(target_colormap->rgba)
-								+ ((line->flags & ML_NOCLIMB) ? -1 : 1) // subtract G
-								* R_GetRgbaG(source_colormap->rgba)
-							, 255), 0);
-
-						blue = max(min(
-							R_GetRgbaB(target_colormap->rgba)
-								+ ((line->flags & ML_EFFECT2) ? -1 : 1) // subtract B
-								* R_GetRgbaB(source_colormap->rgba)
-							, 255), 0);
-
-						alpha = (line->flags & ML_DONTPEGBOTTOM) ? // front (or back!) X offset; needed to subtract A
-							(sides[line->sidenum[line->sidenum[1] != 0xFFFF ? 1 : 0]].textureoffset >> FRACBITS)
-							: R_GetRgbaA(source_colormap->rgba);
-						alpha = max(min(R_GetRgbaA(target_colormap->rgba) + alpha, 25), 0);
-
-						target_colormap->rgba = R_PutRgbaRGBA(red, green, blue, alpha);
-
-						// fade rgba
-						red = max(min(
-							R_GetRgbaR(target_colormap->fadergba)
-								+ ((line->flags & ML_EFFECT1) ? -1 : 1) // subtract R
-								* R_GetRgbaR(source_colormap->fadergba)
-							, 255), 0);
-
-						green = max(min(
-							R_GetRgbaG(target_colormap->fadergba)
-								+ ((line->flags & ML_NOCLIMB) ? -1 : 1) // subtract G
-								* R_GetRgbaG(source_colormap->fadergba)
-							, 255), 0);
-
-						blue = max(min(
-							R_GetRgbaB(target_colormap->fadergba)
-								+ ((line->flags & ML_EFFECT2) ? -1 : 1) // subtract B
-								* R_GetRgbaB(source_colormap->fadergba)
-							, 255), 0);
-
-						alpha = (line->flags & ML_DONTPEGBOTTOM) ? // front (or back!) Y offset; needed to subtract A
-							(sides[line->sidenum[line->sidenum[1] != 0xFFFF ? 1 : 0]].rowoffset >> FRACBITS)
-							: R_GetRgbaA(source_colormap->fadergba);
-						if (alpha == 25)
-							alpha = 0; // HACK: fadergba A defaults at 25, so don't add anything in this case
-						alpha = max(min(R_GetRgbaA(target_colormap->fadergba) + alpha, 25), 0);
-
-						target_colormap->fadergba = R_PutRgbaRGBA(red, green, blue, alpha);
-
-						if (!(sectors[secnum].extra_colormap = R_GetColormapFromList(target_colormap)))
-						{
-							target_colormap->colormap = R_CreateLightTable(target_colormap);
-							R_AddColormapToList(target_colormap);
-							sectors[secnum].extra_colormap = target_colormap;
-						}
-						else
-							memset(target_colormap, 0, sizeof(*target_colormap));
-					}
-				}
+					sectors[secnum].extra_colormap = R_AddColormaps(
+						sectors[secnum].extra_colormap, line->frontsector->extra_colormap,
+						line->flags & ML_EFFECT1,  // subtract R
+						line->flags & ML_NOCLIMB,  // subtract G
+						line->flags & ML_EFFECT2,  // subtract B
+						false,                     // subtract A (no flag for this, just pass negative alpha)
+						line->flags & ML_EFFECT1,  // subtract FadeR
+						line->flags & ML_NOCLIMB,  // subtract FadeG
+						line->flags & ML_EFFECT2,  // subtract FadeB
+						false,                     // subtract FadeA (no flag for this, just pass negative alpha)
+						line->flags & ML_DONTPEGBOTTOM,
+						(line->flags & ML_DONTPEGBOTTOM) ? (sides[line->sidenum[0]].textureoffset >> FRACBITS) : 0,
+						(line->flags & ML_DONTPEGBOTTOM) ? (sides[line->sidenum[0]].rowoffset >> FRACBITS) : 0,
+						true);
 				else
 					sectors[secnum].extra_colormap = line->frontsector->extra_colormap;
 			}

From 5e59b8c55af1e79c1f5bf10ceb52676ed9b2624d Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Tue, 11 Sep 2018 22:49:32 -0400
Subject: [PATCH 14/20] Duplicate lines

---
 src/r_data.c | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/src/r_data.c b/src/r_data.c
index 5598dafcd..1de51fedd 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -1849,15 +1849,6 @@ extracolormap_t *R_CreateColormap(char *p1, char *p2, char *p3)
 	rgba = R_PutRgbaRGBA(cr, cg, cb, ca);
 	fadergba = R_PutRgbaRGBA(cfr, cfg, cfb, cfa);
 
-	// Did we just make a default colormap?
-#ifdef EXTRACOLORMAPLUMPS
-	if (R_CheckDefaultColormapByValues(true, true, true, rgba, fadergba, fadestart, fadeend, fog, LUMPERROR))
-		return NULL;
-#else
-	if (R_CheckDefaultColormapByValues(true, true, true, rgba, fadergba, fadestart, fadeend, fog))
-		return NULL;
-#endif
-
 	// Did we just make a default colormap?
 #ifdef EXTRACOLORMAPLUMPS
 	if (R_CheckDefaultColormapByValues(true, true, true, rgba, fadergba, fadestart, fadeend, fog, LUMPERROR))

From 8754268abe34f70a3b71be70808c39351aed3f64 Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Wed, 12 Sep 2018 07:06:45 -0400
Subject: [PATCH 15/20] Add fadestart/fadeend/fog to R_AddColormaps

---
 src/r_data.c | 32 +++++++++++++++++++++++++++++++-
 src/r_data.h |  1 +
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/src/r_data.c b/src/r_data.c
index 1de51fedd..53044bc2e 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -1901,6 +1901,7 @@ extracolormap_t *R_CreateColormap(char *p1, char *p2, char *p3)
 extracolormap_t *R_AddColormaps(extracolormap_t *exc_augend, extracolormap_t *exc_addend,
 	boolean subR, boolean subG, boolean subB, boolean subA,
 	boolean subFadeR, boolean subFadeG, boolean subFadeB, boolean subFadeA,
+	boolean subFadeStart, boolean subFadeEnd, boolean ignoreFog,
 	boolean useAltAlpha, INT16 altAlpha, INT16 altFadeAlpha,
 	boolean lighttable)
 {
@@ -1917,7 +1918,10 @@ extracolormap_t *R_AddColormaps(extracolormap_t *exc_augend, extracolormap_t *ex
 
 	INT16 red, green, blue, alpha;
 
+	///////////////////
 	// base rgba
+	///////////////////
+
 	red = max(min(
 		R_GetRgbaR(exc_augend->rgba)
 			+ (subR ? -1 : 1) // subtract R
@@ -1941,7 +1945,10 @@ extracolormap_t *R_AddColormaps(extracolormap_t *exc_augend, extracolormap_t *ex
 
 	exc_augend->rgba = R_PutRgbaRGBA(red, green, blue, alpha);
 
-	// fade rgba
+	///////////////////
+	// fade/dark rgba
+	///////////////////
+
 	red = max(min(
 		R_GetRgbaR(exc_augend->fadergba)
 			+ (subFadeR ? -1 : 1) // subtract R
@@ -1967,6 +1974,29 @@ extracolormap_t *R_AddColormaps(extracolormap_t *exc_augend, extracolormap_t *ex
 
 	exc_augend->fadergba = R_PutRgbaRGBA(red, green, blue, alpha);
 
+	///////////////////
+	// parameters
+	///////////////////
+
+	exc_augend->fadestart = max(min(
+		exc_augend->fadestart
+			+ (subFadeStart ? -1 : 1) // subtract fadestart
+			* exc_addend->fadestart
+		, 31), 0);
+
+	exc_augend->fadeend = max(min(
+		exc_augend->fadeend
+			+ (subFadeEnd ? -1 : 1) // subtract fadeend
+			* exc_addend->fadeend
+		, 31), 0);
+
+	if (!ignoreFog) // overwrite fog with new value
+		exc_augend->fog = exc_addend->fog;
+
+	///////////////////
+	// put it together
+	///////////////////
+
 	if (!(exc = R_GetColormapFromList(exc_augend)))
 	{
 		exc_augend->colormap = lighttable ? R_CreateLightTable(exc_augend) : NULL;
diff --git a/src/r_data.h b/src/r_data.h
index df0fe75b3..3a7740c96 100644
--- a/src/r_data.h
+++ b/src/r_data.h
@@ -128,6 +128,7 @@ extracolormap_t *R_CreateColormap(char *p1, char *p2, char *p3);
 extracolormap_t *R_AddColormaps(extracolormap_t *exc_augend, extracolormap_t *exc_addend,
 	boolean subR, boolean subG, boolean subB, boolean subA,
 	boolean subFadeR, boolean subFadeG, boolean subFadeB, boolean subFadeA,
+	boolean subFadeStart, boolean subFadeEnd, boolean ignoreFog,
 	boolean useAltAlpha, INT16 altAlpha, INT16 altFadeAlpha,
 	boolean lighttable);
 #ifdef EXTRACOLORMAPLUMPS

From 6059b8edc909b1ac5cbbf65c6b821852c69f53cf Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Wed, 12 Sep 2018 07:06:58 -0400
Subject: [PATCH 16/20] 447: Extra params for R_AddColormaps

---
 src/p_spec.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/p_spec.c b/src/p_spec.c
index 2c607f74e..41756423a 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3268,6 +3268,9 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 						line->flags & ML_NOCLIMB,  // subtract FadeG
 						line->flags & ML_EFFECT2,  // subtract FadeB
 						false,                     // subtract FadeA (no flag for this, just pass negative alpha)
+						false,                     // subtract FadeStart (we ran out of flags)
+						false,                     // subtract FadeEnd (we ran out of flags)
+						false,                     // ignore Fog (we ran out of flags)
 						line->flags & ML_DONTPEGBOTTOM,
 						(line->flags & ML_DONTPEGBOTTOM) ? (sides[line->sidenum[0]].textureoffset >> FRACBITS) : 0,
 						(line->flags & ML_DONTPEGBOTTOM) ? (sides[line->sidenum[0]].rowoffset >> FRACBITS) : 0,

From 9a388af8ec6a38e6f3e90b3dee0b6b153612278b Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Wed, 12 Sep 2018 07:31:10 -0400
Subject: [PATCH 17/20] 447: AddColormap no longer returns chained colormap, so
 chain it ourselves

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

diff --git a/src/p_spec.c b/src/p_spec.c
index 41756423a..2742f1b44 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3258,7 +3258,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 			for (secnum = -1; (secnum = P_FindSectorFromLineTag(line, secnum)) >= 0 ;)
 			{
 				if (line->flags & ML_EFFECT3) // relative calc
-					sectors[secnum].extra_colormap = R_AddColormaps(
+				{
+					extracolormap_t *exc = R_AddColormaps(
 						sectors[secnum].extra_colormap, line->frontsector->extra_colormap,
 						line->flags & ML_EFFECT1,  // subtract R
 						line->flags & ML_NOCLIMB,  // subtract G
@@ -3274,7 +3275,17 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 						line->flags & ML_DONTPEGBOTTOM,
 						(line->flags & ML_DONTPEGBOTTOM) ? (sides[line->sidenum[0]].textureoffset >> FRACBITS) : 0,
 						(line->flags & ML_DONTPEGBOTTOM) ? (sides[line->sidenum[0]].rowoffset >> FRACBITS) : 0,
-						true);
+						false);
+
+					if (!(sectors[secnum].extra_colormap = R_GetColormapFromList(exc)))
+					{
+						exc->colormap = R_CreateLightTable(exc);
+						R_AddColormapToList(exc);
+						sectors[secnum].extra_colormap = exc;
+					}
+					else
+						Z_Free(exc);
+				}
 				else
 					sectors[secnum].extra_colormap = line->frontsector->extra_colormap;
 			}

From 6f0b28c48f0256c6194dee11d7714a31f51eff59 Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Wed, 12 Sep 2018 07:38:51 -0400
Subject: [PATCH 18/20] 447: Allow alternate alpha without relative calc

---
 src/p_spec.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/src/p_spec.c b/src/p_spec.c
index 2742f1b44..637f90af8 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3287,7 +3287,25 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 						Z_Free(exc);
 				}
 				else
-					sectors[secnum].extra_colormap = line->frontsector->extra_colormap;
+				{
+					if (line->flags & ML_DONTPEGBOTTOM) // alternate alpha (by texture offsets)
+					{
+						extracolormap_t *exc = R_CopyColormap(line->frontsector->extra_colormap, false);
+						exc->rgba = R_GetRgbaRGB(exc->rgba) + R_PutRgbaA(max(min(sides[line->sidenum[0]].textureoffset >> FRACBITS, 25), 0));
+						exc->fadergba = R_GetRgbaRGB(exc->fadergba) + R_PutRgbaA(max(min(sides[line->sidenum[0]].rowoffset >> FRACBITS, 25), 0));
+
+						if (!(sectors[secnum].extra_colormap = R_GetColormapFromList(exc)))
+						{
+							exc->colormap = R_CreateLightTable(exc);
+							R_AddColormapToList(exc);
+							sectors[secnum].extra_colormap = exc;
+						}
+						else
+							Z_Free(exc);
+					}
+					else
+						sectors[secnum].extra_colormap = line->frontsector->extra_colormap;
+				}
 			}
 			break;
 

From 4d26cf63304005ac745909ace8b85bbde6fa1425 Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Wed, 12 Sep 2018 07:55:47 -0400
Subject: [PATCH 19/20] 447: Allow relative calc from backside colormap
 (ML_TFERLINE)

---
 src/p_spec.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/p_spec.c b/src/p_spec.c
index 637f90af8..914c9821e 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3260,7 +3260,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 				if (line->flags & ML_EFFECT3) // relative calc
 				{
 					extracolormap_t *exc = R_AddColormaps(
-						sectors[secnum].extra_colormap, line->frontsector->extra_colormap,
+						(line->flags & ML_TFERLINE) ? line->backsector->extra_colormap : sectors[secnum].extra_colormap, // use back colormap instead of target sector
+						line->frontsector->extra_colormap,
 						line->flags & ML_EFFECT1,  // subtract R
 						line->flags & ML_NOCLIMB,  // subtract G
 						line->flags & ML_EFFECT2,  // subtract B

From cb2ac9b4d3943ab9c569afcb52a9d4a76a75edc1 Mon Sep 17 00:00:00 2001
From: mazmazz <mar.marcoz@outlook.com>
Date: Wed, 12 Sep 2018 08:06:44 -0400
Subject: [PATCH 20/20] Formatting

---
 src/p_spec.c | 27 ++++++++++++---------------
 1 file changed, 12 insertions(+), 15 deletions(-)

diff --git a/src/p_spec.c b/src/p_spec.c
index 914c9821e..fd02803cc 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3287,26 +3287,23 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 					else
 						Z_Free(exc);
 				}
-				else
+				else if (line->flags & ML_DONTPEGBOTTOM) // alternate alpha (by texture offsets)
 				{
-					if (line->flags & ML_DONTPEGBOTTOM) // alternate alpha (by texture offsets)
-					{
-						extracolormap_t *exc = R_CopyColormap(line->frontsector->extra_colormap, false);
-						exc->rgba = R_GetRgbaRGB(exc->rgba) + R_PutRgbaA(max(min(sides[line->sidenum[0]].textureoffset >> FRACBITS, 25), 0));
-						exc->fadergba = R_GetRgbaRGB(exc->fadergba) + R_PutRgbaA(max(min(sides[line->sidenum[0]].rowoffset >> FRACBITS, 25), 0));
+					extracolormap_t *exc = R_CopyColormap(line->frontsector->extra_colormap, false);
+					exc->rgba = R_GetRgbaRGB(exc->rgba) + R_PutRgbaA(max(min(sides[line->sidenum[0]].textureoffset >> FRACBITS, 25), 0));
+					exc->fadergba = R_GetRgbaRGB(exc->fadergba) + R_PutRgbaA(max(min(sides[line->sidenum[0]].rowoffset >> FRACBITS, 25), 0));
 
-						if (!(sectors[secnum].extra_colormap = R_GetColormapFromList(exc)))
-						{
-							exc->colormap = R_CreateLightTable(exc);
-							R_AddColormapToList(exc);
-							sectors[secnum].extra_colormap = exc;
-						}
-						else
-							Z_Free(exc);
+					if (!(sectors[secnum].extra_colormap = R_GetColormapFromList(exc)))
+					{
+						exc->colormap = R_CreateLightTable(exc);
+						R_AddColormapToList(exc);
+						sectors[secnum].extra_colormap = exc;
 					}
 					else
-						sectors[secnum].extra_colormap = line->frontsector->extra_colormap;
+						Z_Free(exc);
 				}
+				else
+					sectors[secnum].extra_colormap = line->frontsector->extra_colormap;
 			}
 			break;