diff --git a/docs/rh-log.txt b/docs/rh-log.txt
index 005aa5e1e..8b26fa2e6 100644
--- a/docs/rh-log.txt
+++ b/docs/rh-log.txt
@@ -1,3 +1,10 @@
+September 21, 2009  (Changes by Graf Zahl)
+- Fixed: When drawing with a special colormap the quad's flags weren't cleared
+  which could cause crashes.
+- Added custom special colormaps to DECORATE.
+- Cleaned up special colormap code and removed lots of dependencies on the
+  knowledge of the tables' contents.
+
 September 20, 2009  (Changes by Graf Zahl)
 - Changed call to R_DrawRemainingPlayerSprites into a virtual function
   of DFrameBuffer because its implementation is specific to the software
diff --git a/src/colormatcher.h b/src/colormatcher.h
index ca7992d6d..04b9f7198 100644
--- a/src/colormatcher.h
+++ b/src/colormatcher.h
@@ -43,6 +43,11 @@ public:
 
 	void SetPalette (const DWORD *palette);
 	BYTE Pick (int r, int g, int b);
+	BYTE Pick (PalEntry pe)
+	{
+		return Pick(pe.r, pe.g, pe.b);
+	}
+
 	FColorMatcher &operator= (const FColorMatcher &other);
 
 private:
diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp
index 5b7f016cf..fa2c1e59f 100644
--- a/src/g_shared/a_artifacts.cpp
+++ b/src/g_shared/a_artifacts.cpp
@@ -139,14 +139,7 @@ PalEntry APowerup::GetBlend ()
 	if (EffectTics <= BLINKTHRESHOLD && !(EffectTics & 8))
 		return 0;
 
-	if (BlendColor == INVERSECOLOR ||
-		BlendColor == GOLDCOLOR ||
-		// [BC] HAX!
-		BlendColor == REDCOLOR ||
-		BlendColor == GREENCOLOR ||
-		BlendColor == BLUECOLOR)
-		return 0;
-
+	if (IsSpecialColormap(BlendColor)) return 0;
 	return BlendColor;
 }
 
@@ -175,37 +168,19 @@ void APowerup::DoEffect ()
 
 	if (EffectTics > 0)
 	{
-		int oldcolormap = Owner->player->fixedcolormap;
-		if (EffectTics > BLINKTHRESHOLD || (EffectTics & 8))
+		int Colormap = GetSpecialColormap(BlendColor);
+
+		if (Colormap != NOFIXEDCOLORMAP)
 		{
-			if (BlendColor == INVERSECOLOR)
+			if (EffectTics > BLINKTHRESHOLD || (EffectTics & 8))
 			{
-				Owner->player->fixedcolormap = INVERSECOLORMAP;
+				Owner->player->fixedcolormap = Colormap;
 			}
-			else if (BlendColor == GOLDCOLOR)
+			else if (Owner->player->fixedcolormap == Colormap)	
 			{
-				Owner->player->fixedcolormap = GOLDCOLORMAP;
+				// only unset if the fixed colormap comes from this item
+				Owner->player->fixedcolormap = NOFIXEDCOLORMAP;
 			}
-			else if (BlendColor == REDCOLOR)
-			{
-				Owner->player->fixedcolormap = REDCOLORMAP;
-			}
-			else if (BlendColor == GREENCOLOR)
-			{
-				Owner->player->fixedcolormap = GREENCOLORMAP;
-			}
-			else if (BlendColor == BLUECOLOR)
-			{
-				Owner->player->fixedcolormap = BLUECOLORMAP;
-			}
-		}
-		else if ((BlendColor == INVERSECOLOR && Owner->player->fixedcolormap == INVERSECOLORMAP) || 
-				 (BlendColor == GOLDCOLOR && Owner->player->fixedcolormap == GOLDCOLORMAP) ||
-				 (BlendColor == REDCOLOR && Owner->player->fixedcolormap == REDCOLORMAP) ||
-				 (BlendColor == GREENCOLOR && Owner->player->fixedcolormap == GREENCOLORMAP) ||
-				 (BlendColor == BLUECOLOR && Owner->player->fixedcolormap == BLUECOLORMAP))
-		{
-			Owner->player->fixedcolormap = NOFIXEDCOLORMAP;
 		}
 	}
 }
@@ -711,7 +686,7 @@ int APowerInvisibility::AlterWeaponSprite (vissprite_t *vis)
 	if ((vis->alpha < TRANSLUC25 && special1 > 0) || (vis->alpha == 0))
 	{
 		vis->alpha = clamp<fixed_t>((OPAQUE - Strength), 0, OPAQUE);
-		vis->colormap = SpecialColormaps[INVERSECOLORMAP];
+		vis->colormap = SpecialColormaps[INVERSECOLORMAP].Colormap;
 	}
 	return -1;	// This item is valid so another one shouldn't reset the translucency
 }
diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h
index 1272de60d..93352a719 100644
--- a/src/g_shared/a_artifacts.h
+++ b/src/g_shared/a_artifacts.h
@@ -3,14 +3,6 @@
 
 #include "a_pickups.h"
 
-#define INVERSECOLOR	0x00345678
-#define GOLDCOLOR		0x009abcde
-
-// [BC] More hacks!
-#define REDCOLOR		0x00beefee
-#define GREENCOLOR		0x00beefad
-#define BLUECOLOR		0x00befeed
-
 class player_t;
 
 // A powerup is a pseudo-inventory item that applies an effect to its
diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp
index b34ed4878..17333f7d7 100644
--- a/src/p_lnspec.cpp
+++ b/src/p_lnspec.cpp
@@ -2532,7 +2532,10 @@ FUNC(LS_SetPlayerProperty)
 				if (power != 4)
 				{
 					APowerup *item = static_cast<APowerup*>(it->GiveInventoryType (powers[power]));
-					if (item != NULL && power == 0) item->BlendColor = INVERSECOLOR;
+					if (item != NULL && power == 0 && arg1 == 1) 
+					{
+						item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP);
+					}
 				}
 				else if (it->player - players == consoleplayer)
 				{
@@ -2568,7 +2571,11 @@ FUNC(LS_SetPlayerProperty)
 				{ // Give power
 					if (power != 4)
 					{
-						players[i].mo->GiveInventoryType (powers[power]);
+						APowerup *item = static_cast<APowerup*>(players[i].mo->GiveInventoryType (powers[power]));
+						if (item != NULL && power == 0 && arg1 == 1) 
+						{
+							item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP);
+						}
 					}
 					else if (i == consoleplayer)
 					{
diff --git a/src/r_main.cpp b/src/r_main.cpp
index 00dfe8353..ea3936768 100644
--- a/src/r_main.cpp
+++ b/src/r_main.cpp
@@ -1163,9 +1163,9 @@ void R_SetupFrame (AActor *actor)
 
 	if (player != NULL && camera == player->mo)
 	{
-		if (player->fixedcolormap >= 0 && player->fixedcolormap < NUM_SPECIALCOLORMAPS)
+		if (player->fixedcolormap >= 0 && player->fixedcolormap < (int)SpecialColormaps.Size())
 		{
-			fixedcolormap = SpecialColormaps[player->fixedcolormap];
+			fixedcolormap = SpecialColormaps[player->fixedcolormap].Colormap;
 		}
 		else if (player->fixedlightlevel >= 0 && player->fixedlightlevel < NUMCOLORMAPS)
 		{
@@ -1175,7 +1175,7 @@ void R_SetupFrame (AActor *actor)
 	// [RH] Inverse light for shooting the Sigil
 	if (fixedcolormap == NULL && extralight == INT_MIN)
 	{
-		fixedcolormap = SpecialColormaps[INVERSECOLORMAP];
+		fixedcolormap = SpecialColormaps[INVERSECOLORMAP].Colormap;
 		extralight = 0;
 	}
 
diff --git a/src/r_things.cpp b/src/r_things.cpp
index 552241be2..e0e6a63cc 100644
--- a/src/r_things.cpp
+++ b/src/r_things.cpp
@@ -1680,7 +1680,8 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, fixed_t sx, fixed_
 				// The colormap has changed. Is it one we can easily identify?
 				// If not, then don't bother trying to identify it for
 				// hardware accelerated drawing.
-				if (vis->colormap < SpecialColormaps[0] || vis->colormap >= SpecialColormaps[NUM_SPECIALCOLORMAPS])
+				if (vis->colormap < SpecialColormaps[0].Colormap || 
+					vis->colormap >= SpecialColormaps[SpecialColormaps.Size()].Colormap)
 				{
 					noaccel = true;
 				}
@@ -1812,19 +1813,21 @@ void R_DrawRemainingPlayerSprites()
 		{
 			FDynamicColormap *colormap = VisPSpritesBaseColormap[i];
 			bool flip = vis->xiscale < 0;
-			FSpecialColormapParameters *special = NULL;
+			FSpecialColormap *special = NULL;
 			PalEntry overlay = 0;
 			FColormapStyle colormapstyle;
 			bool usecolormapstyle = false;
 
-			if (vis->colormap >= SpecialColormaps[0] && vis->colormap < SpecialColormaps[NUM_SPECIALCOLORMAPS])
+			if (vis->colormap >= SpecialColormaps[0].Colormap && 
+				vis->colormap < SpecialColormaps[SpecialColormaps.Size()].Colormap)
 			{
-				ptrdiff_t specialmap = (vis->colormap - SpecialColormaps[0]) >> 8;
-				if (SpecialColormapParms[specialmap].Inverted)
+				// Yuck! There needs to be a better way to store colormaps in the vissprite... :(
+				ptrdiff_t specialmap = (vis->colormap - SpecialColormaps[0].Colormap) / sizeof(FSpecialColormap);
+				if (SpecialColormaps[specialmap].Inverted)
 				{
 					vis->RenderStyle.Flags ^= STYLEF_InvertSource;
 				}
-				special = &SpecialColormapParms[specialmap];
+				special = &SpecialColormaps[specialmap];
 			}
 			else if (colormap->Color == PalEntry(255,255,255) &&
 				colormap->Desaturate == 0)
diff --git a/src/tarray.h b/src/tarray.h
index 72bbc5e61..92a6552e4 100644
--- a/src/tarray.h
+++ b/src/tarray.h
@@ -120,12 +120,12 @@ public:
 		}
 	}
 	// Return a reference to an element
-	T &operator[] (unsigned int index) const
+	T &operator[] (size_t index) const
 	{
 		return Array[index];
 	}
 	// Returns the value of an element
-	TT operator() (unsigned int index) const
+	TT operator() (size_t index) const
 	{
 		return Array[index];
 	}
diff --git a/src/textures/bitmap.cpp b/src/textures/bitmap.cpp
index c985e1494..913aa507e 100644
--- a/src/textures/bitmap.cpp
+++ b/src/textures/bitmap.cpp
@@ -35,6 +35,7 @@
 #include "bitmap.h"
 #include "templates.h"
 #include "r_translate.h"
+#include "v_palette.h"
 
 
 //===========================================================================
@@ -70,86 +71,6 @@ void iCopyColors(BYTE *pout, const BYTE *pin, int count, int step, FCopyInfo *in
 		}
 		break;
 
-	case BLEND_INVERSEMAP:
-		// Doom's inverted invulnerability map
-		for(i=0;i<count;i++)
-		{
-			a = TSrc::A(pin);
-			if (TBlend::ProcessAlpha0() || a)
-			{
-				gray = clamp<int>(255 - TSrc::Gray(pin),0,255);
-
-				TBlend::OpC(pout[TDest::RED], gray, a, inf);
-				TBlend::OpC(pout[TDest::GREEN], gray, a, inf);
-				TBlend::OpC(pout[TDest::BLUE], gray, a, inf);
-				TBlend::OpA(pout[TDest::ALPHA], a, inf);
-			}
-			pout+=4;
-			pin+=step;
-		}
-		break;
-
-	case BLEND_GOLDMAP:
-		// Heretic's golden invulnerability map
-		for(i=0;i<count;i++)
-		{
-			a = TSrc::A(pin);
-			if (TBlend::ProcessAlpha0() || a)
-			{
-				gray = TSrc::Gray(pin);
-				r=clamp<int>(gray+(gray>>1),0,255);
-				g=clamp<int>(gray-(gray>>2),0,255);
-
-				TBlend::OpC(pout[TDest::RED], r, a, inf);
-				TBlend::OpC(pout[TDest::GREEN], g, a, inf);
-				TBlend::OpC(pout[TDest::BLUE], 0, a, inf);
-				TBlend::OpA(pout[TDest::ALPHA], a, inf);
-			}
-			pout+=4;
-			pin+=step;
-		}
-		break;
-
-	case BLEND_REDMAP:
-		// Skulltag's red Doomsphere map
-		for(i=0;i<count;i++)
-		{
-			a = TSrc::A(pin);
-			if (TBlend::ProcessAlpha0() || a)
-			{
-				gray = TSrc::Gray(pin);
-				r=clamp<int>(gray+(gray>>1),0,255);
-
-				TBlend::OpC(pout[TDest::RED], r, a, inf);
-				TBlend::OpC(pout[TDest::GREEN], 0, a, inf);
-				TBlend::OpC(pout[TDest::BLUE], 0, a, inf);
-				TBlend::OpA(pout[TDest::ALPHA], a, inf);
-			}
-			pout+=4;
-			pin+=step;
-		}
-		break;
-
-	case BLEND_GREENMAP:
-		// Skulltag's Guardsphere map
-		for(i=0;i<count;i++)
-		{
-			a = TSrc::A(pin);
-			if (TBlend::ProcessAlpha0() || a)
-			{
-				gray = TSrc::Gray(pin);
-				r=clamp<int>(gray+(gray>>1),0,255);
-
-				TBlend::OpC(pout[TDest::RED], r, a, inf);
-				TBlend::OpC(pout[TDest::GREEN], r, a, inf);
-				TBlend::OpC(pout[TDest::BLUE], gray, a, inf);
-				TBlend::OpA(pout[TDest::ALPHA], a, inf);
-			}
-			pout+=4;
-			pin+=step;
-		}
-		break;
-
 	case BLEND_ICEMAP:
 		// Create the ice translation table, based on Hexen's.
 		// Since this is done in True Color the purplish tint is fully preserved - even in Doom!
@@ -171,7 +92,28 @@ void iCopyColors(BYTE *pout, const BYTE *pin, int count, int step, FCopyInfo *in
 		break;
 
 	default:
-		if (inf->blend >= BLEND_DESATURATE1 && inf->blend<=BLEND_DESATURATE31)
+
+		if (inf->blend >= BLEND_SPECIALCOLORMAP1)
+		{
+			FSpecialColormap *cm = &SpecialColormaps[inf->blend - BLEND_SPECIALCOLORMAP1];
+			for(i=0;i<count;i++)
+			{
+				a = TSrc::A(pin);
+				if (TBlend::ProcessAlpha0() || a)
+				{
+					gray = clamp<int>(255 - TSrc::Gray(pin),0,255);
+
+					PalEntry pe = cm->GrayscaleToColor[gray];
+					TBlend::OpC(pout[TDest::RED], pe.r , a, inf);
+					TBlend::OpC(pout[TDest::GREEN], pe.g, a, inf);
+					TBlend::OpC(pout[TDest::BLUE], pe.b, a, inf);
+					TBlend::OpA(pout[TDest::ALPHA], a, inf);
+				}
+				pout+=4;
+				pin+=step;
+			}
+		}
+		else if (inf->blend >= BLEND_DESATURATE1 && inf->blend<=BLEND_DESATURATE31)
 		{
 			// Desaturated light settings.
 			fac=inf->blend-BLEND_DESATURATE1+1;
diff --git a/src/textures/bitmap.h b/src/textures/bitmap.h
index 5d9b58a6f..04bd580cd 100644
--- a/src/textures/bitmap.h
+++ b/src/textures/bitmap.h
@@ -262,13 +262,10 @@ enum ColorType
 enum EBlend
 {
 	BLEND_NONE = 0,
-	BLEND_INVERSEMAP = 1,
-	BLEND_GOLDMAP = 2,
-	BLEND_REDMAP = 3,
-	BLEND_GREENMAP = 4,
-	BLEND_ICEMAP = 5,
-	BLEND_DESATURATE1 = 6,
-	BLEND_DESATURATE31 = 36,
+	BLEND_ICEMAP = 1,
+	BLEND_DESATURATE1 = 2,
+	BLEND_DESATURATE31 = 32,
+	BLEND_SPECIALCOLORMAP1 = 33,
 	BLEND_MODULATE = -1,	
 	BLEND_OVERLAY = -2,
 };
diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp
index 86bab74f8..a52bd2e37 100644
--- a/src/textures/multipatchtexture.cpp
+++ b/src/textures/multipatchtexture.cpp
@@ -425,23 +425,15 @@ BYTE *GetBlendMap(PalEntry blend, BYTE *blendwork)
 
 	switch (blend.a==0 ? blend.r : -1)
 	{
-	case BLEND_INVERSEMAP:
-		return SpecialColormaps[INVERSECOLORMAP];
-
-	case BLEND_GOLDMAP:
-		return SpecialColormaps[GOLDCOLORMAP];
-
-	case BLEND_REDMAP:
-		return SpecialColormaps[REDCOLORMAP];
-
-	case BLEND_GREENMAP:
-		return SpecialColormaps[GREENCOLORMAP];
-
 	case BLEND_ICEMAP:
 		return TranslationToTable(TRANSLATION(TRANSLATION_Standard, 7))->Remap;
 
 	default:
-		if (blend.r >= BLEND_DESATURATE1 && blend.r <= BLEND_DESATURATE31)
+		if (blend.r >= BLEND_SPECIALCOLORMAP1)
+		{
+			return SpecialColormaps[blend.r - BLEND_SPECIALCOLORMAP1].Colormap;
+		}
+		else if (blend.r >= BLEND_DESATURATE1 && blend.r <= BLEND_DESATURATE31)
 		{
 			return DesaturateColormap[blend.r - BLEND_DESATURATE1];
 		}
@@ -1044,22 +1036,29 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part)
 			}
 			else if (sc.Compare("Translation"))
 			{
+				int match;
+
 				bComplex = true;
 				if (part.Translation != NULL) delete part.Translation;
 				part.Translation = NULL;
 				part.Blend = 0;
-				static const char *maps[] = { "inverse", "gold", "red", "green", "ice", "desaturate", NULL };
+				static const char *maps[] = { "inverse", "gold", "red", "green", "blue", NULL };
 				sc.MustGetString();
-				int match = sc.MatchString(maps);
+
+				match = sc.MatchString(maps);
 				if (match >= 0)
 				{
-					part.Blend.r = 1 + match;
-					if (part.Blend.r == BLEND_DESATURATE1)
-					{
-						sc.MustGetStringName(",");
-						sc.MustGetNumber();
-						part.Blend.r += clamp(sc.Number-1, 0, 30);
-					}
+					part.Blend.r = BLEND_SPECIALCOLORMAP1 + match;
+				}
+				else if (sc.Compare("ICE"))
+				{
+					part.Blend.r = BLEND_ICEMAP;
+				}
+				else if (sc.Compare("DESATURATE"))
+				{
+					sc.MustGetStringName(",");
+					sc.MustGetNumber();
+					part.Blend.r = BLEND_DESATURATE1 + clamp(sc.Number-1, 0, 30);
 				}
 				else
 				{
diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp
index 4f29d272c..0c579efa2 100644
--- a/src/thingdef/thingdef_properties.cpp
+++ b/src/thingdef/thingdef_properties.cpp
@@ -1556,7 +1556,8 @@ DEFINE_CLASS_PROPERTY(weapon, S, WeaponPiece)
 //==========================================================================
 DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory)
 {
-	PROP_INT_PARM(i, 0);
+	static const char *specialcolormapnames[] = {
+		"INVERSEMAP", "GOLDMAP", "REDMAP", "GREENMAP", "BLUEMAP", NULL };
 
 	int alpha;
 	PalEntry * pBlendColor;
@@ -1582,30 +1583,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory)
 	{
 		PROP_STRING_PARM(name, 1);
 
-		if (!stricmp(name, "INVERSEMAP"))
+		// We must check the old special colormap names for compatibility
+		int v = MatchString(name, specialcolormapnames);
+		if (v >= 0)
 		{
-			*pBlendColor = INVERSECOLOR;
-			return;
-		}
-		else if (!stricmp(name, "GOLDMAP"))
-		{
-			*pBlendColor = GOLDCOLOR;
-			return;
-		}
-		// [BC] Yay, more hacks.
-		else if (!stricmp(name, "REDMAP" ))
-		{
-			*pBlendColor = REDCOLOR;
-			return;
-		}
-		else if (!stricmp(name, "GREENMAP" ))
-		{
-			*pBlendColor = GREENCOLOR;
-			return;
-		}
-		else if (!stricmp(name, "BLUEMAP"))
-		{
-			*pBlendColor = BLUECOLOR;
+			*pBlendColor = MakeSpecialColormap(v);
 			return;
 		}
 
@@ -1623,6 +1605,37 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory)
 	else *pBlendColor = 0;
 }
 
+//==========================================================================
+//
+//==========================================================================
+DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFI, Inventory)
+{
+	PalEntry * pBlendColor;
+
+	if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerup)))
+	{
+		pBlendColor = &((APowerup*)defaults)->BlendColor;
+	}
+	else if (info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
+	{
+		pBlendColor = &((APowerupGiver*)defaults)->BlendColor;
+	}
+	else
+	{
+		I_Error("\"powerup.colormap\" requires an actor of type \"Powerup\"\n");
+		return;
+	}
+
+	PROP_FLOAT_PARM(r, 0);
+	PROP_FLOAT_PARM(g, 1);
+	PROP_FLOAT_PARM(b, 2);
+	PROP_INT_PARM(inv, 3);
+
+
+
+	*pBlendColor = MakeSpecialColormap(AddSpecialColormap(r, g, b, !!inv));
+}
+
 //==========================================================================
 //
 //==========================================================================
diff --git a/src/v_draw.cpp b/src/v_draw.cpp
index 90fb4beff..05cd73c5c 100644
--- a/src/v_draw.cpp
+++ b/src/v_draw.cpp
@@ -584,7 +584,7 @@ bool DCanvas::ParseDrawTextureTags (FTexture *img, int x, int y, DWORD tag, va_l
 			break;
 
 		case DTA_SpecialColormap:
-			parms->specialcolormap = va_arg (tags, FSpecialColormapParameters *);
+			parms->specialcolormap = va_arg (tags, FSpecialColormap *);
 			break;
 
 		case DTA_ColormapStyle:
diff --git a/src/v_palette.cpp b/src/v_palette.cpp
index d0d50efaa..85570caa0 100644
--- a/src/v_palette.cpp
+++ b/src/v_palette.cpp
@@ -61,10 +61,16 @@ extern "C" {
 FDynamicColormap NormalLight;
 }
 FPalette GPalette;
-BYTE SpecialColormaps[NUM_SPECIALCOLORMAPS][256];
+TArray<FSpecialColormap> SpecialColormaps;
 BYTE DesaturateColormap[31][256];
 
-FSpecialColormapParameters SpecialColormapParms[NUM_SPECIALCOLORMAPS] =
+struct FSpecialColormapParameters
+{
+	float Colorize[3];
+	bool Inverted;
+};
+
+static FSpecialColormapParameters SpecialColormapParms[] =
 {
 	// Doom invulnerability is an inverted grayscale.
 	// Strife uses it when firing the Sigil
@@ -355,10 +361,57 @@ static bool FixBuildPalette (BYTE *opal, int lump, bool blood)
 	return true;
 }
 
+int AddSpecialColormap(double r, double g, double b, bool inv)
+{
+	for(unsigned i=0; i<SpecialColormaps.Size(); i++)
+	{
+		if (SpecialColormaps[i].Colorize[0] == r &&
+			SpecialColormaps[i].Colorize[1] == g &&
+			SpecialColormaps[i].Colorize[2] == b &&
+			SpecialColormaps[i].Inverted == inv)
+		{
+			return i;	// The map already exists
+		}
+	}
+
+	FSpecialColormap *cm = &SpecialColormaps[SpecialColormaps.Reserve(1)];
+
+	cm->Colorize[0] = float(r);
+	cm->Colorize[1] = float(g);
+	cm->Colorize[2] = float(b);
+	cm->Inverted = inv;
+
+	for (int c = 0; c < 256; c++)
+	{
+		double intensity = (GPalette.BaseColors[c].r * 77 +
+							GPalette.BaseColors[c].g * 143 +
+							GPalette.BaseColors[c].b * 37) / 256.0;
+		if (inv)
+		{
+			intensity = 255 - intensity;
+		}
+
+		PalEntry pe = PalEntry(	MIN(255, int(intensity*r)), 
+								MIN(255, int(intensity*g)), 
+								MIN(255, int(intensity*b)));
+
+		cm->Colormap[c] = ColorMatcher.Pick(pe);
+
+		// This table is used by the texture composition code
+		for(int i = 0;i < 256; i++)
+		{
+			intensity = inv? 255-i : i;
+			cm->GrayscaleToColor[i] = PalEntry(	MIN(255, int(intensity*r)), 
+												MIN(255, int(intensity*g)), 
+												MIN(255, int(intensity*b)));
+		}
+	}
+	return SpecialColormaps.Size() - 1;
+}
+
 void InitPalette ()
 {
 	BYTE pal[768];
-	BYTE *shade;
 	int c;
 	bool usingBuild = false;
 	int lump;
@@ -398,37 +451,18 @@ void InitPalette ()
 	NormalLight.Fade = 0;
 	// NormalLight.Maps is set by R_InitColormaps()
 
-	// build special maps (e.g. invulnerability)
-	double intensity;
+	// build default special maps (e.g. invulnerability)
+	SpecialColormaps.Clear();
 
 	for (int i = 0; i < countof(SpecialColormapParms); ++i)
 	{
-		double r, g, b;
-		bool inv;
-
-		shade = SpecialColormaps[i];
-		r = SpecialColormapParms[i].Colorize[0];
-		g = SpecialColormapParms[i].Colorize[1];
-		b = SpecialColormapParms[i].Colorize[2];
-		inv = SpecialColormapParms[i].Inverted;
-		for (c = 0; c < 256; c++)
-		{
-			intensity = (GPalette.BaseColors[c].r * 77 +
-						 GPalette.BaseColors[c].g * 143 +
-						 GPalette.BaseColors[c].b * 37) / 256.0;
-			if (inv)
-			{
-				intensity = 255 - intensity;
-			}
-			shade[c] = ColorMatcher.Pick(
-				MIN(255, int(intensity*r)), MIN(255, int(intensity*g)), MIN(255, int(intensity*b)));
-		}
+		AddSpecialColormap(SpecialColormapParms[i].Colorize[0], SpecialColormapParms[i].Colorize[1],
+			SpecialColormapParms[i].Colorize[2], SpecialColormapParms[i].Inverted);
 	}
-
 	// desaturated colormaps
 	for(int m = 0; m < 31; m++)
 	{
-		shade = DesaturateColormap[m];
+		BYTE *shade = DesaturateColormap[m];
 		for (c = 0; c < 256; c++)
 		{
 			int intensity = (GPalette.BaseColors[c].r * 77 +
diff --git a/src/v_palette.h b/src/v_palette.h
index 160ef6cea..a856de97d 100644
--- a/src/v_palette.h
+++ b/src/v_palette.h
@@ -88,25 +88,43 @@ struct FColormapStyle
 	float FadeLevel;
 };
 
-// Special colormaps, like invulnerability.
 enum
 {
 	NOFIXEDCOLORMAP = -1,
-	INVERSECOLORMAP,
-	GOLDCOLORMAP,
-	REDCOLORMAP,		// [BC] New Skulltag colormaps.
-	GREENCOLORMAP,
-	BLUECOLORMAP,
-
-	NUM_SPECIALCOLORMAPS
+	INVERSECOLORMAP,	// the inverse map is used explicitly in a few places.
 };
-struct FSpecialColormapParameters
+
+
+struct FSpecialColormap
 {
 	float Colorize[3];
 	bool Inverted;
+	BYTE Colormap[256];
+	PalEntry GrayscaleToColor[256];
 };
-extern FSpecialColormapParameters SpecialColormapParms[NUM_SPECIALCOLORMAPS];
-extern BYTE SpecialColormaps[NUM_SPECIALCOLORMAPS][256];
+
+extern TArray<FSpecialColormap> SpecialColormaps;
+
+// some utility functions to store special colormaps in powerup blends
+#define SPECIALCOLORMAP_MASK 0x00ff0000
+
+inline int MakeSpecialColormap(int index)
+{
+	return index | SPECIALCOLORMAP_MASK;
+}
+
+inline bool IsSpecialColormap(int map)
+{
+	return (map & SPECIALCOLORMAP_MASK) == SPECIALCOLORMAP_MASK;
+}
+
+inline int GetSpecialColormap(int blend)
+{
+	return IsSpecialColormap(blend)? blend & ~SPECIALCOLORMAP_MASK : NOFIXEDCOLORMAP;
+}
+
+int AddSpecialColormap(double r, double g, double b, bool inv);
+
 
 
 extern BYTE DesaturateColormap[31][256];
diff --git a/src/v_video.h b/src/v_video.h
index 3ce0e2849..a6f30a43a 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -227,7 +227,7 @@ public:
 		INTBOOL masked;
 		INTBOOL bilinear;
 		FRenderStyle style;
-		struct FSpecialColormapParameters *specialcolormap;
+		struct FSpecialColormap *specialcolormap;
 		struct FColormapStyle *colormapstyle;
 	};
 
diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp
index a81c2ca7c..519d69010 100644
--- a/src/win32/fb_d3d9.cpp
+++ b/src/win32/fb_d3d9.cpp
@@ -3089,6 +3089,7 @@ bool D3DFB::SetStyle(D3DTex *tex, DrawParms &parms, D3DCOLOR &color0, D3DCOLOR &
 
 	stencilling = false;
 	quad.Palette = NULL;
+	quad.Flags = 0;
 
 	switch (style.BlendOp)
 	{
@@ -3124,7 +3125,7 @@ bool D3DFB::SetStyle(D3DTex *tex, DrawParms &parms, D3DCOLOR &color0, D3DCOLOR &
 		quad.ShaderNum = BQS_SpecialColormap;
 		color0 = D3DCOLOR_COLORVALUE(parms.specialcolormap->Colorize[0]/2,
 			parms.specialcolormap->Colorize[1]/2, parms.specialcolormap->Colorize[2]/2, 1);
-		color1 = 0;
+		color1 = D3DCOLOR_ARGB(255,0,0,0);
 	}
 	else if (parms.colormapstyle != NULL)
 	{ // Emulate the fading from an in-game colormap (colorized, faded, and desaturated)