diff --git a/src/am_map.cpp b/src/am_map.cpp
index 57eccc19d2..9968f4ac43 100644
--- a/src/am_map.cpp
+++ b/src/am_map.cpp
@@ -1901,7 +1901,6 @@ void AM_drawSubsectors()
 	PalEntry flatcolor;
 	mpoint_t originpt;
 
-	screen->StartSimplePolys();
 	for (int i = 0; i < numsubsectors; ++i)
 	{
 		if (subsectors[i].flags & SSECF_POLYORG)
@@ -2058,7 +2057,6 @@ void AM_drawSubsectors()
 				);
 		}
 	}
-	screen->FinishSimplePolys();
 }
 
 //=============================================================================
diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp
index 82be8663e0..768392c6c6 100644
--- a/src/c_cvars.cpp
+++ b/src/c_cvars.cpp
@@ -181,6 +181,27 @@ void FBaseCVar::SetGenericRep (UCVarValue value, ECVarType type)
 	}
 }
 
+DEFINE_ACTION_FUNCTION(_CVar, GetInt)
+{
+	PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar);
+	auto v = self->GetGenericRep(CVAR_Int);
+	ACTION_RETURN_INT(v.Int);
+}
+
+DEFINE_ACTION_FUNCTION(_CVar, GetFloat)
+{
+	PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar);
+	auto v = self->GetGenericRep(CVAR_Float);
+	ACTION_RETURN_FLOAT(v.Int);
+}
+
+DEFINE_ACTION_FUNCTION(_CVar, GetString)
+{
+	PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar);
+	auto v = self->GetGenericRep(CVAR_String);
+	ACTION_RETURN_STRING(v.String);
+}
+
 bool FBaseCVar::ToBool (UCVarValue value, ECVarType type)
 {
 	switch (type)
diff --git a/src/dobject.cpp b/src/dobject.cpp
index 68f3aab8ec..747c1f9bfa 100644
--- a/src/dobject.cpp
+++ b/src/dobject.cpp
@@ -616,6 +616,10 @@ DEFINE_ACTION_FUNCTION(DObject, GetClassName)
 	ACTION_RETURN_INT(self->GetClass()->TypeName);
 }
 
+DEFINE_ACTION_FUNCTION(DObject, MSTime)
+{
+	ACTION_RETURN_INT(I_MSTime());
+}
 
 void *DObject::ScriptVar(FName field, PType *type)
 {
diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h
index 95739e86df..ed2c523f28 100644
--- a/src/gl/renderer/gl_renderer.h
+++ b/src/gl/renderer/gl_renderer.h
@@ -211,9 +211,6 @@ public:
 	bool StartOffscreen();
 	void EndOffscreen();
 
-	void StartSimplePolys();
-	void FinishSimplePolys();
-
 	void FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
 		double originx, double originy, double scalex, double scaley,
 		DAngle rotation, FDynamicColormap *colormap, PalEntry flatcolor, int lightlevel, int bottomclip);
diff --git a/src/menu/colorpickermenu.cpp b/src/menu/colorpickermenu.cpp
index 6f73a709e5..7fc3e2ecd8 100644
--- a/src/menu/colorpickermenu.cpp
+++ b/src/menu/colorpickermenu.cpp
@@ -118,81 +118,6 @@ public:
 		mBlue = (float)BPART(DWORD(*mCVar));
 	}
 
-	//=============================================================================
-	//
-	//
-	//
-	//=============================================================================
-
-	void Drawer()
-	{
-		Super::Drawer();
-
-		if (mCVar == NULL) return;
-		int y = (-mDesc->mPosition + BigFont->GetHeight() + mDesc->mItems.Size() * OptionSettings.mLinespacing) * CleanYfac_1;
-		int h = (screen->GetHeight() - y) / 16;
-		int fh = OptionSettings.mLinespacing * CleanYfac_1;
-		int w = fh;
-		int yy = y;
-
-		if (h > fh) h = fh;
-		else if (h < 4) return;	// no space to draw it.
-		
-		int indent = (screen->GetWidth() / 2);
-		int p = 0;
-
-		for(int i = 0; i < 16; i++, y += h)
-		{
-			int box_x, box_y;
-			int x1;
-
-			box_y = y - 2 * CleanYfac_1;
-			box_x = indent - 16*w;
-			for (x1 = 0; x1 < 16; ++x1, p++)
-			{
-				screen->Clear (box_x, box_y, box_x + w, box_y + h, p, 0);
-				if ((mDesc->mSelectedItem == mStartItem+7) && 
-					(/*p == CurrColorIndex ||*/ (i == mGridPosY && x1 == mGridPosX)))
-				{
-					int r, g, b;
-					DWORD col;
-					double blinky;
-					if (i == mGridPosY && x1 == mGridPosX)
-					{
-						r = 255, g = 128, b = 0;
-					}
-					else
-					{
-						r = 200, g = 200, b = 255;
-					}
-					// Make sure the cursors stand out against similar colors
-					// by pulsing them.
-					blinky = fabs(sin(I_MSTime()/1000.0)) * 0.5 + 0.5;
-					col = MAKEARGB(255,int(r*blinky),int(g*blinky),int(b*blinky));
-
-					screen->Clear (box_x, box_y, box_x + w, box_y + 1, -1, col);
-					screen->Clear (box_x, box_y + h-1, box_x + w, box_y + h, -1, col);
-					screen->Clear (box_x, box_y, box_x + 1, box_y + h, -1, col);
-					screen->Clear (box_x + w - 1, box_y, box_x + w, box_y + h, -1, col);
-				}
-				box_x += w;
-			}
-		}
-		y = yy;
-		DWORD newColor = MAKEARGB(255, int(mRed), int(mGreen), int(mBlue));
-		DWORD oldColor = DWORD(*mCVar) | 0xFF000000;
-
-		int x = screen->GetWidth()*2/3;
-
-		screen->Clear (x, y, x + 48*CleanXfac_1, y + 48*CleanYfac_1, -1, oldColor);
-		screen->Clear (x + 48*CleanXfac_1, y, x + 48*2*CleanXfac_1, y + 48*CleanYfac_1, -1, newColor);
-
-		y += 49*CleanYfac_1;
-		screen->DrawText (SmallFont, CR_GRAY, x+(24-SmallFont->StringWidth("Old")/2)*CleanXfac_1, y,
-			"Old", DTA_CleanNoMove_1, true, TAG_DONE);
-		screen->DrawText (SmallFont, CR_WHITE, x+(48+24-SmallFont->StringWidth("New")/2)*CleanXfac_1, y,
-			"New", DTA_CleanNoMove_1, true, TAG_DONE);
-	}
 };
 
 IMPLEMENT_CLASS(DColorPickerMenu, true, false)
diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp
index adaf1990c7..1f3ac189ec 100644
--- a/src/menu/menu.cpp
+++ b/src/menu/menu.cpp
@@ -357,6 +357,26 @@ void DMenu::Drawer ()
 	}
 }
 
+
+DEFINE_ACTION_FUNCTION(DMenu, Drawer)
+{
+	PARAM_SELF_PROLOGUE(DMenu);
+	self->Drawer();
+	return 0;
+}
+
+void DMenu::CallDrawer()
+{
+	IFVIRTUAL(DMenu, Drawer)
+	{
+		VMValue params[] = { (DObject*)this };
+		GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
+	}
+	else Drawer();
+}
+
+
+
 bool DMenu::DimAllowed()
 {
 	return true;
@@ -800,7 +820,7 @@ void M_Drawer (void)
 			screen->Dim(fade);
 			V_SetBorderNeedRefresh();
 		}
-		DMenu::CurrentMenu->Drawer();
+		DMenu::CurrentMenu->CallDrawer();
 	}
 }
 
diff --git a/src/menu/menu.h b/src/menu/menu.h
index ceab87603b..e8d5b9a823 100644
--- a/src/menu/menu.h
+++ b/src/menu/menu.h
@@ -245,6 +245,7 @@ public:
 
 	bool CallMenuEvent(int mkey, bool fromcontroller);
 	bool CallMouseEvent(int type, int x, int y);
+	void CallDrawer();
 
 	bool MouseEventBack(int type, int x, int y);
 	void SetCapture();
diff --git a/src/menu/menuinput.cpp b/src/menu/menuinput.cpp
index ab372a6ae8..67f34635ee 100644
--- a/src/menu/menuinput.cpp
+++ b/src/menu/menuinput.cpp
@@ -297,7 +297,7 @@ bool DTextEnterMenu::MenuEvent (int key, bool fromcontroller)
 
 void DTextEnterMenu::Drawer ()
 {
-	mParentMenu->Drawer();
+	mParentMenu->CallDrawer();
 	if (mInputGridOkay)
 	{
 		const int cell_width = 18 * CleanXfac;
diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h
index 904bf8ff87..a7c16ec8c4 100644
--- a/src/menu/optionmenuitems.h
+++ b/src/menu/optionmenuitems.h
@@ -426,7 +426,7 @@ public:
 
 	void Drawer()
 	{
-		mParentMenu->Drawer();
+		mParentMenu->CallDrawer();
 	}
 };
 
diff --git a/src/v_draw.cpp b/src/v_draw.cpp
index 4b90720157..d2b09b0d10 100644
--- a/src/v_draw.cpp
+++ b/src/v_draw.cpp
@@ -498,12 +498,15 @@ static void ListEnd(VMVa_List &tags)
 
 int ListGetInt(VMVa_List &tags)
 {
-	if (tags.curindex < tags.numargs && tags.args[tags.curindex].Type == REGT_INT)
+	if (tags.curindex < tags.numargs)
 	{
-		return tags.args[tags.curindex++].i;
+		if (tags.args[tags.curindex].Type == REGT_INT)
+		{
+			return tags.args[tags.curindex++].i;
+		}
+		ThrowAbortException(X_OTHER, "Invalid parameter in draw function, int expected");
 	}
-	ThrowAbortException(X_OTHER, "Invalid parameter in draw function, int expected");
-	return 0;
+	return TAG_DONE;
 }
 
 static inline double ListGetDouble(VMVa_List &tags)
@@ -1350,18 +1353,18 @@ void DCanvas::Clear (int left, int top, int right, int bottom, int palcolor, uin
 	}
 }
 
-//==========================================================================
-//
-// no-ops. This is so that renderer backends can better manage the
-// processing of the subsector drawing in the automap
-//
-//==========================================================================
-
-void DCanvas::StartSimplePolys()
-{}
-
-void DCanvas::FinishSimplePolys()
-{}
+DEFINE_ACTION_FUNCTION(_Screen, Clear)
+{
+	PARAM_PROLOGUE;
+	PARAM_INT(x1);
+	PARAM_INT(y1);
+	PARAM_INT(x2);
+	PARAM_INT(y2);
+	PARAM_INT(color);
+	PARAM_INT_DEF(palcol);
+	screen->Clear(x1, y1, x2, y2, palcol, color);
+	return 0;
+}
 
 //==========================================================================
 //
diff --git a/src/v_text.cpp b/src/v_text.cpp
index 8b612e83ce..85b3de7db1 100644
--- a/src/v_text.cpp
+++ b/src/v_text.cpp
@@ -46,6 +46,7 @@
 
 #include "doomstat.h"
 #include "templates.h"
+#include "gstrings.h"
 
 int ListGetInt(VMVa_List &tags);
 
@@ -239,7 +240,8 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawText)
 	PARAM_STRING(chr);
 
 	VMVa_List args = { param + 5, 0, numparam - 5 };
-	screen->DrawText(font, cr, x, y, chr, args);
+	const char *txt = chr[0] == '$' ? GStrings(chr) : chr.GetChars();
+	screen->DrawText(font, cr, x, y, txt, args);
 	return 0;
 }
 
diff --git a/src/v_video.h b/src/v_video.h
index a2586d5a75..72474ee288 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -228,9 +228,6 @@ public:
 	// Fill an area with a texture
 	virtual void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin=false);
 
-	virtual void StartSimplePolys();
-	virtual void FinishSimplePolys();
-
 	// Fill a simple polygon with a texture
 	virtual void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
 		double originx, double originy, double scalex, double scaley, DAngle rotation,
diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt
index 863e8d010d..8e77c32121 100644
--- a/wadsrc/static/zscript/base.txt
+++ b/wadsrc/static/zscript/base.txt
@@ -103,6 +103,32 @@ enum DrawTextureTags
 };
 
 struct Screen native
+{
+	int CleanWidth, CleanHeight;
+	int CleanXFac, CleanYFac;
+	int CleanWidth_1, CleanHeight_1;
+	int CleanXFac_1, CleanYFac_1;
+	
+	native static Color PaletteColor(int index);
+	native static int GetWidth();
+	native static int GetHeight();
+	native static void Clear(int left, int top, int right, int bottom, Color color, int palcolor = -1);
+
+	native static void DrawHUDTexture(TextureID tex, double x, double y);
+	native static vararg void DrawTexture(TextureID tex, bool animate, double x, double y, ...);
+	native static vararg void DrawChar(Font font, int normalcolor, double x, double y, int character, ...);
+	native static vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...);
+
+}
+
+class BrokenLines : Object native
+{
+	native int Count();
+	native int StringWidth(int line);
+	native String StringAt(int line);
+}
+
+struct Font native
 {
 	enum EColorRange
 	{
@@ -132,31 +158,7 @@ struct Screen native
 		CR_CYAN,
 		NUM_TEXT_COLORS
 	};
-	
-	int CleanWidth, CleanHeight;
-	int CleanXFac, CleanYFac;
-	int CleanWidth_1, CleanHeight_1;
-	int CleanXFac_1, CleanYFac_1;
-	
-	native static Color PaletteColor(int index);
-	native static int GetWidth();
-	native static int GetHeight();
-	native static void DrawHUDTexture(TextureID tex, double x, double y);
-	native static vararg void DrawTexture(TextureID tex, bool animate, double x, double y, ...);
-	native static vararg void DrawChar(Font font, int normalcolor, double x, double y, int character, ...);
-	native static vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...);
 
-}
-
-class BrokenLines : Object native
-{
-	native int Count();
-	native int StringWidth(int line);
-	native String StringAt(int line);
-}
-
-struct Font native
-{
 	native int GetCharWidth(int code);
 	native int StringWidth(String code);
 	native int GetHeight();
@@ -180,6 +182,9 @@ struct DamageTypeDefinition native
 
 struct CVar native
 {
+	native int GetInt();
+	native double GetFloat();
+	native String GetString();
 }
 
 struct GameInfoStruct native
@@ -207,6 +212,7 @@ class Object native
 	native static bool S_ChangeMusic(String music_name, int order = 0, bool looping = true, bool force = false);
 	native static uint BAM(double angle);
 	native static void SetMusicVolume(float vol);
+	native static uint MSTime();
 
 	native Name GetClassName();
 	native void Destroy();
diff --git a/wadsrc/static/zscript/menu/colorpickermenu.txt b/wadsrc/static/zscript/menu/colorpickermenu.txt
index 2ed3cf0763..30c2a183ea 100644
--- a/wadsrc/static/zscript/menu/colorpickermenu.txt
+++ b/wadsrc/static/zscript/menu/colorpickermenu.txt
@@ -1,3 +1,36 @@
+/*
+** colorpickermenu.txt
+** The color picker menu
+**
+**---------------------------------------------------------------------------
+** Copyright 2010-2017 Christoph Oelckers
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+**    derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**---------------------------------------------------------------------------
+**
+*/
 
 class ColorpickerMenu : Menu native
 {
@@ -147,5 +180,81 @@ class ColorpickerMenu : Menu native
 		return res;
 	}
 
+	//=============================================================================
+	//
+	//
+	//
+	//=============================================================================
+
+	override void Drawer()
+	{
+		Super.Drawer();
+
+		if (mCVar == null) return;
+		int y = (-mDesc.mPosition + BigFont.GetHeight() + mDesc.mItems.Size() * OptionMenuSettings.mLinespacing) * CleanYfac_1;
+		int fh = OptionMenuSettings.mLinespacing * CleanYfac_1;
+		int h = (screen.GetHeight() - y) / 16;
+		int w = fh;
+		int yy = y;
+
+		if (h > fh) h = fh;
+		else if (h < 4) return;	// no space to draw it.
+		
+		int indent = (screen.GetWidth() / 2);
+		int p = 0;
+
+		for(int i = 0; i < 16; i++)
+		{
+			int box_x, box_y;
+			int x1;
+
+			box_y = y - 2 * CleanYfac_1;
+			box_x = indent - 16*w;
+			for (x1 = 0; x1 < 16; ++x1)
+			{
+				screen.Clear (box_x, box_y, box_x + w, box_y + h, 0, p);
+				if ((mDesc.mSelectedItem == mStartItem+7) && 
+					(/*p == CurrColorIndex ||*/ (i == mGridPosY && x1 == mGridPosX)))
+				{
+					int r, g, b;
+					Color col;
+					double blinky;
+					if (i == mGridPosY && x1 == mGridPosX)
+					{
+						r = 255; g = 128; b = 0;
+					}
+					else
+					{
+						r = 200; g = 200; b = 255;
+					}
+					// Make sure the cursors stand out against similar colors
+					// by pulsing them.
+					blinky = abs(sin(MSTime()/1000.0)) * 0.5 + 0.5;
+					col = Color(255, int(r*blinky), int(g*blinky), int(b*blinky));
+
+					screen.Clear (box_x, box_y, box_x + w, box_y + 1, col);
+					screen.Clear (box_x, box_y + h-1, box_x + w, box_y + h, col);
+					screen.Clear (box_x, box_y, box_x + 1, box_y + h, col);
+					screen.Clear (box_x + w - 1, box_y, box_x + w, box_y + h, col);
+				}
+				box_x += w;
+				p++;
+			}
+			y += h;
+		}
+		y = yy;
+		color newColor = Color(255, int(mRed), int(mGreen), int(mBlue));
+		color oldColor = mCVar.GetInt() | 0xFF000000;
+
+		int x = screen.GetWidth()*2/3;
+
+		screen.Clear (x, y, x + 48*CleanXfac_1, y + 48*CleanYfac_1, oldColor);
+		screen.Clear (x + 48*CleanXfac_1, y, x + 48*2*CleanXfac_1, y + 48*CleanYfac_1, newColor);
+
+		y += 49*CleanYfac_1;
+		screen.DrawText (SmallFont, Font.CR_GRAY, x+(24-SmallFont.StringWidth("Old")/2)*CleanXfac_1, y, "Old", DTA_CleanNoMove_1, true);
+		screen.DrawText (SmallFont, Font.CR_WHITE, x+(48+24-SmallFont.StringWidth("New")/2)*CleanXfac_1, y, "New", DTA_CleanNoMove_1, true);
+	}
+	
 	
 }
\ No newline at end of file
diff --git a/wadsrc/static/zscript/menu/menu.txt b/wadsrc/static/zscript/menu/menu.txt
index 14ff55fb92..c759e83510 100644
--- a/wadsrc/static/zscript/menu/menu.txt
+++ b/wadsrc/static/zscript/menu/menu.txt
@@ -33,6 +33,7 @@ class Menu : Object native
 	
 	native virtual bool MenuEvent (int mkey, bool fromcontroller);
 	native virtual bool MouseEvent(int type, int mx, int my);
+	native virtual void Drawer();
 	
 	void MenuSound(Sound snd)
 	{