diff --git a/source/blood/src/levels.cpp b/source/blood/src/levels.cpp
index 08c519eea..4392aed8b 100644
--- a/source/blood/src/levels.cpp
+++ b/source/blood/src/levels.cpp
@@ -218,11 +218,17 @@ void levelLoadMapInfo(IniFile *pIni, MapRecord *pLevelInfo, const char *pzSectio
     }
 }
 
+static const char* DefFile(void)
+{
+    // The command line parser stores this in the CON field.
+    return userConfig.DefaultCon.IsNotEmpty() ? userConfig.DefaultCon.GetChars() : "blood.ini";
+}
+
 void levelLoadDefaults(void)
 {
     char buffer[64];
     char buffer2[16];
-    levelInitINI(G_ConFile());	// This doubles for the INI in the global code.
+    levelInitINI(DefFile());
     memset(gEpisodeInfo, 0, sizeof(gEpisodeInfo));
     quoteMgr.InitializeQuote(MUS_INTRO, "PESTIS.MID");
     int i;
diff --git a/source/common/scripting/interface/vmnatives.cpp b/source/common/scripting/interface/vmnatives.cpp
index 74cba2701..e1aa14957 100644
--- a/source/common/scripting/interface/vmnatives.cpp
+++ b/source/common/scripting/interface/vmnatives.cpp
@@ -541,7 +541,7 @@ DEFINE_ACTION_FUNCTION(_CVar, FindCVar)
 //
 //
 //=============================================================================
-
+#if 0
 DEFINE_ACTION_FUNCTION(FKeyBindings, SetBind)
 {
 	PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings);
@@ -606,7 +606,7 @@ DEFINE_ACTION_FUNCTION(DOptionMenuItemCommand, DoCommand)
 	C_DoCommand(cmd);
 	return 0;
 }
-
+#endif
 DEFINE_ACTION_FUNCTION(_Console, MidPrint)
 {
 	PARAM_PROLOGUE;
diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp
index e1b30cf74..1dba146be 100644
--- a/source/core/gamecontrol.cpp
+++ b/source/core/gamecontrol.cpp
@@ -406,6 +406,32 @@ void UserConfig::ProcessOptions()
 
 }
 
+//==========================================================================
+//
+//
+//
+//==========================================================================
+
+void CheckUserMap()
+{
+	if (userConfig.CommandMap.IsEmpty()) return;
+	FString startupMap = userConfig.CommandMap;
+	if (startupMap.IndexOfAny("/\\") < 0) startupMap.Insert(0, "/");
+	DefaultExtension(startupMap, ".map");
+	startupMap.Substitute("\\", "/");
+	NormalizeFileName(startupMap);
+
+	if (fileSystem.FileExists(startupMap))
+	{
+		Printf("Using level: \"%s\".\n", startupMap.GetChars());
+	}
+	else
+	{
+		Printf("Level \"%s\" not found.\n", startupMap.GetChars());
+		startupMap = "";
+	}
+	userConfig.CommandMap = startupMap;
+}
 
 //==========================================================================
 //
@@ -798,6 +824,7 @@ int RunGame()
 	{
 		playername = userConfig.CommandName;
 	}
+	CheckUserMap();
 	GPalette.Init(MAXPALOOKUPS + 2);    // one slot for each translation, plus a separate one for the base palettes and the internal one
 	TexMan.Init([]() {}, [](BuildInfo &) {});
 	V_InitFonts();
@@ -811,7 +838,6 @@ int RunGame()
 	LoadScripts();
 	M_Init();
 	SetDefaultStrings();
-	if (g_gameType & (GAMEFLAG_RR)) InitRREndMap();	// this needs to be done better later
 	if (Args->CheckParm("-sounddebug"))
 		C_DoCommand("stat sounddebug");
 
diff --git a/source/core/gamecontrol.h b/source/core/gamecontrol.h
index b2afefcf2..d9222d9ae 100644
--- a/source/core/gamecontrol.h
+++ b/source/core/gamecontrol.h
@@ -146,8 +146,6 @@ struct GrpEntry
 extern int g_gameType;
 const char* G_DefaultDefFile(void);
 const char* G_DefFile(void);
-const char* G_DefaultConFile(void);
-const char* G_ConFile(void);
 
 // game check shortcuts
 inline bool isNam()
diff --git a/source/core/mapinfo.cpp b/source/core/mapinfo.cpp
index daa4c1627..611a2c9d2 100644
--- a/source/core/mapinfo.cpp
+++ b/source/core/mapinfo.cpp
@@ -134,13 +134,3 @@ MapRecord* SetupUserMap(const char* boardfilename, const char *defaultmusic)
 	map->music = G_SetupFilenameBasedMusic(boardfilename, defaultmusic);
 	return map;
 }
-
-
-
-void InitRREndMap()
-{
-	// RR defines its end map ad-hoc so give it a proper entry to reference (the last one in episode 2 because it needs to be in Ep. 2.)
-	mapList[127].SetName("$TXT_CLOSEENCOUNTERS");
-	mapList[127].SetFileName("endgame.map");
-	mapList[127].levelNumber = 163;	// last one in Ep. 2.
-}
diff --git a/source/core/mapinfo.h b/source/core/mapinfo.h
index fddf666ec..340184e40 100644
--- a/source/core/mapinfo.h
+++ b/source/core/mapinfo.h
@@ -73,7 +73,6 @@ extern MapRecord mapList[512];
 extern MapRecord *currentLevel;	
 
 bool SetMusicForMap(const char* mapname, const char* music, bool namehack = false);
-void InitRREndMap();
 
 MapRecord *FindMapByName(const char *nm);
 MapRecord *FindMapByLevelNum(int num);
diff --git a/source/core/menu/savegamemanager.cpp b/source/core/menu/savegamemanager.cpp
index b0a0d2c49..2f6bf131f 100644
--- a/source/core/menu/savegamemanager.cpp
+++ b/source/core/menu/savegamemanager.cpp
@@ -58,6 +58,7 @@ FSavegameManager savegameManager;
 
 void FSavegameManager::LoadGame(FSaveGameNode* node)
 {
+	inputState.ClearAllInput();
 	if (gi->CleanupForLoad())
 	{
 		if (OpenSaveGameForRead(node->Filename))
diff --git a/source/core/searchpaths.cpp b/source/core/searchpaths.cpp
index c0ede06df..0e552bf9c 100644
--- a/source/core/searchpaths.cpp
+++ b/source/core/searchpaths.cpp
@@ -924,53 +924,6 @@ const char* G_DefFile(void)
 }
 
 
-//==========================================================================
-//
-// Fallback in case nothing got defined.
-// Also used by 'includedefault' which forces this to be statically defined
-//
-//==========================================================================
-
-const char* G_DefaultConFile(void)
-{
-	if (g_gameType & GAMEFLAG_BLOOD)
-		return "blood.ini";	// Blood doesn't have CON files but the common code treats its INI files the same, so return that here.
-
-	if (g_gameType & GAMEFLAG_WW2GI)
-	{
-		if (fileSystem.FindFile("ww2gi.con") >= 0) return "ww2gi.con";
-	}
-
-	if (g_gameType & (GAMEFLAG_SW|GAMEFLAG_PSEXHUMED))
-		return nullptr;	// Exhumed and SW have no scripts of any kind.
-
-	if (g_gameType & GAMEFLAG_NAM)
-	{
-		if (fileSystem.FindFile("nam.con") >= 0) return "nam.con";
-		if (fileSystem.FindFile("napalm.con") >= 0) return "napalm.con";
-	}
-
-	if (g_gameType & GAMEFLAG_NAPALM)
-	{
-		if (fileSystem.FindFile("napalm.con") >= 0) return "napalm.con";
-		if (fileSystem.FindFile("nam.con") >= 0) return "nam.con";
-	}
-
-	if (g_gameType & GAMEFLAG_DUKE)
-	{
-		if (fileSystem.FindFile("eduke.con") >= 0) return "eduke.con";	// No, we're not EDUKE, but several mods expect this to work.
-	}
-
-	// the other games only use game.con.
-	return "game.con";
-}
-
-const char* G_ConFile(void)
-{
-	return userConfig.DefaultCon.IsNotEmpty() ? userConfig.DefaultCon.GetChars() : G_DefaultConFile();
-}
-
-
 #if 0
 // Should this be added to the game data collector?
 bool AddINIFile(const char* pzFile, bool bForce = false)
diff --git a/source/games/duke/src/2d_r.cpp b/source/games/duke/src/2d_r.cpp
index c5a989cc0..a5f13c7c3 100644
--- a/source/games/duke/src/2d_r.cpp
+++ b/source/games/duke/src/2d_r.cpp
@@ -572,7 +572,7 @@ void dobonus_r(bool bonusonly, CompletionFunc completion)
 	}
 	else if (!bonusonly && ud.multimode <= 1)
 	{
-		if (isRRRA() && !boardfilename[0] && currentLevel->levelNumber < 106) // fixme: The logic here is awful. Shift more control to the map records.
+		if (isRRRA() && !(currentLevel->flags & MI_USERMAP) && currentLevel->levelNumber < 106) // fixme: The logic here is awful. Shift more control to the map records.
 		{
 			jobs[job++] = { Create<DRRLevelSummaryScreen>(true) };
 			int levnum = clamp((currentLevel->levelNumber / 100) * 7 + (currentLevel->levelNumber % 100), 0, 13);
diff --git a/source/games/duke/src/ccmds.cpp b/source/games/duke/src/ccmds.cpp
index d75123b2c..2d71ab993 100644
--- a/source/games/duke/src/ccmds.cpp
+++ b/source/games/duke/src/ccmds.cpp
@@ -161,6 +161,8 @@ static int ccmd_restartmap(CCmdFuncPtr)
     return CCMD_OK;
 }
 
+int getlabelvalue(const char* text);
+
 static int ccmd_spawn(CCmdFuncPtr parm)
 {
     int x = 0, y = 0, z = 0;
@@ -191,20 +193,8 @@ static int ccmd_spawn(CCmdFuncPtr parm)
             picnum = (unsigned short)atol(parm->parms[0]);
         }
         else {
-            int i, j;
-            for (j = 0; j < 2; j++) {
-                for (i = 0; i < labelcnt; i++) {
-                    if (
-                        (j == 0 && !strcmp(label + (i * MAXLABELLEN), parm->parms[0])) ||
-                        (j == 1 && !stricmp(label + (i * MAXLABELLEN), parm->parms[0]))
-                        ) {
-                        picnum = (unsigned short)labelcode[i];
-                        break;
-                    }
-                }
-                if (i < labelcnt) break;
-            }
-            if (i == labelcnt) {
+            picnum = getlabelvalue(parm->parms[0]);
+            if (picnum < 0) {
                 Printf("spawn: Invalid tile label given\n");
                 return CCMD_OK;
             }
diff --git a/source/games/duke/src/game.h b/source/games/duke/src/game.h
index 311884ad5..18e96ad27 100644
--- a/source/games/duke/src/game.h
+++ b/source/games/duke/src/game.h
@@ -43,8 +43,6 @@ extern int rtsplaying;
 
 #ifndef ONLY_USERDEFS
 
-extern char boardfilename[BMAX_PATH];
-
 extern int32_t g_Shareware;
 extern int32_t cameraclock;
 extern int32_t cameradist;
diff --git a/source/games/duke/src/gamedef.cpp b/source/games/duke/src/gamedef.cpp
index 4340f73ee..05072a614 100644
--- a/source/games/duke/src/gamedef.cpp
+++ b/source/games/duke/src/gamedef.cpp
@@ -46,11 +46,10 @@ into many sub-files.
 
 BEGIN_DUKE_NS
 
+
 // parser state: todo: turn into a class
 char* textptr;
-char* label;
 int line_number;
-int labelcnt;
 int errorcount, warningcount;	// was named 'error' and 'warning' which is too generic for public variables and may clash with other code.
 int g_currentSourceFile;
 uint32_t parsing_actor, parsing_event;
@@ -60,7 +59,6 @@ int checking_ifelse;
 
 //G_EXTERN char tempbuf[MAXSECTORS << 1], buf[1024]; todo - move to compile state. tempbuf gets used nearly everywhere as scratchpad memory.
 extern char tempbuf[];
-extern int* labelcode;
 
 TArray<int> ScriptCode;
 
@@ -111,6 +109,62 @@ void SortCommands()
 	qsort(cmdList, countof(cmdList), sizeof(ConCommand), cmdCmp);
 }
 
+//---------------------------------------------------------------------------
+//
+// label data
+//
+//---------------------------------------------------------------------------
+
+enum labeltypes {
+	LABEL_ANY = -1,
+	LABEL_DEFINE = 1,
+	LABEL_STATE = 2,
+	LABEL_ACTOR = 4,
+	LABEL_ACTION = 8,
+	LABEL_AI = 16,
+	LABEL_MOVE = 32,
+};
+
+static const char* labeltypenames[] = {
+	"define",
+	"state",
+	"actor",
+	"action",
+	"ai",
+	"move"
+};
+
+class labelstring
+{
+	char text[64];
+
+public:
+	char& operator[](size_t pos)
+	{
+		return text[pos];
+	}
+	operator const char* () { return text; }
+	const char* GetChars() { return text; }
+	int compare(const char* c) const { return strcmp(text, c); }
+	int comparei(const char* c) const { return stricmp(text, c); }
+	labelstring& operator=(const char* c) { strncpy(text, c, 64); text[63] = 0; }
+
+};
+
+struct labeldef
+{
+	labelstring name;
+	labeltypes type;
+	int value;
+
+	int compare(const char* c) const { return name.compare(c); }
+	const char* GetChars() { return name.GetChars(); }
+
+};
+
+TArray<labeldef> labels;
+static labelstring parselabel;
+
 //---------------------------------------------------------------------------
 //
 // 
@@ -138,7 +192,7 @@ void ReportError(int iError)
 	{
 	case ERROR_ISAKEYWORD:
 		Printf(TEXTCOLOR_RED "  * ERROR!(%s, line %d) Symbol '%s' is a key word.\n",
-			fn, line_number, label + (labelcnt << 6));
+			fn, line_number, parselabel.GetChars());
 		break;
 	case ERROR_PARMUNDEFINED:
 		Printf(TEXTCOLOR_RED "  * ERROR!(%s, line %d) Parameter '%s' is undefined.\n",
@@ -146,23 +200,23 @@ void ReportError(int iError)
 		break;
 	case WARNING_DUPLICATEDEFINITION:
 		Printf(TEXTCOLOR_YELLOW "  * WARNING.(%s, line %d) Duplicate definition '%s' ignored.\n",
-			fn, line_number, label + (labelcnt << 6));
+			fn, line_number, parselabel.GetChars());
 		break;
 	case ERROR_COULDNOTFIND:
 		Printf(TEXTCOLOR_RED "  * ERROR!(%s, line %d) Could not find '%s'.\n",
-			fn, line_number, label + (labelcnt << 6));
+			fn, line_number, parselabel.GetChars());
 		break;
 	case ERROR_VARREADONLY:
 		Printf(TEXTCOLOR_RED "  * ERROR!(%s, line %d) Variable '%s' is read-only.\n",
-			fn, line_number, label + (labelcnt << 6));
+			fn, line_number, parselabel.GetChars());
 		break;
 	case ERROR_NOTAGAMEDEF:
 		Printf(TEXTCOLOR_RED "  * ERROR!(%s, line %d) Symbol '%s' is not a Game Definition.\n",
-			fn, line_number, label + (labelcnt << 6));
+			fn, line_number, parselabel.GetChars());
 		break;
 	case ERROR_NOTAGAMEVAR:
 		Printf(TEXTCOLOR_RED "  * ERROR! (%s, line %d) Symbol '%s' is not a defined Game Variable.\n",
-			fn, line_number, label + (labelcnt << 6));
+			fn, line_number, parselabel.GetChars());
 		break;
 	case ERROR_OPENBRACKET:
 		Printf(TEXTCOLOR_RED "  * ERROR! (%s, line %d) Found more '{' than '}' before '%s'.\n",
@@ -218,18 +272,48 @@ int getkeyword(const char* text)
 //
 //---------------------------------------------------------------------------
 
-int findlabel(const char* text)
+FString translatelabeltype(int type)
 {
-	for (int j = 0; j < labelcnt; j++)
+	FString buf;
+	for (int i = 0; i < 6; i++) 
 	{
-		if (strcmp(label + (j << 6), text) == 0)
+		if (!(type & (1 << i))) continue;
+		if (buf.Len()) buf += " or ";
+		buf += labeltypenames[i];
+	}
+	return buf;
+}
+
+int findlabel(const char* text, bool ignorecase = false)
+{
+	for (unsigned j = 0; j < labels.Size(); j++)
+	{
+		if (labels[j].compare(text) == 0)
 		{
 			return j;
 		}
 	}
+	if (ignorecase)
+	{
+		for (unsigned j = 0; j < labels.Size(); j++)
+		{
+			if (labels[j].name.comparei(text) == 0)
+			{
+				return j;
+			}
+		}
+	}
 	return -1;
 }
 
+// This is for the 'spawn' CCMD.
+int getlabelvalue(const char* text)
+{
+	int lnum = findlabel(text, true);
+	if (labels[lnum].type != LABEL_DEFINE) return -1;
+	return lnum < 0 ? -1 : labels[lnum].value;
+}
+
 //---------------------------------------------------------------------------
 //
 // 
@@ -367,9 +451,9 @@ void getlabel(void)
 
 	i = 0;
 	while (ispecial(*textptr) == 0)
-		label[(labelcnt << 6) + i++] = *(textptr++);
+		parselabel[i++] = *(textptr++);
 
-	label[(labelcnt << 6) + i] = 0;
+	parselabel[i] = 0;
 }
 
 //---------------------------------------------------------------------------
@@ -413,21 +497,20 @@ void pushlabeladdress()
 }
 */
 
-
-void appendlabeladdress(int offset = 0)
+void appendlabelvalue(labeltypes type, int value)
 {
-	labelcode[labelcnt++] = ScriptCode.Size() + offset;
-	labelcnt++;
+	labels.Reserve(1);
+	labels.Last().type = type;
+	labels.Last().name = parselabel;
+	labels.Last().value = value;
 }
 
-void appendlabelvalue(int value)
+void appendlabeladdress(labeltypes type, int offset = 0)
 {
-	labelcode[labelcnt++] = value;
-	labelcnt++;
+	appendlabelvalue(type, ScriptCode.Size() + offset);
 }
 
 
-
 //---------------------------------------------------------------------------
 //
 // 
@@ -493,9 +576,9 @@ int transword(void) //Returns its code #
 //
 //---------------------------------------------------------------------------
 
-int transnum(void)
+int transnum(int type)
 {
-	int i, l;
+	int l;
 
 	while (isaltok(*textptr) == 0)
 	{
@@ -525,13 +608,24 @@ int transnum(void)
 	}
 
 
-	for (i = 0; i < labelcnt; i++)
+	for (unsigned i = 0; i < labels.Size(); i++)
 	{
-		if (strcmp(tempbuf, label + (i << 6)) == 0)
+		if (labels[i].compare(tempbuf) == 0)
 		{
-			appendscriptvalue(labelcode[i]);
+			// Non-values can be compared with 0.
+			if (labels[i].type & type || (labels[i].value == 0))
+			{
+				appendscriptvalue(labels[i].value);
+				textptr += l;
+				return labels[i].value;
+			}
+			appendscriptvalue(0);
 			textptr += l;
-			return labelcode[i];
+			auto el = translatelabeltype(type);
+			auto gl = translatelabeltype(labels[i].type);
+			const char* fn = fileSystem.GetFileFullName(g_currentSourceFile);
+			Printf(TEXTCOLOR_YELLOW "  * WARNING.(%s, line %d) %s: Expected a '%s' label but found a '%s' label instead.\n", fn, line_number, labels[i].GetChars(), el.GetChars(), gl.GetChars());
+			return -1;  // valid label name, but wrong type
 		}
 	}
 
@@ -553,14 +647,22 @@ int transnum(void)
 	// that ignores octal conversion.
 	int64_t value;
 	char *outp;
-	bool ishex = (textptr[0] == 0 && tolower(textptr[1]) == 'x') || (textptr[0] == '-' && textptr[1] == 0 && tolower(textptr[2]) == 'x');
-	if (*textptr == '-') value = strtoll(textptr, &outp, ishex? 16 : 10);
-	else value = strtoull(textptr, &outp, ishex ? 16 : 10);
+	bool ishex = (textptr[0] == '0' && tolower(textptr[1]) == 'x') || (textptr[0] == '-' && textptr[1] == '0' && tolower(textptr[2]) == 'x');
+	if (*textptr == '-') value = strtoll(textptr, &outp, ishex? 0 : 10);
+	else value = strtoull(textptr, &outp, ishex ? 0 : 10);
 	if (*outp != 0)
 	{
 		// conversion was not successful.
 	}
 	appendscriptvalue(int(value));	// truncate the parsed value to 32 bit.
+
+	if (type != LABEL_DEFINE && value != 0)
+	{
+		const char* fn = fileSystem.GetFileFullName(g_currentSourceFile);
+		Printf(TEXTCOLOR_YELLOW "  * WARNING.(%s, line %d) Expected an identifier, got a numeric literal %d.\n", fn, line_number, (int)value);
+	}
+
+
 	textptr += l;
 	return int(value);
 }
@@ -574,7 +676,7 @@ int transnum(void)
 
 void checkforkeyword()
 {
-	if (getkeyword(label + (labelcnt << 6)) >= 0)
+	if (getkeyword(parselabel) >= 0)
 	{
 		errorcount++;
 		ReportError(ERROR_ISAKEYWORD);
@@ -614,7 +716,7 @@ int parsecommand()
 		{
 			getlabel();
 			popscriptvalue();
-			appendlabeladdress();
+			appendlabeladdress(LABEL_STATE);
 
 			parsing_state = 1;
 
@@ -624,14 +726,14 @@ int parsecommand()
 		getlabel();
 		checkforkeyword();
 
-		lnum = findlabel(label + (labelcnt << 6));
+		lnum = findlabel(parselabel);
 
 		if (lnum < 0)
 		{
-			Printf(TEXTCOLOR_RED "  * ERROR!(%s, line %d) State '%s' not found.\n", fn, line_number, label + (labelcnt << 6));
+			Printf(TEXTCOLOR_RED "  * ERROR!(%s, line %d) State '%s' not found.\n", fn, line_number, parselabel.GetChars());
 			errorcount++;
 		}
-		appendscriptvalue(labelcode[lnum]);
+		appendscriptvalue(labels[lnum].value);
 		return 0;
 
 	case concmd_ends:
@@ -665,25 +767,25 @@ int parsecommand()
 		// Check to see it's already defined
 		popscriptvalue();
 
-		if (getkeyword(label + (labelcnt << 6)) >= 0)
+		if (getkeyword(parselabel) >= 0)
 		{
 			errorcount++;
 			ReportError(ERROR_ISAKEYWORD);
 			return 0;
 		}
 
-		transnum();	// get initial value
+		transnum(LABEL_DEFINE);	// get initial value
 		j = popscriptvalue();
 
-		transnum();	// get flags
+		transnum(LABEL_DEFINE);	// get flags
 		lnum = popscriptvalue();
-		AddGameVar(label + (labelcnt << 6), j, lnum & (~(GAMEVAR_FLAG_DEFAULT | GAMEVAR_FLAG_SECRET)));
+		AddGameVar(parselabel, j, lnum & (~(GAMEVAR_FLAG_DEFAULT | GAMEVAR_FLAG_SECRET)));
 		return 0;
 
 	case concmd_define:
 		getlabel();
 		checkforkeyword();
-		lnum = findlabel(label + (labelcnt << 6));
+		lnum = findlabel(parselabel);
 		if (lnum >= 0)
 		{
 			warningcount++;
@@ -691,11 +793,11 @@ int parsecommand()
 			break;
 		}
 
-		transnum();
+		transnum(LABEL_DEFINE);
 		i = popscriptvalue();
 		if (lnum < 0)
 		{
-			appendlabelvalue(i);
+			appendlabelvalue(LABEL_DEFINE, i);
 		}
 		popscriptvalue();
 		return 0;
@@ -705,7 +807,7 @@ int parsecommand()
 		for (j = 0; j < 4; j++)
 		{
 			if (keyword() == -1)
-				transnum();
+				transnum(LABEL_DEFINE);
 			else break;
 		}
 
@@ -719,12 +821,12 @@ int parsecommand()
 	case concmd_move:
 		if (parsing_actor || parsing_state)
 		{
-			transnum();
+			transnum(LABEL_MOVE);
 
 			j = 0;
 			while (keyword() == -1)
 			{
-				transnum();
+				transnum(LABEL_DEFINE);
 				j |= popscriptvalue();
 			}
 			appendscriptvalue(j);
@@ -737,19 +839,19 @@ int parsecommand()
 
 			checkforkeyword();
 
-			for (i = 0; i < labelcnt; i++)
-				if (strcmp(label + (labelcnt << 6), label + (i << 6)) == 0)
+			for (i = 0; i < (int)labels.Size(); i++)
+				if (labels[i].compare(parselabel) == 0)
 				{
 					warningcount++;
-					Printf(TEXTCOLOR_RED "  * WARNING.(%s, line %d) Duplicate move '%s' ignored.\n", fn, line_number, label + (labelcnt << 6));
+					Printf(TEXTCOLOR_RED "  * WARNING.(%s, line %d) Duplicate move '%s' ignored.\n", fn, line_number, parselabel);
 					break;
 				}
-			if (i == labelcnt)
-				appendlabeladdress();
+			if (i == labels.Size())
+				appendlabeladdress(LABEL_MOVE);
 			for (j = 0; j < 2; j++)
 			{
 				if (keyword() >= 0) break;
-				transnum();
+				transnum(LABEL_DEFINE);
 			}
 			for (k = j; k < 2; k++)
 			{
@@ -761,7 +863,7 @@ int parsecommand()
 	case concmd_music:
 	{
 		popscriptvalue();
-		transnum(); // Volume Number (0/4)
+		transnum(LABEL_DEFINE); // Volume Number (0/4)
 		k = popscriptvalue() - 1;
 		if (k < 0) specialmusic.Clear();
 
@@ -856,20 +958,20 @@ int parsecommand()
 
 	case concmd_ai:
 		if (parsing_actor || parsing_state)
-			transnum();
+			transnum(LABEL_AI);
 		else
 		{
 			popscriptvalue();
 			getlabel();
 			checkforkeyword();
 
-			lnum = findlabel(label + (labelcnt << 6));
+			lnum = findlabel(parselabel);
 			if (lnum >= 0)
 			{
 				warningcount++;
-				Printf(TEXTCOLOR_RED "  * WARNING.(%s, line %d) Duplicate ai '%s' ignored.\n", fn, line_number, label + (labelcnt << 6));
+				Printf(TEXTCOLOR_RED "  * WARNING.(%s, line %d) Duplicate ai '%s' ignored.\n", fn, line_number, parselabel);
 			}
-			else appendlabeladdress();
+			else appendlabeladdress(LABEL_AI);
 
 			for (j = 0; j < 3; j++)
 			{
@@ -879,13 +981,13 @@ int parsecommand()
 					k = 0;
 					while (keyword() == -1)
 					{
-						transnum();
+						transnum(LABEL_DEFINE);
 						k |= popscriptvalue();
 					}
 					appendscriptvalue(k);
 					return 0;
 				}
-				else transnum();
+				else transnum(j==0? LABEL_ACTION : LABEL_MOVE);
 			}
 			for (k = j; k < 3; k++)
 			{
@@ -896,25 +998,25 @@ int parsecommand()
 
 	case concmd_action:
 		if (parsing_actor || parsing_state)
-			transnum();
+			transnum(LABEL_ACTION);
 		else
 		{
 			popscriptvalue();
 			getlabel();
 			checkforkeyword();
 
-			lnum = findlabel(label + (labelcnt << 6));
+			lnum = findlabel(parselabel);
 			if (lnum >= 0)
 			{
 				warningcount++;
-				Printf(TEXTCOLOR_RED "  * WARNING.(%s, line %d) Duplicate event '%s' ignored.\n", fn, line_number, label + (labelcnt << 6));
+				Printf(TEXTCOLOR_RED "  * WARNING.(%s, line %d) Duplicate event '%s' ignored.\n", fn, line_number, parselabel);
 			}
-			else appendlabeladdress();
+			else appendlabeladdress(LABEL_ACTION);
 
 			for (j = 0; j < 5; j++)
 			{
 				if (keyword() >= 0) break;
-				transnum();
+				transnum(LABEL_DEFINE);
 			}
 			for (k = j; k < 5; k++)
 			{
@@ -944,11 +1046,11 @@ int parsecommand()
 
 		if (tw == concmd_useractor)
 		{ 
-			transnum();
+			transnum(LABEL_DEFINE);
 			j = popscriptvalue();
 		}
 
-		transnum();
+		transnum(LABEL_DEFINE);
 		lnum = popscriptvalue();
 
 		actorinfo[lnum].scriptaddress = parsing_actor;	// TRANSITIONAL should only store an index
@@ -969,7 +1071,7 @@ int parsecommand()
 				j = 0;
 				while (keyword() == -1)
 				{
-					transnum();
+					transnum(LABEL_DEFINE);
 					
 					j |= popscriptvalue();
 				}
@@ -983,7 +1085,12 @@ int parsecommand()
 					reservescriptspace(4 - j);
 					break;
 				}
-				transnum();
+				switch (j)
+				{
+				case 0: transnum(LABEL_DEFINE); break;
+				case 1: transnum(LABEL_ACTION); break;
+				case 2: transnum(LABEL_MOVE | LABEL_DEFINE); break;
+				}
 				// This code was originally here but is a no-op, because both source and destination are the same here.			
 				//*(parsing_actor + j) = *(scriptaddress - 1);
 			}
@@ -1011,7 +1118,7 @@ int parsecommand()
 		popscriptvalue();
 		parsing_event = parsing_actor = scriptpos();
 
-		transnum();
+		transnum(LABEL_DEFINE);
 		j = popscriptvalue();
 		if (j< 0 || j> EVENT_MAXEVENT)
 		{
@@ -1027,7 +1134,7 @@ int parsecommand()
 
 
 	case concmd_cstat:
-		transnum();
+		transnum(LABEL_DEFINE);
 #if 0
 		// the following checks are being performed by EDuke32 and RedNukem - not sure if this really should be done.
 		// DukeGDX and RedneckGDX do not perform these checks. Code pasted here for making a decision later.
@@ -1076,7 +1183,7 @@ int parsecommand()
 	case concmd_isdrunk:
 	case concmd_iseat:
 	case concmd_newpic:
-		transnum();
+		transnum(LABEL_DEFINE);
 		return 0;
 
 	case concmd_addammo:
@@ -1086,16 +1193,16 @@ int parsecommand()
 	case concmd_debris:
 	case concmd_addinventory:
 	case concmd_guts:
-		transnum();
-		transnum();
+		transnum(LABEL_DEFINE);
+		transnum(LABEL_DEFINE);
 		return 0;
 
 	case concmd_hitradius:
-		transnum();
-		transnum();
-		transnum();
-		transnum();
-		transnum();
+		transnum(LABEL_DEFINE);
+		transnum(LABEL_DEFINE);
+		transnum(LABEL_DEFINE);
+		transnum(LABEL_DEFINE);
+		transnum(LABEL_DEFINE);
 		break;
 
 	case concmd_else:
@@ -1127,7 +1234,7 @@ int parsecommand()
 		// Check to see if it's a keyword
 		checkforkeyword();
 
-		i = GetDefID(label + (labelcnt << 6));
+		i = GetDefID(parselabel);
 		if (i < 0)
 		{	// not a defined DEF
 			errorcount++;
@@ -1143,7 +1250,7 @@ int parsecommand()
 		}
 		appendscriptvalue(i);	// the ID of the DEF (offset into array...)
 
-		transnum();	// the number to check against...
+		transnum(LABEL_DEFINE);	// the number to check against...
 		return 0;
 
 	case concmd_setvarvar:
@@ -1157,7 +1264,7 @@ int parsecommand()
 
 		checkforkeyword();
 
-		i = GetDefID(label + (labelcnt << 6));
+		i = GetDefID(parselabel);
 		if (i < 0)
 		{	// not a defined DEF
 			errorcount++;
@@ -1177,7 +1284,7 @@ int parsecommand()
 		getlabel();	//GetGameVarLabel();
 		checkforkeyword();
 
-		i = GetDefID(label + (labelcnt << 6));
+		i = GetDefID(parselabel);
 		if (i < 0)
 		{	// not a defined DEF
 			errorcount++;
@@ -1197,7 +1304,7 @@ int parsecommand()
 
 		checkforkeyword();
 
-		i = GetDefID(label + (labelcnt << 6));
+		i = GetDefID(parselabel);
 		if (i < 0)
 		{	// not a defined DEF
 			errorcount++;
@@ -1211,7 +1318,7 @@ int parsecommand()
 
 		checkforkeyword();
 
-		i = GetDefID(label + (labelcnt << 6));
+		i = GetDefID(parselabel);
 		if (i < 0)
 		{	// not a defined DEF
 			errorcount++;
@@ -1229,7 +1336,7 @@ int parsecommand()
 		getlabel();	//GetGameVarLabel();
 
 		checkforkeyword();
-		i = GetDefID(label + (labelcnt << 6));
+		i = GetDefID(parselabel);
 		if (i < 0)
 		{	// not a defined DEF
 			errorcount++;
@@ -1238,7 +1345,7 @@ int parsecommand()
 		}
 		appendscriptvalue(i);	// the ID of the DEF (offset into array...)
 
-		transnum();	// the number to check against...
+		transnum(LABEL_DEFINE);	// the number to check against...
 		goto if_common;
 
 	case concmd_addlogvar:
@@ -1252,7 +1359,7 @@ int parsecommand()
 
 		checkforkeyword();
 
-		i = GetDefID(label + (labelcnt << 6));
+		i = GetDefID(parselabel);
 		if (i < 0)
 		{	// not a defined DEF
 			errorcount++;
@@ -1277,14 +1384,14 @@ int parsecommand()
 		j = 0;
 		do
 		{
-			transnum();
+			transnum(LABEL_DEFINE);
 			j |= popscriptvalue();
 		} while (keyword() == -1);
 		appendscriptvalue(j);
 		goto if_common;
 
 	case concmd_ifpinventory:
-		transnum();
+		transnum(LABEL_DEFINE);
 	case concmd_ifrnd:
 	case concmd_ifpdistl:
 	case concmd_ifpdistg:
@@ -1309,7 +1416,7 @@ int parsecommand()
 	case concmd_ifactorhealthl:
 	case concmd_ifsoundid:
 	case concmd_ifsounddist:
-		transnum();
+		transnum(tw == concmd_ifai? LABEL_AI : tw == concmd_ifaction? LABEL_ACTION : tw == concmd_ifmove? LABEL_MOVE : LABEL_DEFINE);
 	case concmd_ifonwater:
 	case concmd_ifinwater:
 	case concmd_ifactornotstayput:
@@ -1377,7 +1484,7 @@ int parsecommand()
 
 	case concmd_definevolumename:
 		popscriptvalue();
-		transnum();
+		transnum(LABEL_DEFINE);
 		j = popscriptvalue();
 		while (*textptr == ' ' || *textptr == '\t') textptr++;
 
@@ -1394,7 +1501,7 @@ int parsecommand()
 		return 0;
 	case concmd_defineskillname:
 		popscriptvalue();
-		transnum();
+		transnum(LABEL_DEFINE);
 		j = popscriptvalue();
 		while (*textptr == ' ') textptr++;
 
@@ -1413,9 +1520,9 @@ int parsecommand()
 	case concmd_definelevelname:
 	{
 		popscriptvalue();
-		transnum();
+		transnum(LABEL_DEFINE);
 		j = popscriptvalue();
-		transnum();
+		transnum(LABEL_DEFINE);
 		k = popscriptvalue();
 		while (*textptr == ' ') textptr++;
 
@@ -1464,7 +1571,7 @@ int parsecommand()
 	}
 	case concmd_definequote:
 		popscriptvalue();
-		transnum();
+		transnum(LABEL_DEFINE);
 		k = popscriptvalue();
 		if (k >= MAXQUOTES)
 		{
@@ -1488,7 +1595,7 @@ int parsecommand()
 	case concmd_definesound:
 	{
 		popscriptvalue();
-		transnum();
+		transnum(LABEL_DEFINE);
 		k = popscriptvalue();
 		i = 0;
 		while (*textptr == ' ')
@@ -1502,15 +1609,15 @@ int parsecommand()
 		}
 		parsebuffer.Push(0);
 
-		transnum();
+		transnum(LABEL_DEFINE);
 		int ps = popscriptvalue();
-		transnum();
+		transnum(LABEL_DEFINE);
 		int pe = popscriptvalue();
-		transnum();
+		transnum(LABEL_DEFINE);
 		int pr = popscriptvalue();
-		transnum();
+		transnum(LABEL_DEFINE);
 		int m = popscriptvalue();
-		transnum();
+		transnum(LABEL_DEFINE);
 		int vo = popscriptvalue();
 		S_DefineSound(k, parsebuffer.Data(), ps, pe, pr, m, vo, 1.f);
 		return 0;
@@ -1595,7 +1702,7 @@ int parsecommand()
 	case concmd_gamestartup:
 	{
 		popscriptvalue();
-		auto parseone = []() { transnum(); return popscriptvalue(); };
+		auto parseone = []() { transnum(LABEL_DEFINE); return popscriptvalue(); };
 		ud.const_visibility = parseone();
 		impact_damage = parseone();
 		max_player_health = parseone();
@@ -1670,13 +1777,52 @@ void compilecon(const char *filenam)
 
 }
 
+//==========================================================================
+//
+// Fallback in case nothing got defined.
+//
+//==========================================================================
+
+static const char* ConFile(void)
+{
+	if (userConfig.DefaultCon.IsNotEmpty()) return userConfig.DefaultCon.GetChars();
+
+	// WW2GI anf NAM special con names got introduced by EDuke32.
+	// Do we really need these?
+	if (g_gameType & GAMEFLAG_WW2GI)
+	{
+		if (fileSystem.FindFile("ww2gi.con") >= 0) return "ww2gi.con";
+	}
+
+	if (g_gameType & GAMEFLAG_NAM)
+	{
+		if (fileSystem.FindFile("nam.con") >= 0) return "nam.con";
+		if (fileSystem.FindFile("napalm.con") >= 0) return "napalm.con";
+	}
+
+	if (g_gameType & GAMEFLAG_NAPALM)
+	{
+		if (fileSystem.FindFile("napalm.con") >= 0) return "napalm.con";
+		if (fileSystem.FindFile("nam.con") >= 0) return "nam.con";
+	}
+
+	// This got introduced by EDuke 2.0.
+	if (g_gameType & GAMEFLAG_DUKE)
+	{
+		if (fileSystem.FindFile("eduke.con") >= 0) return "eduke.con";	
+	}
+
+	// the other games only use game.con.
+	return "game.con";
+}
+
 //---------------------------------------------------------------------------
 //
 // why was this called loadefs?
 //
 //---------------------------------------------------------------------------
 
-void loadcons(const char* filenam)
+void loadcons()
 {
 	for (int i = 0; i < MAXTILES; i++)
 	{
@@ -1684,8 +1830,7 @@ void loadcons(const char* filenam)
 	}
 
 	ScriptCode.Clear();
-
-	labelcnt = 0;
+	labels.Clear();
 
 	SortCommands();
 
@@ -1696,25 +1841,27 @@ void loadcons(const char* filenam)
 	auto before = I_nsTime();
 
 	ScriptCode.Push(0);
-	compilecon(filenam); //Tokenize
+	compilecon(ConFile()); //Tokenize
 
 	if (userConfig.AddCons) for (FString& m : *userConfig.AddCons.get())
 	{
-		compilecon(filenam);
+		compilecon(m);
 	}
+	ScriptCode.ShrinkToFit();
+	labels.ShrinkToFit();
 	userConfig.AddCons.reset();
 	setscriptvalue(0, scriptpos());
 
 	if (errorcount)
 	{
-		I_FatalError("\nError in %s.", filenam);
+		I_FatalError("Failed to compile CONs.");
 	}
 	else
 	{
 		auto after = I_nsTime();
-		Printf("Compilation time:%.2f ms, Code Size:%d bytes. %d labels. %d/%d Variables.\n", (after-before) / 1000000.,
+		Printf("Compilation time:%.2f ms, Code Size:%u bytes. %u labels. %d/%d Variables.\n", (after-before) / 1000000.,
 			(ScriptCode.Size() << 2) - 4,
-			labelcnt,
+			labels.Size(),
 			0,//iGameVarCount,
 			MAXGAMEVARS
 		);
@@ -1723,11 +1870,6 @@ void loadcons(const char* filenam)
 	// These can only be retrieved AFTER loading the scripts.
 	InitGameVarPointers();
 	ResetSystemDefaults();
-	for (auto& tm : tempMusic)
-	{
-		auto map = FindMapByLevelNum(tm.levnum);
-		if (map) map->music = tm.music;
-	}
 	if (isRRRA())
 	{
 		// RRRA goes directly to the second episode after E1L7 to continue the game.
@@ -1756,6 +1898,11 @@ void loadcons(const char* filenam)
 			maprec->levelNumber = levelnum(1, 7);
 		}
 	}
+	for (auto& tm : tempMusic)
+	{
+		auto map = FindMapByLevelNum(tm.levnum);
+		if (map) map->music = tm.music;
+	}
 	tempMusic.Clear();
 
 }
diff --git a/source/games/duke/src/gamedef.h b/source/games/duke/src/gamedef.h
index 8c6878b55..92f96f66e 100644
--- a/source/games/duke/src/gamedef.h
+++ b/source/games/duke/src/gamedef.h
@@ -62,7 +62,7 @@ void C_DefineMusic(int volumeNum, int levelNum, const char *fileName);
 
 void C_DefineVolumeFlags(int32_t vol, int32_t flags);
 void ReportError(int32_t iError);
-void loadcons(const char *filenam);
+void loadcons();
 
 extern int32_t g_errorLineNum;
 extern int32_t g_tw;
diff --git a/source/games/duke/src/global.h b/source/games/duke/src/global.h
index 0db0e1b02..f624ff774 100644
--- a/source/games/duke/src/global.h
+++ b/source/games/duke/src/global.h
@@ -85,7 +85,6 @@ enum
     MAXLABELLEN = 64
 };
 
-extern char *label;
 G_EXTERN char g_loadFromGroupOnly;
 G_EXTERN char g_skillCnt;
 G_EXTERN char pus,pub;
@@ -126,7 +125,6 @@ G_EXTERN int32_t g_freezerSelfDamage;
 G_EXTERN int32_t g_gameQuit;
 G_EXTERN int32_t global_random;
 G_EXTERN int32_t impact_damage;
-extern int32_t labelcnt;
 G_EXTERN int32_t g_maxPlayerHealth;
 G_EXTERN int32_t mirrorcnt;
 G_EXTERN int32_t playerswhenstarted;
@@ -159,10 +157,6 @@ G_EXTERN int16_t g_cyclers[MAXCYCLERS][6];
 #define cyclers g_cyclers
 G_EXTERN int16_t mirrorsector[64];
 G_EXTERN int16_t mirrorwall[64];
-G_EXTERN int32_t *labelcode;
-#if 0
-G_EXTERN int32_t *labeltype;
-#endif
 G_EXTERN ClockTicks lockclock;
 G_EXTERN ClockTicks ototalclock;
 
diff --git a/source/games/duke/src/zz_game.cpp b/source/games/duke/src/zz_game.cpp
index f9e9a492c..e2bb7d3cd 100644
--- a/source/games/duke/src/zz_game.cpp
+++ b/source/games/duke/src/zz_game.cpp
@@ -66,8 +66,6 @@ uint8_t shadedsector[MAXSECTORS];
 
 int32_t cameradist = 0, cameraclock = 0;
 
-char boardfilename[BMAX_PATH] = {0};
-
 int32_t g_Shareware = 0;
 
 int32_t tempwallptr;
@@ -289,9 +287,6 @@ static void G_Cleanup(void)
     {
         Xfree(g_player[i].input);
     }
-
-    if (label != (char *)&sprite[0]) Xfree(label);
-    if (labelcode != (int32_t *)&sector[0]) Xfree(labelcode);
 }
 
 /*
@@ -302,44 +297,6 @@ static void G_Cleanup(void)
 ===================
 */
 
-static void G_CompileScripts(void)
-{
-    label     = (char *)&sprite[0];     // V8: 16384*44/64 = 11264  V7: 4096*44/64 = 2816
-    labelcode = (int32_t *)&sector[0]; // V8: 4096*40/4 = 40960    V7: 1024*40/4 = 10240
-
-    loadcons(G_ConFile());
-	fi.initactorflags();
-
-    if ((uint32_t)labelcnt > MAXSPRITES*sizeof(spritetype)/64)   // see the arithmetic above for why
-        I_FatalError("Error: too many labels defined!");
-
-    {
-        char *newlabel;
-        int32_t *newlabelcode;
-        int32_t *newlabeltype;
-
-        newlabel     = (char *)Xmalloc(labelcnt << 6);
-        newlabelcode = (int32_t *)Xmalloc(labelcnt * sizeof(int32_t));
-        newlabeltype = (int32_t *)Xmalloc(labelcnt * sizeof(int32_t));
-
-        Bmemcpy(newlabel, label, labelcnt*64);
-        Bmemcpy(newlabelcode, labelcode, labelcnt*sizeof(int32_t));
-
-        label = newlabel;
-        labelcode = newlabelcode;
-    }
-
-    Bmemset(sprite, 0, MAXSPRITES*sizeof(spritetype));
-    Bmemset(sector, 0, MAXSECTORS*sizeof(sectortype));
-    Bmemset(wall, 0, MAXWALLS*sizeof(walltype));
-
-    if (IsGameEvent(EVENT_INIT))
-    {
-        SetGameVarID(g_iReturnVarID, -1, -1, -1);
-        OnEvent(EVENT_INIT);
-    }
-}
-
 inline int G_CheckPlayerColor(int color)
 {
     static int32_t player_pals[] = { 0, 9, 10, 11, 12, 13, 14, 15, 16, 21, 23, };
@@ -353,7 +310,14 @@ static void G_Startup(void)
     timerInit(TICRATE);
     timerSetCallback(gameTimerHandler);
 
-    G_CompileScripts();
+    loadcons();
+    fi.initactorflags();
+
+    if (IsGameEvent(EVENT_INIT))
+    {
+        SetGameVarID(g_iReturnVarID, -1, -1, -1);
+        OnEvent(EVENT_INIT);
+    }
 
     enginecompatibility_mode = ENGINECOMPATIBILITY_19961112;
 
@@ -366,30 +330,11 @@ static void G_Startup(void)
 
 	if (userConfig.CommandMap.IsNotEmpty())
 	{
-		FString startupMap;
         if (VOLUMEONE)
         {
             Printf("The -map option is available in the registered version only!\n");
+			userConfig.CommandMap = "";
         }
-        else
-        {
-			startupMap = userConfig.CommandMap;
-			if (startupMap.IndexOfAny("/\\") < 0) startupMap.Insert(0, "/");
-			DefaultExtension(startupMap, ".map");
-			startupMap.Substitute("\\", "/");
-			NormalizeFileName(startupMap);
-
-			if (fileSystem.FileExists(startupMap))
-			{
-                Printf("Using level: \"%s\".\n",startupMap.GetChars());
-            }
-            else
-            {
-                Printf("Level \"%s\" not found.\n",startupMap.GetChars());
-                boardfilename[0] = 0;
-            }
-        }
-		strncpy(boardfilename, startupMap, BMAX_PATH);
     }
 
     if (numplayers > 1)
@@ -445,7 +390,6 @@ void G_UpdatePlayerFromMenu(void)
 
 void G_BackToMenu(void)
 {
-    boardfilename[0] = 0;
     ps[myconnectindex].gm = 0;
 	M_StartControlPanel(false);
 	M_SetMenu(NAME_Mainmenu);
@@ -658,9 +602,9 @@ MAIN_LOOP_RESTART:
     //if (ud.warp_on == 0)
     {
 #if 0 // fixme once the game loop has been done.
-        if ((ud.multimode > 1) && boardfilename[0] != 0)
+        if ((ud.multimode > 1) && startupMap.IsNotEmpty())
         {
-            auto maprecord = FindMap(boardfilename);
+            auto maprecord = FindMap(startupMap);
             ud.m_respawn_monsters = ud.m_player_skill == 4;
 
             for (int i = 0; i != -1; i = connectpoint2[i])
diff --git a/source/games/duke/src/zz_savegame.cpp b/source/games/duke/src/zz_savegame.cpp
index 225787cbb..471d9aa50 100644
--- a/source/games/duke/src/zz_savegame.cpp
+++ b/source/games/duke/src/zz_savegame.cpp
@@ -164,9 +164,6 @@ int32_t G_LoadPlayer(const char *path)
 
     ud.m_player_skill = h.skill;
 
-    // NOTE: Bmemcpy needed for SAVEGAME_MUSIC.
-    strcpy(boardfilename, currentLevel->fileName);
-
 	char workbuffer[BMAX_PATH];
 	Bstrcpy(workbuffer, currentLevel->fileName);