diff --git a/.travis.yml b/.travis.yml
index c652584f8879153f879a24c0f3f5a741cc8eae4f..df89593c4ab62be3b9bd89c2d83162491bf58eee 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,14 +2,17 @@ language: c
 sudo: required
 dist: trusty
 
-env:
-- CFLAGS=-Wno-absolute-value -Werror
+os:
+  - linux
+  - osx
 
 compiler:
   - gcc
   - clang
 
 cache:
+  apt:  true
+  ccache: true
   directories:
   - $HOME/srb2_cache
 
@@ -30,4 +33,10 @@ before_script:
   - cd build
   - cmake ..
 
+before_install:
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install sdl2_mixer game-music-emu p7zip ; fi
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then curl -O -L https://www.libsdl.org/release/SDL2-2.0.4.dmg; hdiutil attach SDL2-2.0.4.dmg; sudo cp -a /Volumes/SDL2/SDL2.framework /Library/Frameworks/; fi
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then curl -O -L https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.1.dmg; hdiutil attach SDL2_mixer-2.0.1.dmg; sudo cp -a /Volumes/SDL2_mixer/SDL2_mixer.framework /Library/Frameworks/; fi
+
 script: make
diff --git a/cmake/Modules/FindGME.cmake b/cmake/Modules/FindGME.cmake
index 3b0c68de735e67458ce4652c600b5768c8124046..ea80af45442c098f21cef962082ce0602546cd29 100644
--- a/cmake/Modules/FindGME.cmake
+++ b/cmake/Modules/FindGME.cmake
@@ -6,16 +6,16 @@ find_path(GME_INCLUDE_DIR
 	NAMES gme.h
 	PATHS
 		${GME_PKGCONF_INCLUDE_DIRS}
-		/usr/include/gme
-		/usr/local/include/gme
+		"/usr/include/gme"
+		"/usr/local/include/gme"
 )
 
 find_library(GME_LIBRARY
 	NAMES gme
 	PATHS
 		${GME_PKGCONF_LIBRARY_DIRS}
-		/usr/lib
-		/usr/local/lib
+		"/usr/lib"
+		"/usr/local/lib"
 )
 
 set(GME_PROCESS_INCLUDES GME_INCLUDE_DIR)
diff --git a/comptime.bat b/comptime.bat
index 9e127f001a984ebf3e6febffb8307adb21d08aaf..0c7ea06d60955ec1cd5015a9b660625dae0b6d2c 100644
--- a/comptime.bat
+++ b/comptime.bat
@@ -1,4 +1,4 @@
-@ECHO OFF
+@echo off
 set BRA=Unknown
 set REV=illegal
 
@@ -13,20 +13,20 @@ goto filwri
 :gitrev
 set GIT=%2
 if "%GIT%"=="" set GIT=git
-FOR /F "usebackq" %%s IN (`%GIT% rev-parse --abbrev-ref HEAD`) DO @SET BRA=%%s
-FOR /F "usebackq" %%s IN (`%GIT% rev-parse HEAD`) DO @SET REV=%%s
+for /f "usebackq" %%s in (`%GIT% rev-parse --abbrev-ref HEAD`) do @set BRA=%%s
+for /f "usebackq" %%s in (`%GIT% rev-parse HEAD`) do @set REV=%%s
 set REV=%REV:~0,8%
 goto filwri
 
 :svnrev
 set BRA=Subversion
-FOR /F "usebackq" %%s IN (`svnversion .`) DO @SET REV=%%s
+for /f "usebackq" %%s in (`svnversion .`) do @set REV=%%s
 set REV=r%REV%
 goto filwri
 
 :filwri
-ECHO // Do not edit!  This file was autogenerated > %1\comptime.h
-ECHO // by the %0 batch file >> %1\comptime.h
-ECHO // >> %1\comptime.h
-ECHO const char* compbranch = "%BRA%"; >> %1\comptime.h
-ECHO const char* comprevision = "%REV%"; >> %1\comptime.h
+echo // Do not edit!  This file was autogenerated > %1\comptime.h
+echo // by the %0 batch file >> %1\comptime.h
+echo // >> %1\comptime.h
+echo const char* compbranch = "%BRA%"; >> %1\comptime.h
+echo const char* comprevision = "%REV%"; >> %1\comptime.h
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 54a08ea0bb31b03d23c3758b37874dc99f3fdcd0..13d3312dd02aae2d0efcaec4da9287ac4072fc15 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -316,6 +316,7 @@ if(${SRB2_CONFIG_HAVE_GME})
 	find_package(GME)
 	if(${GME_FOUND})
 		set(SRB2_HAVE_GME ON)
+		add_definitions(-DHAVE_LIBGME)
 	else()
 		message(WARNING "You have specified that GME is available but it was not found.")
 	endif()
diff --git a/src/Makefile b/src/Makefile
index bee60804720da1dcbee09065c29f616e145848f0..449b4065d2967f742a8ad4f917f6b4c96a2f0e19 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -262,9 +262,7 @@ else
 	OBJS+=$(OBJDIR)/hw3sound.o
 endif
 
-ifndef NOVERSION
 OPTS += -DCOMPVERSION
-endif
 
 ifndef NONX86
 ifndef GCC29
@@ -551,15 +549,11 @@ cleandep:
 	$(REMOVE) comptime.h
 
 pre-build:
-ifdef NOVERSION
-	-@touch comptime.c
-else
 ifdef WINDOWSHELL
 	-..\comptime.bat .
 else
 	-@../comptime.sh .
 endif
-endif
 
 clean:
 	$(REMOVE) *~ *.flc
diff --git a/src/config.h.in b/src/config.h.in
index 5cd75fa5a50962f34a638b3dda519cfe2483fa47..eef4fec1314a44baa2ddaf1f59cb8f460dda9c9f 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -15,7 +15,9 @@
 #define ASSET_HASH_PLAYER_DTA "${SRB2_ASSET_player.dta_HASH}"
 #define ASSET_HASH_RINGS_DTA  "${SRB2_ASSET_rings.dta_HASH}"
 #define ASSET_HASH_ZONES_DTA  "${SRB2_ASSET_zones.dta_HASH}"
+#ifdef USE_PATCH_DTA
 #define ASSET_HASH_PATCH_DTA  "${SRB2_ASSET_patch.dta_HASH}"
+#endif
 
 #define SRB2_COMP_REVISION    "${SRB2_COMP_REVISION}"
 #define SRB2_COMP_BRANCH      "${SRB2_COMP_BRANCH}"
@@ -26,10 +28,16 @@
 
 #else
 
+/* Manually defined asset hashes for non-CMake builds
+ * Last updated 2000 / 00 / 00
+ */
 #define ASSET_HASH_SRB2_SRB   "c1b9577687f8a795104aef4600720ea7"
 #define ASSET_HASH_ZONES_DTA  "303838c6c534d9540288360fa49cca60"
 #define ASSET_HASH_PLAYER_DTA "cfca0f1c73023cbbd8f844f45480f799"
 #define ASSET_HASH_RINGS_DTA  "85901ad4bf94637e5753d2ac2c03ea26"
+#ifdef USE_PATCH_DTA
+#define ASSET_HASH_PATCH_DTA  "0c66790502e648bfce90fdc5bb15722e"
+#endif
 
 #endif
 #endif
diff --git a/src/d_main.c b/src/d_main.c
index 3918d8118c0c1cfd242c70b7f04148b26612f8c8..b04c55cbf668510284410c1bd36b75e0488e3f10 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -513,7 +513,6 @@ static void D_Display(void)
 // =========================================================================
 
 tic_t rendergametic;
-boolean supdate;
 
 void D_SRB2Loop(void)
 {
@@ -604,7 +603,6 @@ void D_SRB2Loop(void)
 
 			// Update display, next frame, with current state.
 			D_Display();
-			supdate = false;
 
 			if (moviemode)
 				M_SaveFrame();
@@ -841,8 +839,10 @@ static void IdentifyVersion(void)
 	// Add the weapons
 	D_AddFile(va(pandf,srb2waddir,"rings.dta"));
 
+#ifdef USE_PATCH_DTA
 	// Add our crappy patches to fix our bugs
-	// D_AddFile(va(pandf,srb2waddir,"patch.dta"));
+	D_AddFile(va(pandf,srb2waddir,"patch.dta"));
+#endif
 
 #if !defined (HAVE_SDL) || defined (HAVE_MIXER)
 	{
@@ -1133,12 +1133,18 @@ void D_SRB2Main(void)
 	W_VerifyFileMD5(1, ASSET_HASH_ZONES_DTA); // zones.dta
 	W_VerifyFileMD5(2, ASSET_HASH_PLAYER_DTA); // player.dta
 	W_VerifyFileMD5(3, ASSET_HASH_RINGS_DTA); // rings.dta
-	//W_VerifyFileMD5(4, "0c66790502e648bfce90fdc5bb15722e"); // patch.dta
+#ifdef USE_PATCH_DTA
+	W_VerifyFileMD5(4, ASSET_HASH_PATCH_DTA); // patch.dta
+#endif
+
 	// don't check music.dta because people like to modify it, and it doesn't matter if they do
 	// ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for.
-#endif
+#endif //ifndef DEVELOP
 
-	mainwads = 4; // there are 5 wads not to unload
+	mainwads = 4; // there are 4 wads not to unload
+#ifdef USE_PATCH_DTA
+	++mainwads; // patch.dta adds one more
+#endif
 
 	cht_Init();
 
diff --git a/src/d_main.h b/src/d_main.h
index 800b61f531fb9c79f6b19f4d2eb0d23c1430b045..c5ce19ef4cb199ca489840e1899f0e40d0c3f775 100644
--- a/src/d_main.h
+++ b/src/d_main.h
@@ -17,7 +17,6 @@
 #include "d_event.h"
 #include "w_wad.h"   // for MAX_WADFILES
 
-extern boolean supdate;
 extern boolean advancedemo;
 
 // make sure not to write back the config until it's been correctly loaded
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 02bc464e61e882c2bc36ab0e4fb8afa72a3a4e5c..5eb35283414b7f807249df101c14d4048bb1251e 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -1854,10 +1854,10 @@ static void Got_Pause(UINT8 **cp, INT32 playernum)
 		if (paused)
 		{
 			if (!menuactive || netgame)
-				S_PauseSound();
+				S_PauseAudio();
 		}
 		else
-			S_ResumeSound();
+			S_ResumeAudio();
 	}
 }
 
@@ -3761,50 +3761,66 @@ static void Command_Displayplayer_f(void)
 static void Command_Tunes_f(void)
 {
 	const char *tunearg;
-	UINT16 tune, track = 0;
+	UINT16 tunenum, track = 0;
 	const size_t argc = COM_Argc();
 
 	if (argc < 2) //tunes slot ...
 	{
-		CONS_Printf("tunes <slot #/map name/\"default\"> <speed> <track>:\n");
-		CONS_Printf(M_GetText("Play a music slot at a set speed (\"1\" being normal speed).\n"));
-		CONS_Printf(M_GetText("If the format supports multiple songs, you can specify which one to play.\n"));
-		CONS_Printf(M_GetText("The current tune is: %d\nThe current track is: %d\n"),
-			(mapmusic & MUSIC_SONGMASK), ((mapmusic & MUSIC_TRACKMASK) >> MUSIC_TRACKSHIFT));
+		CONS_Printf("tunes <name/num> [track] [speed] / <-show> / <-default> / <-none>:\n");
+		CONS_Printf(M_GetText("Play an arbitrary music lump. If a map number is used, 'MAP##M' is played.\n"));
+		CONS_Printf(M_GetText("If the format supports multiple songs, you can specify which one to play.\n\n"));
+		CONS_Printf(M_GetText("* With \"-show\", shows the currently playing tune and track.\n"));
+		CONS_Printf(M_GetText("* With \"-default\", returns to the default music for the map.\n"));
+		CONS_Printf(M_GetText("* With \"-none\", any music playing will be stopped.\n"));
 		return;
 	}
 
 	tunearg = COM_Argv(1);
-	tune = (UINT16)atoi(tunearg);
+	tunenum = (UINT16)atoi(tunearg);
 	track = 0;
 
-	if (!strcasecmp(tunearg, "default"))
+	if (!strcasecmp(tunearg, "-show"))
 	{
-		tune = mapheaderinfo[gamemap-1]->musicslot;
-		track = mapheaderinfo[gamemap-1]->musicslottrack;
+		CONS_Printf(M_GetText("The current tune is: %s [track %d]\n"),
+			mapmusname, (mapmusflags & MUSIC_TRACKMASK));
+		return;
 	}
-	else if (toupper(tunearg[0]) >= 'A' && toupper(tunearg[0]) <= 'Z')
-		tune = (UINT16)M_MapNumber(tunearg[0], tunearg[1]);
-
-	if (tune >= NUMMUSIC)
+	if (!strcasecmp(tunearg, "-none"))
 	{
-		CONS_Alert(CONS_NOTICE, M_GetText("Valid slots are 1 to %d, or 0 to stop music\n"), NUMMUSIC - 1);
+		S_StopMusic();
 		return;
 	}
+	else if (!strcasecmp(tunearg, "-default"))
+	{
+		tunearg = mapheaderinfo[gamemap-1]->musname;
+		track = mapheaderinfo[gamemap-1]->mustrack;
+	}
+	else if (!tunearg[2] && toupper(tunearg[0]) >= 'A' && toupper(tunearg[0]) <= 'Z')
+		tunenum = (UINT16)M_MapNumber(tunearg[0], tunearg[1]);
 
-	if (argc > 3)
-		track = (UINT16)atoi(COM_Argv(3))-1;
+	if (tunenum && tunenum >= 1036)
+	{
+		CONS_Alert(CONS_NOTICE, M_GetText("Valid music slots are 1 to 1035.\n"));
+		return;
+	}
+	if (!tunenum && strlen(tunearg) > 6) // This is automatic -- just show the error just in case
+		CONS_Alert(CONS_NOTICE, M_GetText("Music name too long - truncated to six characters.\n"));
 
-	mapmusic = tune | (track << MUSIC_TRACKSHIFT);
+	if (argc > 2)
+		track = (UINT16)atoi(COM_Argv(2))-1;
 
-	if (tune == mus_None)
-		S_StopMusic();
+	if (tunenum)
+		snprintf(mapmusname, 7, "%sM", G_BuildMapName(tunenum));
 	else
-		S_ChangeMusic(mapmusic, true);
+		strncpy(mapmusname, tunearg, 7);
+	mapmusname[6] = 0;
+	mapmusflags = (track & MUSIC_TRACKMASK);
 
-	if (argc > 2)
+	S_ChangeMusic(mapmusname, mapmusflags, true);
+
+	if (argc > 3)
 	{
-		float speed = (float)atof(COM_Argv(2));
+		float speed = (float)atof(COM_Argv(3));
 		if (speed > 0.0f)
 			S_SpeedMusic(speed);
 	}
diff --git a/src/dehacked.c b/src/dehacked.c
index d6a1881e6359eeace3886a4f0a76061cd08aaf3b..4dc23777d3b342b110a74557fbd7702d40ea748e 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -65,7 +65,9 @@ static mobjtype_t get_mobjtype(const char *word);
 static statenum_t get_state(const char *word);
 static spritenum_t get_sprite(const char *word);
 static sfxenum_t get_sfx(const char *word);
-static UINT16 get_mus(const char *word);
+#ifdef MUSICSLOT_COMPATIBILITY
+static UINT16 get_mus(const char *word, UINT8 dehacked_mode);
+#endif
 static hudnum_t get_huditem(const char *word);
 #ifndef HAVE_BLUA
 static powertype_t get_power(const char *word);
@@ -1164,19 +1166,31 @@ static void readlevelheader(MYFILE *f, INT32 num)
 					mapheaderinfo[num-1]->typeoflevel = tol;
 				}
 			}
+			else if (fastcmp(word, "MUSIC"))
+			{
+				if (fastcmp(word2, "NONE"))
+					mapheaderinfo[num-1]->musname[0] = 0; // becomes empty string
+				else
+				{
+					deh_strlcpy(mapheaderinfo[num-1]->musname, word2,
+						sizeof(mapheaderinfo[num-1]->musname), va("Level header %d: music", num));
+				}
+			}
+#ifdef MUSICSLOT_COMPATIBILITY
 			else if (fastcmp(word, "MUSICSLOT"))
 			{
-				// Convert to map number
-				if (word2[0] >= 'A' && word2[0] <= 'Z' && word2[2] == '\0')
-					i = M_MapNumber(word2[0], word2[1]);
-
-				if (i) // it's just a number
-					mapheaderinfo[num-1]->musicslot = (UINT16)i;
-				else // No? Okay, now we'll get technical.
-					mapheaderinfo[num-1]->musicslot = get_mus(word2); // accepts all of O_CHRSEL, mus_chrsel, or just plain ChrSel
+				i = get_mus(word2, true);
+				if (i && i <= 1035)
+					snprintf(mapheaderinfo[num-1]->musname, 7, "%sM", G_BuildMapName(i));
+				else if (i && i <= 1050)
+					strncpy(mapheaderinfo[num-1]->musname, compat_special_music_slots[i - 1036], 7);
+				else
+					mapheaderinfo[num-1]->musname[0] = 0; // becomes empty string
+				mapheaderinfo[num-1]->musname[6] = 0;
 			}
-			else if (fastcmp(word, "MUSICSLOTTRACK"))
-				mapheaderinfo[num-1]->musicslottrack = ((UINT16)i - 1);
+#endif
+			else if (fastcmp(word, "MUSICTRACK"))
+				mapheaderinfo[num-1]->mustrack = ((UINT16)i - 1);
 			else if (fastcmp(word, "FORCECHARACTER"))
 			{
 				strlcpy(mapheaderinfo[num-1]->forcecharacter, word2, SKINNAMESIZE+1);
@@ -1443,10 +1457,30 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum)
 				else
 					deh_warning("CutSceneScene %d: unknown word '%s'", num, word);
 			}
+			else if (fastcmp(word, "MUSIC"))
+			{
+				DEH_WriteUndoline(word, cutscenes[num]->scene[scenenum].musswitch, UNDO_NONE);
+				strncpy(cutscenes[num]->scene[scenenum].musswitch, word2, 7);
+				cutscenes[num]->scene[scenenum].musswitch[6] = 0;
+			}
+#ifdef MUSICSLOT_COMPATIBILITY
 			else if (fastcmp(word, "MUSICSLOT"))
 			{
-				DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].musicslot), UNDO_NONE);
-				cutscenes[num]->scene[scenenum].musicslot = get_mus(word2); // accepts all of O_MAP01M, mus_map01m, or just plain MAP01M
+				DEH_WriteUndoline(word, cutscenes[num]->scene[scenenum].musswitch, UNDO_NONE);
+				i = get_mus(word2, true);
+				if (i && i <= 1035)
+					snprintf(cutscenes[num]->scene[scenenum].musswitch, 7, "%sM", G_BuildMapName(i));
+				else if (i && i <= 1050)
+					strncpy(cutscenes[num]->scene[scenenum].musswitch, compat_special_music_slots[i - 1036], 7);
+				else
+					cutscenes[num]->scene[scenenum].musswitch[0] = 0; // becomes empty string
+				cutscenes[num]->scene[scenenum].musswitch[6] = 0;
+			}
+#endif
+			else if (fastcmp(word, "MUSICTRACK"))
+			{
+				DEH_WriteUndoline(word, va("%u", cutscenes[num]->scene[scenenum].musswitchflags), UNDO_NONE);
+				cutscenes[num]->scene[scenenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK;
 			}
 			else if (fastcmp(word, "MUSICLOOP"))
 			{
@@ -6195,9 +6229,7 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	// Collectible Items
 	"MT_RING",
 	"MT_FLINGRING", // Lost ring
-#ifdef BLUE_SPHERES
 	"MT_BLUEBALL",  // Blue sphere replacement for special stages
-#endif
 	"MT_REDTEAMRING",  //Rings collectable by red team.
 	"MT_BLUETEAMRING", //Rings collectable by blue team.
 	"MT_EMMY", // emerald token for special stage
@@ -6650,6 +6682,7 @@ static const char *const MOBJFLAG2_LIST[] = {
 	"EXPLOSION",	// Thrown ring has explosive properties
 	"SCATTER",		// Thrown ring has scatter properties
 	"BEYONDTHEGRAVE",// Source of this missile has died and has since respawned.
+	"PUSHED",		// Mobj was already pushed this tic
 	"SLIDEPUSH",	// MF_PUSHABLE that pushes continuously.
 	"CLASSICPUSH",	// Drops straight down when object has negative Z.
 	"STANDONME",	// While not pushable, stand on me anyway.
@@ -6678,7 +6711,7 @@ static const char *const MOBJEFLAG_LIST[] = {
 	"JUSTSTEPPEDDOWN", // used for ramp sectors
 	"VERTICALFLIP", // Vertically flip sprite/allow upside-down physics
 	"GOOWATER", // Goo water
-	"PUSHED", // Mobj was already pushed this tic
+	"\x01", // free: 1<<7 (name un-matchable)
 	"SPRUNG", // Mobj was already sprung this tic
 	"APPLYPMOMZ", // Platform movement
 	NULL
@@ -6941,6 +6974,8 @@ struct {
 	{"PUSHACCEL",PUSHACCEL},
 	{"MODID",MODID}, // I don't know, I just thought it would be cool for a wad to potentially know what mod it was loaded into.
 	{"CODEBASE",CODEBASE}, // or what release of SRB2 this is.
+	{"VERSION",VERSION}, // Grab the game's version!
+	{"SUBVERSION",SUBVERSION}, // more precise version number
 
 	// Special linedef executor tag numbers!
 	{"LE_PINCHPHASE",LE_PINCHPHASE}, // A boss entered pinch phase (and, in most cases, is preparing their pinch phase attack!)
@@ -7231,36 +7266,36 @@ struct {
 	{"FF_GOOWATER",FF_GOOWATER},               ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop.
 
 	// Angles
-	{"ANG1",ANG1>>16},
-	{"ANG2",ANG2>>16},
-	{"ANG10",ANG10>>16},
-	{"ANG15",ANG15>>16},
-	{"ANG20",ANG20>>16},
-	{"ANG30",ANG30>>16},
-	{"ANG60",ANG60>>16},
-	{"ANG64h",ANG64h>>16},
-	{"ANG105",ANG105>>16},
-	{"ANG210",ANG210>>16},
-	{"ANG255",ANG255>>16},
-	{"ANG340",ANG340>>16},
-	{"ANG350",ANG350>>16},
-	{"ANGLE_11hh",ANGLE_11hh>>16},
-	{"ANGLE_22h",ANGLE_22h>>16},
-	{"ANGLE_45",ANGLE_45>>16},
-	{"ANGLE_67h",ANGLE_67h>>16},
-	{"ANGLE_90",ANGLE_90>>16},
-	{"ANGLE_112h",ANGLE_112h>>16},
-	{"ANGLE_135",ANGLE_135>>16},
-	{"ANGLE_157h",ANGLE_157h>>16},
-	{"ANGLE_180",ANGLE_180>>16},
-	{"ANGLE_202h",ANGLE_202h>>16},
-	{"ANGLE_225",ANGLE_225>>16},
-	{"ANGLE_247h",ANGLE_247h>>16},
-	{"ANGLE_270",ANGLE_270>>16},
-	{"ANGLE_292h",ANGLE_292h>>16},
-	{"ANGLE_315",ANGLE_315>>16},
-	{"ANGLE_337h",ANGLE_337h>>16},
-	{"ANGLE_MAX",ANGLE_MAX>>16},
+	{"ANG1",ANG1},
+	{"ANG2",ANG2},
+	{"ANG10",ANG10},
+	{"ANG15",ANG15},
+	{"ANG20",ANG20},
+	{"ANG30",ANG30},
+	{"ANG60",ANG60},
+	{"ANG64h",ANG64h},
+	{"ANG105",ANG105},
+	{"ANG210",ANG210},
+	{"ANG255",ANG255},
+	{"ANG340",ANG340},
+	{"ANG350",ANG350},
+	{"ANGLE_11hh",ANGLE_11hh},
+	{"ANGLE_22h",ANGLE_22h},
+	{"ANGLE_45",ANGLE_45},
+	{"ANGLE_67h",ANGLE_67h},
+	{"ANGLE_90",ANGLE_90},
+	{"ANGLE_112h",ANGLE_112h},
+	{"ANGLE_135",ANGLE_135},
+	{"ANGLE_157h",ANGLE_157h},
+	{"ANGLE_180",ANGLE_180},
+	{"ANGLE_202h",ANGLE_202h},
+	{"ANGLE_225",ANGLE_225},
+	{"ANGLE_247h",ANGLE_247h},
+	{"ANGLE_270",ANGLE_270},
+	{"ANGLE_292h",ANGLE_292h},
+	{"ANGLE_315",ANGLE_315},
+	{"ANGLE_337h",ANGLE_337h},
+	{"ANGLE_MAX",ANGLE_MAX},
 
 	// P_Chase directions (dirtype_t)
 	{"DI_NODIR",DI_NODIR},
@@ -7428,21 +7463,45 @@ static sfxenum_t get_sfx(const char *word)
 	return sfx_None;
 }
 
-static UINT16 get_mus(const char *word)
-{ // Returns the value of SFX_ enumerations
+#ifdef MUSICSLOT_COMPATIBILITY
+static UINT16 get_mus(const char *word, UINT8 dehacked_mode)
+{ // Returns the value of MUS_ enumerations
 	UINT16 i;
+	char lumptmp[4];
+
 	if (*word >= '0' && *word <= '9')
 		return atoi(word);
+	if (!word[2] && toupper(word[0]) >= 'A' && toupper(word[0]) <= 'Z')
+		return (UINT16)M_MapNumber(word[0], word[1]);
+
 	if (fastncmp("MUS_",word,4))
 		word += 4; // take off the MUS_
 	else if (fastncmp("O_",word,2) || fastncmp("D_",word,2))
 		word += 2; // take off the O_ or D_
-	for (i = 0; i < NUMMUSIC; i++)
-		if (S_music[i].name && fasticmp(word, S_music[i].name))
+
+	strncpy(lumptmp, word, 4);
+	lumptmp[3] = 0;
+	if (fasticmp("MAP",lumptmp))
+	{
+		word += 3;
+		if (toupper(word[0]) >= 'A' && toupper(word[0]) <= 'Z')
+			return (UINT16)M_MapNumber(word[0], word[1]);
+		else if ((i = atoi(word)))
 			return i;
-	deh_warning("Couldn't find music named 'MUS_%s'",word);
-	return mus_None;
+
+		word -= 3;
+		if (dehacked_mode)
+			deh_warning("Couldn't find music named 'MUS_%s'",word);
+		return 0;
+	}
+	for (i = 0; compat_special_music_slots[i][0]; ++i)
+		if (fasticmp(word, compat_special_music_slots[i]))
+			return i + 1036;
+	if (dehacked_mode)
+		deh_warning("Couldn't find music named 'MUS_%s'",word);
+	return 0;
 }
+#endif
 
 static hudnum_t get_huditem(const char *word)
 { // Returns the value of HUD_ enumerations
@@ -7642,11 +7701,13 @@ static fixed_t find_const(const char **rword)
 		free(word);
 		return r;
 	}
+#ifdef MUSICSLOT_COMPATIBILITY
 	else if (fastncmp("MUS_",word,4) || fastncmp("O_",word,2)) {
-		r = get_mus(word);
+		r = get_mus(word, true);
 		free(word);
 		return r;
 	}
+#endif
 	else if (fastncmp("PW_",word,3)) {
 		r = get_power(word);
 		free(word);
@@ -8016,33 +8077,29 @@ static inline int lib_getenum(lua_State *L)
 		if (mathlib) return luaL_error(L, "sfx '%s' could not be found.\n", word);
 		return 0;
 	}
+#ifdef MUSICSLOT_COMPATIBILITY
 	else if (!mathlib && fastncmp("mus_",word,4)) {
 		p = word+4;
-		for (i = 0; i < NUMMUSIC; i++)
-			if (S_music[i].name && fastcmp(p, S_music[i].name)) {
-				lua_pushinteger(L, i);
-				return 1;
-			}
-		return 0;
+		if ((i = get_mus(p, false)) == 0)
+			return 0;
+		lua_pushinteger(L, i);
+		return 1;
 	}
 	else if (mathlib && fastncmp("MUS_",word,4)) { // SOCs are ALL CAPS!
 		p = word+4;
-		for (i = 0; i < NUMMUSIC; i++)
-			if (S_music[i].name && fasticmp(p, S_music[i].name)) {
-				lua_pushinteger(L, i);
-				return 1;
-			}
-		return luaL_error(L, "music '%s' could not be found.\n", word);
+		if ((i = get_mus(p, false)) == 0)
+			return luaL_error(L, "music '%s' could not be found.\n", word);
+		lua_pushinteger(L, i);
+		return 1;
 	}
 	else if (mathlib && (fastncmp("O_",word,2) || fastncmp("D_",word,2))) {
 		p = word+2;
-		for (i = 0; i < NUMMUSIC; i++)
-			if (S_music[i].name && fasticmp(p, S_music[i].name)) {
-				lua_pushinteger(L, i);
-				return 1;
-			}
-		return luaL_error(L, "music '%s' could not be found.\n", word);
+		if ((i = get_mus(p, false)) == 0)
+			return luaL_error(L, "music '%s' could not be found.\n", word);
+		lua_pushinteger(L, i);
+		return 1;
 	}
+#endif
 	else if (!mathlib && fastncmp("pw_",word,3)) {
 		p = word+3;
 		for (i = 0; i < NUMPOWERS; i++)
@@ -8194,8 +8251,11 @@ static inline int lib_getenum(lua_State *L)
 	} else if (fastcmp(word,"globallevelskynum")) {
 		lua_pushinteger(L, globallevelskynum);
 		return 1;
-	} else if (fastcmp(word,"mapmusic")) {
-		lua_pushinteger(L, mapmusic);
+	} else if (fastcmp(word,"mapmusname")) {
+		lua_pushstring(L, mapmusname);
+		return 1;
+	} else if (fastcmp(word,"mapmusflags")) {
+		lua_pushinteger(L, mapmusflags);
 		return 1;
 	} else if (fastcmp(word,"server")) {
 		if ((!multiplayer || !netgame) && !playeringame[serverplayer])
@@ -8213,6 +8273,9 @@ static inline int lib_getenum(lua_State *L)
 	} else if (fastcmp(word,"gravity")) {
 		lua_pushinteger(L, gravity);
 		return 1;
+	} else if (fastcmp(word,"VERSIONSTRING")) {
+		lua_pushstring(L, VERSIONSTRING);
+		return 1;
 	}
 
 	return 0;
diff --git a/src/doomdef.h b/src/doomdef.h
index 8935eb1179b866b1e105007feb44c3e261203442..c3a0bfa6e3ca37ec3f534c15ab67aa42c5217e4c 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -148,13 +148,17 @@ extern FILE *logstream;
 // we use comprevision and compbranch instead.
 #else
 #define VERSION    201 // Game version
-#define SUBVERSION 14  // more precise version number
-#define VERSIONSTRING "v2.1.14"
-#define VERSIONSTRINGW L"v2.1.14"
+#define SUBVERSION 15  // more precise version number
+#define VERSIONSTRING "v2.1.15"
+#define VERSIONSTRINGW L"v2.1.15"
 // Hey! If you change this, add 1 to the MODVERSION below!
 // Otherwise we can't force updates!
 #endif
 
+// Does this version require an added patch file?
+// Comment or uncomment this as necessary.
+#define USE_PATCH_DTA
+
 // Modification options
 // If you want to take advantage of the Master Server's ability to force clients to update
 // to the latest version, fill these out.  Otherwise, just comment out UPDATE_ALERT and leave
@@ -208,7 +212,7 @@ extern FILE *logstream;
 // it's only for detection of the version the player is using so the MS can alert them of an update.
 // Only set it higher, not lower, obviously.
 // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
-#define MODVERSION 19
+#define MODVERSION 20
 
 // =========================================================================
 
@@ -427,9 +431,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
 ///	\note	obsoleted by cv_maxportals
 //#define PORTAL_LIMIT 8
 
-///	Fun experimental slope stuff!
-//#define SLOPENESS
-
 /// Kalaron/Eternity Engine slope code (SRB2CB ported)
 #define ESLOPE
 
@@ -449,10 +450,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
 ///	Polyobject fake flat code
 #define POLYOBJECTS_PLANES
 
-///	Blue spheres for future use.
-///	\todo	Remove this define.
-#define BLUE_SPHERES // Blue spheres for future use.
-
 ///	Improved way of dealing with ping values and a ping limit.
 #define NEWPING
 
@@ -490,4 +487,8 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
 /// Experimental tweaks to analog mode. (Needs a lot of work before it's ready for primetime.)
 //#define REDSANALOG
 
+/// Backwards compatibility with musicslots.
+/// \note	You should leave this enabled unless you're working with a future SRB2 version.
+#define MUSICSLOT_COMPATIBILITY
+
 #endif // __DOOMDEF__
diff --git a/src/doomstat.h b/src/doomstat.h
index 44cf6feaabc586a449c1b55ea729a5c0ec401ef2..ffdbcaecd51d9a96f72c91180218b2f91bb41dba 100644
--- a/src/doomstat.h
+++ b/src/doomstat.h
@@ -31,15 +31,11 @@
 
 // Selected by user.
 extern INT16 gamemap;
-
-// ----------------xxxxxxxxxxxxxxxx = music slot
-// -xxxxxxxxxxxxxxx---------------- = track slot
-// x------------------------------- = reset music bit
-extern UINT32 mapmusic;
-#define MUSIC_TRACKSHIFT  16
-#define MUSIC_SONGMASK    0x0000FFFF
-#define MUSIC_TRACKMASK   0x7FFF0000
-#define MUSIC_RELOADRESET 0x80000000
+extern char mapmusname[7];
+extern UINT16 mapmusflags;
+#define MUSIC_TRACKMASK   0x0FFF // ----************
+#define MUSIC_RELOADRESET 0x8000 // *---------------
+// Use other bits if necessary.
 
 extern INT16 maptol;
 extern UINT8 globalweather;
@@ -146,11 +142,13 @@ typedef struct
 	UINT16 xcoord[8];
 	UINT16 ycoord[8];
 	UINT16 picduration[8];
-	UINT16 musicslot;
 	UINT8 musicloop;
 	UINT16 textxpos;
 	UINT16 textypos;
 
+	char   musswitch[7];
+	UINT16 musswitchflags;
+
 	UINT8 fadecolor; // Color number for fade, 0 means don't do the first fade
 	UINT8 fadeinid;  // ID of the first fade, to a color -- ignored if fadecolor is 0
 	UINT8 fadeoutid; // ID of the second fade, to the new screen
@@ -218,8 +216,8 @@ typedef struct
 	UINT8 actnum;          ///< Act number or 0 for none.
 	UINT16 typeoflevel;    ///< Combination of typeoflevel flags.
 	INT16 nextlevel;       ///< Map number of next level, or 1100-1102 to end.
-	UINT16 musicslot;      ///< Music slot number to play. 0 for no music.
-	UINT16 musicslottrack; ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore.
+	char musname[7];       ///< Music track to play. "" for no music.
+	UINT16 mustrack;       ///< Subsong to play. Only really relevant for music modules and specific formats supported by GME. 0 to ignore.
 	char forcecharacter[17];  ///< (SKINNAMESIZE+1) Skin to switch to or "" to disable.
 	UINT8 weather;         ///< 0 = sunny day, 1 = storm, 2 = snow, 3 = rain, 4 = blank, 5 = thunder w/o rain, 6 = rain w/o lightning, 7 = heat wave.
 	INT16 skynum;          ///< Sky number to use.
diff --git a/src/doomtype.h b/src/doomtype.h
index 8e7da6881df87beb351470bbc1d6bfb01fead98a..d833176f780d32f9dd357ed0bbf9850b06830b68 100644
--- a/src/doomtype.h
+++ b/src/doomtype.h
@@ -94,7 +94,6 @@ typedef long ssize_t;
 #ifdef __APPLE_CC__
 #define DIRECTFULLSCREEN
 #define DEBUG_LOG
-#define HWRENDER
 #define NOIPX
 #endif
 
diff --git a/src/f_finale.c b/src/f_finale.c
index 2a1e5cce2685ec16d2e5ef88d8af13c3169ecabd..cb85cb196bdb3a1705b61b4e711d835280c6ef44 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -559,7 +559,7 @@ static void F_IntroDrawScene(void)
 				if (finalecount < 4)
 					S_StopMusic();
 				if (finalecount == 4)
-					S_ChangeMusic(mus_stjr, false);
+					S_ChangeMusicInternal("stjr", false);
 				x = (BASEVIDWIDTH<<FRACBITS)/2 - FixedMul(334<<FRACBITS, aspect)/2;
 				y = (BASEVIDHEIGHT<<FRACBITS)/2 - FixedMul(358<<FRACBITS, aspect)/2;
 				V_DrawSciencePatch(x, y, 0, (patch = W_CachePatchName("WAHH1", PU_CACHE)), aspect);
@@ -771,7 +771,7 @@ void F_IntroDrawer(void)
 				F_RunWipe(99,true);
 			}
 
-			S_ChangeMusic(mus_read_m, false);
+			S_ChangeMusicInternal("read_m", false);
 		}
 		else if (intro_scenenum == 3)
 			roidtics = BASEVIDWIDTH - 64;
@@ -1126,7 +1126,7 @@ void F_StartCredits(void)
 	CON_ClearHUD();
 	S_StopMusic();
 
-	S_ChangeMusic(mus_credit, false);
+	S_ChangeMusicInternal("credit", false);
 
 	finalecount = 0;
 	animtimer = 0;
@@ -1423,7 +1423,7 @@ void F_StartTitleScreen(void)
 
 	// IWAD dependent stuff.
 
-	S_ChangeMusic(mus_titles, looptitle);
+	S_ChangeMusicInternal("titles", looptitle);
 
 	animtimer = 0;
 
@@ -1589,7 +1589,7 @@ void F_StartContinue(void)
 	// In case menus are still up?!!
 	M_ClearMenus(true);
 
-	S_ChangeMusic(mus_contsc, false);
+	S_ChangeMusicInternal("contsc", false);
 	S_StopSounds();
 
 	timetonext = TICRATE*11;
@@ -1703,8 +1703,10 @@ static void F_AdvanceToNextScene(void)
 	picxpos = cutscenes[cutnum]->scene[scenenum].xcoord[picnum];
 	picypos = cutscenes[cutnum]->scene[scenenum].ycoord[picnum];
 
-	if (cutscenes[cutnum]->scene[scenenum].musicslot != 0)
-		S_ChangeMusic(cutscenes[cutnum]->scene[scenenum].musicslot, cutscenes[cutnum]->scene[scenenum].musicloop);
+	if (cutscenes[cutnum]->scene[scenenum].musswitch[0])
+		S_ChangeMusic(cutscenes[cutnum]->scene[scenenum].musswitch,
+			cutscenes[cutnum]->scene[scenenum].musswitchflags,
+			cutscenes[cutnum]->scene[scenenum].musicloop);
 
 	// Fade to the next
 	dofadenow = true;
@@ -1775,8 +1777,10 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
 	animtimer = cutscenes[cutnum]->scene[0].picduration[0]; // Picture duration
 	stoptimer = 0;
 
-	if (cutscenes[cutnum]->scene[scenenum].musicslot != 0)
-		S_ChangeMusic(cutscenes[cutnum]->scene[scenenum].musicslot, cutscenes[cutnum]->scene[scenenum].musicloop);
+	if (cutscenes[cutnum]->scene[0].musswitch[0])
+		S_ChangeMusic(cutscenes[cutnum]->scene[0].musswitch,
+			cutscenes[cutnum]->scene[0].musswitchflags,
+			cutscenes[cutnum]->scene[0].musicloop);
 	else
 		S_StopMusic();
 }
diff --git a/src/g_game.c b/src/g_game.c
index dda8793bb58d5291a447d1a4baf57837235612ee..3b7ef158f3748eec3b3ceff6985f2a84cf786ce5 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -69,8 +69,10 @@ static void G_DoStartContinue(void);
 static void G_DoContinued(void);
 static void G_DoWorldDone(void);
 
+char   mapmusname[7]; // Music name
+UINT16 mapmusflags; // Track and reset bit
+
 INT16 gamemap = 1;
-UINT32 mapmusic; // music, track, and reset bit
 INT16 maptol;
 UINT8 globalweather = 0;
 INT32 curWeather = PRECIP_NONE;
@@ -2182,12 +2184,13 @@ void G_PlayerReborn(INT32 player)
 
 	if (p-players == consoleplayer)
 	{
-		if (mapmusic & MUSIC_RELOADRESET) // TODO: Might not need this here
+		if (mapmusflags & MUSIC_RELOADRESET)
 		{
-			mapmusic = mapheaderinfo[gamemap-1]->musicslot
-				| (mapheaderinfo[gamemap-1]->musicslottrack << MUSIC_TRACKSHIFT);
+			strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7);
+			mapmusname[6] = 0;
+			mapmusflags = mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK;
 		}
-		S_ChangeMusic(mapmusic, true);
+		S_ChangeMusic(mapmusname, mapmusflags, true);
 	}
 
 	if (gametype == GT_COOP)
@@ -2328,6 +2331,11 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost)
 		}
 	}
 	P_MovePlayerToSpawn(playernum, spawnpoint);
+	
+#ifdef HAVE_BLUA 
+	LUAh_PlayerSpawn(&players[playernum]); // Lua hook for player spawning :)
+#endif
+
 }
 
 mapthing_t *G_FindCTFStart(INT32 playernum)
@@ -2871,7 +2879,8 @@ static void G_DoCompleted(void)
 
 	// We are committed to this map now.
 	// We may as well allocate its header if it doesn't exist
-	if(!mapheaderinfo[nextmap])
+	// (That is, if it's a real map)
+	if (nextmap < NUMMAPS && !mapheaderinfo[nextmap])
 		P_AllocMapHeader(nextmap);
 
 	if (skipstats)
@@ -3521,7 +3530,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean
 	if (paused)
 	{
 		paused = false;
-		S_ResumeSound();
+		S_ResumeAudio();
 	}
 
 	if (netgame || multiplayer) // Nice try, haxor.
@@ -3595,7 +3604,7 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer, boolean
 	globalweather = mapheaderinfo[gamemap-1]->weather;
 
 	// Don't carry over custom music change to another map.
-	mapmusic |= MUSIC_RELOADRESET;
+	mapmusflags |= MUSIC_RELOADRESET;
 
 	ultimatemode = pultmode;
 	playerdeadview = false;
diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h
index 83dff02f877e17db254f5e0e35bb47095bc7c18e..94eef1d3e46e95f825f7ac89088cbb6674636225 100644
--- a/src/hardware/hw_glob.h
+++ b/src/hardware/hw_glob.h
@@ -36,9 +36,7 @@ typedef struct
 {
 	float x;
 	float y;
-//#ifdef SLOPENESS
 	float z;
-//#endif
 } polyvertex_t;
 
 #ifdef _MSC_VER
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 409900b986f989b7a001bfd262ec1bf33a394eba..58e4e87f2bf431ec3168c78ce45d33143e95ef82 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -539,6 +539,8 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fi
 	static FOutVector *planeVerts = NULL;
 	static UINT16 numAllocedPlaneVerts = 0;
 
+	(void)sector;
+
 	// no convex poly were generated for this subsector
 	if (!xsub->planepoly)
 		return;
@@ -678,25 +680,6 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fi
 		v3d->x = pv->x;
 		v3d->y = height;
 		v3d->z = pv->y;
-#ifdef SLOPENESS
-		if (sector && sector->special == 65535)
-		{
-			size_t q;
-			for (q = 0; q < sector->linecount; q++)
-			{
-				if (v3d->x == sector->lines[q]->v1->x>>FRACBITS)
-				{
-					if (v3d->z == sector->lines[q]->v1->y>>FRACBITS)
-					{
-						v3d->y += sector->lines[q]->v1->z>>FRACBITS;
-						break;
-					}
-				}
-			}
-		}
-#else
-		(void)sector;
-#endif
 	}
 
 	// only useful for flat coloured triangles
diff --git a/src/info.c b/src/info.c
index fb19fa2b43113e5f5e5747e654c38b205ef1a5d9..0eda417708b0980515f528e05cd253b697621e7c 100644
--- a/src/info.c
+++ b/src/info.c
@@ -4569,7 +4569,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
-#ifdef BLUE_SPHERES
 	{           // MT_BLUEBALL
 		-1,             // doomednum
 		S_BLUEBALL,    // spawnstate
@@ -4596,7 +4595,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
 		S_NULL          // raisestate
 	},
-#endif
 
 	{           // MT_REDTEAMRING
 		308,            // doomednum
diff --git a/src/info.h b/src/info.h
index 9596f038421bd82f2b7c8b6235c63a8ce1994326..6e14448f470db76359c825d5ec993603249e1a4d 100644
--- a/src/info.h
+++ b/src/info.h
@@ -3049,9 +3049,7 @@ typedef enum mobj_type
 	// Collectible Items
 	MT_RING,
 	MT_FLINGRING, // Lost ring
-#ifdef BLUE_SPHERES
 	MT_BLUEBALL,  // Blue sphere replacement for special stages
-#endif
 	MT_REDTEAMRING,  //Rings collectable by red team.
 	MT_BLUETEAMRING, //Rings collectable by blue team.
 	MT_EMMY, // emerald token for special stage
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index be06982f3391ddd06cd2173960be1d0e898ccde9..a7f2eb39fc4887e33a2c19108a52d2da9c322c85 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -85,6 +85,14 @@ static int lib_print(lua_State *L)
 	return 0;
 }
 
+static int lib_evalMath(lua_State *L)
+{
+	const char *word = luaL_checkstring(L, 1);
+	LUA_Deprecated(L, "EvalMath(string)", "_G[string]");
+	lua_pushinteger(L, LUA_EvalMath(word));
+	return 1;
+}
+
 // M_RANDOM
 //////////////
 
@@ -1660,18 +1668,63 @@ static int lib_sStopSound(lua_State *L)
 
 static int lib_sChangeMusic(lua_State *L)
 {
-	UINT32 music_num = (UINT32)luaL_checkinteger(L, 1);
+#ifdef MUSICSLOT_COMPATIBILITY
+	const char *music_name;
+	UINT32 music_num;
+	char music_compat_name[7];
+
+	boolean looping;
+	player_t *player = NULL;
+	UINT16 music_flags = 0;
+	NOHUD
+
+	if (lua_isnumber(L, 1))
+	{
+		music_num = (UINT32)luaL_checkinteger(L, 1);
+		music_flags = (UINT16)(music_num & 0x0000FFFF);
+		if (music_flags && music_flags <= 1035)
+			snprintf(music_compat_name, 7, "%sM", G_BuildMapName((INT32)music_flags));
+		else if (music_flags && music_flags <= 1050)
+			strncpy(music_compat_name, compat_special_music_slots[music_flags - 1036], 7);
+		else
+			music_compat_name[0] = 0; // becomes empty string
+		music_compat_name[6] = 0;
+		music_name = (const char *)&music_compat_name;
+		music_flags = 0;
+	}
+	else
+	{
+		music_num = 0;
+		music_name = luaL_checkstring(L, 1);
+	}
+
+
+	looping = (boolean)lua_opttrueboolean(L, 2);
+
+#else
+	const char *music_name = luaL_checkstring(L, 1);
 	boolean looping = (boolean)lua_opttrueboolean(L, 2);
 	player_t *player = NULL;
+	UINT16 music_flags = 0;
 	NOHUD
+
+#endif
 	if (!lua_isnone(L, 3) && lua_isuserdata(L, 3))
 	{
 		player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER));
 		if (!player)
 			return LUA_ErrInvalid(L, "player_t");
 	}
+
+#ifdef MUSICSLOT_COMPATIBILITY
+	if (music_num)
+		music_flags = (UINT16)((music_num & 0x7FFF0000) >> 16);
+	else
+#endif
+	music_flags = (UINT16)luaL_optinteger(L, 4, 0);
+
 	if (!player || P_IsLocalPlayer(player))
-	S_ChangeMusic(music_num, looping);
+		S_ChangeMusic(music_name, music_flags, looping);
 	return 0;
 }
 
@@ -1878,6 +1931,7 @@ static int lib_gTicsToMilliseconds(lua_State *L)
 
 static luaL_Reg lib[] = {
 	{"print", lib_print},
+	{"EvalMath", lib_evalMath},
 
 	// m_random
 	{"P_Random",lib_pRandom},
diff --git a/src/lua_hook.h b/src/lua_hook.h
index da2dcdc380461cefd958b9f42bfbe738a98d724b..4eb083780ea69e5d1674483e9ef83908a5dd9cba 100644
--- a/src/lua_hook.h
+++ b/src/lua_hook.h
@@ -42,6 +42,7 @@ enum hook {
 	hook_LinedefExecute,
 	hook_PlayerMsg,
 	hook_HurtMsg,
+	hook_PlayerSpawn,
 
 	hook_MAX // last hook
 };
@@ -75,5 +76,6 @@ boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); // Hook for B_B
 boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector); // Hook for linedef executors
 boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg); // Hook for chat messages
 boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages
+#define LUAh_PlayerSpawn(player) LUAh_PlayerHook(player, hook_PlayerSpawn) // Hook for G_SpawnPlayer 
 
 #endif
diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c
index 0415d23e61acfe98705ec8855846b06297fcdf02..2c1aa1cea97cffcaf833015ac8cacaa5f6395ce6 100644
--- a/src/lua_hooklib.c
+++ b/src/lua_hooklib.c
@@ -53,6 +53,7 @@ const char *const hookNames[hook_MAX+1] = {
 	"LinedefExecute",
 	"PlayerMsg",
 	"HurtMsg",
+	"PlayerSpawn",
 	NULL
 };
 
@@ -768,4 +769,33 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source)
 	return hooked;
 }
 
+void LUAh_NetArchiveHook(lua_CFunction archFunc)
+{
+	hook_p hookp;
+
+	if (!gL || !(hooksAvailable[hook_NetVars/8] & (1<<(hook_NetVars%8))))
+		return;
+
+	// stack: tables
+	I_Assert(lua_gettop(gL) > 0);
+	I_Assert(lua_istable(gL, -1));
+
+	// tables becomes an upvalue of archFunc
+	lua_pushvalue(gL, -1);
+	lua_pushcclosure(gL, archFunc, 1);
+	// stack: tables, archFunc
+
+	for (hookp = roothook; hookp; hookp = hookp->next)
+		if (hookp->type == hook_NetVars)
+		{
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -2); // archFunc
+			LUA_Call(gL, 1);
+		}
+
+	lua_pop(gL, 1); // pop archFunc
+	// stack: tables
+}
+
 #endif
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 5a83d95b56a6a3a39cf7d0364c39a2866964dd26..325f00b013e5495f67d79b2ca78775e02812a4c6 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -16,7 +16,9 @@
 #include "r_local.h"
 #include "st_stuff.h" // hudinfo[]
 #include "g_game.h"
+#include "i_video.h" // rendermode
 #include "p_local.h" // camera_t
+#include "screen.h" // screen width/height
 #include "v_video.h"
 #include "w_wad.h"
 #include "z_zone.h"
@@ -486,7 +488,7 @@ static int libd_getColormap(lua_State *L)
 	INT32 skinnum = TC_DEFAULT;
 	skincolors_t color = luaL_optinteger(L, 2, 0);
 	UINT8* colormap = NULL;
-	//HUDSAFE
+	HUDONLY
 	if (lua_isnoneornil(L, 1))
 		; // defaults to TC_DEFAULT
 	else if (lua_type(L, 1) == LUA_TNUMBER) // skin number
@@ -510,6 +512,31 @@ static int libd_getColormap(lua_State *L)
 	return 1;
 }
 
+static int libd_width(lua_State *L)
+{
+	HUDONLY
+	lua_pushinteger(L, vid.width); // push screen width
+	return 1;
+}
+
+static int libd_height(lua_State *L)
+{
+	HUDONLY
+	lua_pushinteger(L, vid.height); // push screen height
+	return 1;
+}
+
+static int libd_renderer(lua_State *L)
+{
+	HUDONLY
+	switch (rendermode) {
+		case render_opengl: lua_pushliteral(L, "opengl");   break; // OpenGL renderer
+		case render_soft:   lua_pushliteral(L, "software"); break; // Software renderer
+		default:            lua_pushliteral(L, "none");     break; // render_none (for dedicated), in case there's any reason this should be run
+	}
+	return 1;
+}
+
 static luaL_Reg lib_draw[] = {
 	{"patchExists", libd_patchExists},
 	{"cachePatch", libd_cachePatch},
@@ -521,6 +548,9 @@ static luaL_Reg lib_draw[] = {
 	{"drawString", libd_drawString},
 	{"stringWidth", libd_stringWidth},
 	{"getColormap", libd_getColormap},
+	{"width", libd_width},
+	{"height", libd_height},
+	{"renderer", libd_renderer},
 	{NULL, NULL}
 };
 
diff --git a/src/lua_libs.h b/src/lua_libs.h
index d19ad88578de24bfa4a3f14163f2b39ac750c717..25552eacbe507a9c09f18007923959f0220a9e9a 100644
--- a/src/lua_libs.h
+++ b/src/lua_libs.h
@@ -42,6 +42,7 @@ extern lua_State *gL;
 
 #define META_CVAR "CONSVAR_T*"
 
+#define META_SECTORLINES "SECTOR_T*LINES"
 #define META_SIDENUM "LINE_T*SIDENUM"
 
 #define META_HUDINFO "HUDINFO_T*"
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index 16d05dacdfeb839ac3aa33d449f51695423c0604..b6b5147a9abbfa939c14e3bb14a5f7bc0af9cf39 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -37,6 +37,7 @@ enum sector_e {
 	sector_thinglist,
 	sector_heightsec,
 	sector_camsec,
+	sector_lines,
 	sector_ffloors
 };
 
@@ -52,6 +53,7 @@ static const char *const sector_opt[] = {
 	"thinglist",
 	"heightsec",
 	"camsec",
+	"lines",
 	"ffloors",
 	NULL};
 
@@ -260,6 +262,67 @@ static int sector_iterate(lua_State *L)
 	return 3;
 }
 
+// sector.lines, i -> sector.lines[i]
+// sector.lines.valid, for validity checking
+static int sectorlines_get(lua_State *L)
+{
+	line_t **seclines = *((line_t ***)luaL_checkudata(L, 1, META_SECTORLINES));
+	size_t i;
+	size_t numoflines = 0;
+	lua_settop(L, 2);
+	if (!lua_isnumber(L, 2))
+	{
+		int field = luaL_checkoption(L, 2, NULL, valid_opt);
+		if (!seclines)
+		{
+			if (field == 0) {
+				lua_pushboolean(L, 0);
+				return 1;
+			}
+			return luaL_error(L, "accessed sector_t doesn't exist anymore.");
+		} else if (field == 0) {
+			lua_pushboolean(L, 1);
+			return 1;
+		}
+	}
+
+	// check first linedef to figure which of its sectors owns this sector->lines pointer
+	// then check that sector's linecount to get a maximum index
+	//if (!seclines[0])
+		//return luaL_error(L, "no lines found!"); // no first linedef?????
+	if (seclines[0]->frontsector->lines == seclines)
+		numoflines = seclines[0]->frontsector->linecount;
+	else if (seclines[0]->backsector && seclines[0]->backsector->lines == seclines) // check backsector exists first
+		numoflines = seclines[0]->backsector->linecount;
+	//if neither sector has it then ???
+
+	if (!numoflines)
+		return luaL_error(L, "no lines found!");
+
+	i = (size_t)lua_tointeger(L, 2);
+	if (i >= numoflines)
+		return 0;
+	LUA_PushUserdata(L, seclines[i], META_LINE);
+	return 1;
+}
+
+static int sectorlines_num(lua_State *L)
+{
+	line_t **seclines = *((line_t ***)luaL_checkudata(L, 1, META_SECTORLINES));
+	size_t numoflines = 0;
+	// check first linedef to figure which of its sectors owns this sector->lines pointer
+	// then check that sector's linecount to get a maximum index
+	//if (!seclines[0])
+		//return luaL_error(L, "no lines found!"); // no first linedef?????
+	if (seclines[0]->frontsector->lines == seclines)
+		numoflines = seclines[0]->frontsector->linecount;
+	else if (seclines[0]->backsector && seclines[0]->backsector->lines == seclines) // check backsector exists first
+		numoflines = seclines[0]->backsector->linecount;
+	//if neither sector has it then ???
+	lua_pushinteger(L, numoflines);
+	return 1;
+}
+
 static int sector_get(lua_State *L)
 {
 	sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
@@ -325,6 +388,9 @@ static int sector_get(lua_State *L)
 			return 0;
 		LUA_PushUserdata(L, &sectors[sector->camsec], META_SECTOR);
 		return 1;
+	case sector_lines: // lines
+		LUA_PushUserdata(L, sector->lines, META_SECTORLINES);
+		return 1;
 	case sector_ffloors: // ffloors
 		lua_pushcfunction(L, lib_iterateSectorFFloors);
 		LUA_PushUserdata(L, sector->ffloors, META_FFLOOR);
@@ -1172,10 +1238,10 @@ static int mapheaderinfo_get(lua_State *L)
 		lua_pushinteger(L, header->typeoflevel);
 	else if (fastcmp(field,"nextlevel"))
 		lua_pushinteger(L, header->nextlevel);
-	else if (fastcmp(field,"musicslot"))
-		lua_pushinteger(L, header->musicslot);
-	else if (fastcmp(field,"musicslottrack"))
-		lua_pushinteger(L, header->musicslottrack);
+	else if (fastcmp(field,"musname"))
+		lua_pushstring(L, header->musname);
+	else if (fastcmp(field,"mustrack"))
+		lua_pushinteger(L, header->mustrack);
 	else if (fastcmp(field,"forcecharacter"))
 		lua_pushstring(L, header->forcecharacter);
 	else if (fastcmp(field,"weather"))
@@ -1234,6 +1300,14 @@ static int mapheaderinfo_get(lua_State *L)
 
 int LUA_MapLib(lua_State *L)
 {
+	luaL_newmetatable(L, META_SECTORLINES);
+		lua_pushcfunction(L, sectorlines_get);
+		lua_setfield(L, -2, "__index");
+
+		lua_pushcfunction(L, sectorlines_num);
+		lua_setfield(L, -2, "__len");
+	lua_pop(L, 1);
+
 	luaL_newmetatable(L, META_SECTOR);
 		lua_pushcfunction(L, sector_get);
 		lua_setfield(L, -2, "__index");
diff --git a/src/lua_script.c b/src/lua_script.c
index a7315ad622438608ad207d805ea455aec3570a3a..9925bac02ee05cf5d7f686b6ddde09005f69f5be 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -915,30 +915,6 @@ static void UnArchiveTables(void)
 	}
 }
 
-static void NetArchiveHook(lua_CFunction archFunc)
-{
-	int TABLESINDEX;
-
-	if (!gL)
-		return;
-
-	TABLESINDEX = lua_gettop(gL);
-	lua_getfield(gL, LUA_REGISTRYINDEX, "hook");
-	I_Assert(lua_istable(gL, -1));
-	lua_rawgeti(gL, -1, hook_NetVars);
-	lua_remove(gL, -2);
-	I_Assert(lua_istable(gL, -1));
-
-	lua_pushvalue(gL, TABLESINDEX);
-	lua_pushcclosure(gL, archFunc, 1);
-	lua_pushnil(gL);
-	while (lua_next(gL, -3) != 0) {
-		lua_pushvalue(gL, -3); // function
-		LUA_Call(gL, 1);
-	}
-	lua_pop(gL, 2);
-}
-
 void LUA_Step(void)
 {
 	if (!gL)
@@ -972,7 +948,7 @@ void LUA_Archive(void)
 		}
 	WRITEUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum.
 
-	NetArchiveHook(NetArchive); // call the NetArchive hook in archive mode
+	LUAh_NetArchiveHook(NetArchive); // call the NetArchive hook in archive mode
 	ArchiveTables();
 
 	if (gL)
@@ -1003,7 +979,7 @@ void LUA_UnArchive(void)
 				UnArchiveExtVars(th); // apply variables
 	} while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker.
 
-	NetArchiveHook(NetUnArchive); // call the NetArchive hook in unarchive mode
+	LUAh_NetArchiveHook(NetUnArchive); // call the NetArchive hook in unarchive mode
 	UnArchiveTables();
 
 	if (gL)
diff --git a/src/lua_script.h b/src/lua_script.h
index 292160a0b5356e2494d6557207dfe20c2167d993..45fab2f53570f4118fdb14026807532b59dc9080 100644
--- a/src/lua_script.h
+++ b/src/lua_script.h
@@ -30,9 +30,9 @@
 #define lua_pushfixed(L, f) lua_pushinteger(L, f)
 
 // angle_t casting
-// we reduce the angle to a fixed point between 0.0 and 1.0
-#define luaL_checkangle(L, i) (((angle_t)(luaL_checkfixed(L, i)&0xFFFF))<<16)
-#define lua_pushangle(L, a) lua_pushfixed(L, a>>16)
+// TODO deal with signedness
+#define luaL_checkangle(L, i) ((angle_t)luaL_checkinteger(L, i))
+#define lua_pushangle(L, a) lua_pushinteger(L, a)
 
 #ifdef _DEBUG
 void LUA_ClearExtVars(void);
@@ -55,6 +55,7 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c
 void LUA_CVarChanged(const char *name); // lua_consolelib.c
 int Lua_optoption(lua_State *L, int narg,
 	const char *def, const char *const lst[]);
+void LUAh_NetArchiveHook(lua_CFunction archFunc);
 
 // Console wrapper
 void COM_Lua_f(void);
@@ -69,4 +70,15 @@ void COM_Lua_f(void);
 
 #define LUA_ErrInvalid(L, type) luaL_error(L, "accessed " type " doesn't exist anymore, please check 'valid' before using " type ".");
 
+// Deprecation warnings
+// Shows once upon use. Then doesn't show again.
+#define LUA_Deprecated(L,this_func,use_instead)\
+{\
+	static UINT8 seen = 0;\
+	if (!seen) {\
+		seen = 1;\
+		CONS_Alert(CONS_WARNING,"\"%s\" is deprecated and will be removed.\nUse \"%s\" instead.\n", this_func, use_instead);\
+	}\
+}
+
 #endif
diff --git a/src/m_menu.c b/src/m_menu.c
index 780de7ad5f5984e3a74f5a3e7a062938cc02de56..95752c7aacc1f34de012bb820e6f894fdd26ede8 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -4751,7 +4751,7 @@ static void M_SetupChoosePlayer(INT32 choice)
 	if (Playing() == false)
 	{
 		S_StopMusic();
-		S_ChangeMusic(mus_chrsel, true);
+		S_ChangeMusicInternal("chrsel", true);
 	}
 
 	SP_PlayerDef.prevMenu = currentMenu;
@@ -5202,7 +5202,7 @@ void M_DrawTimeAttackMenu(void)
 	lumpnum_t lumpnum;
 	char beststr[40];
 
-	S_ChangeMusic(mus_racent, true); // Eww, but needed for when user hits escape during demo playback
+	S_ChangeMusicInternal("racent", true); // Eww, but needed for when user hits escape during demo playback
 
 	V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE));
 
@@ -5365,7 +5365,7 @@ static void M_TimeAttack(INT32 choice)
 	itemOn = tastart; // "Start" is selected.
 
 	G_SetGamestate(GS_TIMEATTACK);
-	S_ChangeMusic(mus_racent, true);
+	S_ChangeMusicInternal("racent", true);
 }
 
 // Drawing function for Nights Attack
@@ -5375,7 +5375,7 @@ void M_DrawNightsAttackMenu(void)
 	lumpnum_t lumpnum;
 	char beststr[40];
 
-	S_ChangeMusic(mus_racent, true); // Eww, but needed for when user hits escape during demo playback
+	S_ChangeMusicInternal("racent", true); // Eww, but needed for when user hits escape during demo playback
 
 	V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE));
 
@@ -5498,7 +5498,7 @@ static void M_NightsAttack(INT32 choice)
 	itemOn = nastart; // "Start" is selected.
 
 	G_SetGamestate(GS_TIMEATTACK);
-	S_ChangeMusic(mus_racent, true);
+	S_ChangeMusicInternal("racent", true);
 }
 
 // Player has selected the "START" from the nights attack screen
@@ -5732,7 +5732,7 @@ static void M_ModeAttackEndGame(INT32 choice)
 	itemOn = currentMenu->lastOn;
 	G_SetGamestate(GS_TIMEATTACK);
 	modeattacking = ATTACKING_NONE;
-	S_ChangeMusic(mus_racent, true);
+	S_ChangeMusicInternal("racent", true);
 	// Update replay availability.
 	CV_AddValue(&cv_nextmap, 1);
 	CV_AddValue(&cv_nextmap, -1);
@@ -6944,7 +6944,7 @@ static void M_ToggleDigital(void)
 		if (nodigimusic) return;
 		S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value);
 		S_StopMusic();
-		S_ChangeMusic(mus_lclear, false);
+		S_ChangeMusicInternal("lclear", false);
 		M_StartMessage(M_GetText("Digital Music Enabled\n"), NULL, MM_NOTHING);
 	}
 	else
@@ -6971,7 +6971,7 @@ static void M_ToggleMIDI(void)
 		I_InitMIDIMusic();
 		if (nomidimusic) return;
 		S_Init(cv_soundvolume.value, cv_digmusicvolume.value, cv_midimusicvolume.value);
-		S_ChangeMusic(mus_lclear, false);
+		S_ChangeMusicInternal("lclear", false);
 		M_StartMessage(M_GetText("MIDI Music Enabled\n"), NULL, MM_NOTHING);
 	}
 	else
diff --git a/src/md5.c b/src/md5.c
index aeaac2cdee6d5421e0c8c391b0da3246351f6e31..ba89c499b11ba6875e3420b450444ef365ac96ff 100644
--- a/src/md5.c
+++ b/src/md5.c
@@ -36,7 +36,7 @@
  #include <stdlib.h>
 #else
  #ifndef HAVE_MEMCPY
-  #if !((defined (_WIN32) || defined (_WIN32_WCE)) && !defined (__CYGWIN__))
+  #if !((defined (_WIN32) || defined (_WIN32_WCE)) && !defined (__CYGWIN__)) && !defined (__APPLE__)
    #define memcpy(d, s, n) bcopy ((s), (d), (n))
   #endif
  #endif
diff --git a/src/p_enemy.c b/src/p_enemy.c
index bc6f604810448cbf65d917a731c2d91f5a42407e..ffb69082213b86374f923ab2875452407ea0ac3f 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -3063,12 +3063,8 @@ void A_Invincibility(mobj_t *actor)
 	{
 		S_StopMusic();
 		if (mariomode)
-		{
-			S_ChangeMusic(mus_minvnc, false);
 			G_GhostAddColor(GHC_INVINCIBLE);
-		}
-		else
-			S_ChangeMusic(mus_invinc, false);
+		S_ChangeMusicInternal((mariomode) ? "minvnc" : "invinc", false);
 	}
 }
 
@@ -3104,7 +3100,7 @@ void A_SuperSneakers(mobj_t *actor)
 		else
 		{
 			S_StopMusic();
-			S_ChangeMusic(mus_shoes, false);
+			S_ChangeMusicInternal("shoes", false);
 		}
 	}
 }
@@ -7227,7 +7223,7 @@ void A_ChangeAngleAbsolute(mobj_t *actor)
 	//const angle_t amin = FixedAngle(locvar1*FRACUNIT);
 	//const angle_t amax = FixedAngle(locvar2*FRACUNIT);
 #ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ChangeAngelAbsolute", actor))
+	if (LUA_CallAction("A_ChangeAngleAbsolute", actor))
 		return;
 #endif
 
diff --git a/src/p_floor.c b/src/p_floor.c
index b8d3f7b5e0098605bb44dd37e4e25dfca6d4d81b..cacaadf8101406b47f10a75969ea7783cbca4edf 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -1973,71 +1973,51 @@ void T_NoEnemiesSector(levelspecthink_t *nobaddies)
 {
 	size_t i;
 	fixed_t upperbound, lowerbound;
-	sector_t *sec = NULL;
-	sector_t *targetsec = NULL;
-	INT32 secnum = -1;
+	INT32 s;
+	sector_t *checksector;
 	msecnode_t *node;
 	mobj_t *thing;
-	boolean FOFsector = false;
+	boolean exists = false;
 
-	while ((secnum = P_FindSectorFromLineTag(nobaddies->sourceline, secnum)) >= 0)
+	for (i = 0; i < nobaddies->sector->linecount; i++)
 	{
-		sec = &sectors[secnum];
-
-		FOFsector = false;
-
-		// Check the lines of this sector, to see if it is a FOF control sector.
-		for (i = 0; i < sec->linecount; i++)
+		if (nobaddies->sector->lines[i]->special == 223)
 		{
-			INT32 targetsecnum = -1;
-
-			if (sec->lines[i]->special < 100 || sec->lines[i]->special >= 300)
-				continue;
 
-			FOFsector = true;
+			upperbound = nobaddies->sector->ceilingheight;
+			lowerbound = nobaddies->sector->floorheight;
 
-			while ((targetsecnum = P_FindSectorFromLineTag(sec->lines[i], targetsecnum)) >= 0)
+			for (s = -1; (s = P_FindSectorFromLineTag(nobaddies->sector->lines[i], s)) >= 0 ;)
 			{
-				targetsec = &sectors[targetsecnum];
+				checksector = &sectors[s];
 
-				upperbound = targetsec->ceilingheight;
-				lowerbound = targetsec->floorheight;
-				node = targetsec->touching_thinglist; // things touching this sector
+				node = checksector->touching_thinglist; // things touching this sector
 				while (node)
 				{
 					thing = node->m_thing;
 
 					if ((thing->flags & (MF_ENEMY|MF_BOSS)) && thing->health > 0
-					&& thing->z < upperbound && thing->z+thing->height > lowerbound)
-						return;
+						&& thing->z < upperbound && thing->z+thing->height > lowerbound)
+					{
+						exists = true;
+						goto foundenemy;
+					}
 
 					node = node->m_snext;
 				}
 			}
 		}
-
-		if (!FOFsector)
-		{
-			upperbound = sec->ceilingheight;
-			lowerbound = sec->floorheight;
-			node = sec->touching_thinglist; // things touching this sector
-			while (node)
-			{
-				thing = node->m_thing;
-
-				if ((thing->flags & (MF_ENEMY|MF_BOSS)) && thing->health > 0
-				&& thing->z < upperbound && thing->z+thing->height > lowerbound)
-					return;
-
-				node = node->m_snext;
-			}
-		}
 	}
+foundenemy:
+	if (exists)
+		return;
+
+	s = P_AproxDistance(nobaddies->sourceline->dx, nobaddies->sourceline->dy)>>FRACBITS;
 
-	CONS_Debug(DBG_GAMELOGIC, "Running no-more-enemies exec with tag of %d\n", nobaddies->sourceline->tag);
+	CONS_Debug(DBG_GAMELOGIC, "Running no-more-enemies exec with tag of %d\n", s);
 
-	// No enemies found, run the linedef exec and terminate this thinker
-	P_RunTriggerLinedef(nobaddies->sourceline, NULL, NULL);
+	// Otherwise, run the linedef exec and terminate this thinker
+	P_LinedefExecute((INT16)s, NULL, NULL);
 	P_RemoveThinker(&nobaddies->thinker);
 }
 
diff --git a/src/p_inter.c b/src/p_inter.c
index 55d36a1dee451882bb84298c9c3c2473c0d85d1d..b8101f12b1561f97c88e64bebd30ce99e215c189 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -405,7 +405,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			if ((maptol & TOL_NIGHTS) && special->type != MT_FLINGCOIN)
 				P_DoNightsScore(player);
 			break;
-#ifdef BLUE_SPHERES
 		case MT_BLUEBALL:
 			if (!(P_CanPickupItem(player, false)))
 				return;
@@ -422,7 +421,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			if (maptol & TOL_NIGHTS)
 				P_DoNightsScore(player);
 			break;
-#endif
 		case MT_AUTOPICKUP:
 		case MT_BOUNCEPICKUP:
 		case MT_SCATTERPICKUP:
@@ -766,10 +764,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 					}
 
 					if (!(mo2->type == MT_NIGHTSWING || mo2->type == MT_RING || mo2->type == MT_COIN
-#ifdef BLUE_SPHERES
-					      || mo2->type == MT_BLUEBALL
-#endif
-					     ))
+					   || mo2->type == MT_BLUEBALL))
 						continue;
 
 					// Yay! The thing's in reach! Pull it in!
@@ -2076,7 +2071,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source)
 				if (P_IsLocalPlayer(target->player) && target->player == &players[consoleplayer])
 				{
 					S_StopMusic(); // Stop the Music! Tails 03-14-2000
-					S_ChangeMusic(mus_gmover, false); // Yousa dead now, Okieday? Tails 03-14-2000
+					S_ChangeMusicInternal("gmover", false); // Yousa dead now, Okieday? Tails 03-14-2000
 				}
 			}
 		}
@@ -2464,7 +2459,7 @@ static inline void P_NiGHTSDamage(mobj_t *target, mobj_t *source)
 			&& player->nightstime < 10*TICRATE)
 		{
 			//S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH
-			S_ChangeMusic(mus_drown,false);
+			S_ChangeMusicInternal("drown",false);
 		}
 	}
 }
diff --git a/src/p_mobj.c b/src/p_mobj.c
index d2454f267616901413bdc445d270abe899357ae6..4e60ad6121c83f92aebe9508a6d40b09965fa60c 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -2188,9 +2188,7 @@ static boolean P_ZMovement(mobj_t *mo)
 
 		case MT_RING: // Ignore still rings
 		case MT_COIN:
-#ifdef BLUE_SPHERES
 		case MT_BLUEBALL:
-#endif
 		case MT_REDTEAMRING:
 		case MT_BLUETEAMRING:
 		case MT_FLINGRING:
@@ -6083,7 +6081,8 @@ void P_MobjThinker(mobj_t *mobj)
 	if (mobj->tracer && P_MobjWasRemoved(mobj->tracer))
 		P_SetTarget(&mobj->tracer, NULL);
 
-	mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG);
+	mobj->flags2 &= ~MF2_PUSHED;
+	mobj->eflags &= ~MFE_SPRUNG;
 
 	tmfloorthing = tmhitthing = NULL;
 
@@ -6478,14 +6477,12 @@ void P_MobjThinker(mobj_t *mobj)
 	else if (mobj->health <= 0) // Dead things think differently than the living.
 		switch (mobj->type)
 		{
-#ifdef BLUE_SPHERES
 		case MT_BLUEBALL:
 			if ((mobj->tics>>2)+1 > 0 && (mobj->tics>>2)+1 <= tr_trans60) // tr_trans50 through tr_trans90, shifting once every second frame
 				mobj->frame = (NUMTRANSMAPS-((mobj->tics>>2)+1))<<FF_TRANSSHIFT;
 			else // tr_trans60 otherwise
 				mobj->frame = tr_trans60<<FF_TRANSSHIFT;
 			break;
-#endif
 		case MT_EGGCAPSULE:
 			if (mobj->z <= mobj->floorz)
 			{
@@ -6943,9 +6940,7 @@ void P_MobjThinker(mobj_t *mobj)
 			break;
 		case MT_RING:
 		case MT_COIN:
-#ifdef BLUE_SPHERES
 		case MT_BLUEBALL:
-#endif
 		case MT_REDTEAMRING:
 		case MT_BLUETEAMRING:
 			// No need to check water. Who cares?
@@ -7711,9 +7706,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 			break;
 		case MT_RING:
 		case MT_COIN:
-#ifdef BLUE_SPHERES
 		case MT_BLUEBALL:
-#endif
 			nummaprings++;
 		default:
 			break;
@@ -7839,9 +7832,7 @@ void P_RemoveMobj(mobj_t *mobj)
 	if (mobj->spawnpoint &&
 		(mobj->type == MT_RING
 		|| mobj->type == MT_COIN
-#ifdef BLUE_SPHERES
 		|| mobj->type == MT_BLUEBALL
-#endif
 		|| mobj->type == MT_REDTEAMRING
 		|| mobj->type == MT_BLUETEAMRING
 		|| P_WeaponOrPanel(mobj->type))
@@ -9627,11 +9618,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
 				ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING;
 				break;
 			default:
-#ifdef BLUE_SPHERES
 				// Spawn rings as blue spheres in special stages, ala S3+K.
 				if (G_IsSpecialStage(gamemap) && useNightsSS)
 					ringthing = MT_BLUEBALL;
-#endif
 				break;
 		}
 
@@ -9696,11 +9685,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
 		if (ultimatemode && !(G_IsSpecialStage(gamemap) || maptol & TOL_NIGHTS))
 			return;
 
-#ifdef BLUE_SPHERES
 		// Spawn rings as blue spheres in special stages, ala S3+K.
 		if (G_IsSpecialStage(gamemap) && useNightsSS)
 			ringthing = MT_BLUEBALL;
-#endif
 
 		for (r = 1; r <= 5; r++)
 		{
@@ -9751,11 +9738,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
 		if (ultimatemode && !(G_IsSpecialStage(gamemap) || maptol & TOL_NIGHTS))
 			return;
 
-#ifdef BLUE_SPHERES
 		// Spawn rings as blue spheres in special stages, ala S3+K.
 		if (G_IsSpecialStage(gamemap) && useNightsSS)
 			ringthing = MT_BLUEBALL;
-#endif
 
 		angle >>= ANGLETOFINESHIFT;
 
@@ -9848,11 +9833,9 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
 				if (ultimatemode && !(G_IsSpecialStage(gamemap) || (maptol & TOL_NIGHTS)))
 					continue;
 
-#ifdef BLUE_SPHERES
 				// Spawn rings as blue spheres in special stages, ala S3+K.
 				if (G_IsSpecialStage(gamemap) && useNightsSS)
 					itemToSpawn = MT_BLUEBALL;
-#endif
 			}
 
 			fa = i*FINEANGLES/numitems;
diff --git a/src/p_mobj.h b/src/p_mobj.h
index 6198f5bec1c623876265144d508d400d48bbac2c..e24b09652d61ddd91113422ec65a9101c47fb7d1 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -175,23 +175,24 @@ typedef enum
 	MF2_EXPLOSION      = 1<<7,  // Thrown ring has explosive properties
 	MF2_SCATTER        = 1<<8,  // Thrown ring has scatter properties
 	MF2_BEYONDTHEGRAVE = 1<<9,  // Source of this missile has died and has since respawned.
-	MF2_SLIDEPUSH      = 1<<10, // MF_PUSHABLE that pushes continuously.
-	MF2_CLASSICPUSH    = 1<<11, // Drops straight down when object has negative Z.
-	MF2_STANDONME      = 1<<12, // While not pushable, stand on me anyway.
-	MF2_INFLOAT        = 1<<13, // Floating to a height for a move, don't auto float to target's height.
-	MF2_DEBRIS         = 1<<14, // Splash ring from explosion ring
-	MF2_NIGHTSPULL     = 1<<15, // Attracted from a paraloop
-	MF2_JUSTATTACKED   = 1<<16, // can be pushed by other moving mobjs
-	MF2_FIRING         = 1<<17, // turret fire
-	MF2_SUPERFIRE      = 1<<18, // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
-	MF2_SHADOW         = 1<<19, // Fuzzy draw, makes targeting harder.
-	MF2_STRONGBOX      = 1<<20, // Flag used for "strong" random monitors.
-	MF2_OBJECTFLIP     = 1<<21, // Flag for objects that always have flipped gravity.
-	MF2_SKULLFLY       = 1<<22, // Special handling: skull in flight.
-	MF2_FRET           = 1<<23, // Flashing from a previous hit
-	MF2_BOSSNOTRAP     = 1<<24, // No Egg Trap after boss
-	MF2_BOSSFLEE       = 1<<25, // Boss is fleeing!
-	MF2_BOSSDEAD       = 1<<26, // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
+	MF2_PUSHED         = 1<<10, // Mobj was already pushed this tic
+	MF2_SLIDEPUSH      = 1<<11, // MF_PUSHABLE that pushes continuously.
+	MF2_CLASSICPUSH    = 1<<12, // Drops straight down when object has negative Z.
+	MF2_STANDONME      = 1<<13, // While not pushable, stand on me anyway.
+	MF2_INFLOAT        = 1<<14, // Floating to a height for a move, don't auto float to target's height.
+	MF2_DEBRIS         = 1<<15, // Splash ring from explosion ring
+	MF2_NIGHTSPULL     = 1<<16, // Attracted from a paraloop
+	MF2_JUSTATTACKED   = 1<<17, // can be pushed by other moving mobjs
+	MF2_FIRING         = 1<<18, // turret fire
+	MF2_SUPERFIRE      = 1<<19, // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
+	MF2_SHADOW         = 1<<20, // Fuzzy draw, makes targeting harder.
+	MF2_STRONGBOX      = 1<<21, // Flag used for "strong" random monitors.
+	MF2_OBJECTFLIP     = 1<<22, // Flag for objects that always have flipped gravity.
+	MF2_SKULLFLY       = 1<<23, // Special handling: skull in flight.
+	MF2_FRET           = 1<<24, // Flashing from a previous hit
+	MF2_BOSSNOTRAP     = 1<<25, // No Egg Trap after boss
+	MF2_BOSSFLEE       = 1<<26, // Boss is fleeing!
+	MF2_BOSSDEAD       = 1<<27, // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
 	// free: to and including 1<<31
 } mobjflag2_t;
 
@@ -231,8 +232,7 @@ typedef enum
 	MFE_VERTICALFLIP      = 1<<5,
 	// Goo water
 	MFE_GOOWATER          = 1<<6,
-	// Mobj was already pushed this tic
-	MFE_PUSHED            = 1<<7,
+	// free: to and including 1<<7
 	// Mobj was already sprung this tic
 	MFE_SPRUNG            = 1<<8,
 	// Platform movement
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 565ff0bd0540c459ddd445ae25eefe894a86075b..e0112bb79b84c5169b018f090c56117efb0cdef3 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -3203,7 +3203,7 @@ static inline boolean P_NetUnArchiveMisc(void)
 
 	// tell the sound code to reset the music since we're skipping what
 	// normally sets this flag
-	mapmusic |= MUSIC_RELOADRESET;
+	mapmusflags |= MUSIC_RELOADRESET;
 
 	G_SetGamestate(READINT16(save_p));
 
diff --git a/src/p_setup.c b/src/p_setup.c
index dc0e4ffd50cd5362f288fb75b05071f66128726d..a778469fba003dd5ae58021b70609dc7fea782e7 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -180,10 +180,11 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
 	mapheaderinfo[num]->typeoflevel = 0;
 	DEH_WriteUndoline("NEXTLEVEL", va("%d", mapheaderinfo[num]->nextlevel), UNDO_NONE);
 	mapheaderinfo[num]->nextlevel = (INT16)(i + 1);
-	DEH_WriteUndoline("MUSICSLOT", va("%d", mapheaderinfo[num]->musicslot), UNDO_NONE);
-	mapheaderinfo[num]->musicslot = mus_map01m + num;
-	DEH_WriteUndoline("MUSICSLOTTRACK", va("%d", mapheaderinfo[num]->musicslottrack), UNDO_NONE);
-	mapheaderinfo[num]->musicslottrack = 0;
+	DEH_WriteUndoline("MUSIC", mapheaderinfo[num]->musname, UNDO_NONE);
+	snprintf(mapheaderinfo[num]->musname, 7, "%sM", G_BuildMapName(i));
+	mapheaderinfo[num]->musname[6] = 0;
+	DEH_WriteUndoline("MUSICTRACK", va("%d", mapheaderinfo[num]->mustrack), UNDO_NONE);
+	mapheaderinfo[num]->mustrack = 0;
 	DEH_WriteUndoline("FORCECHARACTER", va("%d", mapheaderinfo[num]->forcecharacter), UNDO_NONE);
 	mapheaderinfo[num]->forcecharacter[0] = '\0';
 	DEH_WriteUndoline("WEATHER", va("%d", mapheaderinfo[num]->weather), UNDO_NONE);
@@ -1439,6 +1440,29 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum)
 #endif
 
 			case 413: // Change music
+			{
+				char process[8+1];
+
+				sd->toptexture = sd->midtexture = sd->bottomtexture = 0;
+				if (msd->bottomtexture[0] != '-' || msd->bottomtexture[1] != '\0')
+				{
+					M_Memcpy(process,msd->bottomtexture,8);
+					process[8] = '\0';
+					sd->bottomtexture = get_number(process)-1;
+				}
+				M_Memcpy(process,msd->toptexture,8);
+				process[8] = '\0';
+				sd->text = Z_Malloc(7, PU_LEVEL, NULL);
+
+				// If they type in O_ or D_ and their music name, just shrug,
+				// then copy the rest instead.
+				if ((process[0] == 'O' || process[0] == 'D') && process[7])
+					M_Memcpy(sd->text, process+2, 6);
+				else // Assume it's a proper music name.
+					M_Memcpy(sd->text, process, 6);
+				sd->text[6] = 0;
+				break;
+			}
 			case 414: // Play SFX
 			{
 				sd->toptexture = sd->midtexture = sd->bottomtexture = 0;
@@ -1449,13 +1473,6 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum)
 					process[8] = '\0';
 					sd->toptexture = get_number(process);
 				}
-				if (sd->special == 413 && (msd->bottomtexture[0] != '-' || msd->bottomtexture[1] != '\0'))
-				{
-					char process[8+1];
-					M_Memcpy(process,msd->bottomtexture,8);
-					process[8] = '\0';
-					sd->bottomtexture = get_number(process)-1;
-				}
 				break;
 			}
 
diff --git a/src/p_spec.c b/src/p_spec.c
index 2c471fa9e6574f943925c846520b91bf5538133f..277fe19eb3616cc4da0f5f5a567fb75372272425 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -1891,7 +1891,6 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
 	 || specialtype == 304  // Ring count - Once
 	 || specialtype == 307  // Character ability - Once
 	 || specialtype == 308  // Race only - Once
-	 || specialtype == 313  // No More Enemies - Once
 	 || specialtype == 315  // No of pushables - Once
 	 || specialtype == 318  // Unlockable trigger - Once
 	 || specialtype == 320  // Unlockable - Once
@@ -2390,20 +2389,19 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 			// console player only unless NOCLIMB is set
 			if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player)))
 			{
-				UINT16 musicnum = (UINT16)sides[line->sidenum[0]].toptexture; //P_AproxDistance(line->dx, line->dy)>>FRACBITS;
 				UINT16 tracknum = (UINT16)sides[line->sidenum[0]].bottomtexture;
 
-				mapmusic = musicnum | (tracknum << MUSIC_TRACKSHIFT);
+				strncpy(mapmusname, sides[line->sidenum[0]].text, 7);
+				mapmusname[6] = 0;
+
+				mapmusflags = tracknum & MUSIC_TRACKMASK;
 				if (!(line->flags & ML_BLOCKMONSTERS))
-					mapmusic |= MUSIC_RELOADRESET;
+					mapmusflags |= MUSIC_RELOADRESET;
 
-				if (musicnum >= NUMMUSIC || musicnum == mus_None)
-					S_StopMusic();
-				else
-					S_ChangeMusic(mapmusic, !(line->flags & ML_EFFECT4));
+				S_ChangeMusic(mapmusname, mapmusflags, !(line->flags & ML_EFFECT4));
 
 				// Except, you can use the ML_BLOCKMONSTERS flag to change this behavior.
-				// if (mapmusic & MUSIC_RELOADRESET) then it will reset the music in G_PlayerReborn.
+				// if (mapmusflags & MUSIC_RELOADRESET) then it will reset the music in G_PlayerReborn.
 			}
 			break;
 
@@ -6030,31 +6028,6 @@ void P_SpawnSpecials(INT32 fromnetsave)
 				P_AddRaiseThinker(lines[i].frontsector, &lines[i]);
 				break;
 
-#ifdef SLOPENESS
-			case 999:
-				sec = sides[*lines[i].sidenum].sector-sectors;
-				for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;)
-				{
-					size_t counting;
-
-					sectors[s].floorangle = ANGLE_45;
-					for (counting = 0; counting < sectors[s].linecount/2; counting++)
-					{
-						sectors[s].lines[counting]->v1->z = sectors[sec].floorheight;
-						CONS_Debug(DBG_GAMELOGIC, "Set it to %d\n", sectors[s].lines[counting]->v1->z>>FRACBITS);
-					}
-
-					for (counting = sectors[s].linecount/2; counting < sectors[s].linecount; counting++)
-					{
-						sectors[s].lines[counting]->v1->z = sectors[sec].ceilingheight;
-						CONS_Debug(DBG_GAMELOGIC, "Set it to %d\n", sectors[s].lines[counting]->v1->z>>FRACBITS);
-					}
-					sectors[s].special = 65535;
-					CONS_Debug(DBG_GAMELOGIC, "Found & Set slope!\n");
-				}
-				break;
-#endif
-
 			case 200: // Double light effect
 				P_AddFakeFloorsByLine(i, FF_EXISTS|FF_CUTSPRITES|FF_DOUBLESHADOW, secthinkers);
 				break;
@@ -6469,7 +6442,7 @@ static void P_DoScrollMove(mobj_t *thing, fixed_t dx, fixed_t dy, INT32 exclusiv
 	thing->momy += dy;
 
 	if (exclusive)
-		thing->eflags |= MFE_PUSHED;
+		thing->flags2 |= MF2_PUSHED;
 }
 
 /** Processes an active scroller.
@@ -6573,7 +6546,7 @@ void T_Scroll(scroll_t *s)
 					{
 						thing = node->m_thing;
 
-						if (thing->eflags & MFE_PUSHED) // Already pushed this tic by an exclusive pusher.
+						if (thing->flags2 & MF2_PUSHED) // Already pushed this tic by an exclusive pusher.
 							continue;
 
 						height = P_GetSpecialBottomZ(thing, sec, psec);
@@ -6595,7 +6568,7 @@ void T_Scroll(scroll_t *s)
 				{
 					thing = node->m_thing;
 
-					if (thing->eflags & MFE_PUSHED)
+					if (thing->flags2 & MF2_PUSHED)
 						continue;
 
 					height = P_GetSpecialBottomZ(thing, sec, sec);
@@ -6636,7 +6609,7 @@ void T_Scroll(scroll_t *s)
 					{
 						thing = node->m_thing;
 
-						if (thing->eflags & MFE_PUSHED)
+						if (thing->flags2 & MF2_PUSHED)
 							continue;
 
 						height = P_GetSpecialTopZ(thing, sec, psec);
@@ -6658,7 +6631,7 @@ void T_Scroll(scroll_t *s)
 				{
 					thing = node->m_thing;
 
-					if (thing->eflags & MFE_PUSHED)
+					if (thing->flags2 & MF2_PUSHED)
 						continue;
 
 					height = P_GetSpecialTopZ(thing, sec, sec);
@@ -7141,7 +7114,7 @@ static pusher_t *tmpusher; // pusher structure for blockmap searches
   */
 static inline boolean PIT_PushThing(mobj_t *thing)
 {
-	if (thing->eflags & MFE_PUSHED)
+	if (thing->flags2 & MF2_PUSHED)
 		return false;
 
 	if (thing->player && thing->player->pflags & PF_ROPEHANG)
@@ -7271,7 +7244,7 @@ static inline boolean PIT_PushThing(mobj_t *thing)
 	}
 
 	if (tmpusher->exclusive)
-		thing->eflags |= MFE_PUSHED;
+		thing->flags2 |= MF2_PUSHED;
 
 	return true;
 }
@@ -7374,7 +7347,7 @@ void T_Pusher(pusher_t *p)
 			|| thing->type == MT_BIGTUMBLEWEED))
 			continue;
 
-		if (thing->eflags & MFE_PUSHED)
+		if (thing->flags2 & MF2_PUSHED)
 			continue;
 
 		if (thing->player && thing->player->pflags & PF_ROPEHANG)
@@ -7541,7 +7514,7 @@ void T_Pusher(pusher_t *p)
 			}
 
 			if (p->exclusive)
-				thing->eflags |= MFE_PUSHED;
+				thing->flags2 |= MF2_PUSHED;
 		}
 	}
 }
diff --git a/src/p_user.c b/src/p_user.c
index 89b530c3502475b412834f3fc73d5281332578b5..03b2c1dd87a7a39a8a291277133db86eba4f34c2 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -962,7 +962,7 @@ void P_DoSuperTransformation(player_t *player, boolean giverings)
 	if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC) && P_IsLocalPlayer(player))
 	{
 		S_StopMusic();
-		S_ChangeMusic(mus_supers, true);
+		S_ChangeMusicInternal("supers", true);
 	}
 
 	S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi
@@ -1098,7 +1098,7 @@ void P_PlayLivesJingle(player_t *player)
 		if (player)
 			player->powers[pw_extralife] = extralifetics + 1;
 		S_StopMusic(); // otherwise it won't restart if this is done twice in a row
-		S_ChangeMusic(mus_xtlife, false);
+		S_ChangeMusicInternal("xtlife", false);
 	}
 }
 
@@ -1116,21 +1116,21 @@ void P_RestoreMusic(player_t *player)
 		return;
 	S_SpeedMusic(1.0f);
 	if (player->powers[pw_super] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC))
-		S_ChangeMusic(mus_supers, true);
+		S_ChangeMusicInternal("supers", true);
 	else if (player->powers[pw_invulnerability] > 1)
-		S_ChangeMusic((mariomode) ? mus_minvnc : mus_invinc, false);
+		S_ChangeMusicInternal((mariomode) ? "minvnc" : "invinc", false);
 	else if (player->powers[pw_sneakers] > 1 && !player->powers[pw_super])
 	{
 		if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)
 		{
 			S_SpeedMusic(1.4f);
-			S_ChangeMusic(mapmusic, true);
+			S_ChangeMusic(mapmusname, mapmusflags, true);
 		}
 		else
-			S_ChangeMusic(mus_shoes, true);
+			S_ChangeMusicInternal("shoes", true);
 	}
 	else
-		S_ChangeMusic(mapmusic, true);
+		S_ChangeMusic(mapmusname, mapmusflags, true);
 }
 
 //
@@ -2039,7 +2039,7 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player)
 		mobj_t *killer;
 
 		if ((netgame || multiplayer) && P_IsLocalPlayer(player))
-			S_ChangeMusic(mapmusic, true);
+			S_ChangeMusic(mapmusname, mapmusflags, true);
 
 		killer = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_NULL);
 		killer->threshold = 42; // Special flag that it was drowning which killed you.
@@ -2048,7 +2048,7 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player)
 	else if (player->powers[pw_spacetime] == 1)
 	{
 		if ((netgame || multiplayer) && P_IsLocalPlayer(player))
-			S_ChangeMusic(mapmusic, true);
+			S_ChangeMusic(mapmusname, mapmusflags, true);
 
 		P_DamageMobj(player->mo, NULL, NULL, 10000);
 	}
@@ -2083,7 +2083,7 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player)
 		&& player == &players[consoleplayer])
 		{
 			S_StopMusic();
-			S_ChangeMusic(mus_drown, false);
+			S_ChangeMusicInternal("drown", false);
 		}
 
 		if (player->powers[pw_underwater] == 25*TICRATE + 1)
@@ -5579,7 +5579,7 @@ static void P_NiGHTSMovement(player_t *player)
 	}
 	else if (P_IsLocalPlayer(player) && player->nightstime == 10*TICRATE)
 //		S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS. Dummied out, as some on the dev team thought it wasn't Sonic-y enough (Mystic, notably). Uncomment to restore. -SH
-		S_ChangeMusic(mus_drown,false);
+		S_ChangeMusicInternal("drown",false);
 
 
 	if (player->mo->z < player->mo->floorz)
@@ -7717,7 +7717,7 @@ static void P_DeathThink(player_t *player)
 
 		// Return to level music
 		if (netgame && player->deadtimer == gameovertics && P_IsLocalPlayer(player))
-			S_ChangeMusic(mapmusic, true);
+			S_ChangeMusic(mapmusname, mapmusflags, true);
 	}
 
 	if (!player->mo)
@@ -8703,7 +8703,7 @@ void P_PlayerThink(player_t *player)
 		if (countdown == 11*TICRATE - 1)
 		{
 			if (P_IsLocalPlayer(player))
-				S_ChangeMusic(mus_drown, false);
+				S_ChangeMusicInternal("drown", false);
 		}
 
 		// If you've hit the countdown and you haven't made
@@ -8857,10 +8857,7 @@ void P_PlayerThink(player_t *player)
 			mo2 = (mobj_t *)th;
 
 			if (!(mo2->type == MT_NIGHTSWING || mo2->type == MT_RING || mo2->type == MT_COIN
-#ifdef BLUE_SPHERES
-			      || mo2->type == MT_BLUEBALL
-#endif
-			     ))
+			   || mo2->type == MT_BLUEBALL))
 				continue;
 
 			if (P_AproxDistance(P_AproxDistance(mo2->x - x, mo2->y - y), mo2->z - z) > FixedMul(128*FRACUNIT, player->mo->scale))
diff --git a/src/r_defs.h b/src/r_defs.h
index f18410fe88139cfd52827ae90bf3d18880fbc20b..2915b9259e46730069f0eb6fd614265eb2f41675 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -369,14 +369,6 @@ typedef struct sector_s
 	double lineoutLength;
 #endif // ----- end special tricks -----
 
-	// ZDoom C++ to Legacy C conversion (for slopes)
-	// store floor and ceiling planes instead of heights
-	//secplane_t floorplane, ceilingplane;
-#ifdef SLOPENESS
-	//fixed_t floortexz, ceilingtexz; // [RH] used for wall texture mapping
-	angle_t floorangle;
-#endif
-
 	// This points to the master's floorheight, so it can be changed in realtime!
 	fixed_t *gravity; // per-sector gravity
 	boolean verticalflip; // If gravity < 0, then allow flipped physics
diff --git a/src/s_sound.c b/src/s_sound.c
index 14a8cc425affc371676b146cdbddcaefa430c836..49373d94c445e7354123a36d7c36c63da9036c8a 100644
--- a/src/s_sound.c
+++ b/src/s_sound.c
@@ -141,14 +141,6 @@ typedef struct
 static channel_t *channels = NULL;
 static INT32 numofchannels = 0;
 
-// whether songs are mus_paused
-static boolean mus_paused = 0;
-
-// music currently being played
-musicinfo_t *mus_playing = 0;
-
-static INT32 nextcleanup;
-
 //
 // Internals.
 //
@@ -307,47 +299,6 @@ static void SetChannelsNum(void)
 		channels[i].sfxinfo = 0;
 }
 
-//
-// Initializes sound stuff, including volume
-// Sets channels, SFX and music volume,
-//  allocates channel buffer, sets S_sfx lookup.
-//
-void S_Init(INT32 sfxVolume, INT32 digMusicVolume, INT32 midiMusicVolume)
-{
-	INT32 i;
-
-	if (dedicated)
-		return;
-
-	S_SetSfxVolume(sfxVolume);
-	S_SetDigMusicVolume(digMusicVolume);
-	S_SetMIDIMusicVolume(midiMusicVolume);
-
-	SetChannelsNum();
-
-	// no sounds are playing, and they are not mus_paused
-	mus_paused = 0;
-
-	// Note that sounds have not been cached (yet).
-	for (i = 1; i < NUMSFX; i++)
-	{
-		S_sfx[i].usefulness = -1; // for I_GetSfx()
-		S_sfx[i].lumpnum = LUMPERROR;
-	}
-
-	// precache sounds if requested by cmdline, or precachesound var true
-	if (!nosound && (M_CheckParm("-precachesound") || precachesound.value))
-	{
-		// Initialize external data (all sounds) at start, keep static.
-		CONS_Printf(M_GetText("Loading sounds... "));
-
-		for (i = 1; i < NUMSFX; i++)
-			if (S_sfx[i].name)
-				S_sfx[i].data = I_GetSfx(&S_sfx[i]);
-
-		CONS_Printf(M_GetText(" pre-cached all sound data\n"));
-	}
-}
 
 // Retrieve the lump number of sfx
 //
@@ -371,12 +322,6 @@ lumpnum_t S_GetSfxLumpNum(sfxinfo_t *sfx)
 	return W_GetNumForName("dsthok");
 }
 
-//
-// Per level startup code.
-// Kills playing sounds at start of level,
-//  determines music if any, changes music.
-//
-
 // Stop all sounds, load level info, THEN start sounds.
 void S_StopSounds(void)
 {
@@ -442,22 +387,6 @@ void S_StopSoundByNum(sfxenum_t sfxnum)
 	}
 }
 
-void S_Start(void)
-{
-	if (mapmusic & MUSIC_RELOADRESET)
-	{
-		mapmusic = mapheaderinfo[gamemap-1]->musicslot
-			| (mapheaderinfo[gamemap-1]->musicslottrack << MUSIC_TRACKSHIFT);
-	}
-
-	mus_paused = 0;
-
-	if (cv_resetmusic.value)
-		S_StopMusic();
-	S_ChangeMusic(mapmusic, true);
-	nextcleanup = 15;
-}
-
 void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
 {
 	INT32 sep, pitch, priority, cnum;
@@ -745,43 +674,6 @@ void S_StopSound(void *origin)
 	}
 }
 
-//
-// Stop and resume music, during game PAUSE.
-//
-void S_PauseSound(void)
-{
-	if (!nodigimusic)
-		I_PauseSong(0);
-
-	if (mus_playing && !mus_paused)
-	{
-		I_PauseSong(mus_playing->handle);
-		mus_paused = true;
-	}
-
-	// pause cd music
-#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
-	I_PauseCD();
-#else
-	I_StopCD();
-#endif
-}
-
-void S_ResumeSound(void)
-{
-	if (!nodigimusic)
-		I_ResumeSong(0);
-	else
-	if (mus_playing && mus_paused)
-	{
-		I_ResumeSong(mus_playing->handle);
-		mus_paused = false;
-	}
-
-	// resume cd music
-	I_ResumeCD();
-}
-
 //
 // Updates music & sounds
 //
@@ -883,38 +775,6 @@ void S_UpdateSounds(void)
 		}
 	}
 
-	// Clean up unused data.
-#if 0
-	{
-		static tic_t nextcleanup = 0;
-		size_t i;
-		sfxinfo_t *sfx;
-
-		if (!gametic) nextcleanup = 0;
-		if (gametic > nextcleanup)
-		{
-			for (i = 1; i < NUMSFX; i++)
-			{
-				if (S_sfx[i].usefulness == 0)
-				{
-					S_sfx[i].usefulness--;
-
-					// don't forget to unlock it !!!
-					// __dmpi_unlock_....
-					//Z_ChangeTag(S_sfx[i].data, PU_CACHE);
-					I_FreeSfx(S_sfx+i);
-					//S_sfx[i].data = 0;
-
-					CONS_Debug(DBG_GAMELOGIC, "flushed sfx %.6s\n", S_sfx[i].name);
-				}
-			}
-			nextcleanup = gametic + 15;
-		}
-	}
-#endif
-
-	// FIXTHIS: nextcleanup is probably unused
-
 	for (cnum = 0; cnum < numofchannels; cnum++)
 	{
 		c = &channels[cnum];
@@ -984,37 +844,6 @@ void S_UpdateSounds(void)
 	I_UpdateSound();
 }
 
-void S_SetDigMusicVolume(INT32 volume)
-{
-	if (volume < 0 || volume > 31)
-		CONS_Alert(CONS_WARNING, "musicvolume should be between 0-31\n");
-
-	CV_SetValue(&cv_digmusicvolume, volume&31);
-	actualdigmusicvolume = cv_digmusicvolume.value;   //check for change of var
-
-#ifdef DJGPPDOS
-	I_SetDigMusicVolume(31); // Trick for buggy dos drivers. Win32 doesn't need this.
-#endif
-
-	if (!nodigimusic)
-		I_SetDigMusicVolume(volume&31);
-}
-
-void S_SetMIDIMusicVolume(INT32 volume)
-{
-	if (volume < 0 || volume > 31)
-		CONS_Alert(CONS_WARNING, "musicvolume should be between 0-31\n");
-
-	CV_SetValue(&cv_midimusicvolume, volume&0x1f);
-	actualmidimusicvolume = cv_midimusicvolume.value;   //check for change of var
-
-#ifdef DJGPPDOS
-	I_SetMIDIMusicVolume(31); // Trick for buggy dos drivers. Win32 doesn't need this.
-#endif
-
-	I_SetMIDIMusicVolume(volume&0x1f);
-}
-
 void S_SetSfxVolume(INT32 volume)
 {
 	if (volume < 0 || volume > 31)
@@ -1031,137 +860,6 @@ void S_SetSfxVolume(INT32 volume)
 #endif
 }
 
-static boolean S_MIDIMusic(musicinfo_t *music, boolean looping)
-{
-	if (nomidimusic)
-		return true; // no error
-
-	if (music_disabled)
-		return true; // no error
-
-	// get lumpnum if neccessary
-	if (!music->lumpnum)
-	{
-		if (W_CheckNumForName(va("d_%s", music->name)) == LUMPERROR)
-			return false;
-		music->lumpnum = W_GetNumForName(va("d_%s", music->name));
-	}
-
-	// load & register it
-	music->data = W_CacheLumpNum(music->lumpnum, PU_MUSIC);
-#if defined (macintosh) && !defined (HAVE_SDL)
-	music->handle = I_RegisterSong(music_num);
-#else
-	music->handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum));
-#endif
-
-#ifdef MUSSERV
-	if (msg_id != -1)
-	{
-		struct musmsg msg_buffer;
-
-		msg_buffer.msg_type = 6;
-		memset(msg_buffer.msg_text, 0, sizeof (msg_buffer.msg_text));
-		sprintf(msg_buffer.msg_text, "d_%s", music->name);
-		msgsnd(msg_id, (struct msgbuf*)&msg_buffer, sizeof (msg_buffer.msg_text), IPC_NOWAIT);
-	}
-#endif
-
-	// play it
-	if (!I_PlaySong(music->handle, looping))
-		return false;
-
-	mus_playing = music;
-	return true;
-}
-
-static boolean S_DigMusic(musicinfo_t *music, boolean looping)
-{
-	if (nodigimusic)
-		return false; // try midi
-
-	if (digital_disabled)
-		return false; // try midi
-
-	if (!I_StartDigSong(music->name, looping))
-		return false;
-
-	mus_playing = music;
-	return true;
-}
-
-void S_ChangeMusic(UINT32 mslotnum, boolean looping)
-{
-	musicinfo_t *music;
-	musicenum_t music_num = (signed)(mslotnum & MUSIC_SONGMASK);
-	INT32 track_num = (mslotnum & MUSIC_TRACKMASK) >> MUSIC_TRACKSHIFT;
-
-#if defined (DC) || defined (_WIN32_WCE) || defined (PSP) || defined(GP2X)
-	S_ClearSfx();
-#endif
-
-	if (nomidimusic && nodigimusic)
-		return;
-
-	if (music_disabled && digital_disabled)
-		return;
-
-	// No Music
-	if (music_num == mus_None)
-	{
-		S_StopMusic();
-		return;
-	}
-
-	if (music_num >= NUMMUSIC)
-	{
-		CONS_Alert(CONS_ERROR, "Bad music number %d\n", music_num);
-		return;
-	}
-	else
-		music = &S_music[music_num];
-
-	if (mus_playing != music)
-	{
-		S_StopMusic(); // shutdown old music
-		if (!S_DigMusic(music, looping) && !S_MIDIMusic(music, looping))
-		{
-			CONS_Alert(CONS_ERROR, M_GetText("Music lump %.6s not found!\n"), music->name);
-			return;
-		}
-	}
-	I_SetSongTrack(track_num);
-}
-
-boolean S_SpeedMusic(float speed)
-{
-	return I_SetSongSpeed(speed);
-}
-
-void S_StopMusic(void)
-{
-	if (!mus_playing)
-		return;
-
-	if (mus_paused)
-		I_ResumeSong(mus_playing->handle);
-
-	if (!nodigimusic)
-		I_StopDigSong();
-
-	S_SpeedMusic(1.0f);
-	I_StopSong(mus_playing->handle);
-	I_UnRegisterSong(mus_playing->handle);
-
-#ifndef HAVE_SDL //SDL uses RWOPS
-	Z_ChangeTag(mus_playing->data, PU_CACHE);
-#endif
-
-	mus_playing->data = NULL;
-	mus_playing = NULL;
-
-}
-
 void S_ClearSfx(void)
 {
 #ifndef DJGPPDOS
@@ -1452,3 +1150,285 @@ void S_StartSoundName(void *mo, const char *soundname)
 
 	S_StartSound(mo, soundnum);
 }
+
+/// ------------------------
+/// Music
+/// ------------------------
+
+#ifdef MUSICSLOT_COMPATIBILITY
+const char *compat_special_music_slots[16] =
+{
+	"titles", // 1036  title screen
+	"read_m", // 1037  intro
+	"lclear", // 1038  level clear
+	"invinc", // 1039  invincibility
+	"shoes",  // 1040  super sneakers
+	"minvnc", // 1041  Mario invincibility
+	"drown",  // 1042  drowning
+	"gmover", // 1043  game over
+	"xtlife", // 1044  extra life
+	"contsc", // 1045  continue screen
+	"supers", // 1046  Super Sonic
+	"chrsel", // 1047  character select
+	"credit", // 1048  credits
+	"racent", // 1049  Race Results
+	"stjr",   // 1050  Sonic Team Jr. Presents
+	""
+};
+#endif
+
+#define music_playing (music_name[0]) // String is empty if no music is playing
+
+static char      music_name[7]; // up to 6-character name
+static lumpnum_t music_lumpnum; // lump number of music (used??)
+static void     *music_data;    // music raw data
+static INT32     music_handle;  // once registered, the handle for the music
+
+static boolean mus_paused     = 0;  // whether songs are mus_paused
+
+static boolean S_MIDIMusic(const char *mname, boolean looping)
+{
+	lumpnum_t mlumpnum;
+	void *mdata;
+	INT32 mhandle;
+
+	if (nomidimusic || music_disabled)
+		return false; // didn't search.
+
+	if (W_CheckNumForName(va("d_%s", mname)) == LUMPERROR)
+		return false;
+	mlumpnum = W_GetNumForName(va("d_%s", mname));
+
+	// load & register it
+	mdata = W_CacheLumpNum(mlumpnum, PU_MUSIC);
+	mhandle = I_RegisterSong(mdata, W_LumpLength(mlumpnum));
+
+#ifdef MUSSERV
+	if (msg_id != -1)
+	{
+		struct musmsg msg_buffer;
+
+		msg_buffer.msg_type = 6;
+		memset(msg_buffer.msg_text, 0, sizeof (msg_buffer.msg_text));
+		sprintf(msg_buffer.msg_text, "d_%s", mname);
+		msgsnd(msg_id, (struct msgbuf*)&msg_buffer, sizeof (msg_buffer.msg_text), IPC_NOWAIT);
+	}
+#endif
+
+	// play it
+	if (!I_PlaySong(mhandle, looping))
+		return false;
+
+	strncpy(music_name, mname, 7);
+	music_name[6] = 0;
+	music_lumpnum = mlumpnum;
+	music_data = mdata;
+	music_handle = mhandle;
+	return true;
+}
+
+static boolean S_DigMusic(const char *mname, boolean looping)
+{
+	if (nodigimusic || digital_disabled)
+		return false; // try midi
+
+	if (!I_StartDigSong(mname, looping))
+		return false;
+
+	strncpy(music_name, mname, 7);
+	music_name[6] = 0;
+	music_lumpnum = LUMPERROR;
+	music_data = NULL;
+	music_handle = 0;
+	return true;
+}
+
+void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping)
+{
+#if defined (DC) || defined (_WIN32_WCE) || defined (PSP) || defined(GP2X)
+	S_ClearSfx();
+#endif
+
+	if ((nomidimusic || music_disabled) && (nodigimusic || digital_disabled))
+		return;
+
+	// No Music (empty string)
+	if (mmusic[0] == 0)
+	{
+		S_StopMusic();
+		return;
+	}
+
+	if (strncmp(music_name, mmusic, 6))
+	{
+		S_StopMusic(); // shutdown old music
+		if (!S_DigMusic(mmusic, looping) && !S_MIDIMusic(mmusic, looping))
+		{
+			CONS_Alert(CONS_ERROR, M_GetText("Music lump %.6s not found!\n"), mmusic);
+			return;
+		}
+	}
+	I_SetSongTrack(mflags & MUSIC_TRACKMASK);
+}
+
+boolean S_SpeedMusic(float speed)
+{
+	return I_SetSongSpeed(speed);
+}
+
+void S_StopMusic(void)
+{
+	if (!music_playing)
+		return;
+
+	if (mus_paused)
+		I_ResumeSong(music_handle);
+
+	if (!nodigimusic)
+		I_StopDigSong();
+
+	S_SpeedMusic(1.0f);
+	I_StopSong(music_handle);
+	I_UnRegisterSong(music_handle);
+
+#ifndef HAVE_SDL //SDL uses RWOPS
+	Z_ChangeTag(music_data, PU_CACHE);
+#endif
+
+	music_data = NULL;
+	music_name[0] = 0;
+}
+
+void S_SetDigMusicVolume(INT32 volume)
+{
+	if (volume < 0 || volume > 31)
+		CONS_Alert(CONS_WARNING, "musicvolume should be between 0-31\n");
+
+	CV_SetValue(&cv_digmusicvolume, volume&31);
+	actualdigmusicvolume = cv_digmusicvolume.value;   //check for change of var
+
+#ifdef DJGPPDOS
+	I_SetDigMusicVolume(31); // Trick for buggy dos drivers. Win32 doesn't need this.
+#endif
+	if (!nodigimusic)
+		I_SetDigMusicVolume(volume&31);
+}
+
+void S_SetMIDIMusicVolume(INT32 volume)
+{
+	if (volume < 0 || volume > 31)
+		CONS_Alert(CONS_WARNING, "musicvolume should be between 0-31\n");
+
+	CV_SetValue(&cv_midimusicvolume, volume&0x1f);
+	actualmidimusicvolume = cv_midimusicvolume.value;   //check for change of var
+
+#ifdef DJGPPDOS
+	I_SetMIDIMusicVolume(31); // Trick for buggy dos drivers. Win32 doesn't need this.
+#endif
+	I_SetMIDIMusicVolume(volume&0x1f);
+}
+
+/// ------------------------
+/// Init & Others
+/// ------------------------
+
+//
+// Initializes sound stuff, including volume
+// Sets channels, SFX and music volume,
+//  allocates channel buffer, sets S_sfx lookup.
+//
+void S_Init(INT32 sfxVolume, INT32 digMusicVolume, INT32 midiMusicVolume)
+{
+	INT32 i;
+
+	if (dedicated)
+		return;
+
+	S_SetSfxVolume(sfxVolume);
+	S_SetDigMusicVolume(digMusicVolume);
+	S_SetMIDIMusicVolume(midiMusicVolume);
+
+	SetChannelsNum();
+
+	// no sounds are playing, and they are not mus_paused
+	mus_paused = 0;
+
+	// Note that sounds have not been cached (yet).
+	for (i = 1; i < NUMSFX; i++)
+	{
+		S_sfx[i].usefulness = -1; // for I_GetSfx()
+		S_sfx[i].lumpnum = LUMPERROR;
+	}
+
+	// precache sounds if requested by cmdline, or precachesound var true
+	if (!nosound && (M_CheckParm("-precachesound") || precachesound.value))
+	{
+		// Initialize external data (all sounds) at start, keep static.
+		CONS_Printf(M_GetText("Loading sounds... "));
+
+		for (i = 1; i < NUMSFX; i++)
+			if (S_sfx[i].name)
+				S_sfx[i].data = I_GetSfx(&S_sfx[i]);
+
+		CONS_Printf(M_GetText(" pre-cached all sound data\n"));
+	}
+}
+
+
+//
+// Per level startup code.
+// Kills playing sounds at start of level,
+//  determines music if any, changes music.
+//
+void S_Start(void)
+{
+	if (mapmusflags & MUSIC_RELOADRESET)
+	{
+		strncpy(mapmusname, mapheaderinfo[gamemap-1]->musname, 7);
+		mapmusname[6] = 0;
+		mapmusflags = (mapheaderinfo[gamemap-1]->mustrack & MUSIC_TRACKMASK);
+	}
+
+	mus_paused = 0;
+
+	if (cv_resetmusic.value)
+		S_StopMusic();
+	S_ChangeMusic(mapmusname, mapmusflags, true);
+}
+
+//
+// Stop and resume music, during game PAUSE.
+//
+void S_PauseAudio(void)
+{
+	if (!nodigimusic)
+		I_PauseSong(0);
+
+	if (music_playing && !mus_paused)
+	{
+		I_PauseSong(music_handle);
+		mus_paused = true;
+	}
+
+	// pause cd music
+#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
+	I_PauseCD();
+#else
+	I_StopCD();
+#endif
+}
+
+void S_ResumeAudio(void)
+{
+	if (!nodigimusic)
+		I_ResumeSong(0);
+	else
+	if (music_playing && mus_paused)
+	{
+		I_ResumeSong(music_handle);
+		mus_paused = false;
+	}
+
+	// resume cd music
+	I_ResumeCD();
+}
diff --git a/src/s_sound.h b/src/s_sound.h
index 6589ca598657c7e63222297e641f10f5e76b9b1b..d5cf3570d5de7de7ab0a240c16f468fde7afd98a 100644
--- a/src/s_sound.h
+++ b/src/s_sound.h
@@ -48,9 +48,6 @@ typedef enum
 extern consvar_t play_mode;
 #endif
 
-//in case you're wondering why:  I need to define this as extern so P_RestoreMusic can get to it so we don't do stupid song/speed changes
-extern musicinfo_t *mus_playing;
-
 typedef enum
 {
 	SF_TOTALLYSINGLE =  1, // Only play one of these sounds at a time...GLOBALLY
@@ -100,11 +97,12 @@ void S_StartSoundAtVolume(const void *origin, sfxenum_t sound_id, INT32 volume);
 // Stop sound for thing at <origin>
 void S_StopSound(void *origin);
 
-// Start music using <music_id> from sounds.h, and set whether looping
-// note: music slot is first 16 bits for songnum,
-//       next 15 bits for tracknum (gme, other formats with more than one track)
+// Start music track, arbitrary, given its name, and set whether looping
+// note: music flags 12 bits for tracknum (gme, other formats with more than one track)
+//       13-15 aren't used yet
 //       and the last bit we ignore (internal game flag for resetting music on reload)
-void S_ChangeMusic(UINT32 mslotnum, boolean looping);
+#define S_ChangeMusicInternal(a,b) S_ChangeMusic(a,0,b)
+void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping);
 
 // Set Speed of Music
 boolean S_SpeedMusic(float speed);
@@ -113,8 +111,8 @@ boolean S_SpeedMusic(float speed);
 void S_StopMusic(void);
 
 // Stop and resume music, during game PAUSE.
-void S_PauseSound(void);
-void S_ResumeSound(void);
+void S_PauseAudio(void);
+void S_ResumeAudio(void);
 
 //
 // Updates music & sounds
@@ -141,4 +139,10 @@ void S_StopSoundByNum(sfxenum_t sfxnum);
 #define S_StartScreamSound S_StartSound
 #endif
 
+#ifdef MUSICSLOT_COMPATIBILITY
+// For compatibility with code/scripts relying on older versions
+// This is a list of all the "special" slot names and their associated numbers
+const char *compat_special_music_slots[16];
+#endif
+
 #endif
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
index b3d734521bed110b4d3c107fd2e52db252ee4523..7f6771262dcbd2415639f41d20ad7a15a3092da4 100644
--- a/src/sdl/CMakeLists.txt
+++ b/src/sdl/CMakeLists.txt
@@ -117,11 +117,13 @@ if(${SDL2_FOUND})
 	add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 ${SRB2_SDL2_TOTAL_SOURCES})
 	set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME ${SRB2_SDL2_EXE_NAME})
 
-	if((CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"))
-		add_framework(CoreFoundation SRB2SDL2)
-		add_framework(SDL2 SRB2SDL2)
-		add_framework(SDL2_mixer SRB2SDL2)
+	if(${CMAKE_SYSTEM} MATCHES Darwin)
+		find_library(CORE_LIB CoreFoundation)
 		target_link_libraries(SRB2SDL2 PRIVATE
+			${CORE_LIB}
+			SDL2
+			SDL2_mixer
+			${GME_LIBRARIES}
 			${PNG_LIBRARIES}
 			${ZLIB_LIBRARIES}
 			${OPENGL_LIBRARIES}
@@ -131,6 +133,7 @@ if(${SDL2_FOUND})
 		target_link_libraries(SRB2SDL2 PRIVATE
 			${SDL2_LIBRARIES}
 			${SDL2_MIXER_LIBRARIES}
+			${GME_LIBRARIES}
 			${PNG_LIBRARIES}
 			${ZLIB_LIBRARIES}
 			${OPENGL_LIBRARIES}
@@ -198,6 +201,7 @@ if(${SDL2_FOUND})
 	target_include_directories(SRB2SDL2 PRIVATE
 		${SDL2_INCLUDE_DIRS}
 		${SDL2_MIXER_INCLUDE_DIRS}
+		${GME_INCLUDE_DIRS}
 		${PNG_INCLUDE_DIRS}
 		${ZLIB_INCLUDE_DIRS}
 		${OPENGL_INCLUDE_DIRS}
@@ -224,7 +228,7 @@ if(${SDL2_FOUND})
 	endif()
 
 	#### Installation ####
-	if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+	if(${CMAKE_SYSTEM} MATCHES Darwin)
 		install(TARGETS SRB2SDL2
 			BUNDLE DESTINATION .
 		)
@@ -265,7 +269,7 @@ if(${SDL2_FOUND})
 
 
 	# Mac bundle fixup
-	if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+	if(${CMAKE_SYSTEM} MATCHES Darwin)
 		install(CODE "
 			include(BundleUtilities)
 			fixup_bundle(\"${CMAKE_INSTALL_PREFIX}/Sonic Robo Blast 2.app\"
diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
index 98599fb60b7ad0a89046d317f63292bc461dbae3..c3f0d3b38ca398116070f687881a551969feefbb 100644
--- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
+++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
@@ -1270,6 +1270,7 @@
 					HAVE_BLUA,
 					LUA_USE_POSIX,
 					COMPVERSION,
+					HWRENDER,
 				);
 				GCC_THREADSAFE_STATICS = NO;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
@@ -1392,6 +1393,7 @@
 					HAVE_BLUA,
 					LUA_USE_POSIX,
 					COMPVERSION,
+					HWRENDER,
 				);
 				GCC_THREADSAFE_STATICS = NO;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c
index 50e5013946e9f59b2ab407163b3a8c16598bb718..0f96f47339e4fee106b506e9266e8f9546b94968 100644
--- a/src/sdl/mixer_sound.c
+++ b/src/sdl/mixer_sound.c
@@ -395,6 +395,7 @@ void I_FreeSfx(sfxinfo_t *sfx)
 	if (sfx->data)
 		Mix_FreeChunk(sfx->data);
 	sfx->data = NULL;
+	sfx->lumpnum = LUMPERROR;
 }
 
 INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority)
diff --git a/src/sounds.c b/src/sounds.c
index 1ec86e7bc9349c4f3fb130898f467183877f4be1..97bdf23ec41fc2742448605b74372353155efc26 100644
--- a/src/sounds.c
+++ b/src/sounds.c
@@ -20,1067 +20,6 @@
 #include "w_wad.h"
 #include "lua_script.h"
 
-//
-// Information about all the music
-//
-
-musicinfo_t S_music[NUMMUSIC] =
-{
-	{NULL, 0, NULL, -1},
-	{"map01m", 0, NULL, -1},
-	{"map02m", 0, NULL, -1},
-	{"map03m", 0, NULL, -1},
-	{"map04m", 0, NULL, -1},
-	{"map05m", 0, NULL, -1},
-	{"map06m", 0, NULL, -1},
-	{"map07m", 0, NULL, -1},
-	{"map08m", 0, NULL, -1},
-	{"map09m", 0, NULL, -1},
-	{"map10m", 0, NULL, -1},
-	{"map11m", 0, NULL, -1},
-	{"map12m", 0, NULL, -1},
-	{"map13m", 0, NULL, -1},
-	{"map14m", 0, NULL, -1},
-	{"map15m", 0, NULL, -1},
-	{"map16m", 0, NULL, -1},
-	{"map17m", 0, NULL, -1},
-	{"map18m", 0, NULL, -1},
-	{"map19m", 0, NULL, -1},
-	{"map20m", 0, NULL, -1},
-	{"map21m", 0, NULL, -1},
-	{"map22m", 0, NULL, -1},
-	{"map23m", 0, NULL, -1},
-	{"map24m", 0, NULL, -1},
-	{"map25m", 0, NULL, -1},
-	{"map26m", 0, NULL, -1},
-	{"map27m", 0, NULL, -1},
-	{"map28m", 0, NULL, -1},
-	{"map29m", 0, NULL, -1},
-	{"map30m", 0, NULL, -1},
-	{"map31m", 0, NULL, -1},
-	{"map32m", 0, NULL, -1},
-	{"map33m", 0, NULL, -1},
-	{"map34m", 0, NULL, -1},
-	{"map35m", 0, NULL, -1},
-	{"map36m", 0, NULL, -1},
-	{"map37m", 0, NULL, -1},
-	{"map38m", 0, NULL, -1},
-	{"map39m", 0, NULL, -1},
-	{"map40m", 0, NULL, -1},
-	{"map41m", 0, NULL, -1},
-	{"map42m", 0, NULL, -1},
-	{"map43m", 0, NULL, -1},
-	{"map44m", 0, NULL, -1},
-	{"map45m", 0, NULL, -1},
-	{"map46m", 0, NULL, -1},
-	{"map47m", 0, NULL, -1},
-	{"map48m", 0, NULL, -1},
-	{"map49m", 0, NULL, -1},
-	{"map50m", 0, NULL, -1},
-	{"map51m", 0, NULL, -1},
-	{"map52m", 0, NULL, -1},
-	{"map53m", 0, NULL, -1},
-	{"map54m", 0, NULL, -1},
-	{"map55m", 0, NULL, -1},
-	{"map56m", 0, NULL, -1},
-	{"map57m", 0, NULL, -1},
-	{"map58m", 0, NULL, -1},
-	{"map59m", 0, NULL, -1},
-	{"map60m", 0, NULL, -1},
-	{"map61m", 0, NULL, -1},
-	{"map62m", 0, NULL, -1},
-	{"map63m", 0, NULL, -1},
-	{"map64m", 0, NULL, -1},
-	{"map65m", 0, NULL, -1},
-	{"map66m", 0, NULL, -1},
-	{"map67m", 0, NULL, -1},
-	{"map68m", 0, NULL, -1},
-	{"map69m", 0, NULL, -1},
-	{"map70m", 0, NULL, -1},
-	{"map71m", 0, NULL, -1},
-	{"map72m", 0, NULL, -1},
-	{"map73m", 0, NULL, -1},
-	{"map74m", 0, NULL, -1},
-	{"map75m", 0, NULL, -1},
-	{"map76m", 0, NULL, -1},
-	{"map77m", 0, NULL, -1},
-	{"map78m", 0, NULL, -1},
-	{"map79m", 0, NULL, -1},
-	{"map80m", 0, NULL, -1},
-	{"map81m", 0, NULL, -1},
-	{"map82m", 0, NULL, -1},
-	{"map83m", 0, NULL, -1},
-	{"map84m", 0, NULL, -1},
-	{"map85m", 0, NULL, -1},
-	{"map86m", 0, NULL, -1},
-	{"map87m", 0, NULL, -1},
-	{"map88m", 0, NULL, -1},
-	{"map89m", 0, NULL, -1},
-	{"map90m", 0, NULL, -1},
-	{"map91m", 0, NULL, -1},
-	{"map92m", 0, NULL, -1},
-	{"map93m", 0, NULL, -1},
-	{"map94m", 0, NULL, -1},
-	{"map95m", 0, NULL, -1},
-	{"map96m", 0, NULL, -1},
-	{"map97m", 0, NULL, -1},
-	{"map98m", 0, NULL, -1},
-	{"map99m", 0, NULL, -1},
-	{"mapa0m", 0, NULL, -1},
-	{"mapa1m", 0, NULL, -1},
-	{"mapa2m", 0, NULL, -1},
-	{"mapa3m", 0, NULL, -1},
-	{"mapa4m", 0, NULL, -1},
-	{"mapa5m", 0, NULL, -1},
-	{"mapa6m", 0, NULL, -1},
-	{"mapa7m", 0, NULL, -1},
-	{"mapa8m", 0, NULL, -1},
-	{"mapa9m", 0, NULL, -1},
-	{"mapaam", 0, NULL, -1},
-	{"mapabm", 0, NULL, -1},
-	{"mapacm", 0, NULL, -1},
-	{"mapadm", 0, NULL, -1},
-	{"mapaem", 0, NULL, -1},
-	{"mapafm", 0, NULL, -1},
-	{"mapagm", 0, NULL, -1},
-	{"mapahm", 0, NULL, -1},
-	{"mapaim", 0, NULL, -1},
-	{"mapajm", 0, NULL, -1},
-	{"mapakm", 0, NULL, -1},
-	{"mapalm", 0, NULL, -1},
-	{"mapamm", 0, NULL, -1},
-	{"mapanm", 0, NULL, -1},
-	{"mapaom", 0, NULL, -1},
-	{"mapapm", 0, NULL, -1},
-	{"mapaqm", 0, NULL, -1},
-	{"maparm", 0, NULL, -1},
-	{"mapasm", 0, NULL, -1},
-	{"mapatm", 0, NULL, -1},
-	{"mapaum", 0, NULL, -1},
-	{"mapavm", 0, NULL, -1},
-	{"mapawm", 0, NULL, -1},
-	{"mapaxm", 0, NULL, -1},
-	{"mapaym", 0, NULL, -1},
-	{"mapazm", 0, NULL, -1},
-	{"mapb0m", 0, NULL, -1},
-	{"mapb1m", 0, NULL, -1},
-	{"mapb2m", 0, NULL, -1},
-	{"mapb3m", 0, NULL, -1},
-	{"mapb4m", 0, NULL, -1},
-	{"mapb5m", 0, NULL, -1},
-	{"mapb6m", 0, NULL, -1},
-	{"mapb7m", 0, NULL, -1},
-	{"mapb8m", 0, NULL, -1},
-	{"mapb9m", 0, NULL, -1},
-	{"mapbam", 0, NULL, -1},
-	{"mapbbm", 0, NULL, -1},
-	{"mapbcm", 0, NULL, -1},
-	{"mapbdm", 0, NULL, -1},
-	{"mapbem", 0, NULL, -1},
-	{"mapbfm", 0, NULL, -1},
-	{"mapbgm", 0, NULL, -1},
-	{"mapbhm", 0, NULL, -1},
-	{"mapbim", 0, NULL, -1},
-	{"mapbjm", 0, NULL, -1},
-	{"mapbkm", 0, NULL, -1},
-	{"mapblm", 0, NULL, -1},
-	{"mapbmm", 0, NULL, -1},
-	{"mapbnm", 0, NULL, -1},
-	{"mapbom", 0, NULL, -1},
-	{"mapbpm", 0, NULL, -1},
-	{"mapbqm", 0, NULL, -1},
-	{"mapbrm", 0, NULL, -1},
-	{"mapbsm", 0, NULL, -1},
-	{"mapbtm", 0, NULL, -1},
-	{"mapbum", 0, NULL, -1},
-	{"mapbvm", 0, NULL, -1},
-	{"mapbwm", 0, NULL, -1},
-	{"mapbxm", 0, NULL, -1},
-	{"mapbym", 0, NULL, -1},
-	{"mapbzm", 0, NULL, -1},
-	{"mapc0m", 0, NULL, -1},
-	{"mapc1m", 0, NULL, -1},
-	{"mapc2m", 0, NULL, -1},
-	{"mapc3m", 0, NULL, -1},
-	{"mapc4m", 0, NULL, -1},
-	{"mapc5m", 0, NULL, -1},
-	{"mapc6m", 0, NULL, -1},
-	{"mapc7m", 0, NULL, -1},
-	{"mapc8m", 0, NULL, -1},
-	{"mapc9m", 0, NULL, -1},
-	{"mapcam", 0, NULL, -1},
-	{"mapcbm", 0, NULL, -1},
-	{"mapccm", 0, NULL, -1},
-	{"mapcdm", 0, NULL, -1},
-	{"mapcem", 0, NULL, -1},
-	{"mapcfm", 0, NULL, -1},
-	{"mapcgm", 0, NULL, -1},
-	{"mapchm", 0, NULL, -1},
-	{"mapcim", 0, NULL, -1},
-	{"mapcjm", 0, NULL, -1},
-	{"mapckm", 0, NULL, -1},
-	{"mapclm", 0, NULL, -1},
-	{"mapcmm", 0, NULL, -1},
-	{"mapcnm", 0, NULL, -1},
-	{"mapcom", 0, NULL, -1},
-	{"mapcpm", 0, NULL, -1},
-	{"mapcqm", 0, NULL, -1},
-	{"mapcrm", 0, NULL, -1},
-	{"mapcsm", 0, NULL, -1},
-	{"mapctm", 0, NULL, -1},
-	{"mapcum", 0, NULL, -1},
-	{"mapcvm", 0, NULL, -1},
-	{"mapcwm", 0, NULL, -1},
-	{"mapcxm", 0, NULL, -1},
-	{"mapcym", 0, NULL, -1},
-	{"mapczm", 0, NULL, -1},
-	{"mapd0m", 0, NULL, -1},
-	{"mapd1m", 0, NULL, -1},
-	{"mapd2m", 0, NULL, -1},
-	{"mapd3m", 0, NULL, -1},
-	{"mapd4m", 0, NULL, -1},
-	{"mapd5m", 0, NULL, -1},
-	{"mapd6m", 0, NULL, -1},
-	{"mapd7m", 0, NULL, -1},
-	{"mapd8m", 0, NULL, -1},
-	{"mapd9m", 0, NULL, -1},
-	{"mapdam", 0, NULL, -1},
-	{"mapdbm", 0, NULL, -1},
-	{"mapdcm", 0, NULL, -1},
-	{"mapddm", 0, NULL, -1},
-	{"mapdem", 0, NULL, -1},
-	{"mapdfm", 0, NULL, -1},
-	{"mapdgm", 0, NULL, -1},
-	{"mapdhm", 0, NULL, -1},
-	{"mapdim", 0, NULL, -1},
-	{"mapdjm", 0, NULL, -1},
-	{"mapdkm", 0, NULL, -1},
-	{"mapdlm", 0, NULL, -1},
-	{"mapdmm", 0, NULL, -1},
-	{"mapdnm", 0, NULL, -1},
-	{"mapdom", 0, NULL, -1},
-	{"mapdpm", 0, NULL, -1},
-	{"mapdqm", 0, NULL, -1},
-	{"mapdrm", 0, NULL, -1},
-	{"mapdsm", 0, NULL, -1},
-	{"mapdtm", 0, NULL, -1},
-	{"mapdum", 0, NULL, -1},
-	{"mapdvm", 0, NULL, -1},
-	{"mapdwm", 0, NULL, -1},
-	{"mapdxm", 0, NULL, -1},
-	{"mapdym", 0, NULL, -1},
-	{"mapdzm", 0, NULL, -1},
-	{"mape0m", 0, NULL, -1},
-	{"mape1m", 0, NULL, -1},
-	{"mape2m", 0, NULL, -1},
-	{"mape3m", 0, NULL, -1},
-	{"mape4m", 0, NULL, -1},
-	{"mape5m", 0, NULL, -1},
-	{"mape6m", 0, NULL, -1},
-	{"mape7m", 0, NULL, -1},
-	{"mape8m", 0, NULL, -1},
-	{"mape9m", 0, NULL, -1},
-	{"mapeam", 0, NULL, -1},
-	{"mapebm", 0, NULL, -1},
-	{"mapecm", 0, NULL, -1},
-	{"mapedm", 0, NULL, -1},
-	{"mapeem", 0, NULL, -1},
-	{"mapefm", 0, NULL, -1},
-	{"mapegm", 0, NULL, -1},
-	{"mapehm", 0, NULL, -1},
-	{"mapeim", 0, NULL, -1},
-	{"mapejm", 0, NULL, -1},
-	{"mapekm", 0, NULL, -1},
-	{"mapelm", 0, NULL, -1},
-	{"mapemm", 0, NULL, -1},
-	{"mapenm", 0, NULL, -1},
-	{"mapeom", 0, NULL, -1},
-	{"mapepm", 0, NULL, -1},
-	{"mapeqm", 0, NULL, -1},
-	{"maperm", 0, NULL, -1},
-	{"mapesm", 0, NULL, -1},
-	{"mapetm", 0, NULL, -1},
-	{"mapeum", 0, NULL, -1},
-	{"mapevm", 0, NULL, -1},
-	{"mapewm", 0, NULL, -1},
-	{"mapexm", 0, NULL, -1},
-	{"mapeym", 0, NULL, -1},
-	{"mapezm", 0, NULL, -1},
-	{"mapf0m", 0, NULL, -1},
-	{"mapf1m", 0, NULL, -1},
-	{"mapf2m", 0, NULL, -1},
-	{"mapf3m", 0, NULL, -1},
-	{"mapf4m", 0, NULL, -1},
-	{"mapf5m", 0, NULL, -1},
-	{"mapf6m", 0, NULL, -1},
-	{"mapf7m", 0, NULL, -1},
-	{"mapf8m", 0, NULL, -1},
-	{"mapf9m", 0, NULL, -1},
-	{"mapfam", 0, NULL, -1},
-	{"mapfbm", 0, NULL, -1},
-	{"mapfcm", 0, NULL, -1},
-	{"mapfdm", 0, NULL, -1},
-	{"mapfem", 0, NULL, -1},
-	{"mapffm", 0, NULL, -1},
-	{"mapfgm", 0, NULL, -1},
-	{"mapfhm", 0, NULL, -1},
-	{"mapfim", 0, NULL, -1},
-	{"mapfjm", 0, NULL, -1},
-	{"mapfkm", 0, NULL, -1},
-	{"mapflm", 0, NULL, -1},
-	{"mapfmm", 0, NULL, -1},
-	{"mapfnm", 0, NULL, -1},
-	{"mapfom", 0, NULL, -1},
-	{"mapfpm", 0, NULL, -1},
-	{"mapfqm", 0, NULL, -1},
-	{"mapfrm", 0, NULL, -1},
-	{"mapfsm", 0, NULL, -1},
-	{"mapftm", 0, NULL, -1},
-	{"mapfum", 0, NULL, -1},
-	{"mapfvm", 0, NULL, -1},
-	{"mapfwm", 0, NULL, -1},
-	{"mapfxm", 0, NULL, -1},
-	{"mapfym", 0, NULL, -1},
-	{"mapfzm", 0, NULL, -1},
-	{"mapg0m", 0, NULL, -1},
-	{"mapg1m", 0, NULL, -1},
-	{"mapg2m", 0, NULL, -1},
-	{"mapg3m", 0, NULL, -1},
-	{"mapg4m", 0, NULL, -1},
-	{"mapg5m", 0, NULL, -1},
-	{"mapg6m", 0, NULL, -1},
-	{"mapg7m", 0, NULL, -1},
-	{"mapg8m", 0, NULL, -1},
-	{"mapg9m", 0, NULL, -1},
-	{"mapgam", 0, NULL, -1},
-	{"mapgbm", 0, NULL, -1},
-	{"mapgcm", 0, NULL, -1},
-	{"mapgdm", 0, NULL, -1},
-	{"mapgem", 0, NULL, -1},
-	{"mapgfm", 0, NULL, -1},
-	{"mapggm", 0, NULL, -1},
-	{"mapghm", 0, NULL, -1},
-	{"mapgim", 0, NULL, -1},
-	{"mapgjm", 0, NULL, -1},
-	{"mapgkm", 0, NULL, -1},
-	{"mapglm", 0, NULL, -1},
-	{"mapgmm", 0, NULL, -1},
-	{"mapgnm", 0, NULL, -1},
-	{"mapgom", 0, NULL, -1},
-	{"mapgpm", 0, NULL, -1},
-	{"mapgqm", 0, NULL, -1},
-	{"mapgrm", 0, NULL, -1},
-	{"mapgsm", 0, NULL, -1},
-	{"mapgtm", 0, NULL, -1},
-	{"mapgum", 0, NULL, -1},
-	{"mapgvm", 0, NULL, -1},
-	{"mapgwm", 0, NULL, -1},
-	{"mapgxm", 0, NULL, -1},
-	{"mapgym", 0, NULL, -1},
-	{"mapgzm", 0, NULL, -1},
-	{"maph0m", 0, NULL, -1},
-	{"maph1m", 0, NULL, -1},
-	{"maph2m", 0, NULL, -1},
-	{"maph3m", 0, NULL, -1},
-	{"maph4m", 0, NULL, -1},
-	{"maph5m", 0, NULL, -1},
-	{"maph6m", 0, NULL, -1},
-	{"maph7m", 0, NULL, -1},
-	{"maph8m", 0, NULL, -1},
-	{"maph9m", 0, NULL, -1},
-	{"mapham", 0, NULL, -1},
-	{"maphbm", 0, NULL, -1},
-	{"maphcm", 0, NULL, -1},
-	{"maphdm", 0, NULL, -1},
-	{"maphem", 0, NULL, -1},
-	{"maphfm", 0, NULL, -1},
-	{"maphgm", 0, NULL, -1},
-	{"maphhm", 0, NULL, -1},
-	{"maphim", 0, NULL, -1},
-	{"maphjm", 0, NULL, -1},
-	{"maphkm", 0, NULL, -1},
-	{"maphlm", 0, NULL, -1},
-	{"maphmm", 0, NULL, -1},
-	{"maphnm", 0, NULL, -1},
-	{"maphom", 0, NULL, -1},
-	{"maphpm", 0, NULL, -1},
-	{"maphqm", 0, NULL, -1},
-	{"maphrm", 0, NULL, -1},
-	{"maphsm", 0, NULL, -1},
-	{"maphtm", 0, NULL, -1},
-	{"maphum", 0, NULL, -1},
-	{"maphvm", 0, NULL, -1},
-	{"maphwm", 0, NULL, -1},
-	{"maphxm", 0, NULL, -1},
-	{"maphym", 0, NULL, -1},
-	{"maphzm", 0, NULL, -1},
-	{"mapi0m", 0, NULL, -1},
-	{"mapi1m", 0, NULL, -1},
-	{"mapi2m", 0, NULL, -1},
-	{"mapi3m", 0, NULL, -1},
-	{"mapi4m", 0, NULL, -1},
-	{"mapi5m", 0, NULL, -1},
-	{"mapi6m", 0, NULL, -1},
-	{"mapi7m", 0, NULL, -1},
-	{"mapi8m", 0, NULL, -1},
-	{"mapi9m", 0, NULL, -1},
-	{"mapiam", 0, NULL, -1},
-	{"mapibm", 0, NULL, -1},
-	{"mapicm", 0, NULL, -1},
-	{"mapidm", 0, NULL, -1},
-	{"mapiem", 0, NULL, -1},
-	{"mapifm", 0, NULL, -1},
-	{"mapigm", 0, NULL, -1},
-	{"mapihm", 0, NULL, -1},
-	{"mapiim", 0, NULL, -1},
-	{"mapijm", 0, NULL, -1},
-	{"mapikm", 0, NULL, -1},
-	{"mapilm", 0, NULL, -1},
-	{"mapimm", 0, NULL, -1},
-	{"mapinm", 0, NULL, -1},
-	{"mapiom", 0, NULL, -1},
-	{"mapipm", 0, NULL, -1},
-	{"mapiqm", 0, NULL, -1},
-	{"mapirm", 0, NULL, -1},
-	{"mapism", 0, NULL, -1},
-	{"mapitm", 0, NULL, -1},
-	{"mapium", 0, NULL, -1},
-	{"mapivm", 0, NULL, -1},
-	{"mapiwm", 0, NULL, -1},
-	{"mapixm", 0, NULL, -1},
-	{"mapiym", 0, NULL, -1},
-	{"mapizm", 0, NULL, -1},
-	{"mapj0m", 0, NULL, -1},
-	{"mapj1m", 0, NULL, -1},
-	{"mapj2m", 0, NULL, -1},
-	{"mapj3m", 0, NULL, -1},
-	{"mapj4m", 0, NULL, -1},
-	{"mapj5m", 0, NULL, -1},
-	{"mapj6m", 0, NULL, -1},
-	{"mapj7m", 0, NULL, -1},
-	{"mapj8m", 0, NULL, -1},
-	{"mapj9m", 0, NULL, -1},
-	{"mapjam", 0, NULL, -1},
-	{"mapjbm", 0, NULL, -1},
-	{"mapjcm", 0, NULL, -1},
-	{"mapjdm", 0, NULL, -1},
-	{"mapjem", 0, NULL, -1},
-	{"mapjfm", 0, NULL, -1},
-	{"mapjgm", 0, NULL, -1},
-	{"mapjhm", 0, NULL, -1},
-	{"mapjim", 0, NULL, -1},
-	{"mapjjm", 0, NULL, -1},
-	{"mapjkm", 0, NULL, -1},
-	{"mapjlm", 0, NULL, -1},
-	{"mapjmm", 0, NULL, -1},
-	{"mapjnm", 0, NULL, -1},
-	{"mapjom", 0, NULL, -1},
-	{"mapjpm", 0, NULL, -1},
-	{"mapjqm", 0, NULL, -1},
-	{"mapjrm", 0, NULL, -1},
-	{"mapjsm", 0, NULL, -1},
-	{"mapjtm", 0, NULL, -1},
-	{"mapjum", 0, NULL, -1},
-	{"mapjvm", 0, NULL, -1},
-	{"mapjwm", 0, NULL, -1},
-	{"mapjxm", 0, NULL, -1},
-	{"mapjym", 0, NULL, -1},
-	{"mapjzm", 0, NULL, -1},
-	{"mapk0m", 0, NULL, -1},
-	{"mapk1m", 0, NULL, -1},
-	{"mapk2m", 0, NULL, -1},
-	{"mapk3m", 0, NULL, -1},
-	{"mapk4m", 0, NULL, -1},
-	{"mapk5m", 0, NULL, -1},
-	{"mapk6m", 0, NULL, -1},
-	{"mapk7m", 0, NULL, -1},
-	{"mapk8m", 0, NULL, -1},
-	{"mapk9m", 0, NULL, -1},
-	{"mapkam", 0, NULL, -1},
-	{"mapkbm", 0, NULL, -1},
-	{"mapkcm", 0, NULL, -1},
-	{"mapkdm", 0, NULL, -1},
-	{"mapkem", 0, NULL, -1},
-	{"mapkfm", 0, NULL, -1},
-	{"mapkgm", 0, NULL, -1},
-	{"mapkhm", 0, NULL, -1},
-	{"mapkim", 0, NULL, -1},
-	{"mapkjm", 0, NULL, -1},
-	{"mapkkm", 0, NULL, -1},
-	{"mapklm", 0, NULL, -1},
-	{"mapkmm", 0, NULL, -1},
-	{"mapknm", 0, NULL, -1},
-	{"mapkom", 0, NULL, -1},
-	{"mapkpm", 0, NULL, -1},
-	{"mapkqm", 0, NULL, -1},
-	{"mapkrm", 0, NULL, -1},
-	{"mapksm", 0, NULL, -1},
-	{"mapktm", 0, NULL, -1},
-	{"mapkum", 0, NULL, -1},
-	{"mapkvm", 0, NULL, -1},
-	{"mapkwm", 0, NULL, -1},
-	{"mapkxm", 0, NULL, -1},
-	{"mapkym", 0, NULL, -1},
-	{"mapkzm", 0, NULL, -1},
-	{"mapl0m", 0, NULL, -1},
-	{"mapl1m", 0, NULL, -1},
-	{"mapl2m", 0, NULL, -1},
-	{"mapl3m", 0, NULL, -1},
-	{"mapl4m", 0, NULL, -1},
-	{"mapl5m", 0, NULL, -1},
-	{"mapl6m", 0, NULL, -1},
-	{"mapl7m", 0, NULL, -1},
-	{"mapl8m", 0, NULL, -1},
-	{"mapl9m", 0, NULL, -1},
-	{"maplam", 0, NULL, -1},
-	{"maplbm", 0, NULL, -1},
-	{"maplcm", 0, NULL, -1},
-	{"mapldm", 0, NULL, -1},
-	{"maplem", 0, NULL, -1},
-	{"maplfm", 0, NULL, -1},
-	{"maplgm", 0, NULL, -1},
-	{"maplhm", 0, NULL, -1},
-	{"maplim", 0, NULL, -1},
-	{"mapljm", 0, NULL, -1},
-	{"maplkm", 0, NULL, -1},
-	{"mapllm", 0, NULL, -1},
-	{"maplmm", 0, NULL, -1},
-	{"maplnm", 0, NULL, -1},
-	{"maplom", 0, NULL, -1},
-	{"maplpm", 0, NULL, -1},
-	{"maplqm", 0, NULL, -1},
-	{"maplrm", 0, NULL, -1},
-	{"maplsm", 0, NULL, -1},
-	{"mapltm", 0, NULL, -1},
-	{"maplum", 0, NULL, -1},
-	{"maplvm", 0, NULL, -1},
-	{"maplwm", 0, NULL, -1},
-	{"maplxm", 0, NULL, -1},
-	{"maplym", 0, NULL, -1},
-	{"maplzm", 0, NULL, -1},
-	{"mapm0m", 0, NULL, -1},
-	{"mapm1m", 0, NULL, -1},
-	{"mapm2m", 0, NULL, -1},
-	{"mapm3m", 0, NULL, -1},
-	{"mapm4m", 0, NULL, -1},
-	{"mapm5m", 0, NULL, -1},
-	{"mapm6m", 0, NULL, -1},
-	{"mapm7m", 0, NULL, -1},
-	{"mapm8m", 0, NULL, -1},
-	{"mapm9m", 0, NULL, -1},
-	{"mapmam", 0, NULL, -1},
-	{"mapmbm", 0, NULL, -1},
-	{"mapmcm", 0, NULL, -1},
-	{"mapmdm", 0, NULL, -1},
-	{"mapmem", 0, NULL, -1},
-	{"mapmfm", 0, NULL, -1},
-	{"mapmgm", 0, NULL, -1},
-	{"mapmhm", 0, NULL, -1},
-	{"mapmim", 0, NULL, -1},
-	{"mapmjm", 0, NULL, -1},
-	{"mapmkm", 0, NULL, -1},
-	{"mapmlm", 0, NULL, -1},
-	{"mapmmm", 0, NULL, -1},
-	{"mapmnm", 0, NULL, -1},
-	{"mapmom", 0, NULL, -1},
-	{"mapmpm", 0, NULL, -1},
-	{"mapmqm", 0, NULL, -1},
-	{"mapmrm", 0, NULL, -1},
-	{"mapmsm", 0, NULL, -1},
-	{"mapmtm", 0, NULL, -1},
-	{"mapmum", 0, NULL, -1},
-	{"mapmvm", 0, NULL, -1},
-	{"mapmwm", 0, NULL, -1},
-	{"mapmxm", 0, NULL, -1},
-	{"mapmym", 0, NULL, -1},
-	{"mapmzm", 0, NULL, -1},
-	{"mapn0m", 0, NULL, -1},
-	{"mapn1m", 0, NULL, -1},
-	{"mapn2m", 0, NULL, -1},
-	{"mapn3m", 0, NULL, -1},
-	{"mapn4m", 0, NULL, -1},
-	{"mapn5m", 0, NULL, -1},
-	{"mapn6m", 0, NULL, -1},
-	{"mapn7m", 0, NULL, -1},
-	{"mapn8m", 0, NULL, -1},
-	{"mapn9m", 0, NULL, -1},
-	{"mapnam", 0, NULL, -1},
-	{"mapnbm", 0, NULL, -1},
-	{"mapncm", 0, NULL, -1},
-	{"mapndm", 0, NULL, -1},
-	{"mapnem", 0, NULL, -1},
-	{"mapnfm", 0, NULL, -1},
-	{"mapngm", 0, NULL, -1},
-	{"mapnhm", 0, NULL, -1},
-	{"mapnim", 0, NULL, -1},
-	{"mapnjm", 0, NULL, -1},
-	{"mapnkm", 0, NULL, -1},
-	{"mapnlm", 0, NULL, -1},
-	{"mapnmm", 0, NULL, -1},
-	{"mapnnm", 0, NULL, -1},
-	{"mapnom", 0, NULL, -1},
-	{"mapnpm", 0, NULL, -1},
-	{"mapnqm", 0, NULL, -1},
-	{"mapnrm", 0, NULL, -1},
-	{"mapnsm", 0, NULL, -1},
-	{"mapntm", 0, NULL, -1},
-	{"mapnum", 0, NULL, -1},
-	{"mapnvm", 0, NULL, -1},
-	{"mapnwm", 0, NULL, -1},
-	{"mapnxm", 0, NULL, -1},
-	{"mapnym", 0, NULL, -1},
-	{"mapnzm", 0, NULL, -1},
-	{"mapo0m", 0, NULL, -1},
-	{"mapo1m", 0, NULL, -1},
-	{"mapo2m", 0, NULL, -1},
-	{"mapo3m", 0, NULL, -1},
-	{"mapo4m", 0, NULL, -1},
-	{"mapo5m", 0, NULL, -1},
-	{"mapo6m", 0, NULL, -1},
-	{"mapo7m", 0, NULL, -1},
-	{"mapo8m", 0, NULL, -1},
-	{"mapo9m", 0, NULL, -1},
-	{"mapoam", 0, NULL, -1},
-	{"mapobm", 0, NULL, -1},
-	{"mapocm", 0, NULL, -1},
-	{"mapodm", 0, NULL, -1},
-	{"mapoem", 0, NULL, -1},
-	{"mapofm", 0, NULL, -1},
-	{"mapogm", 0, NULL, -1},
-	{"mapohm", 0, NULL, -1},
-	{"mapoim", 0, NULL, -1},
-	{"mapojm", 0, NULL, -1},
-	{"mapokm", 0, NULL, -1},
-	{"mapolm", 0, NULL, -1},
-	{"mapomm", 0, NULL, -1},
-	{"maponm", 0, NULL, -1},
-	{"mapoom", 0, NULL, -1},
-	{"mapopm", 0, NULL, -1},
-	{"mapoqm", 0, NULL, -1},
-	{"maporm", 0, NULL, -1},
-	{"maposm", 0, NULL, -1},
-	{"mapotm", 0, NULL, -1},
-	{"mapoum", 0, NULL, -1},
-	{"mapovm", 0, NULL, -1},
-	{"mapowm", 0, NULL, -1},
-	{"mapoxm", 0, NULL, -1},
-	{"mapoym", 0, NULL, -1},
-	{"mapozm", 0, NULL, -1},
-	{"mapp0m", 0, NULL, -1},
-	{"mapp1m", 0, NULL, -1},
-	{"mapp2m", 0, NULL, -1},
-	{"mapp3m", 0, NULL, -1},
-	{"mapp4m", 0, NULL, -1},
-	{"mapp5m", 0, NULL, -1},
-	{"mapp6m", 0, NULL, -1},
-	{"mapp7m", 0, NULL, -1},
-	{"mapp8m", 0, NULL, -1},
-	{"mapp9m", 0, NULL, -1},
-	{"mappam", 0, NULL, -1},
-	{"mappbm", 0, NULL, -1},
-	{"mappcm", 0, NULL, -1},
-	{"mappdm", 0, NULL, -1},
-	{"mappem", 0, NULL, -1},
-	{"mappfm", 0, NULL, -1},
-	{"mappgm", 0, NULL, -1},
-	{"mapphm", 0, NULL, -1},
-	{"mappim", 0, NULL, -1},
-	{"mappjm", 0, NULL, -1},
-	{"mappkm", 0, NULL, -1},
-	{"mapplm", 0, NULL, -1},
-	{"mappmm", 0, NULL, -1},
-	{"mappnm", 0, NULL, -1},
-	{"mappom", 0, NULL, -1},
-	{"mapppm", 0, NULL, -1},
-	{"mappqm", 0, NULL, -1},
-	{"mapprm", 0, NULL, -1},
-	{"mappsm", 0, NULL, -1},
-	{"mapptm", 0, NULL, -1},
-	{"mappum", 0, NULL, -1},
-	{"mappvm", 0, NULL, -1},
-	{"mappwm", 0, NULL, -1},
-	{"mappxm", 0, NULL, -1},
-	{"mappym", 0, NULL, -1},
-	{"mappzm", 0, NULL, -1},
-	{"mapq0m", 0, NULL, -1},
-	{"mapq1m", 0, NULL, -1},
-	{"mapq2m", 0, NULL, -1},
-	{"mapq3m", 0, NULL, -1},
-	{"mapq4m", 0, NULL, -1},
-	{"mapq5m", 0, NULL, -1},
-	{"mapq6m", 0, NULL, -1},
-	{"mapq7m", 0, NULL, -1},
-	{"mapq8m", 0, NULL, -1},
-	{"mapq9m", 0, NULL, -1},
-	{"mapqam", 0, NULL, -1},
-	{"mapqbm", 0, NULL, -1},
-	{"mapqcm", 0, NULL, -1},
-	{"mapqdm", 0, NULL, -1},
-	{"mapqem", 0, NULL, -1},
-	{"mapqfm", 0, NULL, -1},
-	{"mapqgm", 0, NULL, -1},
-	{"mapqhm", 0, NULL, -1},
-	{"mapqim", 0, NULL, -1},
-	{"mapqjm", 0, NULL, -1},
-	{"mapqkm", 0, NULL, -1},
-	{"mapqlm", 0, NULL, -1},
-	{"mapqmm", 0, NULL, -1},
-	{"mapqnm", 0, NULL, -1},
-	{"mapqom", 0, NULL, -1},
-	{"mapqpm", 0, NULL, -1},
-	{"mapqqm", 0, NULL, -1},
-	{"mapqrm", 0, NULL, -1},
-	{"mapqsm", 0, NULL, -1},
-	{"mapqtm", 0, NULL, -1},
-	{"mapqum", 0, NULL, -1},
-	{"mapqvm", 0, NULL, -1},
-	{"mapqwm", 0, NULL, -1},
-	{"mapqxm", 0, NULL, -1},
-	{"mapqym", 0, NULL, -1},
-	{"mapqzm", 0, NULL, -1},
-	{"mapr0m", 0, NULL, -1},
-	{"mapr1m", 0, NULL, -1},
-	{"mapr2m", 0, NULL, -1},
-	{"mapr3m", 0, NULL, -1},
-	{"mapr4m", 0, NULL, -1},
-	{"mapr5m", 0, NULL, -1},
-	{"mapr6m", 0, NULL, -1},
-	{"mapr7m", 0, NULL, -1},
-	{"mapr8m", 0, NULL, -1},
-	{"mapr9m", 0, NULL, -1},
-	{"mapram", 0, NULL, -1},
-	{"maprbm", 0, NULL, -1},
-	{"maprcm", 0, NULL, -1},
-	{"maprdm", 0, NULL, -1},
-	{"maprem", 0, NULL, -1},
-	{"maprfm", 0, NULL, -1},
-	{"maprgm", 0, NULL, -1},
-	{"maprhm", 0, NULL, -1},
-	{"maprim", 0, NULL, -1},
-	{"maprjm", 0, NULL, -1},
-	{"maprkm", 0, NULL, -1},
-	{"maprlm", 0, NULL, -1},
-	{"maprmm", 0, NULL, -1},
-	{"maprnm", 0, NULL, -1},
-	{"maprom", 0, NULL, -1},
-	{"maprpm", 0, NULL, -1},
-	{"maprqm", 0, NULL, -1},
-	{"maprrm", 0, NULL, -1},
-	{"maprsm", 0, NULL, -1},
-	{"maprtm", 0, NULL, -1},
-	{"maprum", 0, NULL, -1},
-	{"maprvm", 0, NULL, -1},
-	{"maprwm", 0, NULL, -1},
-	{"maprxm", 0, NULL, -1},
-	{"maprym", 0, NULL, -1},
-	{"maprzm", 0, NULL, -1},
-	{"maps0m", 0, NULL, -1},
-	{"maps1m", 0, NULL, -1},
-	{"maps2m", 0, NULL, -1},
-	{"maps3m", 0, NULL, -1},
-	{"maps4m", 0, NULL, -1},
-	{"maps5m", 0, NULL, -1},
-	{"maps6m", 0, NULL, -1},
-	{"maps7m", 0, NULL, -1},
-	{"maps8m", 0, NULL, -1},
-	{"maps9m", 0, NULL, -1},
-	{"mapsam", 0, NULL, -1},
-	{"mapsbm", 0, NULL, -1},
-	{"mapscm", 0, NULL, -1},
-	{"mapsdm", 0, NULL, -1},
-	{"mapsem", 0, NULL, -1},
-	{"mapsfm", 0, NULL, -1},
-	{"mapsgm", 0, NULL, -1},
-	{"mapshm", 0, NULL, -1},
-	{"mapsim", 0, NULL, -1},
-	{"mapsjm", 0, NULL, -1},
-	{"mapskm", 0, NULL, -1},
-	{"mapslm", 0, NULL, -1},
-	{"mapsmm", 0, NULL, -1},
-	{"mapsnm", 0, NULL, -1},
-	{"mapsom", 0, NULL, -1},
-	{"mapspm", 0, NULL, -1},
-	{"mapsqm", 0, NULL, -1},
-	{"mapsrm", 0, NULL, -1},
-	{"mapssm", 0, NULL, -1},
-	{"mapstm", 0, NULL, -1},
-	{"mapsum", 0, NULL, -1},
-	{"mapsvm", 0, NULL, -1},
-	{"mapswm", 0, NULL, -1},
-	{"mapsxm", 0, NULL, -1},
-	{"mapsym", 0, NULL, -1},
-	{"mapszm", 0, NULL, -1},
-	{"mapt0m", 0, NULL, -1},
-	{"mapt1m", 0, NULL, -1},
-	{"mapt2m", 0, NULL, -1},
-	{"mapt3m", 0, NULL, -1},
-	{"mapt4m", 0, NULL, -1},
-	{"mapt5m", 0, NULL, -1},
-	{"mapt6m", 0, NULL, -1},
-	{"mapt7m", 0, NULL, -1},
-	{"mapt8m", 0, NULL, -1},
-	{"mapt9m", 0, NULL, -1},
-	{"maptam", 0, NULL, -1},
-	{"maptbm", 0, NULL, -1},
-	{"maptcm", 0, NULL, -1},
-	{"maptdm", 0, NULL, -1},
-	{"maptem", 0, NULL, -1},
-	{"maptfm", 0, NULL, -1},
-	{"maptgm", 0, NULL, -1},
-	{"mapthm", 0, NULL, -1},
-	{"maptim", 0, NULL, -1},
-	{"maptjm", 0, NULL, -1},
-	{"maptkm", 0, NULL, -1},
-	{"maptlm", 0, NULL, -1},
-	{"maptmm", 0, NULL, -1},
-	{"maptnm", 0, NULL, -1},
-	{"maptom", 0, NULL, -1},
-	{"maptpm", 0, NULL, -1},
-	{"maptqm", 0, NULL, -1},
-	{"maptrm", 0, NULL, -1},
-	{"maptsm", 0, NULL, -1},
-	{"mapttm", 0, NULL, -1},
-	{"maptum", 0, NULL, -1},
-	{"maptvm", 0, NULL, -1},
-	{"maptwm", 0, NULL, -1},
-	{"maptxm", 0, NULL, -1},
-	{"maptym", 0, NULL, -1},
-	{"maptzm", 0, NULL, -1},
-	{"mapu0m", 0, NULL, -1},
-	{"mapu1m", 0, NULL, -1},
-	{"mapu2m", 0, NULL, -1},
-	{"mapu3m", 0, NULL, -1},
-	{"mapu4m", 0, NULL, -1},
-	{"mapu5m", 0, NULL, -1},
-	{"mapu6m", 0, NULL, -1},
-	{"mapu7m", 0, NULL, -1},
-	{"mapu8m", 0, NULL, -1},
-	{"mapu9m", 0, NULL, -1},
-	{"mapuam", 0, NULL, -1},
-	{"mapubm", 0, NULL, -1},
-	{"mapucm", 0, NULL, -1},
-	{"mapudm", 0, NULL, -1},
-	{"mapuem", 0, NULL, -1},
-	{"mapufm", 0, NULL, -1},
-	{"mapugm", 0, NULL, -1},
-	{"mapuhm", 0, NULL, -1},
-	{"mapuim", 0, NULL, -1},
-	{"mapujm", 0, NULL, -1},
-	{"mapukm", 0, NULL, -1},
-	{"mapulm", 0, NULL, -1},
-	{"mapumm", 0, NULL, -1},
-	{"mapunm", 0, NULL, -1},
-	{"mapuom", 0, NULL, -1},
-	{"mapupm", 0, NULL, -1},
-	{"mapuqm", 0, NULL, -1},
-	{"mapurm", 0, NULL, -1},
-	{"mapusm", 0, NULL, -1},
-	{"maputm", 0, NULL, -1},
-	{"mapuum", 0, NULL, -1},
-	{"mapuvm", 0, NULL, -1},
-	{"mapuwm", 0, NULL, -1},
-	{"mapuxm", 0, NULL, -1},
-	{"mapuym", 0, NULL, -1},
-	{"mapuzm", 0, NULL, -1},
-	{"mapv0m", 0, NULL, -1},
-	{"mapv1m", 0, NULL, -1},
-	{"mapv2m", 0, NULL, -1},
-	{"mapv3m", 0, NULL, -1},
-	{"mapv4m", 0, NULL, -1},
-	{"mapv5m", 0, NULL, -1},
-	{"mapv6m", 0, NULL, -1},
-	{"mapv7m", 0, NULL, -1},
-	{"mapv8m", 0, NULL, -1},
-	{"mapv9m", 0, NULL, -1},
-	{"mapvam", 0, NULL, -1},
-	{"mapvbm", 0, NULL, -1},
-	{"mapvcm", 0, NULL, -1},
-	{"mapvdm", 0, NULL, -1},
-	{"mapvem", 0, NULL, -1},
-	{"mapvfm", 0, NULL, -1},
-	{"mapvgm", 0, NULL, -1},
-	{"mapvhm", 0, NULL, -1},
-	{"mapvim", 0, NULL, -1},
-	{"mapvjm", 0, NULL, -1},
-	{"mapvkm", 0, NULL, -1},
-	{"mapvlm", 0, NULL, -1},
-	{"mapvmm", 0, NULL, -1},
-	{"mapvnm", 0, NULL, -1},
-	{"mapvom", 0, NULL, -1},
-	{"mapvpm", 0, NULL, -1},
-	{"mapvqm", 0, NULL, -1},
-	{"mapvrm", 0, NULL, -1},
-	{"mapvsm", 0, NULL, -1},
-	{"mapvtm", 0, NULL, -1},
-	{"mapvum", 0, NULL, -1},
-	{"mapvvm", 0, NULL, -1},
-	{"mapvwm", 0, NULL, -1},
-	{"mapvxm", 0, NULL, -1},
-	{"mapvym", 0, NULL, -1},
-	{"mapvzm", 0, NULL, -1},
-	{"mapw0m", 0, NULL, -1},
-	{"mapw1m", 0, NULL, -1},
-	{"mapw2m", 0, NULL, -1},
-	{"mapw3m", 0, NULL, -1},
-	{"mapw4m", 0, NULL, -1},
-	{"mapw5m", 0, NULL, -1},
-	{"mapw6m", 0, NULL, -1},
-	{"mapw7m", 0, NULL, -1},
-	{"mapw8m", 0, NULL, -1},
-	{"mapw9m", 0, NULL, -1},
-	{"mapwam", 0, NULL, -1},
-	{"mapwbm", 0, NULL, -1},
-	{"mapwcm", 0, NULL, -1},
-	{"mapwdm", 0, NULL, -1},
-	{"mapwem", 0, NULL, -1},
-	{"mapwfm", 0, NULL, -1},
-	{"mapwgm", 0, NULL, -1},
-	{"mapwhm", 0, NULL, -1},
-	{"mapwim", 0, NULL, -1},
-	{"mapwjm", 0, NULL, -1},
-	{"mapwkm", 0, NULL, -1},
-	{"mapwlm", 0, NULL, -1},
-	{"mapwmm", 0, NULL, -1},
-	{"mapwnm", 0, NULL, -1},
-	{"mapwom", 0, NULL, -1},
-	{"mapwpm", 0, NULL, -1},
-	{"mapwqm", 0, NULL, -1},
-	{"mapwrm", 0, NULL, -1},
-	{"mapwsm", 0, NULL, -1},
-	{"mapwtm", 0, NULL, -1},
-	{"mapwum", 0, NULL, -1},
-	{"mapwvm", 0, NULL, -1},
-	{"mapwwm", 0, NULL, -1},
-	{"mapwxm", 0, NULL, -1},
-	{"mapwym", 0, NULL, -1},
-	{"mapwzm", 0, NULL, -1},
-	{"mapx0m", 0, NULL, -1},
-	{"mapx1m", 0, NULL, -1},
-	{"mapx2m", 0, NULL, -1},
-	{"mapx3m", 0, NULL, -1},
-	{"mapx4m", 0, NULL, -1},
-	{"mapx5m", 0, NULL, -1},
-	{"mapx6m", 0, NULL, -1},
-	{"mapx7m", 0, NULL, -1},
-	{"mapx8m", 0, NULL, -1},
-	{"mapx9m", 0, NULL, -1},
-	{"mapxam", 0, NULL, -1},
-	{"mapxbm", 0, NULL, -1},
-	{"mapxcm", 0, NULL, -1},
-	{"mapxdm", 0, NULL, -1},
-	{"mapxem", 0, NULL, -1},
-	{"mapxfm", 0, NULL, -1},
-	{"mapxgm", 0, NULL, -1},
-	{"mapxhm", 0, NULL, -1},
-	{"mapxim", 0, NULL, -1},
-	{"mapxjm", 0, NULL, -1},
-	{"mapxkm", 0, NULL, -1},
-	{"mapxlm", 0, NULL, -1},
-	{"mapxmm", 0, NULL, -1},
-	{"mapxnm", 0, NULL, -1},
-	{"mapxom", 0, NULL, -1},
-	{"mapxpm", 0, NULL, -1},
-	{"mapxqm", 0, NULL, -1},
-	{"mapxrm", 0, NULL, -1},
-	{"mapxsm", 0, NULL, -1},
-	{"mapxtm", 0, NULL, -1},
-	{"mapxum", 0, NULL, -1},
-	{"mapxvm", 0, NULL, -1},
-	{"mapxwm", 0, NULL, -1},
-	{"mapxxm", 0, NULL, -1},
-	{"mapxym", 0, NULL, -1},
-	{"mapxzm", 0, NULL, -1},
-	{"mapy0m", 0, NULL, -1},
-	{"mapy1m", 0, NULL, -1},
-	{"mapy2m", 0, NULL, -1},
-	{"mapy3m", 0, NULL, -1},
-	{"mapy4m", 0, NULL, -1},
-	{"mapy5m", 0, NULL, -1},
-	{"mapy6m", 0, NULL, -1},
-	{"mapy7m", 0, NULL, -1},
-	{"mapy8m", 0, NULL, -1},
-	{"mapy9m", 0, NULL, -1},
-	{"mapyam", 0, NULL, -1},
-	{"mapybm", 0, NULL, -1},
-	{"mapycm", 0, NULL, -1},
-	{"mapydm", 0, NULL, -1},
-	{"mapyem", 0, NULL, -1},
-	{"mapyfm", 0, NULL, -1},
-	{"mapygm", 0, NULL, -1},
-	{"mapyhm", 0, NULL, -1},
-	{"mapyim", 0, NULL, -1},
-	{"mapyjm", 0, NULL, -1},
-	{"mapykm", 0, NULL, -1},
-	{"mapylm", 0, NULL, -1},
-	{"mapymm", 0, NULL, -1},
-	{"mapynm", 0, NULL, -1},
-	{"mapyom", 0, NULL, -1},
-	{"mapypm", 0, NULL, -1},
-	{"mapyqm", 0, NULL, -1},
-	{"mapyrm", 0, NULL, -1},
-	{"mapysm", 0, NULL, -1},
-	{"mapytm", 0, NULL, -1},
-	{"mapyum", 0, NULL, -1},
-	{"mapyvm", 0, NULL, -1},
-	{"mapywm", 0, NULL, -1},
-	{"mapyxm", 0, NULL, -1},
-	{"mapyym", 0, NULL, -1},
-	{"mapyzm", 0, NULL, -1},
-	{"mapz0m", 0, NULL, -1},
-	{"mapz1m", 0, NULL, -1},
-	{"mapz2m", 0, NULL, -1},
-	{"mapz3m", 0, NULL, -1},
-	{"mapz4m", 0, NULL, -1},
-	{"mapz5m", 0, NULL, -1},
-	{"mapz6m", 0, NULL, -1},
-	{"mapz7m", 0, NULL, -1},
-	{"mapz8m", 0, NULL, -1},
-	{"mapz9m", 0, NULL, -1},
-	{"mapzam", 0, NULL, -1},
-	{"mapzbm", 0, NULL, -1},
-	{"mapzcm", 0, NULL, -1},
-	{"mapzdm", 0, NULL, -1},
-	{"mapzem", 0, NULL, -1},
-	{"mapzfm", 0, NULL, -1},
-	{"mapzgm", 0, NULL, -1},
-	{"mapzhm", 0, NULL, -1},
-	{"mapzim", 0, NULL, -1},
-	{"mapzjm", 0, NULL, -1},
-	{"mapzkm", 0, NULL, -1},
-	{"mapzlm", 0, NULL, -1},
-	{"mapzmm", 0, NULL, -1},
-	{"mapznm", 0, NULL, -1},
-	{"mapzom", 0, NULL, -1},
-	{"mapzpm", 0, NULL, -1},
-	{"mapzqm", 0, NULL, -1},
-	{"mapzrm", 0, NULL, -1},
-	{"mapzsm", 0, NULL, -1},
-	{"mapztm", 0, NULL, -1},
-	{"mapzum", 0, NULL, -1},
-	{"mapzvm", 0, NULL, -1},
-	{"mapzwm", 0, NULL, -1},
-	{"mapzxm", 0, NULL, -1},
-	{"mapzym", 0, NULL, -1},
-	{"mapzzm", 0, NULL, -1},
-
-	{"titles", 0, NULL, -1}, // Title screen
-	{"read_m", 0, NULL, -1}, // Intro
-	{"lclear", 0, NULL, -1}, // Level clear
-	{"invinc", 0, NULL, -1}, // Invincibility
-	{"shoes", 0, NULL, -1}, // Super sneakers
-	{"minvnc", 0, NULL, -1}, // Mario invincibility
-	{"drown", 0, NULL, -1}, // Drowning
-	{"gmover", 0, NULL, -1}, // Game over
-	{"xtlife", 0, NULL, -1}, // Extra life
-	{"contsc", 0, NULL, -1}, // Continue screen
-	{"supers", 0, NULL, -1}, // Super Sonic
-	{"chrsel", 0, NULL, -1}, // Character select
-	{"credit", 0, NULL, -1}, // Credits
-	{"racent", 0, NULL, -1}, // Race Results
-	{"stjr",   0, NULL, -1}, // Sonic Team Jr. Presents
-};
-
-
 //
 // Information about all the sfx
 //
diff --git a/src/sounds.h b/src/sounds.h
index c5851a346b8944c8f14386a57a2fdfb92bd29fe2..4388d02cf4c75d16e4f3d7c8885096aeec5dfa75 100644
--- a/src/sounds.h
+++ b/src/sounds.h
@@ -86,1095 +86,9 @@ struct sfxinfo_struct
 	lumpnum_t lumpnum;
 };
 
-//
-// MusicInfo struct.
-//
-typedef struct
-{
-	// up to 6-character name
-	const char *name;
-
-	// lump number of music
-	lumpnum_t lumpnum;
-
-	// music data
-	void *data;
-
-	// music handle once registered
-	INT32 handle;
-} musicinfo_t;
-
 // the complete set of sound effects
 extern sfxinfo_t S_sfx[];
 
-// the complete set of music
-extern musicinfo_t S_music[];
-
-//
-// Identifiers for all music in game.
-//
-
-// Music list (don't edit this comment!)
-typedef enum
-{
-	mus_None,
-	mus_map01m,
-	mus_map02m,
-	mus_map03m,
-	mus_map04m,
-	mus_map05m,
-	mus_map06m,
-	mus_map07m,
-	mus_map08m,
-	mus_map09m,
-	mus_map10m,
-	mus_map11m,
-	mus_map12m,
-	mus_map13m,
-	mus_map14m,
-	mus_map15m,
-	mus_map16m,
-	mus_map17m,
-	mus_map18m,
-	mus_map19m,
-	mus_map20m,
-	mus_map21m,
-	mus_map22m,
-	mus_map23m,
-	mus_map24m,
-	mus_map25m,
-	mus_map26m,
-	mus_map27m,
-	mus_map28m,
-	mus_map29m,
-	mus_map30m,
-	mus_map31m,
-	mus_map32m,
-	mus_map33m,
-	mus_map34m,
-	mus_map35m,
-	mus_map36m,
-	mus_map37m,
-	mus_map38m,
-	mus_map39m,
-	mus_map40m,
-	mus_map41m,
-	mus_map42m,
-	mus_map43m,
-	mus_map44m,
-	mus_map45m,
-	mus_map46m,
-	mus_map47m,
-	mus_map48m,
-	mus_map49m,
-	mus_map50m,
-	mus_map51m,
-	mus_map52m,
-	mus_map53m,
-	mus_map54m,
-	mus_map55m,
-	mus_map56m,
-	mus_map57m,
-	mus_map58m,
-	mus_map59m,
-	mus_map60m,
-	mus_map61m,
-	mus_map62m,
-	mus_map63m,
-	mus_map64m,
-	mus_map65m,
-	mus_map66m,
-	mus_map67m,
-	mus_map68m,
-	mus_map69m,
-	mus_map70m,
-	mus_map71m,
-	mus_map72m,
-	mus_map73m,
-	mus_map74m,
-	mus_map75m,
-	mus_map76m,
-	mus_map77m,
-	mus_map78m,
-	mus_map79m,
-	mus_map80m,
-	mus_map81m,
-	mus_map82m,
-	mus_map83m,
-	mus_map84m,
-	mus_map85m,
-	mus_map86m,
-	mus_map87m,
-	mus_map88m,
-	mus_map89m,
-	mus_map90m,
-	mus_map91m,
-	mus_map92m,
-	mus_map93m,
-	mus_map94m,
-	mus_map95m,
-	mus_map96m,
-	mus_map97m,
-	mus_map98m,
-	mus_map99m,
-	mus_mapa0m,
-	mus_mapa1m,
-	mus_mapa2m,
-	mus_mapa3m,
-	mus_mapa4m,
-	mus_mapa5m,
-	mus_mapa6m,
-	mus_mapa7m,
-	mus_mapa8m,
-	mus_mapa9m,
-	mus_mapaam,
-	mus_mapabm,
-	mus_mapacm,
-	mus_mapadm,
-	mus_mapaem,
-	mus_mapafm,
-	mus_mapagm,
-	mus_mapahm,
-	mus_mapaim,
-	mus_mapajm,
-	mus_mapakm,
-	mus_mapalm,
-	mus_mapamm,
-	mus_mapanm,
-	mus_mapaom,
-	mus_mapapm,
-	mus_mapaqm,
-	mus_maparm,
-	mus_mapasm,
-	mus_mapatm,
-	mus_mapaum,
-	mus_mapavm,
-	mus_mapawm,
-	mus_mapaxm,
-	mus_mapaym,
-	mus_mapazm,
-	mus_mapb0m,
-	mus_mapb1m,
-	mus_mapb2m,
-	mus_mapb3m,
-	mus_mapb4m,
-	mus_mapb5m,
-	mus_mapb6m,
-	mus_mapb7m,
-	mus_mapb8m,
-	mus_mapb9m,
-	mus_mapbam,
-	mus_mapbbm,
-	mus_mapbcm,
-	mus_mapbdm,
-	mus_mapbem,
-	mus_mapbfm,
-	mus_mapbgm,
-	mus_mapbhm,
-	mus_mapbim,
-	mus_mapbjm,
-	mus_mapbkm,
-	mus_mapblm,
-	mus_mapbmm,
-	mus_mapbnm,
-	mus_mapbom,
-	mus_mapbpm,
-	mus_mapbqm,
-	mus_mapbrm,
-	mus_mapbsm,
-	mus_mapbtm,
-	mus_mapbum,
-	mus_mapbvm,
-	mus_mapbwm,
-	mus_mapbxm,
-	mus_mapbym,
-	mus_mapbzm,
-	mus_mapc0m,
-	mus_mapc1m,
-	mus_mapc2m,
-	mus_mapc3m,
-	mus_mapc4m,
-	mus_mapc5m,
-	mus_mapc6m,
-	mus_mapc7m,
-	mus_mapc8m,
-	mus_mapc9m,
-	mus_mapcam,
-	mus_mapcbm,
-	mus_mapccm,
-	mus_mapcdm,
-	mus_mapcem,
-	mus_mapcfm,
-	mus_mapcgm,
-	mus_mapchm,
-	mus_mapcim,
-	mus_mapcjm,
-	mus_mapckm,
-	mus_mapclm,
-	mus_mapcmm,
-	mus_mapcnm,
-	mus_mapcom,
-	mus_mapcpm,
-	mus_mapcqm,
-	mus_mapcrm,
-	mus_mapcsm,
-	mus_mapctm,
-	mus_mapcum,
-	mus_mapcvm,
-	mus_mapcwm,
-	mus_mapcxm,
-	mus_mapcym,
-	mus_mapczm,
-	mus_mapd0m,
-	mus_mapd1m,
-	mus_mapd2m,
-	mus_mapd3m,
-	mus_mapd4m,
-	mus_mapd5m,
-	mus_mapd6m,
-	mus_mapd7m,
-	mus_mapd8m,
-	mus_mapd9m,
-	mus_mapdam,
-	mus_mapdbm,
-	mus_mapdcm,
-	mus_mapddm,
-	mus_mapdem,
-	mus_mapdfm,
-	mus_mapdgm,
-	mus_mapdhm,
-	mus_mapdim,
-	mus_mapdjm,
-	mus_mapdkm,
-	mus_mapdlm,
-	mus_mapdmm,
-	mus_mapdnm,
-	mus_mapdom,
-	mus_mapdpm,
-	mus_mapdqm,
-	mus_mapdrm,
-	mus_mapdsm,
-	mus_mapdtm,
-	mus_mapdum,
-	mus_mapdvm,
-	mus_mapdwm,
-	mus_mapdxm,
-	mus_mapdym,
-	mus_mapdzm,
-	mus_mape0m,
-	mus_mape1m,
-	mus_mape2m,
-	mus_mape3m,
-	mus_mape4m,
-	mus_mape5m,
-	mus_mape6m,
-	mus_mape7m,
-	mus_mape8m,
-	mus_mape9m,
-	mus_mapeam,
-	mus_mapebm,
-	mus_mapecm,
-	mus_mapedm,
-	mus_mapeem,
-	mus_mapefm,
-	mus_mapegm,
-	mus_mapehm,
-	mus_mapeim,
-	mus_mapejm,
-	mus_mapekm,
-	mus_mapelm,
-	mus_mapemm,
-	mus_mapenm,
-	mus_mapeom,
-	mus_mapepm,
-	mus_mapeqm,
-	mus_maperm,
-	mus_mapesm,
-	mus_mapetm,
-	mus_mapeum,
-	mus_mapevm,
-	mus_mapewm,
-	mus_mapexm,
-	mus_mapeym,
-	mus_mapezm,
-	mus_mapf0m,
-	mus_mapf1m,
-	mus_mapf2m,
-	mus_mapf3m,
-	mus_mapf4m,
-	mus_mapf5m,
-	mus_mapf6m,
-	mus_mapf7m,
-	mus_mapf8m,
-	mus_mapf9m,
-	mus_mapfam,
-	mus_mapfbm,
-	mus_mapfcm,
-	mus_mapfdm,
-	mus_mapfem,
-	mus_mapffm,
-	mus_mapfgm,
-	mus_mapfhm,
-	mus_mapfim,
-	mus_mapfjm,
-	mus_mapfkm,
-	mus_mapflm,
-	mus_mapfmm,
-	mus_mapfnm,
-	mus_mapfom,
-	mus_mapfpm,
-	mus_mapfqm,
-	mus_mapfrm,
-	mus_mapfsm,
-	mus_mapftm,
-	mus_mapfum,
-	mus_mapfvm,
-	mus_mapfwm,
-	mus_mapfxm,
-	mus_mapfym,
-	mus_mapfzm,
-	mus_mapg0m,
-	mus_mapg1m,
-	mus_mapg2m,
-	mus_mapg3m,
-	mus_mapg4m,
-	mus_mapg5m,
-	mus_mapg6m,
-	mus_mapg7m,
-	mus_mapg8m,
-	mus_mapg9m,
-	mus_mapgam,
-	mus_mapgbm,
-	mus_mapgcm,
-	mus_mapgdm,
-	mus_mapgem,
-	mus_mapgfm,
-	mus_mapggm,
-	mus_mapghm,
-	mus_mapgim,
-	mus_mapgjm,
-	mus_mapgkm,
-	mus_mapglm,
-	mus_mapgmm,
-	mus_mapgnm,
-	mus_mapgom,
-	mus_mapgpm,
-	mus_mapgqm,
-	mus_mapgrm,
-	mus_mapgsm,
-	mus_mapgtm,
-	mus_mapgum,
-	mus_mapgvm,
-	mus_mapgwm,
-	mus_mapgxm,
-	mus_mapgym,
-	mus_mapgzm,
-	mus_maph0m,
-	mus_maph1m,
-	mus_maph2m,
-	mus_maph3m,
-	mus_maph4m,
-	mus_maph5m,
-	mus_maph6m,
-	mus_maph7m,
-	mus_maph8m,
-	mus_maph9m,
-	mus_mapham,
-	mus_maphbm,
-	mus_maphcm,
-	mus_maphdm,
-	mus_maphem,
-	mus_maphfm,
-	mus_maphgm,
-	mus_maphhm,
-	mus_maphim,
-	mus_maphjm,
-	mus_maphkm,
-	mus_maphlm,
-	mus_maphmm,
-	mus_maphnm,
-	mus_maphom,
-	mus_maphpm,
-	mus_maphqm,
-	mus_maphrm,
-	mus_maphsm,
-	mus_maphtm,
-	mus_maphum,
-	mus_maphvm,
-	mus_maphwm,
-	mus_maphxm,
-	mus_maphym,
-	mus_maphzm,
-	mus_mapi0m,
-	mus_mapi1m,
-	mus_mapi2m,
-	mus_mapi3m,
-	mus_mapi4m,
-	mus_mapi5m,
-	mus_mapi6m,
-	mus_mapi7m,
-	mus_mapi8m,
-	mus_mapi9m,
-	mus_mapiam,
-	mus_mapibm,
-	mus_mapicm,
-	mus_mapidm,
-	mus_mapiem,
-	mus_mapifm,
-	mus_mapigm,
-	mus_mapihm,
-	mus_mapiim,
-	mus_mapijm,
-	mus_mapikm,
-	mus_mapilm,
-	mus_mapimm,
-	mus_mapinm,
-	mus_mapiom,
-	mus_mapipm,
-	mus_mapiqm,
-	mus_mapirm,
-	mus_mapism,
-	mus_mapitm,
-	mus_mapium,
-	mus_mapivm,
-	mus_mapiwm,
-	mus_mapixm,
-	mus_mapiym,
-	mus_mapizm,
-	mus_mapj0m,
-	mus_mapj1m,
-	mus_mapj2m,
-	mus_mapj3m,
-	mus_mapj4m,
-	mus_mapj5m,
-	mus_mapj6m,
-	mus_mapj7m,
-	mus_mapj8m,
-	mus_mapj9m,
-	mus_mapjam,
-	mus_mapjbm,
-	mus_mapjcm,
-	mus_mapjdm,
-	mus_mapjem,
-	mus_mapjfm,
-	mus_mapjgm,
-	mus_mapjhm,
-	mus_mapjim,
-	mus_mapjjm,
-	mus_mapjkm,
-	mus_mapjlm,
-	mus_mapjmm,
-	mus_mapjnm,
-	mus_mapjom,
-	mus_mapjpm,
-	mus_mapjqm,
-	mus_mapjrm,
-	mus_mapjsm,
-	mus_mapjtm,
-	mus_mapjum,
-	mus_mapjvm,
-	mus_mapjwm,
-	mus_mapjxm,
-	mus_mapjym,
-	mus_mapjzm,
-	mus_mapk0m,
-	mus_mapk1m,
-	mus_mapk2m,
-	mus_mapk3m,
-	mus_mapk4m,
-	mus_mapk5m,
-	mus_mapk6m,
-	mus_mapk7m,
-	mus_mapk8m,
-	mus_mapk9m,
-	mus_mapkam,
-	mus_mapkbm,
-	mus_mapkcm,
-	mus_mapkdm,
-	mus_mapkem,
-	mus_mapkfm,
-	mus_mapkgm,
-	mus_mapkhm,
-	mus_mapkim,
-	mus_mapkjm,
-	mus_mapkkm,
-	mus_mapklm,
-	mus_mapkmm,
-	mus_mapknm,
-	mus_mapkom,
-	mus_mapkpm,
-	mus_mapkqm,
-	mus_mapkrm,
-	mus_mapksm,
-	mus_mapktm,
-	mus_mapkum,
-	mus_mapkvm,
-	mus_mapkwm,
-	mus_mapkxm,
-	mus_mapkym,
-	mus_mapkzm,
-	mus_mapl0m,
-	mus_mapl1m,
-	mus_mapl2m,
-	mus_mapl3m,
-	mus_mapl4m,
-	mus_mapl5m,
-	mus_mapl6m,
-	mus_mapl7m,
-	mus_mapl8m,
-	mus_mapl9m,
-	mus_maplam,
-	mus_maplbm,
-	mus_maplcm,
-	mus_mapldm,
-	mus_maplem,
-	mus_maplfm,
-	mus_maplgm,
-	mus_maplhm,
-	mus_maplim,
-	mus_mapljm,
-	mus_maplkm,
-	mus_mapllm,
-	mus_maplmm,
-	mus_maplnm,
-	mus_maplom,
-	mus_maplpm,
-	mus_maplqm,
-	mus_maplrm,
-	mus_maplsm,
-	mus_mapltm,
-	mus_maplum,
-	mus_maplvm,
-	mus_maplwm,
-	mus_maplxm,
-	mus_maplym,
-	mus_maplzm,
-	mus_mapm0m,
-	mus_mapm1m,
-	mus_mapm2m,
-	mus_mapm3m,
-	mus_mapm4m,
-	mus_mapm5m,
-	mus_mapm6m,
-	mus_mapm7m,
-	mus_mapm8m,
-	mus_mapm9m,
-	mus_mapmam,
-	mus_mapmbm,
-	mus_mapmcm,
-	mus_mapmdm,
-	mus_mapmem,
-	mus_mapmfm,
-	mus_mapmgm,
-	mus_mapmhm,
-	mus_mapmim,
-	mus_mapmjm,
-	mus_mapmkm,
-	mus_mapmlm,
-	mus_mapmmm,
-	mus_mapmnm,
-	mus_mapmom,
-	mus_mapmpm,
-	mus_mapmqm,
-	mus_mapmrm,
-	mus_mapmsm,
-	mus_mapmtm,
-	mus_mapmum,
-	mus_mapmvm,
-	mus_mapmwm,
-	mus_mapmxm,
-	mus_mapmym,
-	mus_mapmzm,
-	mus_mapn0m,
-	mus_mapn1m,
-	mus_mapn2m,
-	mus_mapn3m,
-	mus_mapn4m,
-	mus_mapn5m,
-	mus_mapn6m,
-	mus_mapn7m,
-	mus_mapn8m,
-	mus_mapn9m,
-	mus_mapnam,
-	mus_mapnbm,
-	mus_mapncm,
-	mus_mapndm,
-	mus_mapnem,
-	mus_mapnfm,
-	mus_mapngm,
-	mus_mapnhm,
-	mus_mapnim,
-	mus_mapnjm,
-	mus_mapnkm,
-	mus_mapnlm,
-	mus_mapnmm,
-	mus_mapnnm,
-	mus_mapnom,
-	mus_mapnpm,
-	mus_mapnqm,
-	mus_mapnrm,
-	mus_mapnsm,
-	mus_mapntm,
-	mus_mapnum,
-	mus_mapnvm,
-	mus_mapnwm,
-	mus_mapnxm,
-	mus_mapnym,
-	mus_mapnzm,
-	mus_mapo0m,
-	mus_mapo1m,
-	mus_mapo2m,
-	mus_mapo3m,
-	mus_mapo4m,
-	mus_mapo5m,
-	mus_mapo6m,
-	mus_mapo7m,
-	mus_mapo8m,
-	mus_mapo9m,
-	mus_mapoam,
-	mus_mapobm,
-	mus_mapocm,
-	mus_mapodm,
-	mus_mapoem,
-	mus_mapofm,
-	mus_mapogm,
-	mus_mapohm,
-	mus_mapoim,
-	mus_mapojm,
-	mus_mapokm,
-	mus_mapolm,
-	mus_mapomm,
-	mus_maponm,
-	mus_mapoom,
-	mus_mapopm,
-	mus_mapoqm,
-	mus_maporm,
-	mus_maposm,
-	mus_mapotm,
-	mus_mapoum,
-	mus_mapovm,
-	mus_mapowm,
-	mus_mapoxm,
-	mus_mapoym,
-	mus_mapozm,
-	mus_mapp0m,
-	mus_mapp1m,
-	mus_mapp2m,
-	mus_mapp3m,
-	mus_mapp4m,
-	mus_mapp5m,
-	mus_mapp6m,
-	mus_mapp7m,
-	mus_mapp8m,
-	mus_mapp9m,
-	mus_mappam,
-	mus_mappbm,
-	mus_mappcm,
-	mus_mappdm,
-	mus_mappem,
-	mus_mappfm,
-	mus_mappgm,
-	mus_mapphm,
-	mus_mappim,
-	mus_mappjm,
-	mus_mappkm,
-	mus_mapplm,
-	mus_mappmm,
-	mus_mappnm,
-	mus_mappom,
-	mus_mapppm,
-	mus_mappqm,
-	mus_mapprm,
-	mus_mappsm,
-	mus_mapptm,
-	mus_mappum,
-	mus_mappvm,
-	mus_mappwm,
-	mus_mappxm,
-	mus_mappym,
-	mus_mappzm,
-	mus_mapq0m,
-	mus_mapq1m,
-	mus_mapq2m,
-	mus_mapq3m,
-	mus_mapq4m,
-	mus_mapq5m,
-	mus_mapq6m,
-	mus_mapq7m,
-	mus_mapq8m,
-	mus_mapq9m,
-	mus_mapqam,
-	mus_mapqbm,
-	mus_mapqcm,
-	mus_mapqdm,
-	mus_mapqem,
-	mus_mapqfm,
-	mus_mapqgm,
-	mus_mapqhm,
-	mus_mapqim,
-	mus_mapqjm,
-	mus_mapqkm,
-	mus_mapqlm,
-	mus_mapqmm,
-	mus_mapqnm,
-	mus_mapqom,
-	mus_mapqpm,
-	mus_mapqqm,
-	mus_mapqrm,
-	mus_mapqsm,
-	mus_mapqtm,
-	mus_mapqum,
-	mus_mapqvm,
-	mus_mapqwm,
-	mus_mapqxm,
-	mus_mapqym,
-	mus_mapqzm,
-	mus_mapr0m,
-	mus_mapr1m,
-	mus_mapr2m,
-	mus_mapr3m,
-	mus_mapr4m,
-	mus_mapr5m,
-	mus_mapr6m,
-	mus_mapr7m,
-	mus_mapr8m,
-	mus_mapr9m,
-	mus_mapram,
-	mus_maprbm,
-	mus_maprcm,
-	mus_maprdm,
-	mus_maprem,
-	mus_maprfm,
-	mus_maprgm,
-	mus_maprhm,
-	mus_maprim,
-	mus_maprjm,
-	mus_maprkm,
-	mus_maprlm,
-	mus_maprmm,
-	mus_maprnm,
-	mus_maprom,
-	mus_maprpm,
-	mus_maprqm,
-	mus_maprrm,
-	mus_maprsm,
-	mus_maprtm,
-	mus_maprum,
-	mus_maprvm,
-	mus_maprwm,
-	mus_maprxm,
-	mus_maprym,
-	mus_maprzm,
-	mus_maps0m,
-	mus_maps1m,
-	mus_maps2m,
-	mus_maps3m,
-	mus_maps4m,
-	mus_maps5m,
-	mus_maps6m,
-	mus_maps7m,
-	mus_maps8m,
-	mus_maps9m,
-	mus_mapsam,
-	mus_mapsbm,
-	mus_mapscm,
-	mus_mapsdm,
-	mus_mapsem,
-	mus_mapsfm,
-	mus_mapsgm,
-	mus_mapshm,
-	mus_mapsim,
-	mus_mapsjm,
-	mus_mapskm,
-	mus_mapslm,
-	mus_mapsmm,
-	mus_mapsnm,
-	mus_mapsom,
-	mus_mapspm,
-	mus_mapsqm,
-	mus_mapsrm,
-	mus_mapssm,
-	mus_mapstm,
-	mus_mapsum,
-	mus_mapsvm,
-	mus_mapswm,
-	mus_mapsxm,
-	mus_mapsym,
-	mus_mapszm,
-	mus_mapt0m,
-	mus_mapt1m,
-	mus_mapt2m,
-	mus_mapt3m,
-	mus_mapt4m,
-	mus_mapt5m,
-	mus_mapt6m,
-	mus_mapt7m,
-	mus_mapt8m,
-	mus_mapt9m,
-	mus_maptam,
-	mus_maptbm,
-	mus_maptcm,
-	mus_maptdm,
-	mus_maptem,
-	mus_maptfm,
-	mus_maptgm,
-	mus_mapthm,
-	mus_maptim,
-	mus_maptjm,
-	mus_maptkm,
-	mus_maptlm,
-	mus_maptmm,
-	mus_maptnm,
-	mus_maptom,
-	mus_maptpm,
-	mus_maptqm,
-	mus_maptrm,
-	mus_maptsm,
-	mus_mapttm,
-	mus_maptum,
-	mus_maptvm,
-	mus_maptwm,
-	mus_maptxm,
-	mus_maptym,
-	mus_maptzm,
-	mus_mapu0m,
-	mus_mapu1m,
-	mus_mapu2m,
-	mus_mapu3m,
-	mus_mapu4m,
-	mus_mapu5m,
-	mus_mapu6m,
-	mus_mapu7m,
-	mus_mapu8m,
-	mus_mapu9m,
-	mus_mapuam,
-	mus_mapubm,
-	mus_mapucm,
-	mus_mapudm,
-	mus_mapuem,
-	mus_mapufm,
-	mus_mapugm,
-	mus_mapuhm,
-	mus_mapuim,
-	mus_mapujm,
-	mus_mapukm,
-	mus_mapulm,
-	mus_mapumm,
-	mus_mapunm,
-	mus_mapuom,
-	mus_mapupm,
-	mus_mapuqm,
-	mus_mapurm,
-	mus_mapusm,
-	mus_maputm,
-	mus_mapuum,
-	mus_mapuvm,
-	mus_mapuwm,
-	mus_mapuxm,
-	mus_mapuym,
-	mus_mapuzm,
-	mus_mapv0m,
-	mus_mapv1m,
-	mus_mapv2m,
-	mus_mapv3m,
-	mus_mapv4m,
-	mus_mapv5m,
-	mus_mapv6m,
-	mus_mapv7m,
-	mus_mapv8m,
-	mus_mapv9m,
-	mus_mapvam,
-	mus_mapvbm,
-	mus_mapvcm,
-	mus_mapvdm,
-	mus_mapvem,
-	mus_mapvfm,
-	mus_mapvgm,
-	mus_mapvhm,
-	mus_mapvim,
-	mus_mapvjm,
-	mus_mapvkm,
-	mus_mapvlm,
-	mus_mapvmm,
-	mus_mapvnm,
-	mus_mapvom,
-	mus_mapvpm,
-	mus_mapvqm,
-	mus_mapvrm,
-	mus_mapvsm,
-	mus_mapvtm,
-	mus_mapvum,
-	mus_mapvvm,
-	mus_mapvwm,
-	mus_mapvxm,
-	mus_mapvym,
-	mus_mapvzm,
-	mus_mapw0m,
-	mus_mapw1m,
-	mus_mapw2m,
-	mus_mapw3m,
-	mus_mapw4m,
-	mus_mapw5m,
-	mus_mapw6m,
-	mus_mapw7m,
-	mus_mapw8m,
-	mus_mapw9m,
-	mus_mapwam,
-	mus_mapwbm,
-	mus_mapwcm,
-	mus_mapwdm,
-	mus_mapwem,
-	mus_mapwfm,
-	mus_mapwgm,
-	mus_mapwhm,
-	mus_mapwim,
-	mus_mapwjm,
-	mus_mapwkm,
-	mus_mapwlm,
-	mus_mapwmm,
-	mus_mapwnm,
-	mus_mapwom,
-	mus_mapwpm,
-	mus_mapwqm,
-	mus_mapwrm,
-	mus_mapwsm,
-	mus_mapwtm,
-	mus_mapwum,
-	mus_mapwvm,
-	mus_mapwwm,
-	mus_mapwxm,
-	mus_mapwym,
-	mus_mapwzm,
-	mus_mapx0m,
-	mus_mapx1m,
-	mus_mapx2m,
-	mus_mapx3m,
-	mus_mapx4m,
-	mus_mapx5m,
-	mus_mapx6m,
-	mus_mapx7m,
-	mus_mapx8m,
-	mus_mapx9m,
-	mus_mapxam,
-	mus_mapxbm,
-	mus_mapxcm,
-	mus_mapxdm,
-	mus_mapxem,
-	mus_mapxfm,
-	mus_mapxgm,
-	mus_mapxhm,
-	mus_mapxim,
-	mus_mapxjm,
-	mus_mapxkm,
-	mus_mapxlm,
-	mus_mapxmm,
-	mus_mapxnm,
-	mus_mapxom,
-	mus_mapxpm,
-	mus_mapxqm,
-	mus_mapxrm,
-	mus_mapxsm,
-	mus_mapxtm,
-	mus_mapxum,
-	mus_mapxvm,
-	mus_mapxwm,
-	mus_mapxxm,
-	mus_mapxym,
-	mus_mapxzm,
-	mus_mapy0m,
-	mus_mapy1m,
-	mus_mapy2m,
-	mus_mapy3m,
-	mus_mapy4m,
-	mus_mapy5m,
-	mus_mapy6m,
-	mus_mapy7m,
-	mus_mapy8m,
-	mus_mapy9m,
-	mus_mapyam,
-	mus_mapybm,
-	mus_mapycm,
-	mus_mapydm,
-	mus_mapyem,
-	mus_mapyfm,
-	mus_mapygm,
-	mus_mapyhm,
-	mus_mapyim,
-	mus_mapyjm,
-	mus_mapykm,
-	mus_mapylm,
-	mus_mapymm,
-	mus_mapynm,
-	mus_mapyom,
-	mus_mapypm,
-	mus_mapyqm,
-	mus_mapyrm,
-	mus_mapysm,
-	mus_mapytm,
-	mus_mapyum,
-	mus_mapyvm,
-	mus_mapywm,
-	mus_mapyxm,
-	mus_mapyym,
-	mus_mapyzm,
-	mus_mapz0m,
-	mus_mapz1m,
-	mus_mapz2m,
-	mus_mapz3m,
-	mus_mapz4m,
-	mus_mapz5m,
-	mus_mapz6m,
-	mus_mapz7m,
-	mus_mapz8m,
-	mus_mapz9m,
-	mus_mapzam,
-	mus_mapzbm,
-	mus_mapzcm,
-	mus_mapzdm,
-	mus_mapzem,
-	mus_mapzfm,
-	mus_mapzgm,
-	mus_mapzhm,
-	mus_mapzim,
-	mus_mapzjm,
-	mus_mapzkm,
-	mus_mapzlm,
-	mus_mapzmm,
-	mus_mapznm,
-	mus_mapzom,
-	mus_mapzpm,
-	mus_mapzqm,
-	mus_mapzrm,
-	mus_mapzsm,
-	mus_mapztm,
-	mus_mapzum,
-	mus_mapzvm,
-	mus_mapzwm,
-	mus_mapzxm,
-	mus_mapzym,
-	mus_mapzzm,
-
-	mus_titles, // title screen
-	mus_read_m, // intro
-	mus_lclear, // level clear
-	mus_invinc, // invincibility
-	mus_shoes,  // super sneakers
-	mus_minvnc, // Mario invincibility
-	mus_drown,  // drowning
-	mus_gmover, // game over
-	mus_xtlife, // extra life
-	mus_contsc, // continue screen
-	mus_supers, // Super Sonic
-	mus_chrsel, // character select
-	mus_credit, // credits
-	mus_racent, // Race Results
-	mus_stjr,   // Sonic Team Jr. Presents
-
-	NUMMUSIC
-} musicenum_t;
-// Note: song number should be a UINT16, as mapmusic only uses 16 bits for music slot number.
-//       (the rest is track number and an internal reload flag)
-
 //
 // Identifiers for all sfx in game.
 //
diff --git a/src/string.c b/src/string.c
index 436757309d96845a8e516e95326132261031fc25..19540547c937bf49b1f8eb755f14f9a87830322d 100644
--- a/src/string.c
+++ b/src/string.c
@@ -15,6 +15,8 @@
 #include <string.h>
 #include "doomdef.h"
 
+#if !defined (__APPLE__)
+
 // Like the OpenBSD version, but it doesn't check for src not being a valid
 // C string.
 size_t strlcat(char *dst, const char *src, size_t siz)
@@ -46,3 +48,5 @@ size_t strlcpy(char *dst, const char *src, size_t siz)
 	dst[0] = '\0';
 	return strlcat(dst, src, siz);
 }
+
+#endif
diff --git a/src/w_wad.c b/src/w_wad.c
index 9d6a11fb5c9f863def81c261a5893aa4aded98a8..132df8fcb838d97e0ad56e29ee19c269c5932459 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -32,6 +32,7 @@
 
 #include "w_wad.h"
 #include "z_zone.h"
+#include "fastcmp.h"
 
 #include "i_video.h" // rendermode
 #include "d_netfil.h"
@@ -147,24 +148,32 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum)
 	}
 #endif
 
-	// Check for MAINCFG
-	for (lump = 0;lump != INT16_MAX;lump++)
-	{
-		lump = W_CheckNumForNamePwad("MAINCFG", wadnum, lump);
-		if (lump == INT16_MAX)
-			break;
-		CONS_Printf(M_GetText("Loading main config from %s\n"), wadfiles[wadnum]->filename);
-		DEH_LoadDehackedLumpPwad(wadnum, lump);
-	}
-
-	// Check for OBJCTCFG
-	for (lump = 0;lump < INT16_MAX;lump++)
 	{
-		lump = W_CheckNumForNamePwad("OBJCTCFG", wadnum, lump);
-		if (lump == INT16_MAX)
-			break;
-		CONS_Printf(M_GetText("Loading object config from %s\n"), wadfiles[wadnum]->filename);
-		DEH_LoadDehackedLumpPwad(wadnum, lump);
+		lumpinfo_t *lump_p = wadfiles[wadnum]->lumpinfo;
+		for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++)
+			if (memcmp(lump_p->name,"SOC_",4)==0) // Check for generic SOC lump
+			{	// shameless copy+paste of code from LUA_LoadLump
+				char *name = malloc(strlen(wadfiles[wadnum]->filename)+10);
+				strcpy(name, wadfiles[wadnum]->filename);
+				if (!fasticmp(&name[strlen(name) - 4], ".soc")) {
+					// If it's not a .soc file, copy the lump name in too.
+					name[strlen(wadfiles[wadnum]->filename)] = '|';
+					M_Memcpy(name+strlen(wadfiles[wadnum]->filename)+1, lump_p->name, 8);
+					name[strlen(wadfiles[wadnum]->filename)+9] = '\0';
+				}
+				CONS_Printf(M_GetText("Loading SOC from %s\n"), name);
+				DEH_LoadDehackedLumpPwad(wadnum, lump);
+			}
+			else if (memcmp(lump_p->name,"MAINCFG",8)==0) // Check for MAINCFG
+			{
+				CONS_Printf(M_GetText("Loading main config from %s\n"), wadfiles[wadnum]->filename);
+				DEH_LoadDehackedLumpPwad(wadnum, lump);
+			}
+			else if (memcmp(lump_p->name,"OBJCTCFG",8)==0) // Check for OBJCTCFG
+			{
+				CONS_Printf(M_GetText("Loading object config from %s\n"), wadfiles[wadnum]->filename);
+				DEH_LoadDehackedLumpPwad(wadnum, lump);
+			}
 	}
 
 #ifdef SCANTHINGS
diff --git a/src/y_inter.c b/src/y_inter.c
index 2f2edf7ca71eef368671f501c88db3e745f52959..104c1004daa0243243601392ff0296de1bb7a3bb 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -632,7 +632,7 @@ void Y_Ticker(void)
 		boolean anybonuses = false;
 
 		if (!intertic) // first time only
-			S_ChangeMusic(mus_lclear, false); // don't loop it
+			S_ChangeMusicInternal("lclear", false); // don't loop it
 
 		if (intertic < TICRATE) // one second pause before tally begins
 			return;
@@ -693,7 +693,7 @@ void Y_Ticker(void)
 
 		if (!intertic) // first time only
 		{
-			S_ChangeMusic(mus_lclear, false); // don't loop it
+			S_ChangeMusicInternal("lclear", false); // don't loop it
 			tallydonetic = 0;
 		}
 
@@ -754,7 +754,7 @@ void Y_Ticker(void)
 	else if (intertype == int_match || intertype == int_ctf || intertype == int_teammatch) // match
 	{
 		if (!intertic) // first time only
-			S_ChangeMusic(mus_racent, true); // loop it
+			S_ChangeMusicInternal("racent", true); // loop it
 
 		// If a player has left or joined, recalculate scores.
 		if (data.match.numplayers != D_NumPlayers())
@@ -763,7 +763,7 @@ void Y_Ticker(void)
 	else if (intertype == int_race || intertype == int_classicrace) // race
 	{
 		if (!intertic) // first time only
-			S_ChangeMusic(mus_racent, true); // loop it
+			S_ChangeMusicInternal("racent", true); // loop it
 
 		// Don't bother recalcing for race. It doesn't make as much sense.
 	}