diff --git a/extras/conf/Includes/Game_SRB222.cfg b/extras/conf/Includes/Game_SRB222.cfg
deleted file mode 100644
index 3c4b11e9f301f90b68a5ee90c366416048946b73..0000000000000000000000000000000000000000
--- a/extras/conf/Includes/Game_SRB222.cfg
+++ /dev/null
@@ -1,77 +0,0 @@
-// Default lump name for new map
-defaultlumpname = "MAP01";
-//GZDB specific. Don't try to load lumps that don't exist.
-basegame = 0;
-
-//Sky textures for vanilla maps
-defaultskytextures
-{
-	SKY1 = "MAP01,MAP02,MAP03,MAP33,MAP50,MAP60,MAPF0,MAPM0";
-	SKY2 = "MAPM7,MAPMB";
-	SKY4 = "MAP04,MAP06,MAP61,MAPF6,MAPM1";
-	SKY6 = "MAP05,MAP51,MAPMA";
-	SKY7 = "MAPM2,MAPM5";
-	SKY8 = "MAP07,MAP08,MAP09,MAP52,MAP62,MAPF1";
-	SKY10 = "MAP10,MAP12,MAP53,MAP63,MAPM3";
-	SKY11 = "MAP11,MAPF7";
-	SKY13 = "MAP13,MAP64";
-	SKY14 = "MAP14";
-	SKY15 = "MAP15,MAP54";
-	SKY17 = "MAP70";
-	SKY20 = "MAP32,MAP55,MAP65,MAPF2,MAPF5";
-	SKY21 = "MAPM4";
-	SKY22 = "MAP22,MAP23,MAP25,MAP26,MAP27,MAP56,MAP66,MAPF4,MAPM6";
-	SKY30 = "MAP30";
-	SKY31 = "MAP31";
-	SKY35 = "MAP42";
-	SKY40 = "MAP41,MAP71,MAPM9";
-	SKY55 = "MAPF3,MAPM8";
-	SKY68 = "MAPF8";
-	SKY99 = "MAP57,MAPZ0";
-	SKY159 = "MAP16";
-	SKY172 = "MAP40";
-	SKY300 = "MAP72";
-	SKY301 = "MAP73";
-}
-
-// Skill levels
-skills
-{
-	1 = "Normal";
-}
-
-// Skins
-skins
-{
-	Sonic;
-	Tails;
-	Knuckles;
-	Amy;
-	Fang;
-	Metalsonic;
-}
-
-// Gametypes
-gametypes
-{
-	-1 = "Single Player";
-	0 = "Co-op";
-	1 = "Competition";
-	2 = "Race";
-	3 = "Match";
-	4 = "Team Match";
-	5 = "Tag";
-	6 = "Hide and Seek";
-	7 = "CTF";
-}
-
-// Texture loading options
-defaultwalltexture = "GFZROCK";
-defaultfloortexture = "GFZFLR01";
-defaultceilingtexture = "F_SKY1";
-
-// Default texture sets
-// (these are not required, but useful for new users)
-texturesets
-{
-}
\ No newline at end of file
diff --git a/extras/conf/Includes/SRB222_common.cfg b/extras/conf/Includes/SRB222_common.cfg
deleted file mode 100644
index a832e6cefe6c2ba1580cbd48083bcf1c2702da81..0000000000000000000000000000000000000000
--- a/extras/conf/Includes/SRB222_common.cfg
+++ /dev/null
@@ -1,309 +0,0 @@
-common
-{
-	// Some common settings
-
-
-
-	// Default testing parameters
-	testparameters = "-file \"%AP\" \"%F\" -warp %L";
-	testshortpaths = true;
-
-	// Action special help (mxd)
-	actionspecialhelp = "https://wiki.srb2.org/wiki/Linedef_type_%K";
-
-	// Default nodebuilder configurations
-	defaultsavecompiler = "zennode_normal";
-	defaulttestcompiler = "zennode_fast";
-
-	// Generalized actions
-	generalizedlinedefs = false;
-	generalizedsectors = true;
-
-	mixtexturesflats = true;
-	defaulttexturescale = 1.0f;
-	defaultflatscale = 1.0f;
-	scaledtextureoffsets = true;
-
-	// Thing number for start position in 3D Mode
-	start3dmode = 3328;
-
-	// Texture sources
-	textures
-	{
-		include("SRB222_misc.cfg", "textures");
-	}
-
-	// Patch sources
-	patches
-	{
-		include("SRB222_misc.cfg", "patches");
-	}
-
-	// Sprite sources
-	sprites
-	{
-		include("SRB222_misc.cfg", "sprites");
-	}
-
-	// Flat sources
-	flats
-	{
-		include("SRB222_misc.cfg", "flats");
-	}
-}
-
-mapformat_doom
-{
-	// The format interface handles the map data format - DoomMapSetIO for SRB2DB2, SRB2MapSetIO for Zone Builder
-	formatinterface = "SRB2MapSetIO";
-
-	/*
-	GAME DETECT PATTERN
-	Used to guess the game for which a WAD file is made.
-
-	1 = One of these lumps must exist
-	2 = None of these lumps must exist
-	3 = All of these lumps must exist
-	*/
-
-	gamedetect
-	{
-		EXTENDED = 2;
-
-
-		BEHAVIOR = 2;
-
-		E#M# = 2;
-
-		MAP?? = 1;
-	}
-
-	/*
-	MAP LUMP NAMES
-	Map lumps are loaded with the map as long as they are right after each other. When the editor
-	meets a lump which is not defined in this list it will ignore the map if not satisfied.
-	The order of items defines the order in which lumps will be written to WAD file on save.
-	To indicate the map header lump, use ~MAP
-
-	Legenda:
-	required = Lump is required to exist.
-	blindcopy = Lump will be copied along with the map blindly. (usefull for lumps Doom Builder doesn't use)
-	nodebuild = The nodebuilder generates this lump.
-	allowempty = The nodebuilder is allowed to leave this lump empty.
-	script = This lump is a text-based script. Specify the filename of the script configuration to use.
-	*/
-
-	maplumpnames
-	{
-		include("SRB222_misc.cfg", "doommaplumpnames");
-	}
-
-	// When this is set to true, sectors with the same tag will light up when a line is highlighted
-	linetagindicatesectors = true;
-
-	// Special linedefs
-	include("SRB222_misc.cfg", "speciallinedefs");
-
-	// Default flags for first new thing (As far as 2.2 goes, they're empty just like in 2.1)
-	defaultthingflags
-	{
-	}
-
-	// DEFAULT SECTOR BRIGHTNESS LEVELS
-	sectorbrightness
-	{
-		include("SRB222_misc.cfg", "sectorbrightness");
-	}
-
-	// SECTOR TYPES-----------------------------------------------------------------
-	sectortypes
-	{
-		include("SRB222_sectors.cfg", "sectortypes");
-	}
-
-	// GENERALISED SECTOR TYPES-----------------------------------------------------------------
-	gen_sectortypes
-	{
-		include("SRB222_sectors.cfg", "gen_sectortypes");
-	}
-
-	// LINEDEF FLAGS
-	linedefflags
-	{
-		include("SRB222_misc.cfg", "linedefflags");
-	}
-
-	// Linedef flags UDMF translation table
-	// This is needed for copy/paste and prefabs to work properly
-	// When the UDMF field name is prefixed with ! it is inverted
-	linedefflagstranslation
-	{
-		include("SRB222_misc.cfg", "linedefflagstranslation");
-	}
-
-	// LINEDEF ACTIVATIONS
-	linedefactivations
-	{
-	}
-
-	// LINEDEF TYPES
-	linedeftypes
-	{
-		include("SRB222_linedefs.cfg", "doom");
-	}
-
-	// THING FLAGS
-	thingflags
-	{
-		include("SRB222_misc.cfg", "thingflags");
-	}
-
-	// Thing flags UDMF translation table
-	// This is needed for copy/paste and prefabs to work properly
-	// When the UDMF field name is prefixed with ! it is inverted
-	thingflagstranslation
-	{
-		include("SRB222_misc.cfg", "thingflagstranslation");
-	}
-
-	// THING FLAGS ERROR MASK
-	// Mask for the thing flags which indicates the options
-	// that make the same thing appear in the same modes
-	thingflagsmask1 = 7;	// 1 + 2 + 4
-	thingflagsmask2 = 0;
-}
-
-mapformat_udmf
-{
-	// The format interface handles the map data format
-	formatinterface = "UniversalMapSetIO";
-
-	// Enables support for long (> 8 chars) texture names
-	// WARNING: this should only be enabled for UDMF game configurations!
-	// WARNING: enabling this will make maps incompatible with Doom Builder 2 and can lead to problems in Slade 3!
-	longtexturenames = false;
-
-	// Default nodebuilder configurations
-	defaultsavecompiler = "zdbsp_udmf_normal";
-	defaulttestcompiler = "zdbsp_udmf_fast";
-
-	engine = "srb2"; // override that so that DB2 uses the correct namespace
-
-	maplumpnames
-	{
-		include("UDMF_misc.cfg", "udmfmaplumpnames_begin");
-		include("SRB222_misc.cfg", "udmfmaplumpnames");
-		include("UDMF_misc.cfg", "udmfmaplumpnames_end");
-	}
-
-	universalfields
-	{
-//		include("SRB222_misc.cfg", "universalfields");
-	}
-
-	// When this is set to true, sectors with the same tag will light up when a line is highlighted
-	linetagindicatesectors = false;
-
-	// Special linedefs
-	include("SRB222_misc.cfg", "speciallinedefs_udmf");
-
-	// Default flags for first new thing (As far as 2.2 goes, they're empty just like in 2.1)
-	defaultthingflags
-	{
-	}
-
-	// Generalized actions
-	generalizedlinedefs = false;
-
-	// SECTOR FLAGS
-	sectorflags
-	{
-//		include("SRB222_misc.cfg", "sectorflags");
-	}
-
-	// DEFAULT SECTOR BRIGHTNESS LEVELS
-	sectorbrightness
-	{
-		include("SRB222_misc.cfg", "sectorbrightness");
-	}
-
-	// SECTOR TYPES
-	sectortypes
-	{
-		include("SRB222_sectors.cfg", "sectortypes");
-	}
-
-	// SECTOR RENSERSTYLES
-/*	sectorrenderstyles
-	{
-		include("SRB222_misc.cfg", "sectorrenderstyles");
-	}*/
-
-	// LINEDEF FLAGS
-	linedefflags
-	{
-		include("SRB222_misc.cfg", "linedefflags_udmf");
-	}
-
-	// LINEDEF ACTIVATIONS
-	linedefactivations
-	{
-		include("SRB222_misc.cfg", "linedefactivations_udmf");
-	}
-
-	linedefflagstranslation
-	{
-	}
-
-
-	// LINEDEF RENSERSTYLES
-	linedefrenderstyles
-	{
-		include("SRB222_misc.cfg", "linedefrenderstyles");
-	}
-
-	//SIDEDEF FLAGS
-/*	sidedefflags
-	{
-		include("UDMF_misc.cfg", "sidedefflags");
-	}*/
-
-	// THING FLAGS
-	thingflags
-	{
-		include("SRB222_misc.cfg", "thingflags_udmf");
-	}
-
-	// Thing flags UDMF translation table
-	// This is needed for copy/paste and prefabs to work properly
-	// When the UDMF field name is prefixed with ! it is inverted
-	thingflagstranslation
-	{
-		include("SRB222_misc.cfg", "thingflagstranslation");
-	}
-
-	// THING RENSERSTYLES
-/*	thingrenderstyles
-	{
-		include("SRB222_misc.cfg", "thingrenderstyles");
-	}*/
-
-	// How to compare thing flags (for the stuck things error checker)
-/*	thingflagscompare
-	{
-		include("UDMF_misc.cfg", "thingflagscompare");
-	}*/
-
-	//mxd. Thing flags UDMF translation table
-	// This is needed for copy/paste and prefabs to work properly
-	// When the UDMF field name is prefixed with ! it is inverted
-	thingflagstranslation
-	{
-	}
-
-	// LINEDEF TYPES
-	linedeftypes
-	{
-		include("SRB222_linedefs.cfg", "udmf");
-	}
-}
\ No newline at end of file
diff --git a/extras/conf/Includes/SRB222_linedefs.cfg b/extras/conf/Includes/SRB222_linedefs.cfg
deleted file mode 100644
index fdf1918502a582abebe398e2ecb7bc8c98db442e..0000000000000000000000000000000000000000
--- a/extras/conf/Includes/SRB222_linedefs.cfg
+++ /dev/null
@@ -1,2486 +0,0 @@
-doom
-{
-	misc
-	{
-		title = "Miscellaneous";
-
-		0
-		{
-			title = "None";
-			prefix = "(0)";
-		}
-
-		1
-		{
-			title = "Per-Sector Gravity";
-			prefix = "(1)";
-			flags64text = "[6] Flip in reverse gravity";
-		}
-
-		5
-		{
-			title = "Camera Scanner";
-			prefix = "(5)";
-		}
-
-		7
-		{
-			title = "Sector Flat Alignment";
-			prefix = "(7)";
-			flags2048text = "[11] Don't align floor";
-			flags4096text = "[12] Don't align ceiling";
-			flags8192text = "[13] Use texture offsets";
-		}
-
-		10
-		{
-			title = "Culling Plane";
-			prefix = "(10)";
-			flags64text = "[6] Cull only while in sector";
-		}
-
-		13
-		{
-			title = "Heat Wave Effect";
-			prefix = "(13)";
-		}
-
-	    40
-		{
-			title = "Visual Portal Between Tagged Linedefs";
-			prefix = "(40)";
-		}
-
-	    41
-		{
-			title = "Horizon Effect";
-			prefix = "(41)";
-		}
-
-		50
-		{
-			title = "Instantly Lower Floor on Level Load";
-			prefix = "(50)";
-		}
-
-		51
-		{
-			title = "Instantly Raise Ceiling on Level Load";
-			prefix = "(51)";
-		}
-
-		63
-		{
-			title = "Fake Floor/Ceiling Planes";
-			prefix = "(63)";
-		}
-
-		540
-		{
-			title = "Floor Friction";
-			prefix = "(540)";
-		}
-	}
-
-	parameters
-	{
-		title = "Parameters";
-
-		2
-		{
-			title = "Custom Exit";
-			prefix = "(2)";
-			flags2text = "[1] Check emeralds";
-			flags64text = "[6] Skip score tally";
-		}
-
-		3
-		{
-			title = "Zoom Tube Parameters";
-			prefix = "(3)";
-			flags512text = "[9] Ignore player direction";
-		}
-
-		4
-		{
-			title = "Speed Pad Parameters";
-			prefix = "(4)";
-			flags512text = "[9] No teleport to center";
-			flags1024text = "[10] Force spinning frames";
-		}
-
-		8
-		{
-			title = "Special Sector Properties";
-			prefix = "(8)";
-			flags32text = "[5] Invert precipitation";
-			flags64text = "[6] Touch only ceiling";
-			flags128text = "[7] Allow opposite gravity";
-			flags256text = "[8] Touch sector edge";
-			flags512text = "[9] Touch floor or ceiling";
-		}
-
-		9
-		{
-			title = "Chain Parameters";
-			prefix = "(9)";
-			flags32text = "[5] Swing instead of spin";
-			flags64text = "[6] Player-turnable chain";
-			flags128text = "[7] Make chain from end item";
-			flags256text = "[8] Spawn link at origin";
-			flags512text = "[9] Don't clip inside ground";
-			flags1024text = "[10] No distance check";
-		}
-
-		11
-		{
-			title = "Rope Hang Parameters";
-			prefix = "(11)";
-			flags32text = "[5] Don't loop";
-			flags64text = "[6] Static";
-		}
-
-		12
-		{
-			title = "Rock Spawner Parameters";
-			prefix = "(12)";
-			flags64text = "[6] Randomize speed";
-		}
-
-		14
-		{
-			title = "Bustable Block Parameters";
-			prefix = "(14)";
-			flags32text = "[5] Particles launch from center";
-		}
-
-		15
-		{
-			title = "Fan Particle Spawner Parameters";
-			prefix = "(15)";
-		}
-
-		16
-		{
-			title = "Minecart Parameters";
-			prefix = "(16)";
-		}
-
-		64
-		{
-			title = "Continuously Appearing/Disappearing FOF";
-			prefix = "(64)";
-			flags2text = "[1] Use control sector tag";
-			flags64text = "[6] No sound effect";
-		}
-
-		65
-		{
-			title = "Bridge Thinker <disabled>";
-			prefix = "(65)";
-		}
-	}
-
-	polyobject
-	{
-		title = "PolyObject";
-
-		20
-		{
-			title = "First Line";
-			prefix = "(20)";
-		}
-
-		21
-		{
-			title = "Explicitly Include Line <disabled>";
-			prefix = "(21)";
-		}
-
-		22
-		{
-			title = "Parameters";
-			prefix = "(22)";
-			flags64text = "[6] Trigger linedef executor";
-			flags128text = "[7] Intangible";
-			flags256text = "[8] Stopped by pushables";
-			flags512text = "[9] Render flats";
-		}
-
-		30
-		{
-			title = "Waving Flag";
-			prefix = "(30)";
-		}
-
-		31
-		{
-			title = "Displacement by Front Sector";
-			prefix = "(31)";
-		}
-
-		32
-		{
-			title = "Angular Displacement by Front Sector";
-			prefix = "(32)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Don't turn players";
-			flags512text = "[9] Turn all objects";
-		}
-	}
-
-	planemove
-	{
-		title = "Plane Movement";
-
-		52
-		{
-			title = "Continuously Falling Sector";
-			prefix = "(52)";
-			flags64text = "[6] Continuously rising";
-		}
-
-		53
-		{
-			title = "Continuous Floor/Ceiling Mover";
-			prefix = "(53)";
-		}
-
-		54
-		{
-			title = "Continuous Floor Mover";
-			prefix = "(54)";
-		}
-
-		55
-		{
-			title = "Continuous Ceiling Mover";
-			prefix = "(55)";
-		}
-
-		56
-		{
-			title = "Continuous Two-Speed Floor/Ceiling Mover";
-			prefix = "(56)";
-		}
-
-		57
-		{
-			title = "Continuous Two-Speed Floor Mover";
-			prefix = "(57)";
-		}
-
-		58
-		{
-			title = "Continuous Two-Speed Ceiling Mover";
-			prefix = "(58)";
-		}
-
-		59
-		{
-			title = "Activate Moving Platform";
-			prefix = "(59)";
-			flags64text = "[6] Move upwards at start";
-		}
-
-		60
-		{
-			title = "Activate Moving Platform (Adjustable Speed)";
-			prefix = "(60)";
-			flags64text = "[6] Move upwards at start";
-		}
-
-		61
-		{
-			title = "Crusher (Ceiling to Floor)";
-			prefix = "(61)";
-			flags512text = "[9] Double, constant speed";
-		}
-
-		62
-		{
-			title = "Crusher (Floor to Ceiling)";
-			prefix = "(62)";
-			flags512text = "[9] Double, constant speed";
-		}
-
-		66
-		{
-			title = "Move Floor by Displacement";
-			prefix = "(66)";
-			flags64text = "[6] Inverse movement";
-		}
-
-		67
-		{
-			title = "Move Ceiling by Displacement";
-			prefix = "(67)";
-			flags64text = "[6] Inverse movement";
-		}
-
-		68
-		{
-			title = "Move Floor and Ceiling by Displacement";
-			prefix = "(68)";
-			flags64text = "[6] Inverse movement";
-		}
-	}
-
-	fofsolid
-	{
-		title = "FOF (solid)";
-
-		100
-		{
-			title = "Solid, Opaque";
-			prefix = "(100)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "19F";
-		}
-
-		101
-		{
-			title = "Solid, Opaque, No Shadow";
-			prefix = "(101)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "1DF";
-		}
-
-		102
-		{
-			title = "Solid, Translucent";
-			prefix = "(102)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Render insides";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "195F";
-			flags643dfloorflagsadd = "7C80";
-		}
-
-		103
-		{
-			title = "Solid, Sides Only";
-			prefix = "(103)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "1CF";
-		}
-
-		104
-		{
-			title = "Solid, No Sides";
-			prefix = "(104)";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Cast shadow";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "1D7";
-			flags643dfloorflagsremove = "40";
-		}
-
-		105
-		{
-			title = "Solid, Invisible";
-			prefix = "(105)";
-			flags32text = "[5] Only block player";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "47";
-		}
-
-		140
-		{
-			title = "Intangible from Bottom, Opaque";
-			prefix = "(140)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Don't cast shadow";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "200841F";
-			flags643dfloorflagsadd = "40";
-		}
-
-		141
-		{
-			title = "Intangible from Bottom, Translucent";
-			prefix = "(141)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Don't cast shadow";
-			flags128text = "[7] Render insides/block non-plr";
-			3dfloor = true;
-			3dfloorflags = "200191F";
-			flags1283dfloorflagsadd = "7C80";
-			flags643dfloorflagsadd = "40";
-		}
-
-		142
-		{
-			title = "Intangible from Bottom, Translucent, No Sides";
-			prefix = "(142)";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Don't cast shadow";
-			flags128text = "[7] Render insides/block non-plr";
-			3dfloor = true;
-			3dfloorflags = "2001917";
-			flags1283dfloorflagsadd = "7C80";
-			flags643dfloorflagsadd = "40";
-		}
-
-		143
-		{
-			title = "Intangible from Top, Opaque";
-			prefix = "(143)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Don't cast shadow";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "400841F";
-			flags643dfloorflagsadd = "40";
-		}
-
-		144
-		{
-			title = "Intangible from Top, Translucent";
-			prefix = "(144)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Don't cast shadow";
-			flags128text = "[7] Render insides/block non-plr";
-			3dfloor = true;
-			3dfloorflags = "400191F";
-			flags1283dfloorflagsadd = "7C80";
-			flags643dfloorflagsadd = "40";
-		}
-
-		145
-		{
-			title = "Intangible from Top, Translucent, No Sides";
-			prefix = "(145)";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Don't cast shadow";
-			flags128text = "[7] Render insides/block non-plr";
-			3dfloor = true;
-			3dfloorflags = "4001917";
-			flags1283dfloorflagsadd = "7C80";
-			flags643dfloorflagsadd = "40";
-		}
-
-		146
-		{
-			title = "Only Tangible from Sides";
-			prefix = "(146)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "600800F";
-		}
-	}
-
-	fofintangible
-	{
-		title = "FOF (intangible)";
-
-		120
-		{
-			title = "Water, Opaque";
-			prefix = "(120)";
-			flags8text = "[3] Slope skew sides";
-			flags64text = "[6] Use two light levels";
-			flags512text = "[9] Use target light level";
-			flags1024text = "[10] Ripple effect";
-			3dfloor = true;
-			3dfloorflags = "8F39";
-			flags643dfloorflagsadd = "20000";
-			flags5123dfloorflagsadd = "80000000";
-			flags10243dfloorflagsadd = "40000000";
-		}
-
-		121
-		{
-			title = "Water, Translucent";
-			prefix = "(121)";
-			flags8text = "[3] Slope skew sides";
-			flags64text = "[6] Use two light levels";
-			flags512text = "[9] Use target light level";
-			flags1024text = "[10] Ripple effect";
-			3dfloor = true;
-			3dfloorflags = "9F39";
-			flags643dfloorflagsadd = "20000";
-			flags5123dfloorflagsadd = "80000000";
-			flags10243dfloorflagsadd = "40000000";
-		}
-
-		122
-		{
-			title = "Water, Opaque, No Sides";
-			prefix = "(122)";
-			flags64text = "[6] Use two light levels";
-			flags512text = "[9] Use target light level";
-			flags1024text = "[10] Ripple effect";
-			3dfloor = true;
-			3dfloorflags = "F31";
-			flags643dfloorflagsadd = "20000";
-			flags5123dfloorflagsadd = "80000000";
-			flags10243dfloorflagsadd = "40000000";
-		}
-
-		123
-		{
-			title = "Water, Translucent, No Sides";
-			prefix = "(123)";
-			flags64text = "[6] Use two light levels";
-			flags512text = "[9] Use target light level";
-			flags1024text = "[10] Ripple effect";
-			3dfloor = true;
-			3dfloorflags = "1F31";
-			flags643dfloorflagsadd = "20000";
-			flags5123dfloorflagsadd = "80000000";
-			flags10243dfloorflagsadd = "40000000";
-		}
-
-		124
-		{
-			title = "Goo Water, Translucent";
-			prefix = "(124)";
-			flags8text = "[3] Slope skew sides";
-			flags64text = "[6] Use two light levels";
-			flags512text = "[9] Use target light level";
-			flags1024text = "[10] Ripple effect";
-			3dfloor = true;
-			3dfloorflags = "209F39";
-			flags643dfloorflagsadd = "20000";
-			flags5123dfloorflagsadd = "80000000";
-			flags10243dfloorflagsadd = "40000000";
-		}
-
-		125
-		{
-			title = "Goo Water, Translucent, No Sides";
-			prefix = "(125)";
-			flags8text = "[3] Slope skew sides";
-			flags64text = "[6] Use two light levels";
-			flags512text = "[9] Use target light level";
-			flags1024text = "[10] Ripple effect";
-			3dfloor = true;
-			3dfloorflags = "201F31";
-			flags643dfloorflagsadd = "20000";
-			flags5123dfloorflagsadd = "80000000";
-			flags10243dfloorflagsadd = "40000000";
-		}
-
-		220
-		{
-			title = "Intangible, Opaque";
-			prefix = "(220)";
-			flags8text = "[3] Slope skew sides";
-			3dfloor = true;
-			3dfloorflags = "8F19";
-		}
-
-		221
-		{
-			title = "Intangible, Translucent";
-			prefix = "(221)";
-			flags8text = "[3] Slope skew sides";
-			flags64text = "[6] Cast shadow";
-			3dfloor = true;
-			3dfloorflags = "1B59";
-			flags643dfloorflagsremove = "40";
-		}
-
-		222
-		{
-			title = "Intangible, Sides Only";
-			prefix = "(222)";
-			flags8text = "[3] Slope skew sides";
-			flags64text = "[6] Cast shadow";
-			3dfloor = true;
-			3dfloorflags = "8249";
-			flags643dfloorflagsremove = "240";
-		}
-
-		223
-		{
-			title = "Intangible, Invisible";
-			prefix = "(223)";
-			3dfloor = true;
-			3dfloorflags = "41";
-		}
-	}
-
-	fofmoving
-	{
-		title = "FOF (moving)";
-
-		150
-		{
-			title = "Air Bobbing";
-			prefix = "(150)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Spindash to move";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "19F";
-		}
-
-		151
-		{
-			title = "Air Bobbing (Adjustable)";
-			prefix = "(151)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Spindash to move";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "19F";
-		}
-
-		152
-		{
-			title = "Reverse Air Bobbing (Adjustable)";
-			prefix = "(152)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Spindash to move";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "19F";
-		}
-
-		160
-		{
-			title = "Floating, Bobbing";
-			prefix = "(160)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "4019F";
-		}
-
-		190
-		{
-			title = "Rising Platform, Solid, Opaque";
-			prefix = "(190)";
-			flags2text = "[1] Sink when stepped on";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Spindash to move";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "19F";
-		}
-
-		191
-		{
-			title = "Rising Platform, Solid, Opaque, No Shadow";
-			prefix = "(191)";
-			flags2text = "[1] Sink when stepped on";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Spindash to move";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "1DF";
-		}
-
-		192
-		{
-			title = "Rising Platform, Solid, Translucent";
-			prefix = "(192)";
-			flags2text = "[1] Sink when stepped on";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Spindash to move";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "195F";
-		}
-
-		193
-		{
-			title = "Rising Platform, Solid, Invisible";
-			prefix = "(193)";
-			flags2text = "[1] Sink when stepped on";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Spindash to move";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "47";
-		}
-
-		194
-		{
-			title = "Rising Platform, Intangible from Bottom, Opaque";
-			prefix = "(194)";
-			flags2text = "[1] Sink when stepped on";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Spindash, no shadow";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "200841F";
-			flags643dfloorflagsadd = "40";
-		}
-
-		195
-		{
-			title = "Rising Platform, Intangible from Bottom, Translucent";
-			prefix = "(195)";
-			flags2text = "[1] Sink when stepped on";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Spindash, no shadow";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "2009D1F";
-			flags643dfloorflagsadd = "40";
-		}
-	}
-
-	fofcrumbling
-	{
-		title = "FOF (crumbling)";
-
-		170
-		{
-			title = "Crumbling, Respawn";
-			prefix = "(170)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "10019F";
-		}
-
-		171
-		{
-			title = "Crumbling, No Respawn";
-			prefix = "(171)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "80019F";
-		}
-
-		172
-		{
-			title = "Crumbling, Respawn, Intangible from Bottom";
-			prefix = "(172)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Don't cast shadow";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "210841F";
-			flags643dfloorflagsadd = "40";
-		}
-
-		173
-		{
-			title = "Crumbling, No Respawn, Intangible from Bottom";
-			prefix = "(173)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Don't cast shadow";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "218841F";
-			flags643dfloorflagsadd = "40";
-		}
-
-		174
-		{
-			title = "Crumbling, Respawn, Int. from Bottom, Translucent";
-			prefix = "(174)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Don't cast shadow";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "210959F";
-			flags643dfloorflagsadd = "40";
-		}
-
-		175
-		{
-			title = "Crumbling, No Respawn, Int. from Bottom, Translucent";
-			prefix = "(175)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Don't cast shadow";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "218959F";
-			flags643dfloorflagsadd = "40";
-		}
-
-		176
-		{
-			title = "Crumbling, Respawn, Floating, Bobbing";
-			prefix = "(176)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Spindash to move";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "14019F";
-		}
-
-		177
-		{
-			title = "Crumbling, No Respawn, Floating, Bobbing";
-			prefix = "(177)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Spindash to move";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "1C019F";
-		}
-
-		178
-		{
-			title = "Crumbling, Respawn, Floating";
-			prefix = "(178)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "14019F";
-		}
-
-		179
-		{
-			title = "Crumbling, No Respawn, Floating";
-			prefix = "(179)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "1C019F";
-		}
-
-		180
-		{
-			title = "Crumbling, Respawn, Air Bobbing";
-			prefix = "(180)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags64text = "[6] Spindash to move";
-			flags128text = "[7] Only block non-players";
-			3dfloor = true;
-			3dfloorflags = "10019F";
-		}
-	}
-
-	fofspecial
-	{
-		title = "FOF (special)";
-
-		200
-		{
-			title = "Light Block";
-			prefix = "(200)";
-			3dfloor = true;
-			3dfloorflags = "20201";
-		}
-
-		201
-		{
-			title = "Half Light Block";
-			prefix = "(201)";
-			3dfloor = true;
-			3dfloorflags = "201";
-		}
-
-		202
-		{
-			title = "Fog Block";
-			prefix = "(202)";
-			3dfloor = true;
-			3dfloorflags = "3EF19";
-		}
-
-		250
-		{
-			title = "Mario Block";
-			prefix = "(250)";
-			flags32text = "[5] Invisible block";
-			flags64text = "[6] Brick block";
-			3dfloor = true;
-			3dfloorflags = "40019F";
-		}
-
-		251
-		{
-			title = "Thwomp Block";
-			prefix = "(251)";
-			flags512text = "[9] Custom crushing sound";
-			flags1024text = "[10] Custom speed";
-			3dfloor = true;
-			3dfloorflags = "19F";
-		}
-
-		252
-		{
-			title = "Shatter Block";
-			prefix = "(252)";
-			flags8text = "[3] Slope skew sides";
-			flags64text = "[6] Shatter only from below";
-			flags512text = "[9] Shattered by pushables";
-			flags1024text = "[10] Trigger linedef executor";
-			3dfloor = true;
-			3dfloorflags = "8800019";
-			flags643dfloorflagsadd = "200006";
-		}
-
-		253
-		{
-			title = "Shatter Block, Translucent";
-			prefix = "(253)";
-			flags8text = "[3] Slope skew sides";
-			flags512text = "[9] Shattered by pushables";
-			flags1024text = "[10] Trigger linedef executor";
-			3dfloor = true;
-			3dfloorflags = "8801019";
-		}
-
-		254
-		{
-			title = "Bustable Block";
-			prefix = "(254)";
-			flags8text = "[3] Slope skew sides";
-			flags64text = "[6] Strong characters only";
-			flags128text = "[7] Only block non-players";
-			flags512text = "[9] Shattered by pushables";
-			flags1024text = "[10] Trigger linedef executor";
-			3dfloor = true;
-			3dfloorflags = "80001F";
-			flags643dfloorflagsadd = "20000000";
-		}
-
-		255
-		{
-			title = "Spin-Bustable Block";
-			prefix = "(255)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags128text = "[7] Only block non-players";
-			flags512text = "[9] Shattered by pushables";
-			flags1024text = "[10] Trigger linedef executor";
-			3dfloor = true;
-			3dfloorflags = "1080001F";
-		}
-
-		256
-		{
-			title = "Spin-Bustable Block, Translucent";
-			prefix = "(256)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Only block player";
-			flags128text = "[7] Only block non-players";
-			flags512text = "[9] Shattered by pushables";
-			flags1024text = "[10] Trigger linedef executor";
-			3dfloor = true;
-			3dfloorflags = "1080101F";
-		}
-
-		257
-		{
-			title = "Quicksand";
-			prefix = "(257)";
-			flags8text = "[3] Slope skew sides";
-			flags1024text = "[10] Ripple effect";
-			3dfloor = true;
-			3dfloorflags = "1008219";
-			flags10243dfloorflagsadd = "40000000";
-		}
-
-		258
-		{
-			title = "Laser";
-			prefix = "(258)";
-			flags8text = "[3] Slope skew sides";
-			flags32text = "[5] Don't damage bosses";
-			3dfloor = true;
-			3dfloorflags = "959";
-		}
-
-		259
-		{
-			title = "Custom FOF";
-			prefix = "(259)";
-			flags32text = "[5] Only block player";
-			flags128text = "[7] Only block non-players";
-			flags512text = "[9] Shattered by pushables";
-			flags1024text = "[10] Trigger linedef executor";
-			3dfloor = true;
-			3dfloorcustom = true;
-		}
-	}
-
-	linedeftrigger
-	{
-		title = "Linedef Executor Trigger";
-
-		300
-		{
-			title = "Continuous";
-			prefix = "(300)";
-		}
-
-		301
-		{
-			title = "Each Time";
-			prefix = "(301)";
-			flags16384text = "[14] Also trigger on exit";
-		}
-
-		302
-		{
-			title = "Once";
-			prefix = "(302)";
-		}
-
-		303
-		{
-			title = "Ring Count - Continuous";
-			prefix = "(303)";
-			flags2text = "[1] Rings greater or equal";
-			flags64text = "[6] Rings less or equal";
-			flags512text = "[9] Consider all players";
-		}
-
-		304
-		{
-			title = "Ring Count - Once";
-			prefix = "(304)";
-			flags2text = "[1] Rings greater or equal";
-			flags64text = "[6] Rings less or equal";
-			flags512text = "[9] Consider all players";
-		}
-
-		305
-		{
-			title = "Character Ability - Continuous";
-			prefix = "(305)";
-		}
-
-		306
-		{
-			title = "Character Ability - Each Time";
-			prefix = "(306)";
-			flags16384text = "[14] Also trigger on exit";
-		}
-
-		307
-		{
-			title = "Character Ability - Once";
-			prefix = "(307)";
-		}
-
-		308
-		{
-			title = "Race Only - Once";
-			prefix = "(308)";
-		}
-
-		309
-		{
-			title = "CTF Red Team - Continuous";
-			prefix = "(309)";
-		}
-
-		310
-		{
-			title = "CTF Red Team - Each Time";
-			prefix = "(310)";
-			flags16384text = "[14] Also trigger on exit";
-		}
-
-		311
-		{
-			title = "CTF Blue Team - Continuous";
-			prefix = "(311)";
-		}
-
-		312
-		{
-			title = "CTF Blue Team - Each Time";
-			prefix = "(312)";
-			flags16384text = "[14] Also trigger on exit";
-		}
-
-		313
-		{
-			title = "No More Enemies - Once";
-			prefix = "(313)";
-		}
-
-		314
-		{
-			title = "Number of Pushables - Continuous";
-			prefix = "(314)";
-			flags64text = "[6] Number greater or equal";
-			flags512text = "[9] Number less";
-		}
-
-		315
-		{
-			title = "Number of Pushables - Once";
-			prefix = "(315)";
-			flags64text = "[6] Number greater or equal";
-			flags512text = "[9] Number less";
-		}
-
-		317
-		{
-			title = "Condition Set Trigger - Continuous";
-			prefix = "(317)";
-		}
-
-		318
-		{
-			title = "Condition Set Trigger - Once";
-			prefix = "(318)";
-		}
-
-		319
-		{
-			title = "Unlockable - Continuous";
-			prefix = "(319)";
-		}
-
-		320
-		{
-			title = "Unlockable - Once";
-			prefix = "(320)";
-		}
-
-		321
-		{
-			title = "Trigger After X Calls - Continuous";
-			prefix = "(321)";
-			flags64text = "[6] Trigger more than once";
-
-		}
-
-		322
-		{
-			title = "Trigger After X Calls - Each Time";
-			prefix = "(322)";
-			flags64text = "[6] Trigger more than once";
-		}
-
-		323
-		{
-			title = "NiGHTSerize - Each Time";
-			prefix = "(323)";
-			flags2text = "[1] Mare >= Front X Offset";
-			flags8text = "[3] Run only if player is NiGHTS";
-			flags16text = "[4] Count from lowest of players";
-			flags32text = "[5] Lap <= Front Y Offset";
-			flags64text = "[6] Mare <= Front X Offset";
-			flags128text = "[7] Lap >= Front Y Offset";
-			flags256text = "[8] Count laps from Bonus Time";
-			flags512text = "[9] Count from triggering player";
-			flags16384text = "[14] Run if no more mares";
-			flags32768text = "[15] Run if player is not NiGHTS";
-		}
-
-		324
-		{
-			title = "NiGHTSerize - Once";
-			flags2text = "[1] Mare >= Front X Offset";
-			flags8text = "[3] Run only if player is NiGHTS";
-			flags16text = "[4] Count from lowest of players";
-			flags32text = "[5] Lap <= Front Y Offset";
-			flags64text = "[6] Mare <= Front X Offset";
-			flags128text = "[7] Lap >= Front Y Offset";
-			flags256text = "[8] Count laps from Bonus Time";
-			flags512text = "[9] Count from triggering player";
-			flags16384text = "[14] Run if no more mares";
-			flags32768text = "[15] Run if player is not NiGHTS";
-			prefix = "(324)";
-		}
-
-		325
-		{
-			title = "De-NiGHTSerize - Each Time";
-			flags2text = "[1] Mare >= Front X Offset";
-			flags8text = "[3] Run if anyone is NiGHTS";
-			flags16text = "[4] Count from lowest of players";
-			flags32text = "[5] Lap <= Front Y Offset";
-			flags64text = "[6] Mare <= Front X Offset";
-			flags128text = "[7] Lap >= Front Y Offset";
-			flags256text = "[8] Count laps from Bonus Time";
-			flags512text = "[9] Count from triggering player";
-			flags32768text = "[15] Run if no one is NiGHTS";
-			prefix = "(325)";
-		}
-
-		326
-		{
-			title = "De-NiGHTSerize - Once";
-			flags2text = "[1] Mare >= Front X Offset";
-			flags8text = "[3] Run if anyone is NiGHTS";
-			flags16text = "[4] Count from lowest of players";
-			flags32text = "[5] Lap <= Front Y Offset";
-			flags64text = "[6] Mare <= Front X Offset";
-			flags128text = "[7] Lap >= Front Y Offset";
-			flags256text = "[8] Count laps from Bonus Time";
-			flags512text = "[9] Count from triggering player";
-			flags32768text = "[15] Run if no one is NiGHTS";
-			prefix = "(326)";
-		}
-
-		327
-		{
-			title = "NiGHTS Lap - Each Time";
-			flags2text = "[1] Mare >= Front X Offset";
-			flags16text = "[4] Count from lowest of players";
-			flags32text = "[5] Lap <= Front Y Offset";
-			flags64text = "[6] Mare <= Front X Offset";
-			flags128text = "[7] Lap >= Front Y Offset";
-			flags256text = "[8] Count laps from Bonus Time";
-			flags512text = "[9] Count from triggering player";
-			prefix = "(327)";
-		}
-
-		328
-		{
-			title = "NiGHTS Lap - Once";
-			flags2text = "[1] Mare >= Front X Offset";
-			flags16text = "[4] Count from lowest of players";
-			flags32text = "[5] Lap <= Front Y Offset";
-			flags64text = "[6] Mare <= Front X Offset";
-			flags128text = "[7] Lap >= Front Y Offset";
-			flags256text = "[8] Count laps from Bonus Time";
-			flags512text = "[9] Count from triggering player";
-			prefix = "(328)";
-		}
-
-		329
-		{
-			title = "Ideya Capture Touch - Each Time";
-			flags2text = "[1] Mare >= Front X Offset";
-			flags8text = "[3] Run regardless of spheres";
-			flags16text = "[4] Count from lowest of players";
-			flags32text = "[5] Lap <= Front Y Offset";
-			flags64text = "[6] Mare <= Front X Offset";
-			flags128text = "[7] Lap >= Front Y Offset";
-			flags256text = "[8] Count laps from Bonus Time";
-			flags512text = "[9] Count from triggering player";
-			flags16384text = "[14] Only if not enough spheres";
-			flags32768text = "[15] Run when entering Capture";
-			prefix = "(329)";
-		}
-
-		330
-		{
-			title = "Ideya Capture Touch - Once";
-			flags2text = "[1] Mare >= Front X Offset";
-			flags8text = "[3] Run regardless of spheres";
-			flags16text = "[4] Count from lowest of players";
-			flags32text = "[5] Lap <= Front Y Offset";
-			flags64text = "[6] Mare <= Front X Offset";
-			flags128text = "[7] Lap >= Front Y Offset";
-			flags256text = "[8] Count laps from Bonus Time";
-			flags512text = "[9] Count from triggering player";
-			flags16384text = "[14] Only if not enough spheres";
-			flags32768text = "[15] Run when entering Capture";
-			prefix = "(330)";
-		}
-
-		331
-		{
-			title = "Player Skin - Continuous";
-			flags64text = "[6] Disable for this skin";
-			prefix = "(331)";
-		}
-
-		332
-		{
-			title = "Player Skin - Each Time";
-			flags64text = "[6] Disable for this skin";
-			prefix = "(332)";
-		}
-
-		333
-		{
-			title = "Player Skin - Once";
-			flags64text = "[6] Disable for this skin";
-			prefix = "(333)";
-		}
-
-		399
-		{
-			title = "Level Load";
-			prefix = "(399)";
-		}
-	}
-
-	linedefexecsector
-	{
-		title = "Linedef Executor (sector)";
-
-		400
-		{
-			title = "Set Tagged Sector's Floor Height/Texture";
-			prefix = "(400)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Keep floor flat";
-		}
-
-		401
-		{
-			title = "Set Tagged Sector's Ceiling Height/Texture";
-			prefix = "(401)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		402
-		{
-			title = "Set Tagged Sector's Light Level";
-			prefix = "(402)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		409
-		{
-			title = "Change Tagged Sector's Tag";
-			prefix = "(409)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		410
-		{
-			title = "Change Front Sector's Tag";
-			prefix = "(410)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		416
-		{
-			title = "Start Adjustable Flickering Light";
-			prefix = "(416)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Second level from back";
-		}
-
-		417
-		{
-			title = "Start Adjustable Pulsating Light";
-			prefix = "(417)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Second level from back";
-		}
-
-		418
-		{
-			title = "Start Adjustable Blinking Light (unsynchronized)";
-			prefix = "(418)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Second level from back";
-		}
-
-		419
-		{
-			title = "Start Adjustable Blinking Light (synchronized)";
-			prefix = "(419)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Second level from back";
-		}
-
-		420
-		{
-			title = "Fade Light Level";
-			prefix = "(420)";
-			flags8text = "[3] Set delay by backside sector";
-			flags16text = "[4] Set params by X/Y offsets";
-			flags512text = "[9] Speed = Tic Duration";
-			flags1024text = "[10] Override existing fade";
-		}
-
-		421
-		{
-			title = "Stop Lighting Effect";
-			prefix = "(421)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		435
-		{
-			title = "Change Plane Scroller Direction";
-			prefix = "(435)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-	}
-
-	linedefexecplane
-	{
-		title = "Linedef Executor (plane movement)";
-
-		403
-		{
-			title = "Move Tagged Sector's Floor";
-			prefix = "(403)";
-			flags2text = "[1] Trigger linedef executor";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Change floor flat";
-		}
-
-		404
-		{
-			title = "Move Tagged Sector's Ceiling";
-			prefix = "(404)";
-			flags2text = "[1] Trigger linedef executor";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Change ceiling flat";
-		}
-
-		405
-		{
-			title = "Move Floor According to Front Texture Offsets";
-			prefix = "(405)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Move instantly";
-		}
-
-		407
-		{
-			title = "Move Ceiling According to Front Texture Offsets";
-			prefix = "(407)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Move instantly";
-		}
-
-		411
-		{
-			title = "Stop Plane Movement";
-			prefix = "(411)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		428
-		{
-			title = "Start Platform Movement";
-			prefix = "(428)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Move upwards at start";
-		}
-
-		429
-		{
-			title = "Crush Ceiling Once";
-			prefix = "(429)";
-			flags8text = "[3] Set delay by backside sector";
-			flags512text = "[9] Double, constant speed";
-		}
-
-		430
-		{
-			title = "Crush Floor Once";
-			prefix = "(430)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		431
-		{
-			title = "Crush Floor and Ceiling Once";
-			prefix = "(431)";
-			flags8text = "[3] Set delay by backside sector";
-			flags512text = "[9] Double, constant speed";
-		}
-	}
-
-	linedefexecplayer
-	{
-		title = "Linedef Executor (player/object)";
-
-		412
-		{
-			title = "Teleporter";
-			prefix = "(412)";
-			flags2text = "[1] Silent";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Retain angle";
-			flags256text = "[8] Relative, silent";
-			flags512text = "[9] Retain momentum";
-		}
-
-		425
-		{
-			title = "Change Object State";
-			prefix = "(425)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		426
-		{
-			title = "Stop Object";
-			prefix = "(426)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Teleport to sector center";
-		}
-
-		427
-		{
-			title = "Award Score";
-			prefix = "(427)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		432
-		{
-			title = "Enable/Disable 2D Mode";
-			prefix = "(432)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Return to 3D";
-		}
-
-		433
-		{
-			title = "Enable/Disable Gravity Flip";
-			prefix = "(433)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Return to normal";
-		}
-
-		434
-		{
-			title = "Award Power-Up";
-			prefix = "(434)";
-			flags2text = "[1] Use back upper texture";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] No time limit";
-		}
-
-		437
-		{
-			title = "Disable Player Control";
-			prefix = "(437)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Allow jumping";
-		}
-
-		438
-		{
-			title = "Change Object Size";
-			prefix = "(438)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		442
-		{
-			title = "Change Object Type State";
-			prefix = "(442)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		457
-		{
-			title = "Track Object's Angle";
-			prefix = "(457)";
-			flags8text = "[3] Set delay by backside sector";
-			flags128text = "[7] Don't stop after first fail";
-		}
-
-		458
-		{
-			title = "Stop Tracking Object's Angle";
-			prefix = "(458)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		460
-		{
-			title = "Award Rings";
-			prefix = "(460)";
-		}
-
-		461
-		{
-			title = "Spawn Object";
-			prefix = "(461)";
-			flags64text = "[6] Spawn inside a range";
-		}
-
-		462
-		{
-			title = "Stop Timer/Exit Stage in Record Attack";
-			prefix = "(462)";
-		}
-	}
-
-	linedefexecmisc
-	{
-		title = "Linedef Executor (misc.)";
-
-		413
-		{
-			title = "Change Music";
-			prefix = "(413)";
-			flags2text = "[1] Keep after death";
-			flags8text = "[3] Set delay by backside sector";
-			flags32text = "[5] Seek to current song position";
-			flags64text = "[6] For everyone";
-			flags128text = "[7] Fade to custom volume";
-			flags512text = "[9] Don't loop";
-			flags16384text = "[14] Force music reload";
-		}
-
-		414
-		{
-			title = "Play Sound Effect";
-			prefix = "(414)";
-			flags2text = "[1] From calling sector";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] From nowhere for triggerer";
-			flags512text = "[9] For everyone";
-			flags1024text = "[10] From tagged sectors";
-		}
-
-		415
-		{
-			title = "Run Script";
-			prefix = "(415)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		422
-		{
-			title = "Switch to Cut-Away View";
-			prefix = "(422)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Adjust pitch";
-		}
-
-		423
-		{
-			title = "Change Sky";
-			prefix = "(423)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] For everyone";
-		}
-
-		424
-		{
-			title = "Change Weather";
-			prefix = "(424)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] For everyone";
-		}
-
-		436
-		{
-			title = "Shatter FOF";
-			prefix = "(436)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		439
-		{
-			title = "Change Tagged Linedef's Textures";
-			prefix = "(439)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Only existing";
-		}
-
-		440
-		{
-			title = "Start Metal Sonic Race";
-			prefix = "(440)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		441
-		{
-			title = "Condition Set Trigger";
-			prefix = "(441)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		443
-		{
-			title = "Call Lua Function";
-			prefix = "(443)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		444
-		{
-			title = "Earthquake";
-			prefix = "(444)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-
-		445
-		{
-			title = "Make FOF Disappear/Reappear";
-			prefix = "(445)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Reappear";
-		}
-
-		446
-		{
-			title = "Make FOF Crumble";
-			prefix = "(446)";
-			flags2text = "[1] Flags determine respawn";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Don't respawn";
-		}
-
-		447
-		{
-			title = "Change Tagged Sector's Colormap";
-			prefix = "(447)";
-			flags8text = "[3] Set delay by backside sector";
-			flags16text = "[4] Front X/Y = Alpha";
-			flags32text = "[5] Subtract Red value";
-			flags64text = "[6] Subtract Green value";
-			flags128text = "[7] Subtract Blue value";
-			flags256text = "[8] Calc relative values";
-			flags32768text = "[15] Use back side colormap";
-		}
-
-		448
-		{
-			title = "Change Skybox";
-			prefix = "(448)";
-			flags2text = "[1] Change centerpoint";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] For everyone";
-			flags512text = "[9] Don't change viewpoint";
-		}
-
-		450
-		{
-			title = "Execute Linedef Executor (specific tag)";
-			prefix = "(450)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		451
-		{
-			title = "Execute Linedef Executor (random tag in range)";
-			prefix = "(451)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		452
-		{
-			title = "Set FOF Translucency";
-			prefix = "(452)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Do not handle FF_TRANS";
-			flags256text = "[8] Set relative to current val";
-		}
-
-		453
-		{
-			title = "Fade FOF";
-			prefix = "(453)";
-			flags2text = "[1] Do not handle FF_EXISTS";
-			flags8text = "[3] Set delay by backside sector";
-			flags32text = "[5] No collision during fade";
-			flags64text = "[6] Do not handle FF_TRANS";
-			flags128text = "[7] Do not handle lighting";
-			flags256text = "[8] Set relative to current val";
-			flags512text = "[9] Speed = Tic Duration";
-			flags1024text = "[10] Override existing fade";
-			flags16384text = "[14] Do not handle collision";
-			flags32768text = "[15] Use exact alpha in OGL";
-		}
-
-		454
-		{
-			title = "Stop Fading FOF";
-			prefix = "(454)";
-			flags2text = "[1] Do not finalize collision";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		455
-		{
-			title = "Fade Tagged Sector's Colormap";
-			prefix = "(455)";
-			flags8text = "[3] Set delay by backside sector";
-			flags16text = "[4] Front X/Y = Alpha";
-			flags32text = "[5] Subtract Red value";
-			flags64text = "[6] Subtract Green value";
-			flags128text = "[7] Subtract Blue value";
-			flags256text = "[8] Calc relative values";
-			flags512text = "[9] Speed = Tic Duration";
-			flags1024text = "[10] Override existing fade";
-			flags16384text = "[14] Fade from invisible black";
-			flags32768text = "[15] Use back side colormap";
-		}
-
-		456
-		{
-			title = "Stop Fading Tagged Sector's Colormap";
-			prefix = "(456)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		459
-		{
-			title = "Control Text Prompt";
-			prefix = "(459)";
-			flags2text = "[1] Close text prompt";
-			flags8text = "[3] Set delay by backside sector";
-			flags32text = "[5] Run executor tag on close";
-			flags64text = "[6] For everyone";
-			flags128text = "[7] Do not block controls";
-			flags256text = "[8] Do not freeze time";
-			flags32768text = "[15] Find prompt by name";
-		}
-	}
-
-	linedefexecpoly
-	{
-		title = "Linedef Executor (polyobject)";
-
-		480
-		{
-			title = "Door Slide";
-			prefix = "(480)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		481
-		{
-			title = "Door Swing";
-			prefix = "(481)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		482
-		{
-			title = "Move";
-			prefix = "(482)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		483
-		{
-			title = "Move, Override";
-			prefix = "(483)";
-			flags8text = "[3] Set delay by backside sector";
-		}
-
-		484
-		{
-			title = "Rotate Right";
-			prefix = "(484)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Don't turn players";
-			flags512text = "[9] Turn all objects";
-		}
-
-		485
-		{
-			title = "Rotate Right, Override";
-			prefix = "(485)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Don't turn players";
-			flags512text = "[9] Turn all objects";
-		}
-
-		486
-		{
-			title = "Rotate Left";
-			prefix = "(486)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Don't turn players";
-			flags512text = "[9] Turn all objects";
-		}
-
-		487
-		{
-			title = "Rotate Left, Override";
-			prefix = "(487)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Don't turn players";
-			flags512text = "[9] Turn all objects";
-		}
-
-		488
-		{
-			title = "Move by Waypoints";
-			prefix = "(488)";
-			flags8text = "[3] Set delay by backside sector";
-			flags32text = "[5] Reverse order";
-			flags128text = "[7] There and back";
-			flags256text = "[8] Return when done";
-			flags512text = "[9] Loop movement";
-		}
-
-		489
-		{
-			title = "Turn Invisible, Intangible";
-			prefix = "(489)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Only invisible";
-		}
-
-		490
-		{
-			title = "Turn Visible, Tangible";
-			prefix = "(490)";
-			flags8text = "[3] Set delay by backside sector";
-			flags64text = "[6] Only visible";
-		}
-
-		491
-		{
-			title = "Set Translucency";
-			prefix = "(491)";
-			flags8text = "[3] Set delay by backside sector";
-			flags16text = "[4] Set raw alpha by Front X";
-			flags256text = "[8] Calc relative values";
-		}
-
-		492
-		{
-			title = "Fade Translucency";
-			prefix = "(492)";
-			flags8text = "[3] Set delay by backside sector";
-			flags16text = "[4] Set raw alpha by Front X";
-			flags32text = "[5] No collision during fade";
-			flags256text = "[8] Calc relative values";
-			flags512text = "[9] Speed = Tic Duration";
-			flags1024text = "[10] Override existing fade";
-			flags16384text = "[14] Do not handle collision";
-		}
-	}
-
-	wallscroll
-	{
-		title = "Wall Scrolling";
-
-		500
-		{
-			title = "Scroll Wall Front Side Left";
-			prefix = "(500)";
-		}
-
-		501
-		{
-			title = "Scroll Wall Front Side Right";
-			prefix = "(501)";
-		}
-
-		502
-		{
-			title = "Scroll Wall According to Linedef";
-			prefix = "(502)";
-		}
-
-		503
-		{
-			title = "Scroll Wall According to Linedef (Accelerative)";
-			prefix = "(503)";
-		}
-
-		504
-		{
-			title = "Scroll Wall According to Linedef (Displacement)";
-			prefix = "(504)";
-		}
-
-		505
-		{
-			title = "Scroll Texture by Front Side Offsets";
-			prefix = "(505)";
-		}
-
-		506
-		{
-			title = "Scroll Texture by Back Side Offsets";
-			prefix = "(506)";
-		}
-	}
-
-	planescroll
-	{
-		title = "Plane Scrolling";
-
-		510
-		{
-			title = "Scroll Floor Texture";
-			prefix = "(510)";
-		}
-
-		511
-		{
-			title = "Scroll Floor Texture (Accelerative)";
-			prefix = "(511)";
-		}
-
-		512
-		{
-			title = "Scroll Floor Texture (Displacement)";
-			prefix = "(512)";
-		}
-
-		513
-		{
-			title = "Scroll Ceiling Texture";
-			prefix = "(513)";
-		}
-
-		514
-		{
-			title = "Scroll Ceiling Texture (Accelerative)";
-			prefix = "(514)";
-		}
-
-		515
-		{
-			title = "Scroll Ceiling Texture (Displacement)";
-			prefix = "(515)";
-		}
-
-		520
-		{
-			title = "Carry Objects on Floor";
-			prefix = "(520)";
-		}
-
-		521
-		{
-			title = "Carry Objects on Floor (Accelerative)";
-			prefix = "(521)";
-			flags64text = "[6] Even across edges";
-		}
-
-		522
-		{
-			title = "Carry Objects on Floor (Displacement)";
-			prefix = "(522)";
-		}
-
-		523
-		{
-			title = "Carry Objects on Ceiling";
-			prefix = "(523)";
-			flags64text = "[6] Even across edges";
-		}
-
-		524
-		{
-			title = "Carry Objects on Ceiling (Accelerative)";
-			prefix = "(524)";
-		}
-
-		525
-		{
-			title = "Carry Objects on Ceiling (Displacement)";
-			prefix = "(525)";
-		}
-
-		530
-		{
-			title = "Scroll Floor Texture and Carry Objects";
-			prefix = "(530)";
-			flags64text = "[6] Even across edges";
-		}
-
-		531
-		{
-			title = "Scroll Floor Texture and Carry Objects (Accelerative)";
-			prefix = "(531)";
-		}
-
-		532
-		{
-			title = "Scroll Floor Texture and Carry Objects (Displacement)";
-			prefix = "(532)";
-		}
-
-		533
-		{
-			title = "Scroll Ceiling Texture and Carry Objects";
-			prefix = "(533)";
-			flags64text = "[6] Even across edges";
-		}
-
-		534
-		{
-			title = "Scroll Ceiling Texture and Carry Objects (Accelerative)";
-			prefix = "(534)";
-		}
-
-		535
-		{
-			title = "Scroll Ceiling Texture and Carry Objects (Displacement)";
-			prefix = "(535)";
-		}
-	}
-
-	pusher
-	{
-		title = "Pusher";
-
-		541
-		{
-			title = "Wind";
-			prefix = "(541)";
-			flags512text = "[9] Player slides";
-			flags64text = "[6] Even across edges";
-		}
-
-		542
-		{
-			title = "Upwards Wind";
-			prefix = "(542)";
-			flags512text = "[9] Player slides";
-			flags64text = "[6] Even across edges";
-		}
-
-		543
-		{
-			title = "Downwards Wind";
-			prefix = "(543)";
-			flags512text = "[9] Player slides";
-			flags64text = "[6] Even across edges";
-		}
-
-		544
-		{
-			title = "Current";
-			prefix = "(544)";
-			flags512text = "[9] Player slides";
-			flags64text = "[6] Even across edges";
-		}
-
-		545
-		{
-			title = "Upwards Current";
-			prefix = "(545)";
-			flags512text = "[9] Player slides";
-			flags64text = "[6] Even across edges";
-		}
-
-		546
-		{
-			title = "Downwards Current";
-			prefix = "(546)";
-			flags512text = "[9] Player slides";
-			flags64text = "[6] Even across edges";
-		}
-
-		547
-		{
-			title = "Push/Pull";
-			prefix = "(547)";
-		}
-	}
-
-	light
-	{
-		title = "Lighting";
-
-		600
-		{
-			title = "Floor Lighting";
-			prefix = "(600)";
-		}
-
-		601
-		{
-			title = "Ceiling Lighting";
-			prefix = "(601)";
-		}
-
-		602
-		{
-			title = "Adjustable Pulsating Light";
-			prefix = "(602)";
-		}
-
-		603
-		{
-			title = "Adjustable Flickering Light";
-			prefix = "(603)";
-		}
-
-		604
-		{
-			title = "Adjustable Blinking Light (unsynchronized)";
-			prefix = "(604)";
-		}
-
-		605
-		{
-			title = "Adjustable Blinking Light (synchronized)";
-			prefix = "(605)";
-		}
-
-		606
-		{
-			title = "Colormap";
-			prefix = "(606)";
-		}
-	}
-
-	slope
-	{
-		title = "Slope";
-
-		700
-		{
-			title = "Slope Frontside Floor";
-			prefix = "(700)";
-			flags2048text = "[11] No physics";
-			flags4096text = "[12] Dynamic";
-			slope = "regular";
-			slopeargs = 1;
-		}
-
-		701
-		{
-			title = "Slope Frontside Ceiling";
-			prefix = "(701)";
-			flags2048text = "[11] No physics";
-			flags4096text = "[12] Dynamic";
-			slope = "regular";
-			slopeargs = 2;
-		}
-
-		702
-		{
-			title = "Slope Frontside Floor and Ceiling";
-			prefix = "(702)";
-			flags2048text = "[11] No physics";
-			flags4096text = "[12] Dynamic";
-			slope = "regular";
-			slopeargs = 3;
-		}
-
-		703
-		{
-			title = "Slope Frontside Floor and Backside Ceiling";
-			prefix = "(703)";
-			flags2048text = "[11] No physics";
-			flags4096text = "[12] Dynamic";
-			slope = "regular";
-			slopeargs = 9;
-		}
-
-		704
-		{
-			title = "Slope Frontside Floor by 3 Tagged Vertex Things";
-			prefix = "(704)";
-			flags2048text = "[11] No physics";
-			flags4096text = "[12] Dynamic";
-			flags8192text = "[13] Use tag and offsets";
-			slope = "vertex";
-			slopeargs = 0;
-		}
-
-		705
-		{
-			title = "Slope Frontside Ceiling by 3 Tagged Vertex Things";
-			prefix = "(705)";
-			flags2048text = "[11] No physics";
-			flags4096text = "[12] Dynamic";
-			flags8192text = "[13] Use tag and offsets";
-			slope = "vertex";
-			slopeargs = 1;
-		}
-
-		710
-		{
-			title = "Slope Backside Floor";
-			prefix = "(710)";
-			flags2048text = "[11] No physics";
-			flags4096text = "[12] Dynamic";
-			slope = "regular";
-			slopeargs = 4;
-		}
-
-		711
-		{
-			title = "Slope Backside Ceiling";
-			prefix = "(711)";
-			flags2048text = "[11] No physics";
-			flags4096text = "[12] Dynamic";
-			slope = "regular";
-			slopeargs = 8;
-		}
-
-		712
-		{
-			title = "Slope Backside Floor and Ceiling";
-			prefix = "(712)";
-			flags2048text = "[11] No physics";
-			flags4096text = "[12] Dynamic";
-			slope = "regular";
-			slopeargs = 12;
-		}
-
-		713
-		{
-			title = "Slope Backside Floor and Frontside Ceiling";
-			prefix = "(713)";
-			flags2048text = "[11] No physics";
-			flags4096text = "[12] Dynamic";
-			slope = "regular";
-			slopeargs = 6;
-		}
-
-		714
-		{
-			title = "Slope Backside Floor by 3 Tagged Vertex Things";
-			prefix = "(714)";
-			flags2048text = "[11] No physics";
-			flags4096text = "[12] Dynamic";
-			flags8192text = "[13] Use tag and offsets";
-			slope = "vertex";
-			slopeargs = 2;
-		}
-
-		715
-		{
-			title = "Slope Backside Ceiling by 3 Tagged Vertex Things";
-			prefix = "(715)";
-			flags2048text = "[11] No physics";
-			flags4096text = "[12] Dynamic";
-			flags8192text = "[13] Use tag and offsets";
-			slope = "vertex";
-			slopeargs = 3;
-		}
-
-		720
-		{
-			title = "Copy Frontside Floor Slope from Line Tag";
-			prefix = "(720)";
-			slope = "copy";
-			slopeargs = 1;
-		}
-
-		721
-		{
-			title = "Copy Frontside Ceiling Slope from Line Tag";
-			prefix = "(721)";
-			slope = "copy";
-			slopeargs = 2;
-		}
-
-		722
-		{
-			title = "Copy Frontside Floor and Ceiling Slope from Line Tag";
-			prefix = "(722)";
-			slope = "copy";
-			slopeargs = 3;
-		}
-
-		799
-		{
-			title = "Set Tagged Dynamic Slope Vertex to Front Sector Height";
-			prefix = "(799)";
-		}
-	}
-
-	transwall
-	{
-		title = "Translucent Wall";
-
-		900
-		{
-			title = "90% Opaque";
-			prefix = "(900)";
-		}
-
-		901
-		{
-			title = "80% Opaque";
-			prefix = "(901)";
-		}
-
-		902
-		{
-			title = "70% Opaque";
-			prefix = "(902)";
-		}
-
-		903
-		{
-			title = "60% Opaque";
-			prefix = "(903)";
-		}
-
-		904
-		{
-			title = "50% Opaque";
-			prefix = "(904)";
-		}
-
-		905
-		{
-			title = "40% Opaque";
-			prefix = "(905)";
-		}
-
-		906
-		{
-			title = "30% Opaque";
-			prefix = "(906)";
-		}
-
-		907
-		{
-			title = "20% Opaque";
-			prefix = "(907)";
-		}
-
-		908
-		{
-			title = "10% Opaque";
-			prefix = "(908)";
-		}
-
-		909
-		{
-			title = "Fog Wall";
-			prefix = "(909)";
-		}
-	}
-}
-
-udmf
-{
-	misc
-	{
-		title = "Miscellaneous";
-
-		0
-		{
-			title = "None";
-			prefix = "(0)";
-		}
-	}
-}
\ No newline at end of file
diff --git a/extras/conf/Includes/SRB222_misc.cfg b/extras/conf/Includes/SRB222_misc.cfg
deleted file mode 100644
index ce23388b2362094d097ff3893a106e6664a0b255..0000000000000000000000000000000000000000
--- a/extras/conf/Includes/SRB222_misc.cfg
+++ /dev/null
@@ -1,726 +0,0 @@
-linedefflags
-{
-	1 = "[0] Impassable";
-	2 = "[1] Block Enemies";
-	4 = "[2] Double-Sided";
-	8 = "[3] Upper Unpegged";
-	16 = "[4] Lower Unpegged";
-	32 = "[5] Slope Skew (E1)";
-	64 = "[6] Not Climbable";
-	128 = "[7] No Midtexture Skew (E2)";
-	256 = "[8] Peg Midtexture (E3)";
-	512 = "[9] Solid Midtexture (E4)";
-	1024 = "[10] Repeat Midtexture (E5)";
-	2048 = "[11] Netgame Only";
-	4096 = "[12] No Netgame";
-	8192 = "[13] Effect 6";
-	16384 = "[14] Bouncy Wall";
-	32768 = "[15] Transfer Line";
-}
-
-
-// LINEDEF ACTIVATIONS
-// Make sure these are in order from lowest value to highest value
-linedefactivations
-{
-}
-
-
-// Linedef flags UDMF translation table
-// This is needed for copy/paste and prefabs to work properly
-// When the UDMF field name is prefixed with ! it is inverted
-linedefflagstranslation
-{
-	1 = "blocking";
-	2 = "blockmonsters";
-	4 = "twosided";
-	8 = "dontpegtop";
-	16 = "dontpegbottom";
-	32 = "skewtd";
-	64 = "noclimb";
-	128 = "noskew";
-	256 = "midpeg";
-	512 = "midsolid";
-	1024 = "wrapmidtex";
-	2048 = "netonly";
-	4096 = "nonet";
-	8192 = "effect6";
-	16384 = "bouncy";
-	32768 = "transfer";
-}
-
-
-linedefflags_udmf
-{
-	blocking = "Impassable";
-	blockmonsters = "Block Enemies";
-	twosided = "Double-Sided";
-	dontpegtop = "Upper Unpegged";
-	dontpegbottom = "Lower Unpegged";
-	skewtd = "Slope Skew";
-	noclimb = "Not Climbable";
-	noskew = "No Midtexture Skew";
-	midpeg = "Peg Midtexture";
-	midsolid = "Solid Midtexture";
-	wrapmidtex = "Repeat Midtexture";
-//	netonly = "Netgame-Only special";
-//	nonet = "No netgame special";
-//	effect6 = "Effect 6";
-	bouncy = "Bouncy Wall";
-//	transfer = "Transfer Line";
-}
-
-
-linedefactivations_udmf
-{
-	notriggerorder = "Out of Order";
-	netonly = "Netgame-Only";
-	nonet = "No netgame";
-}
-
-sidedefflags
-{
-	clipmidtex = "Clip middle texture";
-	wrapmidtex = "Wrap middle texture";
-	smoothlighting = "Smooth lighting";
-	nofakecontrast = "Even lighting";
-	nodecals = "No decals";
-	lightfog = "Use sidedef brightness on fogged walls";
-}
-
-//RENDER STYLES
-thingrenderstyles
-{
-}
-
-linedefrenderstyles
-{
-	translucent = "Translucent";
-	fog = "Fog";
-}
-
-sectorrenderstyles
-{
-}
-
-thingflags
-{
-	1 = "[1] Extra";
-	2 = "[2] Flip";
-	4 = "[4] Special";
-	8 = "[8] Ambush";
-}
-
-// THING FLAGS
-thingflags_udmf
-{
-	extra = "Extra";
-	flip = "Flip";
-	special = "Special";
-	ambush = "Ambush";
-}
-
-
-// Thing flags UDMF translation table
-// This is needed for copy/paste and prefabs to work properly
-// When the UDMF field name is prefixed with ! it is inverted
-thingflagstranslation
-{
-	1 = "extra";
-	2 = "flip";
-	4 = "special";
-	8 = "ambush";
-}
-
-
-// DEFAULT SECTOR BRIGHTNESS LEVELS
-sectorbrightness
-{
-	255;
-	248;
-	240;
-	232;
-	224;
-	216;
-	208;
-	200;
-	192;
-	184;
-	176;
-	168;
-	160;
-	152;
-	144;
-	136;
-	128;
-	120;
-	112;
-	104;
-	96;
-	88;
-	80;
-	72;
-	64;
-	56;
-	48;
-	40;
-	32;
-	24;
-	16;
-	8;
-	0;
-}
-
-/*
-TEXTURES AND FLAT SOURCES
-This tells Doom Builder where to find the information for textures
-and flats in the IWAD file, Addition WAD file and Map WAD file.
-
-Start and end lumps must be given in a structure (of which the
-key name doesnt matter) and any textures or flats in between them
-are loaded in either the textures category or flats category.
-
-For textures: PNAMES, TEXTURE1 and TEXTURE2 are loaded by default.
-*/
-textures
-{
-	zdoom1
-	{
-		start = "TX_START";
-		end = "TX_END";
-	}
-}
-
-/*
-ADDITIONAL UNIVERSAL DOOM MAP FORMAT FIELD DEFINITIONS
-Only add fields here that Doom Builder does not edit with its own user-interface!
-The "default" field must match the UDMF specifications!
-
-Field data types:
-0 = integer *
-1 = float
-2 = string
-3 = bool
-4 = linedef action (integer) *
-5 = sector effect (integer) *
-6 = texture (string)
-7 = flat (string)
-8 = angle in degrees (integer)
-9 = angle in radians (float)
-10 = XXRRGGBB color (integer)
-11 = enum option (integer) *
-12 = enum bits (integer) *
-13 = sector tag (integer) *
-14 = thing tag (integer) *
-15 = linedef tag (integer) *
-16 = enum option (string)
-17 = angle in degrees (float)
-22 = byte angle (integer)
-*/
-universalfields
-{
-	sector
-	{
-		friction
-		{
-			name = "Friction";
-			type = 1;
-			default = 1;
-		}
-
-		specialeffectplanes
-		{
-			type = 11;
-			enum = "floorceiling";
-			default = 0;
-		}
-
-		colormapbegin
-		{
-			type = 0;
-			default = 0;
-		}
-
-		colormapend
-		{
-			type = 0;
-			default = 33;
-		}
-
-		foglighting
-		{
-			type = 3;
-			default = false;
-		}
-
-		teambase
-		{
-			type = 11;
-			enum = "ctfteam";
-			default = 0;
-		}
-
-		triggersector
-		{
-			type = 3;
-			default = false;
-		}
-
-		triggerobject
-		{
-			type = 11;
-			enum = "triggerobjects";
-			default = 0;
-		}
-
-		triggersurface
-		{
-			type = 11;
-			enum = "triggersurfaces";
-			default = 0;
-		}
-
-		ringdrain
-		{
-			type = 1;
-			default = 0;
-		}
-	}
-
-	linedef
-	{
-		executordelay
-		{
-			type = 0;
-			default = 0;
-		}
-		midtexrepetitions
-		{
-			type = 0;
-			default = 0;
-		}
-		arg5
-		{
-			type = 0;
-			default = 0;
-		}
-		arg1str
-		{
-			type = 2;
-			default = "";
-		}
-	}
-
-	thing
-	{
-	}
-}
-
-/*
-MAP LUMP NAMES
-Map lumps are loaded with the map as long as they are right after each other. When the editor
-meets a lump which is not defined in this list it will ignore the map if not satisfied.
-The order of items defines the order in which lumps will be written to WAD file on save.
-To indicate the map header lump, use ~MAP
-
-Legenda:
-required = Lump is required to exist.
-blindcopy = Lump will be copied along with the map blindly. (useful for lumps Doom Builder doesn't use)
-nodebuild = The nodebuilder generates this lump.
-allowempty = The nodebuilder is allowed to leave this lump empty.
-scriptbuild = This lump is a text-based script, which should be compiled using current script compiler;
-script = This lump is a text-based script. Specify the filename of the script configuration to use.
-*/
-
-doommaplumpnames
-{
-	~MAP
-	{
-		required = true;
-		blindcopy = true;
-		nodebuild = false;
-	}
-
-	THINGS
-	{
-		required = true;
-		nodebuild = true;
-		allowempty = true;
-	}
-
-	LINEDEFS
-	{
-		required = true;
-		nodebuild = true;
-		allowempty = false;
-	}
-
-	SIDEDEFS
-	{
-		required = true;
-		nodebuild = true;
-		allowempty = false;
-	}
-
-	VERTEXES
-	{
-		required = true;
-		nodebuild = true;
-		allowempty = false;
-	}
-
-	SEGS
-	{
-		required = false;
-		nodebuild = true;
-		allowempty = false;
-	}
-
-	SSECTORS
-	{
-		required = false;
-		nodebuild = true;
-		allowempty = false;
-	}
-
-	NODES
-	{
-		required = false;
-		nodebuild = true;
-		allowempty = false;
-	}
-
-	SECTORS
-	{
-		required = true;
-		nodebuild = true;
-		allowempty = false;
-	}
-
-	REJECT
-	{
-		required = false;
-		nodebuild = true;
-		allowempty = false;
-	}
-
-	BLOCKMAP
-	{
-		required = false;
-		nodebuild = true;
-		allowempty = true;
-	}
-}
-
-udmfmaplumpnames
-{
-	ZNODES
-	{
-		required = false;
-		nodebuild = true;
-		allowempty = false;
-	}
-
-	REJECT
-	{
-		required = false;
-		nodebuild = true;
-		allowempty = false;
-	}
-
-	BLOCKMAP
-	{
-		required = false;
-		nodebuild = true;
-		allowempty = true;
-	}
-}
-
-// ENUMERATIONS
-// These are enumerated lists for linedef types and UDMF fields.
-// Reserved names are: angledeg, anglerad, color, texture, flat
-enums
-{
-	falsetrue
-	{
-		0 = "False";
-		1 = "True";
-	}
-
-	yesno
-	{
-		0 = "Yes";
-		1 = "No";
-	}
-
-	noyes
-	{
-		0 = "No";
-		1 = "Yes";
-	}
-
-	onoff
-	{
-		0 = "On";
-		1 = "Off";
-	}
-
-	offon
-	{
-		0 = "Off";
-		1 = "On";
-	}
-
-	updown
-	{
-		0 = "Up";
-		1 = "Down";
-	}
-
-	downup
-	{
-		0 = "Down";
-		1 = "Up";
-	}
-
-	addset
-	{
-		0 = "Add";
-		1 = "Set";
-	}
-
-	floorceiling
-	{
-		0 = "Floor";
-		1 = "Ceiling";
-		2 = "Floor and ceiling";
-	}
-
-	triggertype
-	{
-		0 = "Continuous";
-		1 = "Each Time (Enter)";
-		2 = "Each Time (Enter and leave)";
-		3 = "Once";
-	}
-
-	frontback
-	{
-		0 = "None";
-		1 = "Front";
-		2 = "Back";
-	}
-
-	ctfteam
-	{
-		0 = "None";
-		1 = "Red";
-		2 = "Blue";
-	}
-
-	triggerobjects
-	{
-		0 = "Any player";
-		1 = "All players";
-		2 = "Pushable object";
-		3 = "Any object with thinker";
-	}
-
-	triggersurfaces
-	{
-		0 = "Floor touch";
-		1 = "Ceiling touch";
-		2 = "Floor or ceiling touch";
-		3 = "Anywhere in sector";
-	}
-
-	tangibility
-	{
-		1 = "Intangible from top";
-		2 = "Intangible from bottom";
-		4 = "Don't block players";
-		8 = "Don't block non-players";
-	}
-}
-
-//Default things filters
-thingsfilters
-{
-
-	filter0
-	{
-		name = "Player starts";
-		category = "starts";
-		type = -1;
-	}
-
-
-	filter1
-	{
-		name = "Enemies";
-		category = "enemies";
-		type = -1;
-
-	}
-
-
-	filter2
-	{
-		name = "NiGHTS Track";
-		category = "nightstrk";
-		type = -1;
-
-	}
-
-
-	filter3
-	{
-		name = "Normal Gravity";
-		category = "";
-		type = -1;
-
-		fields
-		{
-			2 = false;
-		}
-
-	}
-
-
-	filter4
-	{
-		name = "Reverse Gravity";
-		category = "";
-		type = -1;
-
-		fields
-		{
-			2 = true;
-		}
-
-	}
-}
-
-thingsfilters_udmf
-{
-}
-
-// Special linedefs
-speciallinedefs
-{
-	soundlinedefflag = 64;	// See linedefflags
-	singlesidedflag = 1;	// See linedefflags
-	doublesidedflag = 4;	// See linedefflags
-	impassableflag = 1;
-	upperunpeggedflag = 8;
-	lowerunpeggedflag = 16;
-	repeatmidtextureflag = 1024;
-	pegmidtextureflag = 256;
-}
-
-speciallinedefs_udmf
-{
-	soundlinedefflag = "noclimb";
-	singlesidedflag = "blocking";
-	doublesidedflag = "twosided";
-	impassableflag = "blocking";
-	upperunpeggedflag = "dontpegtop";
-	lowerunpeggedflag = "dontpegbottom";
-	repeatmidtextureflag = "wrapmidtex";
-	pegmidtextureflag = "midpeg";
-}
-
-scriptlumpnames
-{
-	MAINCFG
-	{
-		script = "SOC.cfg";
-	}
-
-	OBJCTCFG
-	{
-		script = "SOC.cfg";
-	}
-
-	SOC_
-	{
-		script = "SOC.cfg";
-		isprefix = true;
-	}
-
-	LUA_
-	{
-		script = "Lua.cfg";
-		isprefix = true;
-	}
-}
-
-// Texture sources
-textures
-{
-	zdoom1
-	{
-		start = "TX_START";
-		end = "TX_END";
-	}
-}
-
-// Patch sources
-patches
-{
-	standard1
-	{
-		start = "P_START";
-		end = "P_END";
-	}
-
-	standard2
-	{
-		start = "PP_START";
-		end = "PP_END";
-	}
-}
-
-// Sprite sources
-sprites
-{
-	standard1
-	{
-		start = "S_START";
-		end = "S_END";
-	}
-
-	standard2
-	{
-		start = "SS_START";
-		end = "SS_END";
-	}
-}
-
-// Flat sources
-flats
-{
-	standard1
-	{
-		start = "F_START";
-		end = "F_END";
-	}
-
-	standard2
-	{
-		start = "FF_START";
-		end = "FF_END";
-	}
-
-	standard3
-	{
-		start = "FF_START";
-		end = "F_END";
-	}
-
-	standard4
-	{
-		start = "F_START";
-		end = "FF_END";
-	}
-}
\ No newline at end of file
diff --git a/extras/conf/Includes/SRB222_sectors.cfg b/extras/conf/Includes/SRB222_sectors.cfg
deleted file mode 100644
index 3bcbeb1b14d8ac6466f79e888a5be7ef3aa9bc24..0000000000000000000000000000000000000000
--- a/extras/conf/Includes/SRB222_sectors.cfg
+++ /dev/null
@@ -1,109 +0,0 @@
-sectortypes
-{
-	0 = "Normal";
-	1 = "Damage";
-	2 = "Damage (Water)";
-	3 = "Damage (Fire)";
-	4 = "Damage (Electrical)";
-	5 = "Spikes";
-	6 = "Death Pit (Camera Tilt)";
-	7 = "Death Pit (No Camera Tilt)";
-	8 = "Instant Kill";
-	9 = "Ring Drainer (Floor Touch)";
-	10 = "Ring Drainer (Anywhere in Sector)";
-	11 = "Special Stage Damage";
-	12 = "Space Countdown";
-	13 = "Ramp Sector (double step-up/down)";
-	14 = "Non-Ramp Sector (no step-down)";
-	15 = "Bouncy FOF";
-	16 = "Trigger Line Ex. (Pushable Objects)";
-	32 = "Trigger Line Ex. (Anywhere, All Players)";
-	48 = "Trigger Line Ex. (Floor Touch, All Players)";
-	64 = "Trigger Line Ex. (Anywhere in Sector)";
-	80 = "Trigger Line Ex. (Floor Touch)";
-	96 = "Trigger Line Ex. (Emerald Check)";
-	112 = "Trigger Line Ex. (NiGHTS Mare)";
-	128 = "Check for Linedef Executor on FOFs";
-	144 = "Egg Capsule";
-	160 = "Special Stage Time/Rings Parameters";
-	176 = "Custom Global Gravity";
-	512 = "Wind/Current";
-	1024 = "Conveyor Belt";
-	1280 = "Speed Pad";
-	4096 = "Star Post Activator";
-	8192 = "Exit/Special Stage Pit/Return Flag";
-	12288 = "CTF Red Team Base";
-	16384 = "CTF Blue Team Base";
-	20480 = "Fan Sector";
-	24576 = "Super Sonic Transform";
-	28672 = "Force Spin";
-	32768 = "Zoom Tube Start";
-	36864 = "Zoom Tube End";
-	40960 = "Circuit Finish Line";
-	45056 = "Rope Hang";
-	49152 = "Intangible to the Camera";
-}
-
-gen_sectortypes
-{
-	first
-	{
-		0 = "Normal";
-		1 = "Damage";
-		2 = "Damage (Water)";
-		3 = "Damage (Fire)";
-		4 = "Damage (Electrical)";
-		5 = "Spikes";
-		6 = "Death Pit (Camera Tilt)";
-		7 = "Death Pit (No Camera Tilt)";
-		8 = "Instant Kill";
-		9 = "Ring Drainer (Floor Touch)";
-		10 = "Ring Drainer (Anywhere in Sector)";
-		11 = "Special Stage Damage";
-		12 = "Space Countdown";
-		13 = "Ramp Sector (double step-up/down)";
-		14 = "Non-Ramp Sector (no step-down)";
-		15 = "Bouncy FOF";
-	}
-
-	second
-	{
-		0 = "Normal";
-		16 = "Trigger Line Ex. (Pushable Objects)";
-		32 = "Trigger Line Ex. (Anywhere, All Players)";
-		48 = "Trigger Line Ex. (Floor Touch, All Players)";
-		64 = "Trigger Line Ex. (Anywhere in Sector)";
-		80 = "Trigger Line Ex. (Floor Touch)";
-		96 = "Trigger Line Ex. (Emerald Check)";
-		112 = "Trigger Line Ex. (NiGHTS Mare)";
-		128 = "Check for Linedef Executor on FOFs";
-		144 = "Egg Capsule";
-		160 = "Special Stage Time/Rings Parameters";
-		176 = "Custom Global Gravity";
-	}
-
-	third
-	{
-		0 = "Normal";
-		512 = "Wind/Current";
-		1024 = "Conveyor Belt";
-		1280 = "Speed Pad";
-	}
-
-	fourth
-	{
-		0 = "Normal";
-		4096 = "Star Post Activator";
-		8192 = "Exit/Special Stage Pit/Return Flag";
-		12288 = "CTF Red Team Base";
-		16384 = "CTF Blue Team Base";
-		20480 = "Fan Sector";
-		24576 = "Super Sonic Transform";
-		28672 = "Force Spin";
-		32768 = "Zoom Tube Start";
-		36864 = "Zoom Tube End";
-		40960 = "Circuit Finish Line";
-		45056 = "Rope Hang";
-		49152 = "Intangible to the Camera";
-	}
-}
\ No newline at end of file
diff --git a/extras/conf/Includes/SRB222_things.cfg b/extras/conf/Includes/SRB222_things.cfg
deleted file mode 100644
index 194e43630b70f5f98b6a3963b4b27371c85d2e02..0000000000000000000000000000000000000000
--- a/extras/conf/Includes/SRB222_things.cfg
+++ /dev/null
@@ -1,3398 +0,0 @@
-// THING TYPES------------------------------------------------------------------
-// Color values: 1-Dark_Blue 2-Dark_Green 3-Turqoise 4-Dark_Red 5-Purple 6-Brown 7-Gray
-// 8-Dark_Gray 9-Blue 10-Green 11-Cyan 12-Red 13-Magenta
-// 14-Yellow 15-White 16-Pink 17-Orange 18-Gold 19-Cream
-
-editor
-{
-	color = 15; // White
-	arrow = 1;
-	title = "<Editor Things>";
-	error = -1;
-	width = 8;
-	height = 16;
-	sort = 1;
-
-	3328 = "3D Mode Start";
-}
-
-starts
-{
-	color = 1; // Blue
-	arrow = 1;
-	title = "Player Starts";
-	width = 16;
-	height = 48;
-	flags8text = "[8] Spawn on ceiling";
-	sprite = "PLAYA0";
-
-	1
-	{
-		title = "Player 01 Start";
-		sprite = "PLAYA0";
-	}
-	2
-	{
-		title = "Player 02 Start";
-		sprite = "PLAYA0";
-	}
-	3
-	{
-		title = "Player 03 Start";
-		sprite = "PLAYA0";
-	}
-	4
-	{
-		title = "Player 04 Start";
-		sprite = "PLAYA0";
-	}
-	5
-	{
-		title = "Player 05 Start";
-		sprite = "PLAYA0";
-	}
-	6
-	{
-		title = "Player 06 Start";
-		sprite = "PLAYA0";
-	}
-	7
-	{
-		title = "Player 07 Start";
-		sprite = "PLAYA0";
-	}
-	8
-	{
-		title = "Player 08 Start";
-		sprite = "PLAYA0";
-	}
-	9
-	{
-		title = "Player 09 Start";
-		sprite = "PLAYA0";
-	}
-	10
-	{
-		title = "Player 10 Start";
-		sprite = "PLAYA0";
-	}
-	11
-	{
-		title = "Player 11 Start";
-		sprite = "PLAYA0";
-	}
-	12
-	{
-		title = "Player 12 Start";
-		sprite = "PLAYA0";
-	}
-	13
-	{
-		title = "Player 13 Start";
-		sprite = "PLAYA0";
-	}
-	14
-	{
-		title = "Player 14 Start";
-		sprite = "PLAYA0";
-	}
-	15
-	{
-		title = "Player 15 Start";
-		sprite = "PLAYA0";
-	}
-	16
-	{
-		title = "Player 16 Start";
-		sprite = "PLAYA0";
-	}
-	17
-	{
-		title = "Player 17 Start";
-		sprite = "PLAYA0";
-	}
-	18
-	{
-		title = "Player 18 Start";
-		sprite = "PLAYA0";
-	}
-	19
-	{
-		title = "Player 19 Start";
-		sprite = "PLAYA0";
-	}
-	20
-	{
-		title = "Player 20 Start";
-		sprite = "PLAYA0";
-	}
-	21
-	{
-		title = "Player 21 Start";
-		sprite = "PLAYA0";
-	}
-	22
-	{
-		title = "Player 22 Start";
-		sprite = "PLAYA0";
-	}
-	23
-	{
-		title = "Player 23 Start";
-		sprite = "PLAYA0";
-	}
-	24
-	{
-		title = "Player 24 Start";
-		sprite = "PLAYA0";
-	}
-	25
-	{
-		title = "Player 25 Start";
-		sprite = "PLAYA0";
-	}
-	26
-	{
-		title = "Player 26 Start";
-		sprite = "PLAYA0";
-	}
-	27
-	{
-		title = "Player 27 Start";
-		sprite = "PLAYA0";
-	}
-	28
-	{
-		title = "Player 28 Start";
-		sprite = "PLAYA0";
-	}
-	29
-	{
-		title = "Player 29 Start";
-		sprite = "PLAYA0";
-	}
-	30
-	{
-		title = "Player 30 Start";
-		sprite = "PLAYA0";
-	}
-	31
-	{
-		title = "Player 31 Start";
-		sprite = "PLAYA0";
-	}
-	32
-	{
-		title = "Player 32 Start";
-		sprite = "PLAYA0";
-	}
-	33
-	{
-		title = "Match Start";
-		sprite = "NDRNA2A8";
-	}
-	34
-	{
-		title = "CTF Red Team Start";
-		sprite = "SIGNG0";
-	}
-	35
-	{
-		title = "CTF Blue Team Start";
-		sprite = "SIGNE0";
-	}
-}
-
-enemies
-{
-	color = 9; // Light_Blue
-	arrow = 1;
-	title = "Enemies";
-
-	100
-	{
-		title = "Crawla (Blue)";
-		sprite = "POSSA1";
-		width = 24;
-		height = 32;
-	}
-	101
-	{
-		title = "Crawla (Red)";
-		sprite = "SPOSA1";
-		width = 24;
-		height = 32;
-	}
-	102
-	{
-		title = "Stupid Dumb Unnamed RoboFish";
-		sprite = "FISHA0";
-		width = 8;
-		height = 28;
-		angletext = "Jump strength";
-	}
-	103
-	{
-		title = "Buzz (Gold)";
-		sprite = "BUZZA1";
-		width = 28;
-		height = 40;
-		flags8text = "[8] Cannot move";
-	}
-	104
-	{
-		title = "Buzz (Red)";
-		sprite = "RBUZA1";
-		width = 28;
-		height = 40;
-		flags8text = "[8] Cannot move";
-	}
-	108
-	{
-		title = "Deton";
-		sprite = "DETNA1";
-		width = 20;
-		height = 32;
-	}
-	110
-	{
-		title = "Turret";
-		sprite = "TRETA1";
-		width = 16;
-		height = 32;
-	}
-	111
-	{
-		title = "Pop-up Turret";
-		sprite = "TURRI1";
-		width = 12;
-		height = 64;
-		angletext = "Firing delay";
-	}
-	122
-	{
-		title = "Spring Shell (Green)";
-		sprite = "SSHLA1";
-		width = 24;
-		height = 40;
-	}
-	125
-	{
-		title = "Spring Shell (Yellow)";
-		sprite = "SSHLI1";
-		width = 24;
-		height = 40;
-	}
-	109
-	{
-		title = "Skim";
-		sprite = "SKIMA1";
-		width = 16;
-		height = 24;
-	}
-	113
-	{
-		title = "Jet Jaw";
-		sprite = "JJAWA3A7";
-		width = 12;
-		height = 20;
-	}
-	126
-	{
-		title = "Crushstacean";
-		sprite = "CRABA0";
-		width = 24;
-		height = 32;
-		flags8text = "[8] Move left from spawn";
-	}
-	138
-	{
-		title = "Banpyura";
-		sprite = "CR2BA0";
-		width = 24;
-		height = 32;
-		flags8text = "[8] Move left from spawn";
-	}
-	117
-	{
-		title = "Robo-Hood";
-		sprite = "ARCHA1";
-		width = 24;
-		height = 32;
-	}
-	118
-	{
-		title = "Lance-a-Bot";
-		sprite = "CBFSA1";
-		width = 32;
-		height = 72;
-	}
-	1113
-	{
-		title = "Suspicious Lance-a-Bot Statue";
-		sprite = "CBBSA1";
-		width = 32;
-		height = 72;
-	}
-	119
-	{
-		title = "Egg Guard";
-		sprite = "ESHIA1";
-		width = 16;
-		height = 48;
-		flags1text = "[1] 90 degrees counter-clockwise";
-		flags4text = "[4] 90 degrees clockwise";
-		flags8text = "[8] Double speed";
-	}
-	115
-	{
-		title = "Bird Aircraft Strike Hazard";
-		sprite = "VLTRF1";
-		width = 12;
-		height = 24;
-	}
-	120
-	{
-		title = "Green Snapper";
-		sprite = "GSNPA1";
-		width = 24;
-		height = 24;
-	}
-	121
-	{
-		title = "Minus";
-		sprite = "MNUSA0";
-		width = 24;
-		height = 32;
-	}
-	134
-	{
-		title = "Canarivore";
-		sprite = "CANAA0";
-		width = 12;
-		height = 80;
-		hangs = 1;
-	}
-	123
-	{
-		title = "Unidus";
-		sprite = "UNIDA1";
-		width = 18;
-		height = 36;
-	}
-	135
-	{
-		title = "Pterabyte Spawner";
-		sprite = "PTERA2A8";
-		width = 16;
-		height = 16;
-		parametertext = "No. Pterabytes";
-	}
-	136
-	{
-		title = "Pyre Fly";
-		sprite = "PYREA0";
-		width = 24;
-		height = 34;
-		flags8text = "[8] Start on fire";
-	}
-	137
-	{
-		title = "Dragonbomber";
-		sprite = "DRABA1";
-		width = 28;
-		height = 48;
-	}
-	105
-	{
-		title = "Jetty-Syn Bomber";
-		sprite = "JETBB1";
-		width = 20;
-		height = 50;
-		flags8text = "[8] Cannot move";
-	}
-	106
-	{
-		title = "Jetty-Syn Gunner";
-		sprite = "JETGB1";
-		width = 20;
-		height = 48;
-		flags8text = "[8] Cannot move";
-	}
-	112
-	{
-		title = "Spincushion";
-		sprite = "SHRPA1";
-		width = 16;
-		height = 24;
-	}
-	114
-	{
-		title = "Snailer";
-		sprite = "SNLRA3A7";
-		width = 24;
-		height = 48;
-	}
-	129
-	{
-		title = "Penguinator";
-		sprite = "PENGA1";
-		width = 24;
-		height = 32;
-	}
-	130
-	{
-		title = "Pophat";
-		sprite = "POPHA1";
-		width = 24;
-		height = 32;
-	}
-	107
-	{
-		title = "Crawla Commander";
-		sprite = "CCOMA1";
-		width = 16;
-		height = 32;
-	}
-	131
-	{
-		title = "Spinbobert";
-		sprite = "SBOBB0";
-		width = 32;
-		height = 32;
-	}
-	132
-	{
-		title = "Cacolantern";
-		sprite = "CACOA0";
-		width = 32;
-		height = 32;
-		flags8text = "[8] Cannot move";
-	}
-	133
-	{
-		title = "Hangster";
-		sprite = "HBATC1";
-		width = 24;
-		height = 24;
-		hangs = 1;
-	}
-	127
-	{
-		title = "Hive Elemental";
-		sprite = "HIVEA0";
-		width = 32;
-		height = 80;
-		parametertext = "No. bees";
-	}
-	128
-	{
-		title = "Bumblebore";
-		sprite = "BUMBA1";
-		width = 16;
-		height = 32;
-	}
-	124
-	{
-		title = "Buggle";
-		sprite = "BBUZA1";
-		width = 20;
-		height = 24;
-	}
-	116
-	{
-		title = "Pointy";
-		sprite = "PNTYA1";
-		width = 8;
-		height = 16;
-	}
-}
-
-bosses
-{
-	color = 8; // Dark_Gray
-	arrow = 1;
-	title = "Bosses";
-
-	200
-	{
-		title = "Egg Mobile";
-		sprite = "EGGMA1";
-		width = 24;
-		height = 76;
-		flags4text = "[4] End level on death";
-		flags8text = "[8] Alternate laser attack";
-	}
-	201
-	{
-		title = "Egg Slimer";
-		sprite = "EGGNA1";
-		width = 24;
-		height = 76;
-		flags4text = "[4] End level on death";
-		flags8text = "[8] Speed up when hit";
-	}
-	202
-	{
-		title = "Sea Egg";
-		sprite = "EGGOA1";
-		width = 32;
-		height = 116;
-		flags4text = "[4] End level on death";
-	}
-	203
-	{
-		title = "Egg Colosseum";
-		sprite = "EGGPA1";
-		width = 24;
-		height = 76;
-		flags4text = "[4] End level on death";
-	}
-	204
-	{
-		title = "Fang";
-		sprite = "FANGA1";
-		width = 24;
-		height = 60;
-		flags1text = "[1] Grayscale mode";
-		flags4text = "[4] End level on death";
-	}
-	206
-	{
-		title = "Brak Eggman (Old)";
-		sprite = "BRAKB1";
-		width = 48;
-		height = 160;
-		flags4text = "[4] End level on death";
-	}
-	207
-	{
-		title = "Metal Sonic (Race)";
-		sprite = "METLI1";
-		width = 16;
-		height = 48;
-		flags1text = "[1] Grayscale mode";
-	}
-	208
-	{
-		title = "Metal Sonic (Battle)";
-		sprite = "METLC1";
-		width = 16;
-		height = 48;
-		flags1text = "[1] Grayscale mode";
-		flags4text = "[4] End level on death";
-	}
-	209
-	{
-		title = "Brak Eggman";
-		sprite = "BRAK01";
-		width = 48;
-		height = 160;
-		flags1text = "[1] No origin-fling death";
-		flags4text = "[4] End level on death";
-		flags8text = "[8] Electric barrier";
-	}
-	290
-	{
-		arrow = 0;
-		title = "Boss Escape Point";
-		width = 8;
-		height = 16;
-		sprite = "internal:eggmanend";
-	}
-	291
-	{
-		arrow = 0;
-		title = "Egg Capsule Center";
-		width = 8;
-		height = 16;
-		sprite = "internal:capsule";
-	}
-	292
-	{
-		arrow = 0;
-		title = "Boss Waypoint";
-		width = 8;
-		height = 16;
-		flags8text = "[8] Sea Egg shooting point";
-		sprite = "internal:eggmanway";
-		angletext = "No. (Sea Egg)";
-		flagsvaluetext = "No. (Brak)";
-		parametertext = "Next";
-	}
-	293
-	{
-		title = "Metal Sonic Gather Point";
-		sprite = "internal:metal";
-		width = 8;
-		height = 16;
-	}
-	294
-	{
-		title = "Fang Waypoint";
-		flags8text = "[8] Center waypoint";
-		sprite = "internal:eggmanway";
-		width = 8;
-		height = 16;
-	}
-}
-
-rings
-{
-	color = 14; // Yellow
-	title = "Rings and Weapon Panels";
-	width = 24;
-	height = 24;
-	flags8height = 24;
-	flags8text = "[8] Float";
-	sprite = "RINGA0";
-
-	300
-	{
-		title = "Ring";
-		sprite = "RINGA0";
-		width = 16;
-	}
-	301
-	{
-		title = "Bounce Ring";
-		sprite = "internal:RNGBA0";
-	}
-	302
-	{
-		title = "Rail Ring";
-		sprite = "internal:RNGRA0";
-	}
-	303
-	{
-		title = "Infinity Ring";
-		sprite = "internal:RNGIA0";
-	}
-	304
-	{
-		title = "Automatic Ring";
-		sprite = "internal:RNGAA0";
-	}
-	305
-	{
-		title = "Explosion Ring";
-		sprite = "internal:RNGEA0";
-	}
-	306
-	{
-		title = "Scatter Ring";
-		sprite = "internal:RNGSA0";
-	}
-	307
-	{
-		title = "Grenade Ring";
-		sprite = "internal:RNGGA0";
-	}
-	308
-	{
-		title = "CTF Team Ring (Red)";
-		sprite = "internal:RRNGA0";
-		width = 16;
-	}
-	309
-	{
-		title = "CTF Team Ring (Blue)";
-		sprite = "internal:BRNGA0";
-		width = 16;
-	}
-	330
-	{
-		title = "Bounce Ring Panel";
-		sprite = "internal:PIKBA0";
-	}
-	331
-	{
-		title = "Rail Ring Panel";
-		sprite = "internal:PIKRA0";
-	}
-	332
-	{
-		title = "Automatic Ring Panel";
-		sprite = "internal:PIKAA0";
-	}
-	333
-	{
-		title = "Explosion Ring Panel";
-		sprite = "internal:PIKEA0";
-	}
-	334
-	{
-		title = "Scatter Ring Panel";
-		sprite = "internal:PIKSA0";
-	}
-	335
-	{
-		title = "Grenade Ring Panel";
-		sprite = "internal:PIKGA0";
-	}
-}
-
-collectibles
-{
-	color = 10; // Light_Green
-	title = "Other Collectibles";
-	width = 16;
-	height = 32;
-	sort = 1;
-	sprite = "CEMGA0";
-
-	310
-	{
-		title = "CTF Red Flag";
-		sprite = "RFLGA0";
-		width = 24;
-		height = 64;
-	}
-	311
-	{
-		title = "CTF Blue Flag";
-		sprite = "BFLGA0";
-		width = 24;
-		height = 64;
-	}
-	312
-	{
-		title = "Emerald Token";
-		sprite = "TOKEA0";
-		width = 16;
-		height = 32;
-		flags8height = 24;
-		flags8text = "[8] Float";
-	}
-	313
-	{
-		title = "Chaos Emerald 1 (Green)";
-		sprite = "CEMGA0";
-	}
-	314
-	{
-		title = "Chaos Emerald 2 (Purple)";
-		sprite = "CEMGB0";
-	}
-	315
-	{
-		title = "Chaos Emerald 3 (Blue)";
-		sprite = "CEMGC0";
-	}
-	316
-	{
-		title = "Chaos Emerald 4 (Cyan)";
-		sprite = "CEMGD0";
-	}
-	317
-	{
-		title = "Chaos Emerald 5 (Orange)";
-		sprite = "CEMGE0";
-	}
-	318
-	{
-		title = "Chaos Emerald 6 (Red)";
-		sprite = "CEMGF0";
-	}
-	319
-	{
-		title = "Chaos Emerald 7 (Gray)";
-		sprite = "CEMGG0";
-	}
-	320
-	{
-		title = "Emerald Hunt Location";
-		sprite = "SHRDA0";
-	}
-	321
-	{
-		title = "Match Chaos Emerald Spawn";
-		sprite = "CEMGA0";
-		flags8height = 24;
-		flags8text = "[8] Float";
-	}
-	322
-	{
-		title = "Emblem";
-		sprite = "EMBMA0";
-		width = 16;
-		height = 30;
-		flags8height = 24;
-		flags8text = "[8] Float";
-		angletext = "Tag";
-	}
-}
-
-boxes
-{
-	color = 7; // Gray
-	blocking = 2;
-	title = "Monitors";
-	width = 18;
-	height = 40;
-	flags1text = "[1] Run Linedef Executor on pop";
-	flags4text = "[4] Random (Strong)";
-	flags8text = "[8] Random (Weak)";
-
-	400
-	{
-		title = "Super Ring (10 Rings)";
-		sprite = "TVRIA0";
-	}
-	401
-	{
-		title = "Pity Shield";
-		sprite = "TVPIA0";
-	}
-	402
-	{
-		title = "Attraction Shield";
-		sprite = "TVATA0";
-	}
-	403
-	{
-		title = "Force Shield";
-		sprite = "TVFOA0";
-	}
-	404
-	{
-		title = "Armageddon Shield";
-		sprite = "TVARA0";
-	}
-	405
-	{
-		title = "Whirlwind Shield";
-		sprite = "TVWWA0";
-	}
-	406
-	{
-		title = "Elemental Shield";
-		sprite = "TVELA0";
-	}
-	407
-	{
-		title = "Super Sneakers";
-		sprite = "TVSSA0";
-	}
-	408
-	{
-		title = "Invincibility";
-		sprite = "TVIVA0";
-	}
-	409
-	{
-		title = "Extra Life";
-		sprite = "TV1UA0";
-		flags4text = "[4] Random (Strong) / 10k points";
-		flags8text = "[8] Random (Weak) / 10k points";
-	}
-	410
-	{
-		title = "Eggman";
-		sprite = "TVEGA0";
-		flags4text = "[4] Special";
-		flags8text = "[8] Ambush";
-	}
-	411
-	{
-		title = "Teleporter";
-		sprite = "TVMXA0";
-	}
-	413
-	{
-		title = "Gravity Boots";
-		sprite = "TVGVA0";
-		flags4text = "[4] Special";
-		flags8text = "[8] Ambush";
-	}
-	414
-	{
-		title = "CTF Team Ring Monitor (Red)";
-		sprite = "TRRIA0";
-		flags4text = "[4] Special";
-		flags8text = "[8] Ambush";
-	}
-	415
-	{
-		title = "CTF Team Ring Monitor (Blue)";
-		sprite = "TBRIA0";
-		flags4text = "[4] Special";
-		flags8text = "[8] Ambush";
-	}
-	416
-	{
-		title = "Recycler";
-		sprite = "TVRCA0";
-	}
-	418
-	{
-		title = "Score (1,000 Points)";
-		sprite = "TV1KA0";
-		flags4text = "[4] Special";
-		flags8text = "[8] Ambush";
-	}
-	419
-	{
-		title = "Score (10,000 Points)";
-		sprite = "TVTKA0";
-		flags4text = "[4] Special";
-		flags8text = "[8] Ambush";
-	}
-	420
-	{
-		title = "Flame Shield";
-		sprite = "TVFLA0";
-	}
-	421
-	{
-		title = "Water Shield";
-		sprite = "TVBBA0";
-	}
-	422
-	{
-		title = "Lightning Shield";
-		sprite = "TVZPA0";
-	}
-}
-
-boxes2
-{
-	color = 18; // Gold
-	blocking = 2;
-	title = "Monitors (Respawning)";
-	width = 20;
-	height = 44;
-	flags1text = "[1] Run Linedef Executor on pop";
-
-	431
-	{
-		title = "Pity Shield (Respawn)";
-		sprite = "TVPIB0";
-	}
-	432
-	{
-		title = "Attraction Shield (Respawn)";
-		sprite = "TVATB0";
-	}
-	433
-	{
-		title = "Force Shield (Respawn)";
-		sprite = "TVFOB0";
-	}
-	434
-	{
-		title = "Armageddon Shield (Respawn)";
-		sprite = "TVARB0";
-	}
-	435
-	{
-		title = "Whirlwind Shield (Respawn)";
-		sprite = "TVWWB0";
-	}
-	436
-	{
-		title = "Elemental Shield (Respawn)";
-		sprite = "TVELB0";
-	}
-	437
-	{
-		title = "Super Sneakers (Respawn)";
-		sprite = "TVSSB0";
-	}
-	438
-	{
-		title = "Invincibility (Respawn)";
-		sprite = "TVIVB0";
-	}
-	440
-	{
-		title = "Eggman (Respawn)";
-		sprite = "TVEGB0";
-	}
-	443
-	{
-		title = "Gravity Boots (Respawn)";
-		sprite = "TVGVB0";
-	}
-	450
-	{
-		title = "Flame Shield (Respawn)";
-		sprite = "TVFLB0";
-	}
-	451
-	{
-		title = "Water Shield (Respawn)";
-		sprite = "TVBBB0";
-	}
-	452
-	{
-		title = "Lightning Shield (Respawn)";
-		sprite = "TVZPB0";
-	}
-}
-
-generic
-{
-	color = 11; // Light_Cyan
-	title = "Generic Items & Hazards";
-
-	500
-	{
-		title = "Air Bubble Patch";
-		sprite = "BUBLE0";
-		width = 8;
-		height = 16;
-		flags8text = "[8] No distance check";
-	}
-	501
-	{
-		title = "Signpost";
-		sprite = "SIGND0";
-		width = 8;
-		height = 32;
-	}
-	502
-	{
-		arrow = 1;
-		title = "Star Post";
-		sprite = "STPTA0M0";
-		width = 64;
-		height = 128;
-		angletext = "Angle/Order";
-	}
-	520
-	{
-		title = "Bomb Sphere";
-		sprite = "SPHRD0";
-		width = 16;
-		height = 24;
-		flags8height = 24;
-		flags8text = "[8] Float";
-		unflippable = true;
-	}
-	521
-	{
-		title = "Spikeball";
-		sprite = "SPIKA0";
-		width = 12;
-		height = 8;
-		flags8height = 24;
-		flags8text = "[8] Float";
-	}
-	522
-	{
-		title = "Wall Spike";
-		sprite = "WSPKALAR";
-		width = 16;
-		height = 14;
-		flags1text = "[1] Start retracted";
-		flags4text = "[4] Retractable";
-		flags8text = "[8] Intangible";
-		parametertext = "Initial delay";
-	}
-	523
-	{
-		title = "Spike";
-		sprite = "USPKA0";
-		width = 8;
-		height = 32;
-		flags1text = "[1] Start retracted";
-		flags4text = "[4] Retractable";
-		flags8text = "[8] Intangible";
-		angletext = "Retraction interval";
-		parametertext = "Initial delay";
-	}
-	1130
-	{
-		title = "Small Mace";
-		sprite = "SMCEA0";
-		width = 17;
-		height = 34;
-	}
-	1131
-	{
-		title = "Big Mace";
-		sprite = "BMCEA0";
-		width = 34;
-		height = 68;
-	}
-	1136
-	{
-		title = "Small Fireball";
-		sprite = "SFBRA0";
-		width = 17;
-		height = 34;
-	}
-	1137
-	{
-		title = "Large Fireball";
-		sprite = "BFBRA0";
-		width = 34;
-		height = 68;
-	}
-}
-
-springs
-{
-	color = 12; // Light_Red
-	title = "Springs and Fans";
-	width = 20;
-	height = 16;
-	sprite = "RSPRD2";
-
-	540
-	{
-		title = "Fan";
-		sprite = "FANSA0D0";
-		width = 16;
-		height = 8;
-		flags4text = "[4] Invisible";
-		flags8text = "[8] No distance check";
-		angletext = "Lift height";
-	}
-	541
-	{
-		title = "Gas Jet";
-		sprite = "STEMD0";
-		flags8text = "[8] No sounds";
-		width = 32;
-	}
-	542
-	{
-		title = "Bumper";
-		sprite = "BUMPA0";
-		width = 32;
-		height = 64;
-		angletext = "Strength";
-	}
-	543
-	{
-		title = "Balloon";
-		sprite = "BLONA0";
-		width = 32;
-		height = 64;
-		flags8text = "[8] Respawn";
-		angletext = "Color";
-	}
-	550
-	{
-		title = "Yellow Spring";
-		sprite = "SPRYA0";
-	}
-	551
-	{
-		title = "Red Spring";
-		sprite = "SPRRA0";
-	}
-	552
-	{
-		title = "Blue Spring";
-		sprite = "SPRBA0";
-	}
-	555
-	{
-		arrow = 1;
-		title = "Diagonal Yellow Spring";
-		sprite = "YSPRD2";
-		width = 16;
-		flags4text = "[4] Ignore gravity";
-		flags8text = "[8] Rotate 22.5° CCW";
-	}
-	556
-	{
-		arrow = 1;
-		title = "Diagonal Red Spring";
-		sprite = "RSPRD2";
-		width = 16;
-		flags4text = "[4] Ignore gravity";
-		flags8text = "[8] Rotate 22.5° CCW";
-	}
-	557
-	{
-		arrow = 1;
-		title = "Diagonal Blue Spring";
-		sprite = "BSPRD2";
-		width = 16;
-		flags4text = "[4] Ignore gravity";
-		flags8text = "[8] Rotate 22.5° CCW";
-	}
-	558
-	{
-		arrow = 1;
-		title = "Horizontal Yellow Spring";
-		sprite = "SSWYD2D8";
-		flags8height = 16;
-		flags8text = "[8] Float";
-		width = 16;
-		height = 32;
-	}
-	559
-	{
-		arrow = 1;
-		title = "Horizontal Red Spring";
-		sprite = "SSWRD2D8";
-		flags8height = 16;
-		flags8text = "[8] Float";
-		width = 16;
-		height = 32;
-	}
-	560
-	{
-		arrow = 1;
-		title = "Horizontal Blue Spring";
-		sprite = "SSWBD2D8";
-		flags8height = 16;
-		flags8text = "[8] Float";
-		width = 16;
-		height = 32;
-	}
-	1134
-	{
-		title = "Yellow Spring Ball";
-		sprite = "YSPBA0";
-		width = 17;
-		height = 34;
-	}
-	1135
-	{
-		title = "Red Spring Ball";
-		sprite = "RSPBA0";
-		width = 17;
-		height = 34;
-	}
-	544
-	{
-		arrow = 1;
-		title = "Yellow Boost Panel";
-		sprite = "BSTYA0";
-		flags8text = "[8] Force spin";
-		width = 28;
-		height = 2;
-	}
-	545
-	{
-		arrow = 1;
-		title = "Red Boost Panel";
-		sprite = "BSTRA0";
-		flags8text = "[8] Force spin";
-		width = 28;
-		height = 2;
-	}
-}
-
-patterns
-{
-	color = 5; // Magenta
-	arrow = 1;
-	title = "Special Placement Patterns";
-	width = 16;
-	height = 384;
-	sprite = "RINGA0";
-
-	600
-	{
-		arrow = 0;
-		title = "5 Vertical Rings (Yellow Spring)";
-		sprite = "RINGA0";
-	}
-	601
-	{
-		arrow = 0;
-		title = "5 Vertical Rings (Red Spring)";
-		sprite = "RINGA0";
-		height = 1024;
-	}
-	602
-	{
-		title = "5 Diagonal Rings (Yellow Spring)";
-		sprite = "RINGA0";
-		height = 32;
-	}
-	603
-	{
-		title = "10 Diagonal Rings (Red Spring)";
-		sprite = "RINGA0";
-		height = 32;
-	}
-	604
-	{
-		title = "Circle of Rings";
-		sprite = "RINGA0";
-		width = 96;
-		height = 192;
-		unflippable = true;
-		centerHitbox = true;
-	}
-	605
-	{
-		title = "Circle of Rings (Big)";
-		sprite = "RINGA0";
-		width = 192;
-		unflippable = true;
-		centerHitbox = true;
-	}
-	606
-	{
-		title = "Circle of Blue Spheres";
-		sprite = "SPHRA0";
-		width = 96;
-		height = 192;
-		unflippable = true;
-		centerHitbox = true;
-	}
-	607
-	{
-		title = "Circle of Blue Spheres (Big)";
-		sprite = "SPHRA0";
-		width = 192;
-		unflippable = true;
-		centerHitbox = true;
-	}
-	608
-	{
-		title = "Circle of Rings and Spheres";
-		sprite = "SPHRA0";
-		width = 96;
-		height = 192;
-		unflippable = true;
-		centerHitbox = true;
-	}
-	609
-	{
-		title = "Circle of Rings and Spheres (Big)";
-		sprite = "SPHRA0";
-		width = 192;
-		unflippable = true;
-		centerHitbox = true;
-	}
-}
-
-invisible
-{
-	color = 15; // White
-	title = "Misc. Invisible";
-	width = 0;
-	height = 0;
-	sprite = "UNKNA0";
-	sort = 1;
-	fixedsize = true;
-	blocking = 0;
-
-	700
-	{
-		title = "Water Ambience A (Large)";
-		sprite = "internal:ambiance";
-	}
-
-	701
-	{
-		title = "Water Ambience B (Large)";
-		sprite = "internal:ambiance";
-	}
-
-	702
-	{
-		title = "Water Ambience C (Medium)";
-		sprite = "internal:ambiance";
-	}
-
-	703
-	{
-		title = "Water Ambience D (Medium)";
-		sprite = "internal:ambiance";
-	}
-
-	704
-	{
-		title = "Water Ambience E (Small)";
-		sprite = "internal:ambiance";
-	}
-
-	705
-	{
-		title = "Water Ambience F (Small)";
-		sprite = "internal:ambiance";
-	}
-
-	706
-	{
-		title = "Water Ambience G (Extra Large)";
-		sprite = "internal:ambiance";
-	}
-
-	707
-	{
-		title = "Water Ambience H (Extra Large)";
-		sprite = "internal:ambiance";
-	}
-
-	708
-	{
-		title = "Disco Ambience";
-		sprite = "internal:ambiance";
-	}
-
-	709
-	{
-		title = "Volcano Ambience";
-		sprite = "internal:ambiance";
-	}
-
-	710
-	{
-		title = "Machine Ambience";
-		sprite = "internal:ambiance";
-	}
-
-	750
-	{
-		title = "Slope Vertex";
-		sprite = "internal:vertexslope";
-		angletext = "Tag";
-	}
-
-	751
-	{
-		arrow = 1;
-		title = "Teleport Destination";
-		sprite = "internal:tele";
-	}
-
-	752
-	{
-		arrow = 1;
-		title = "Alternate View Point";
-		sprite = "internal:view";
-	}
-
-	753
-	{
-		title = "Zoom Tube Waypoint";
-		sprite = "internal:zoom";
-		angletext = "Order";
-	}
-
-	754
-	{
-		title = "Push Point";
-		flags4text = "[4] Fades using XY";
-		flags8text = "[8] Push using XYZ";
-		sprite = "GWLGA0";
-		angletext = "Radius";
-	}
-	755
-	{
-		title = "Pull Point";
-		flags4text = "[4] Fades using XY";
-		flags8text = "[8] Pull using XYZ";
-		sprite = "GWLRA0";
-		angletext = "Radius";
-	}
-	756
-	{
-		title = "Blast Linedef Executor";
-		sprite = "TOADA0";
-		width = 32;
-		height = 16;
-	}
-	757
-	{
-		title = "Fan Particle Generator";
-		sprite = "PRTLA0";
-		width = 8;
-		height = 16;
-		angletext = "Tag";
-	}
-	758
-	{
-		title = "Object Angle Anchor";
-		sprite = "internal:view";
-	}
-	760
-	{
-		title = "PolyObject Anchor";
-		sprite = "internal:polyanchor";
-		angletext = "ID";
-	}
-
-	761
-	{
-		title = "PolyObject Spawn Point";
-		sprite = "internal:polycenter";
-		angletext = "ID";
-	}
-
-	762
-	{
-		title = "PolyObject Spawn Point (Crush)";
-		sprite = "internal:polycentercrush";
-		angletext = "ID";
-	}
-	780
-	{
-		title = "Skybox View Point";
-		sprite = "internal:skyb";
-		flags4text = "[4] In-map centerpoint";
-		parametertext = "ID";
-	}
-}
-
-greenflower
-{
-	color = 10; // Green
-	title = "Greenflower";
-
-	800
-	{
-		title = "GFZ Flower";
-		sprite = "FWR1A0";
-		width = 16;
-		height = 40;
-	}
-	801
-	{
-		title = "Sunflower";
-		sprite = "FWR2A0";
-		width = 16;
-		height = 96;
-	}
-	802
-	{
-		title = "Budding Flower";
-		sprite = "FWR3A0";
-		width = 8;
-		height = 32;
-	}
-	803
-	{
-		title = "Blueberry Bush";
-		sprite = "BUS3A0";
-		width = 16;
-		height = 32;
-	}
-	804
-	{
-		title = "Berry Bush";
-		sprite = "BUS1A0";
-		width = 16;
-		height = 32;
-	}
-	805
-	{
-		title = "Bush";
-		sprite = "BUS2A0";
-		width = 16;
-		height = 32;
-	}
-	806
-	{
-		title = "GFZ Tree";
-		sprite = "TRE1A0";
-		width = 20;
-		height = 128;
-	}
-	807
-	{
-		title = "GFZ Berry Tree";
-		sprite = "TRE1B0";
-		width = 20;
-		height = 128;
-	}
-	808
-	{
-		title = "GFZ Cherry Tree";
-		sprite = "TRE1C0";
-		width = 20;
-		height = 128;
-	}
-	809
-	{
-		title = "Checkered Tree";
-		sprite = "TRE2A0";
-		width = 20;
-		height = 200;
-	}
-	810
-	{
-		title = "Checkered Tree (Sunset)";
-		sprite = "TRE2B0";
-		width = 20;
-		height = 200;
-	}
-	811
-	{
-		title = "Polygon Tree";
-		sprite = "TRE4A0";
-		width = 20;
-		height = 200;
-	}
-	812
-	{
-		title = "Bush Tree";
-		sprite = "TRE5A0";
-		width = 20;
-		height = 200;
-	}
-	813
-	{
-		title = "Red Bush Tree";
-		sprite = "TRE5B0";
-		width = 20;
-		height = 200;
-	}
-}
-
-technohill
-{
-	color = 10; // Green
-	title = "Techno Hill";
-
-	900
-	{
-		title = "THZ Steam Flower";
-		sprite = "THZPA0";
-		width = 8;
-		height = 32;
-	}
-	901
-	{
-		title = "Alarm";
-		sprite = "ALRMA0";
-		width = 8;
-		height = 16;
-		hangs = 1;
-	}
-	902
-	{
-		title = "THZ Spin Flower (Red)";
-		sprite = "FWR5A0";
-		width = 16;
-		height = 64;
-	}
-	903
-	{
-		title = "THZ Spin Flower (Yellow)";
-		sprite = "FWR6A0";
-		width = 16;
-		height = 64;
-	}
-	904
-	{
-		arrow = 1;
-		title = "Whistlebush";
-		sprite = "THZTA0";
-		width = 16;
-		height = 64;
-	}
-}
-
-deepsea
-{
-	color = 10; // Green
-	title = "Deep Sea";
-
-	1000
-	{
-		arrow = 1;
-		blocking = 2;
-		title = "Gargoyle";
-		sprite = "GARGA1";
-		width = 16;
-		height = 40;
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-	1009
-	{
-		arrow = 1;
-		blocking = 2;
-		title = "Gargoyle (Big)";
-		sprite = "GARGB1";
-		width = 32;
-		height = 80;
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-	1001
-	{
-		title = "Seaweed";
-		sprite = "SEWEA0";
-		width = 24;
-		height = 56;
-	}
-	1002
-	{
-		title = "Dripping Water";
-		sprite = "DRIPD0";
-		width = 8;
-		height = 16;
-		hangs = 1;
-		angletext = "Dripping interval";
-	}
-	1003
-	{
-		title = "Coral (Green)";
-		sprite = "CORLA0";
-		width = 29;
-		height = 40;
-	}
-	1004
-	{
-		title = "Coral (Red)";
-		sprite = "CORLB0";
-		width = 30;
-		height = 53;
-	}
-	1005
-	{
-		title = "Coral (Orange)";
-		sprite = "CORLC0";
-		width = 28;
-		height = 41;
-	}
-	1006
-	{
-		title = "Blue Crystal";
-		sprite = "BCRYA1";
-		width = 8;
-		height = 16;
-	}
-	1007
-	{
-		title = "Kelp";
-		sprite = "KELPA0";
-		width = 16;
-		height = 292;
-		flags4text = "[4] Double size";
-	}
-	1008
-	{
-		title = "Stalagmite (DSZ1)";
-		sprite = "DSTGA0";
-		width = 8;
-		height = 116;
-		flags4text = "[4] Double size";
-	}
-	1010
-	{
-		arrow = 1;
-		title = "Light Beam";
-		sprite = "LIBEARAL";
-		width = 16;
-		height = 16;
-	}
-	1011
-	{
-		title = "Stalagmite (DSZ2)";
-		sprite = "DSTGA0";
-		width = 8;
-		height = 116;
-		flags4text = "[4] Double size";
-	}
-	1012
-	{
-		arrow = 1;
-		title = "Big Floating Mine";
-		width = 28;
-		height = 56;
-		sprite = "BMNEA1";
-	}
-	1013
-	{
-		title = "Animated Kelp";
-		sprite = "ALGAA0";
-		width = 48;
-		height = 120;
-	}
-	1014
-	{
-		title = "Large Coral (Brown)";
-		sprite = "CORLD0";
-		width = 56;
-		height = 112;
-	}
-	1015
-	{
-		title = "Large Coral (Beige)";
-		sprite = "CORLE0";
-		width = 56;
-		height = 112;
-	}
-}
-
-castleeggman
-{
-	color = 10; // Green
-	title = "Castle Eggman";
-
-	1100
-	{
-		title = "Chain (Decorative)";
-		sprite = "CHANA0";
-		width = 4;
-		height = 128;
-		hangs = 1;
-	}
-	1101
-	{
-		title = "Torch";
-		sprite = "FLAMA0E0";
-		width = 8;
-		height = 32;
-		flags1text = "[1] Add corona";
-	}
-	1102
-	{
-		arrow = 1;
-		blocking = 2;
-		title = "Eggman Statue";
-		sprite = "ESTAA1";
-		width = 32;
-		height = 240;
-		flags1text = "[1] Solid gold";
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-	1103
-	{
-		title = "CEZ Flower";
-		sprite = "FWR4A0";
-		width = 16;
-		height = 40;
-	}
-	1104
-	{
-		title = "Mace Spawnpoint";
-		sprite = "SMCEA0";
-		width = 17;
-		height = 34;
-		flags4text = "[4] No sounds";
-		flags8text = "[8] Double size";
-		angletext = "Tag";
-	}
-	1105
-	{
-		title = "Chain with Maces Spawnpoint";
-		sprite = "SMCEA0";
-		width = 17;
-		height = 34;
-		flags4text = "[4] No sounds";
-		flags8text = "[8] Double size";
-		angletext = "Tag";
-	}
-	1106
-	{
-		title = "Chained Spring Spawnpoint";
-		sprite = "YSPBA0";
-		width = 17;
-		height = 34;
-		flags4text = "[4] No sounds";
-		flags8text = "[8] Red spring";
-		angletext = "Tag";
-	}
-	1107
-	{
-		title = "Chain Spawnpoint";
-		sprite = "BMCHA0";
-		width = 17;
-		height = 34;
-		flags8text = "[8] Double size";
-		angletext = "Tag";
-	}
-	1108
-	{
-		arrow = 1;
-		title = "Hidden Chain Spawnpoint";
-		sprite = "internal:chain3";
-		width = 17;
-		height = 34;
-		flags8text = "[8] Double size";
-	}
-	1109
-	{
-		title = "Firebar Spawnpoint";
-		sprite = "BFBRA0";
-		width = 17;
-		height = 34;
-		flags4text = "[4] No sounds";
-		flags8text = "[8] Double size";
-		angletext = "Tag";
-	}
-	1110
-	{
-		title = "Custom Mace Spawnpoint";
-		sprite = "SMCEA0";
-		width = 17;
-		height = 34;
-		flags4text = "[4] No sounds";
-		angletext = "Tag";
-	}
-	1111
-	{
-		arrow = 1;
-		blocking = 2;
-		title = "Crawla Statue";
-		sprite = "CSTAA1";
-		width = 16;
-		height = 40;
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-	1112
-	{
-		arrow = 1;
-		blocking = 2;
-		title = "Lance-a-Bot Statue";
-		sprite = "CBBSA1";
-		width = 32;
-		height = 72;
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-	1114
-	{
-		title = "Pine Tree";
-		sprite = "PINEA0";
-		width = 16;
-		height = 628;
-	}
-	1115
-	{
-		title = "CEZ Shrub (Small)";
-		sprite = "CEZBA0";
-		width = 16;
-		height = 24;
-	}
-	1116
-	{
-		title = "CEZ Shrub (Large)";
-		sprite = "CEZBB0";
-		width = 32;
-		height = 48;
-	}
-	1117
-	{
-		arrow = 1;
-		title = "Pole Banner (Red)";
-		sprite = "BANRA0";
-		width = 40;
-		height = 224;
-	}
-	1118
-	{
-		arrow = 1;
-		title = "Pole Banner (Blue)";
-		sprite = "BANRA0";
-		width = 40;
-		height = 224;
-	}
-	1119
-	{
-		title = "Candle";
-		sprite = "CNDLA0";
-		width = 8;
-		height = 48;
-		flags1text = "[1] Add corona";
-	}
-	1120
-	{
-		title = "Candle Pricket";
-		sprite = "CNDLB0";
-		width = 8;
-		height = 176;
-		flags1text = "[1] Add corona";
-	}
-	1121
-	{
-		title = "Flame Holder";
-		sprite = "FLMHA0";
-		width = 24;
-		height = 80;
-		flags1text = "[1] Add corona";
-		flags4text = "[4] No flame";
-	}
-	1122
-	{
-		title = "Fire Torch";
-		sprite = "CTRCA0";
-		width = 16;
-		height = 80;
-	}
-	1123
-	{
-		title = "Cannonball Launcher";
-		sprite = "internal:cannonball";
-		width = 8;
-		height = 16;
-	}
-	1124
-	{
-		blocking = 2;
-		title = "Cannonball";
-		sprite = "CBLLA0";
-		width = 20;
-		height = 40;
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-	1125
-	{
-		title = "Brambles";
-		sprite = "CABRALAR";
-		width = 48;
-		height = 32;
-	}
-	1126
-	{
-		title = "Invisible Lockon Object";
-		sprite = "LCKNC0";
-		width = 16;
-		height = 32;
-	}
-	1127
-	{
-		title = "Spectator Eggrobo";
-		sprite = "EGR1A1";
-		width = 20;
-		height = 72;
-	}
-	1128
-	{
-		arrow = 1;
-		title = "Waving Flag (Red)";
-		sprite = "CFLGA0";
-		width = 8;
-		height = 208;
-	}
-	1129
-	{
-		arrow = 1;
-		title = "Waving Flag (Blue)";
-		sprite = "CFLGA0";
-		width = 8;
-		height = 208;
-	}
-}
-
-aridcanyon
-{
-	color = 10; // Green
-	title = "Arid Canyon";
-
-	1200
-	{
-		title = "Tumbleweed (Big)";
-		sprite = "BTBLA0";
-		width = 24;
-		height = 48;
-		flags8text = "[8] Moves perpetually";
-	}
-	1201
-	{
-		title = "Tumbleweed (Small)";
-		sprite = "STBLA0";
-		width = 12;
-		height = 24;
-		flags8text = "[8] Moves perpetually";
-	}
-	1202
-	{
-		arrow = 1;
-		title = "Rock Spawner";
-		sprite = "ROIAA0";
-		width = 8;
-		height = 16;
-		angletext = "Tag";
-	}
-	1203
-	{
-		title = "Tiny Red Flower Cactus";
-		sprite = "CACTA0";
-		width = 13;
-		height = 24;
-	}
-	1204
-	{
-		title = "Small Red Flower Cactus";
-		sprite = "CACTB0";
-		width = 15;
-		height = 52;
-	}
-	1205
-	{
-		title = "Tiny Blue Flower Cactus";
-		sprite = "CACTC0";
-		width = 13;
-		height = 24;
-	}
-	1206
-	{
-		title = "Small Blue Flower Cactus";
-		sprite = "CACTD0";
-		width = 15;
-		height = 52;
-	}
-	1207
-	{
-		title = "Prickly Pear";
-		sprite = "CACTE0";
-		width = 32;
-		height = 96;
-	}
-	1208
-	{
-		title = "Barrel Cactus";
-		sprite = "CACTF0";
-		width = 20;
-		height = 128;
-	}
-	1209
-	{
-		title = "Tall Barrel Cactus";
-		sprite = "CACTG0";
-		width = 24;
-		height = 224;
-	}
-	1210
-	{
-		title = "Armed Cactus";
-		sprite = "CACTH0";
-		width = 24;
-		height = 256;
-	}
-	1211
-	{
-		title = "Ball Cactus";
-		sprite = "CACTI0";
-		width = 48;
-		height = 96;
-	}
-	1212
-	{
-		title = "Caution Sign";
-		sprite = "WWSGAR";
-		width = 22;
-		height = 64;
-	}
-	1213
-	{
-		title = "Cacti Sign";
-		sprite = "WWS2AR";
-		width = 22;
-		height = 64;
-	}
-	1214
-	{
-		title = "Sharp Turn Sign";
-		sprite = "WWS3ALAR";
-		width = 16;
-		height = 192;
-	}
-	1215
-	{
-		title = "Mine Oil Lamp";
-		sprite = "OILLA0";
-		width = 22;
-		height = 64;
-		hangs = 1;
-	}
-	1216
-	{
-		title = "TNT Barrel";
-		sprite = "BARRA1";
-		width = 24;
-		height = 63;
-	}
-	1217
-	{
-		title = "TNT Proximity Shell";
-		sprite = "REMTA0";
-		width = 64;
-		height = 40;
-	}
-	1218
-	{
-		title = "Dust Devil";
-		sprite = "TAZDCR";
-		width = 80;
-		height = 416;
-	}
-	1219
-	{
-		title = "Minecart Spawner";
-		sprite = "MCRTCLFR";
-		width = 22;
-		height = 32;
-	}
-	1220
-	{
-		title = "Minecart Stopper";
-		sprite = "MCRTIR";
-		width = 32;
-		height = 32;
-	}
-	1221
-	{
-		title = "Minecart Saloon Door";
-		sprite = "SALDARAL";
-		width = 96;
-		height = 160;
-		flags8text = "[8] Allow non-minecart players";
-	}
-	1222
-	{
-		title = "Train Cameo Spawner";
-		sprite = "TRAEBRBL";
-		width = 28;
-		height = 32;
-	}
-	1223
-	{
-		title = "Train Dust Spawner";
-		sprite = "ADSTA0";
-		width = 4;
-		height = 4;
-	}
-	1224
-	{
-		title = "Train Steam Spawner";
-		sprite = "STEAA0";
-		width = 4;
-		height = 4;
-	}
-	1229
-	{
-		title = "Minecart Switch Point";
-		sprite = "internal:zoom";
-		width = 8;
-		height = 16;
-		flags8text = "[8] Enable switching";
-	}
-	1230
-	{
-		title = "Tiny Cactus";
-		sprite = "CACTJ0";
-		width = 13;
-		height = 28;
-	}
-	1231
-	{
-		title = "Small Cactus";
-		sprite = "CACTK0";
-		width = 15;
-		height = 60;
-	}
-}
-
-redvolcano
-{
-	color = 10; // Green
-	title = "Red Volcano";
-
-	1300
-	{
-		arrow = 1;
-		title = "Flame Jet (Horizontal)";
-		sprite = "internal:flameh";
-		width = 16;
-		height = 40;
-		flags8text = "[8] Waves vertically";
-		angletext = "On/Off time";
-		parametertext = "Strength";
-	}
-	1301
-	{
-		title = "Flame Jet (Vertical)";
-		sprite = "internal:flamev";
-		width = 16;
-		height = 40;
-		flags8text = "[8] Shoot downwards";
-		angletext = "On/Off time";
-		parametertext = "Strength";
-	}
-	1302
-	{
-		title = "Spinning Flame Jet (Counter-Clockwise)";
-		sprite = "internal:flame2";
-		width = 16;
-		height = 24;
-	}
-	1303
-	{
-		title = "Spinning Flame Jet (Clockwise)";
-		sprite = "internal:flame1";
-		width = 16;
-		height = 24;
-	}
-	1304
-	{
-		title = "Lavafall";
-		sprite = "LFALF0";
-		width = 30;
-		height = 32;
-		angletext = "Initial delay";
-		flags8text = "[8] Double size";
-	}
-	1305
-	{
-		title = "Rollout Rock";
-		sprite = "PUMIA1A5";
-		width = 30;
-		height = 60;
-		flags8text = "[8] Non-buoyant";
-	}
-	1306
-	{
-		title = "Big Fern";
-		sprite = "JPLAB0";
-		width = 32;
-		height = 48;
-	}
-	1307
-	{
-		title = "Jungle Palm";
-		sprite = "JPLAC0";
-		width = 32;
-		height = 48;
-	}
-	1308
-	{
-		title = "Torch Flower";
-		sprite = "TFLOA0";
-		width = 14;
-		height = 110;
-	}
-	1309
-	{
-		title = "RVZ1 Wall Vine (Long)";
-		sprite = "WVINALAR";
-		width = 1;
-		height = 288;
-	}
-	1310
-	{
-		title = "RVZ1 Wall Vine (Short)";
-		sprite = "WVINBLBR";
-		width = 1;
-		height = 288;
-	}
-}
-
-botanicserenity
-{
-	color = 10; // Green
-	title = "Botanic Serenity";
-	width = 16;
-	height = 32;
-	sprite = "BSZ1A0";
-	1400
-	{
-		title = "Tall Flower (Red)";
-		sprite = "BSZ1A0";
-	}
-	1401
-	{
-		title = "Tall Flower (Purple)";
-		sprite = "BSZ1B0";
-	}
-	1402
-	{
-		title = "Tall Flower (Blue)";
-		sprite = "BSZ1C0";
-	}
-	1403
-	{
-		title = "Tall Flower (Cyan)";
-		sprite = "BSZ1D0";
-	}
-	1404
-	{
-		title = "Tall Flower (Yellow)";
-		sprite = "BSZ1E0";
-	}
-	1405
-	{
-		title = "Tall Flower (Orange)";
-		sprite = "BSZ1F0";
-	}
-	1410
-	{
-		title = "Medium Flower (Red)";
-		sprite = "BSZ2A0";
-	}
-	1411
-	{
-		title = "Medium Flower (Purple)";
-		sprite = "BSZ2B0";
-	}
-	1412
-	{
-		title = "Medium Flower (Blue)";
-		sprite = "BSZ2C0";
-	}
-	1413
-	{
-		title = "Medium Flower (Cyan)";
-		sprite = "BSZ2D0";
-	}
-	1414
-	{
-		title = "Medium Flower (Yellow)";
-		sprite = "BSZ2E0";
-	}
-	1415
-	{
-		title = "Medium Flower (Orange)";
-		sprite = "BSZ2F0";
-	}
-	1420
-	{
-		title = "Short Flower (Red)";
-		sprite = "BSZ3A0";
-	}
-	1421
-	{
-		title = "Short Flower (Purple)";
-		sprite = "BSZ3B0";
-	}
-	1422
-	{
-		title = "Short Flower (Blue)";
-		sprite = "BSZ3C0";
-	}
-	1423
-	{
-		title = "Short Flower (Cyan)";
-		sprite = "BSZ3D0";
-	}
-	1424
-	{
-		title = "Short Flower (Yellow)";
-		sprite = "BSZ3E0";
-	}
-	1425
-	{
-		title = "Short Flower (Orange)";
-		sprite = "BSZ3F0";
-	}
-	1430
-	{
-		title = "Tulip (Red)";
-		sprite = "BST1A0";
-	}
-	1431
-	{
-		title = "Tulip (Purple)";
-		sprite = "BST2A0";
-	}
-	1432
-	{
-		title = "Tulip (Blue)";
-		sprite = "BST3A0";
-	}
-	1433
-	{
-		title = "Tulip (Cyan)";
-		sprite = "BST4A0";
-	}
-	1434
-	{
-		title = "Tulip (Yellow)";
-		sprite = "BST5A0";
-	}
-	1435
-	{
-		title = "Tulip (Orange)";
-		sprite = "BST6A0";
-	}
-	1440
-	{
-		title = "Cluster (Red)";
-		sprite = "BSZ5A0";
-	}
-	1441
-	{
-		title = "Cluster (Purple)";
-		sprite = "BSZ5B0";
-	}
-	1442
-	{
-		title = "Cluster (Blue)";
-		sprite = "BSZ5C0";
-	}
-	1443
-	{
-		title = "Cluster (Cyan)";
-		sprite = "BSZ5D0";
-	}
-	1444
-	{
-		title = "Cluster (Yellow)";
-		sprite = "BSZ5E0";
-	}
-	1445
-	{
-		title = "Cluster (Orange)";
-		sprite = "BSZ5F0";
-	}
-	1450
-	{
-		title = "Bush (Red)";
-		sprite = "BSZ6A0";
-	}
-	1451
-	{
-		title = "Bush (Purple)";
-		sprite = "BSZ6B0";
-	}
-	1452
-	{
-		title = "Bush (Blue)";
-		sprite = "BSZ6C0";
-	}
-	1453
-	{
-		title = "Bush (Cyan)";
-		sprite = "BSZ6D0";
-	}
-	1454
-	{
-		title = "Bush (Yellow)";
-		sprite = "BSZ6E0";
-	}
-	1455
-	{
-		title = "Bush (Orange)";
-		sprite = "BSZ6F0";
-	}
-	1460
-	{
-		title = "Vine (Red)";
-		sprite = "BSZ7A0";
-	}
-	1461
-	{
-		title = "Vine (Purple)";
-		sprite = "BSZ7B0";
-	}
-	1462
-	{
-		title = "Vine (Blue)";
-		sprite = "BSZ7C0";
-	}
-	1463
-	{
-		title = "Vine (Cyan)";
-		sprite = "BSZ7D0";
-	}
-	1464
-	{
-		title = "Vine (Yellow)";
-		sprite = "BSZ7E0";
-	}
-	1465
-	{
-		title = "Vine (Orange)";
-		sprite = "BSZ7F0";
-	}
-	1470
-	{
-		title = "BSZ Shrub";
-		sprite = "BSZ8A0";
-	}
-	1471
-	{
-		title = "BSZ Clover";
-		sprite = "BSZ8B0";
-	}
-	1473
-	{
-		title = "Palm Tree (Big)";
-		width = 16;
-		height = 160;
-		sprite = "BSZ8D0";
-	}
-	1475
-	{
-		title = "Palm Tree (Small)";
-		width = 16;
-		height = 80;
-		sprite = "BSZ8F0";
-	}
-}
-
-azuretemple
-{
-	color = 10; // Green
-	title = "Azure Temple";
-
-	1500
-	{
-		arrow = 1;
-		blocking = 2;
-		title = "Glaregoyle";
-		sprite = "BGARA1";
-		width = 16;
-		height = 40;
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-	1501
-	{
-		arrow = 1;
-		blocking = 2;
-		title = "Glaregoyle (Up)";
-		sprite = "BGARA1";
-		width = 16;
-		height = 40;
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-	1502
-	{
-		arrow = 1;
-		blocking = 2;
-		title = "Glaregoyle (Down)";
-		sprite = "BGARA1";
-		width = 16;
-		height = 40;
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-	1503
-	{
-		arrow = 1;
-		blocking = 2;
-		title = "Glaregoyle (Long)";
-		sprite = "BGARA1";
-		width = 16;
-		height = 40;
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-	1504
-	{
-		title = "ATZ Target";
-		sprite = "RCRYB0";
-		width = 24;
-		height = 32;
-	}
-	1505
-	{
-		title = "Green Flame";
-		sprite = "CFLMA0E0";
-		width = 8;
-		height = 32;
-	}
-	1506
-	{
-		arrow = 1;
-		blocking = 2;
-		title = "Blue Gargoyle";
-		sprite = "BGARD1";
-		width = 16;
-		height = 40;
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-}
-
-dreamhill
-{
-	color = 10; // Green
-	title = "Dream Hill";
-
-	1600
-	{
-		title = "Spring Tree";
-		sprite = "TRE6A0";
-		width = 16;
-		height = 32;
-	}
-	1601
-	{
-		title = "Shleep";
-		sprite = "SHLPA0";
-		width = 24;
-		height = 32;
-	}
-	1602
-	{
-		title = "Pian";
-		sprite = "NTPNALAR";
-		width = 16;
-		height = 32;
-	}
-}
-
-nightstrk
-{
-	color = 13; // Pink
-	title = "NiGHTS Track";
-	width = 8;
-	height = 4096;
-	sprite = "UNKNA0";
-
-	1700
-	{
-		title = "Axis";
-		sprite = "internal:axis1";
-		circle = 1;
-		unflippable = true;
-		ignoreZ = true;
-		flagsvaluetext = "Order";
-		angletext = "Radius/Direction";
-		parametertext = "Mare";
-	}
-	1701
-	{
-		title = "Axis Transfer";
-		sprite = "internal:axis2";
-		unflippable = true;
-		ignoreZ = true;
-		flagsvaluetext = "Order";
-		parametertext = "Mare";
-	}
-	1702
-	{
-		title = "Axis Transfer Line";
-		sprite = "internal:axis3";
-		unflippable = true;
-		ignoreZ = true;
-		flagsvaluetext = "Order";
-		parametertext = "Mare";
-	}
-	1710
-	{
-		title = "Ideya Capture";
-		sprite = "CAPSA0";
-		width = 72;
-		height = 144;
-		angletext = "Rings";
-		parametertext = "Mare";
-	}
-}
-
-nights
-{
-	color = 13; // Pink
-	title = "NiGHTS Items";
-	width = 16;
-	height = 32;
-
-	1703
-	{
-		title = "Ideya Drone";
-		sprite = "NDRNA1";
-		width = 16;
-		height = 56;
-		flags1text = "[1] Align player to middle";
-		flags4text = "[4] Align player to top";
-		flags8text = "[8] Die upon time up";
-		angletext = "Time limit";
-		parametertext = "Height";
-	}
-	1704
-	{
-		arrow = 1;
-		title = "NiGHTS Bumper";
-		sprite = "NBMPG3G7";
-		width = 32;
-		height = 64;
-		unflippable = true;
-		flagsvaluetext = "Pitch";
-		angletext = "Yaw";
-	}
-	1705
-	{
-		arrow = 1;
-		title = "Hoop (Generic)";
-		sprite = "HOOPA0";
-		width = 80;
-		height = 160;
-		unflippable = true;
-		centerHitbox = true;
-		flagsvaluetext = "Height";
-		angletext = "Pitch/Yaw";
-	}
-	1706
-	{
-		title = "Blue Sphere";
-		sprite = "SPHRA0";
-		width = 16;
-		height = 24;
-		flags8height = 24;
-		flags8text = "[8] Float";
-		unflippable = true;
-	}
-	1707
-	{
-		title = "Super Paraloop";
-		sprite = "NPRUA0";
-		flags4text = "[4] Bonus time only";
-		flags8text = "[8] Spawn immediately";
-	}
-	1708
-	{
-		title = "Drill Refill";
-		sprite = "NPRUB0";
-		flags4text = "[4] Bonus time only";
-		flags8text = "[8] Spawn immediately";
-	}
-	1709
-	{
-		title = "Nightopian Helper";
-		sprite = "NPRUC0";
-		flags4text = "[4] Bonus time only";
-		flags8text = "[8] Spawn immediately";
-	}
-	1711
-	{
-		title = "Extra Time";
-		sprite = "NPRUD0";
-		flags4text = "[4] Bonus time only";
-		flags8text = "[8] Spawn immediately";
-	}
-	1712
-	{
-		title = "Link Freeze";
-		sprite = "NPRUE0";
-		flags4text = "[4] Bonus time only";
-		flags8text = "[8] Spawn immediately";
-	}
-	1713
-	{
-		arrow = 1;
-		title = "Hoop (Customizable)";
-		flags1text = "[1] Radius +16";
-		flags2text = "[2] Radius +32";
-		flags4text = "[4] Radius +64";
-		flags8text = "[8] Radius +128";
-		sprite = "HOOPA0";
-		width = 80;
-		height = 160;
-		unflippable = true;
-		centerHitbox = true;
-	}
-	1714
-	{
-		title = "Ideya Anchor Point";
-		sprite = "internal:axis1";
-		width = 8;
-		height = 16;
-		parametertext = "Ideya";
-	}
-}
-
-mario
-{
-	color = 6; // Brown
-	title = "Mario";
-
-	1800
-	{
-		title = "Coin";
-		sprite = "COINA0";
-		width = 16;
-		height = 24;
-		flags8height = 24;
-		flags8text = "[8] Float";
-	}
-	1801
-	{
-		arrow = 1;
-		title = "Goomba";
-		sprite = "GOOMA0";
-		width = 24;
-		height = 32;
-	}
-	1802
-	{
-		arrow = 1;
-		title = "Goomba (Blue)";
-		sprite = "BGOMA0";
-		width = 24;
-		height = 32;
-	}
-	1803
-	{
-		title = "Fire Flower";
-		sprite = "FFWRB0";
-		width = 16;
-		height = 32;
-	}
-	1804
-	{
-		title = "Koopa Shell";
-		sprite = "SHLLA1";
-		width = 16;
-		height = 20;
-	}
-	1805
-	{
-		title = "Puma (Jumping Fireball)";
-		sprite = "PUMAA0";
-		width = 8;
-		height = 16;
-		angletext = "Jump strength";
-	}
-	1806
-	{
-		title = "King Bowser";
-		sprite = "KOOPA0";
-		width = 16;
-		height = 48;
-	}
-	1807
-	{
-		title = "Axe";
-		sprite = "MAXEA0";
-		width = 8;
-		height = 16;
-	}
-	1808
-	{
-		title = "Bush (Short)";
-		sprite = "MUS1A0";
-		width = 16;
-		height = 32;
-	}
-	1809
-	{
-		title = "Bush (Tall)";
-		sprite = "MUS2A0";
-		width = 16;
-		height = 32;
-	}
-	1810
-	{
-		title = "Toad";
-		sprite = "TOADA0";
-		width = 8;
-		height = 32;
-	}
-}
-
-christmasdisco
-{
-	color = 10; // Green
-	title = "Christmas & Disco";
-
-	1850
-	{
-		title = "Christmas Pole";
-		sprite = "XMS1A0";
-		width = 16;
-		height = 40;
-	}
-	1851
-	{
-		title = "Candy Cane";
-		sprite = "XMS2A0";
-		width = 8;
-		height = 32;
-	}
-	1852
-	{
-		blocking = 2;
-		title = "Snowman";
-		sprite = "XMS3A0";
-		width = 16;
-		height = 64;
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-	1853
-	{
-		blocking = 2;
-		title = "Snowman (With Hat)";
-		sprite = "XMS3B0";
-		width = 16;
-		height = 80;
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-	1854
-	{
-		title = "Lamp Post";
-		sprite = "XMS4A0";
-		width = 8;
-		height = 120;
-	}
-	1855
-	{
-		title = "Lamp Post (Snow)";
-		sprite = "XMS4B0";
-		width = 8;
-		height = 120;
-	}
-	1856
-	{
-		title = "Hanging Star";
-		sprite = "XMS5A0";
-		width = 4;
-		height = 80;
-		hangs = 1;
-	}
-	1857
-	{
-		title = "Berry Bush (Snow)";
-		sprite = "BUS1B0";
-		width = 16;
-		height = 32;
-	}
-	1858
-	{
-		title = "Bush (Snow)";
-		sprite = "BUS2B0";
-		width = 16;
-		height = 32;
-	}
-	1859
-	{
-		title = "Blueberry Bush (Snow)";
-		sprite = "BUS3B0";
-		width = 16;
-		height = 32;
-	}
-	1875
-	{
-		title = "Disco Ball";
-		sprite = "DBALA0";
-		width = 16;
-		height = 54;
-		hangs = 1;
-	}
-	1876
-	{
-		arrow = 1;
-		blocking = 2;
-		title = "Eggman Disco Statue";
-		sprite = "ESTAB1";
-		width = 20;
-		height = 96;
-		flags4text = "[4] Slides when pushed";
-		flags8text = "[8] Not pushable";
-	}
-}
-
-stalagmites
-{
-	color = 10; // Green
-	title = "Stalagmites";
-	width = 16;
-	height = 40;
-
-	1900
-	{
-		title = "Brown Stalagmite (Tall)";
-		sprite = "STLGA0";
-		width = 16;
-		height = 40;
-	}
-	1901
-	{
-		title = "Brown Stalagmite";
-		sprite = "STLGB0";
-		width = 16;
-		height = 40;
-	}
-	1902
-	{
-		title = "Orange Stalagmite (Tall)";
-		sprite = "STLGC0";
-		width = 16;
-		height = 40;
-	}
-	1903
-	{
-		title = "Orange Stalagmite";
-		sprite = "STLGD0";
-		width = 16;
-		height = 40;
-	}
-	1904
-	{
-		title = "Red Stalagmite (Tall)";
-		sprite = "STLGE0";
-		width = 16;
-		height = 40;
-	}
-	1905
-	{
-		title = "Red Stalagmite";
-		sprite = "STLGF0";
-		width = 16;
-		height = 40;
-	}
-	1906
-	{
-		title = "Gray Stalagmite (Tall)";
-		sprite = "STLGG0";
-		width = 24;
-		height = 96;
-	}
-	1907
-	{
-		title = "Gray Stalagmite";
-		sprite = "STLGH0";
-		width = 16;
-		height = 40;
-	}
-	1908
-	{
-		title = "Blue Stalagmite (Tall)";
-		sprite = "STLGI0";
-		width = 16;
-		height = 40;
-	}
-	1909
-	{
-		title = "Blue Stalagmite";
-		sprite = "STLGJ0";
-		width = 16;
-		height = 40;
-	}
-}
-
-hauntedheights
-{
-	color = 10; // Green
-	title = "Haunted Heights";
-
-	2000
-	{
-		title = "Smashing Spikeball";
-		sprite = "FMCEA0";
-		width = 18;
-		height = 28;
-		angletext = "Initial delay";
-	}
-	2001
-	{
-		title = "HHZ Grass";
-		sprite = "HHZMA0";
-		width = 16;
-		height = 40;
-	}
-	2002
-	{
-		title = "HHZ Tentacle 1";
-		sprite = "HHZMB0";
-		width = 16;
-		height = 40;
-	}
-	2003
-	{
-		title = "HHZ Tentacle 2";
-		sprite = "HHZMC0";
-		width = 16;
-		height = 40;
-	}
-	2004
-	{
-		title = "HHZ Stalagmite (Tall)";
-		sprite = "HHZME0";
-		width = 16;
-		height = 40;
-	}
-	2005
-	{
-		title = "HHZ Stalagmite (Short)";
-		sprite = "HHZMF0";
-		width = 16;
-		height = 40;
-	}
-	2006
-	{
-		title = "Jack-o'-lantern 1";
-		sprite = "PUMKA0";
-		width = 16;
-		height = 40;
-		flags1text = "Don't flicker";
-	}
-	2007
-	{
-		title = "Jack-o'-lantern 2";
-		sprite = "PUMKB0";
-		width = 16;
-		height = 40;
-		flags1text = "Don't flicker";
-	}
-	2008
-	{
-		title = "Jack-o'-lantern 3";
-		sprite = "PUMKC0";
-		width = 16;
-		height = 40;
-		flags1text = "Don't flicker";
-	}
-	2009
-	{
-		title = "Purple Mushroom";
-		sprite = "SHRMD0";
-		width = 16;
-		height = 48;
-	}
-	2010
-	{
-		title = "HHZ Tree";
-		sprite = "HHPLC0";
-		width = 12;
-		height = 40;
-	}
-}
-
-frozenhillside
-{
-	color = 10; // Green
-	title = "Frozen Hillside";
-
-	2100
-	{
-		title = "Ice Shard (Small)";
-		sprite = "FHZIA0";
-		width = 8;
-		height = 32;
-	}
-	2101
-	{
-		title = "Ice Shard (Large)";
-		sprite = "FHZIB0";
-		width = 8;
-		height = 32;
-	}
-	2102
-	{
-		title = "Crystal Tree (Aqua)";
-		sprite = "TRE3A0";
-		width = 20;
-		height = 200;
-	}
-	2103
-	{
-		title = "Crystal Tree (Pink)";
-		sprite = "TRE3B0";
-		width = 20;
-		height = 200;
-	}
-	2104
-	{
-		title = "Amy Cameo";
-		sprite = "ROSYA1";
-		width = 16;
-		height = 48;
-		flags1text = "[1] Grayscale mode";
-	}
-	2105
-	{
-		title = "Mistletoe";
-		sprite = "XMS6A0";
-		width = 52;
-		height = 106;
-	}
-}
-
-flickies
-{
-	color = 10; // Green
-	title = "Flickies";
-	width = 8;
-	height = 20;
-	flags1text = "[1] Move aimlessly";
-	flags4text = "[4] No movement";
-	flags8text = "[8] Hop";
-	angletext = "Radius";
-
-	2200
-	{
-		title = "Bluebird";
-		sprite = "FL01A1";
-	}
-	2201
-	{
-		title = "Rabbit";
-		sprite = "FL02A1";
-	}
-	2202
-	{
-		title = "Chicken";
-		sprite = "FL03A1";
-	}
-	2203
-	{
-		title = "Seal";
-		sprite = "FL04A1";
-	}
-	2204
-	{
-		title = "Pig";
-		sprite = "FL05A1";
-	}
-	2205
-	{
-		title = "Chipmunk";
-		sprite = "FL06A1";
-	}
-	2206
-	{
-		title = "Penguin";
-		sprite = "FL07A1";
-	}
-	2207
-	{
-		title = "Fish";
-		sprite = "FL08A1";
-		parametertext = "Color";
-	}
-	2208
-	{
-		title = "Ram";
-		sprite = "FL09A1";
-	}
-	2209
-	{
-		title = "Puffin";
-		sprite = "FL10A1";
-	}
-	2210
-	{
-		title = "Cow";
-		sprite = "FL11A1";
-	}
-	2211
-	{
-		title = "Rat";
-		sprite = "FL12A1";
-	}
-	2212
-	{
-		title = "Bear";
-		sprite = "FL13A1";
-	}
-	2213
-	{
-		title = "Dove";
-		sprite = "FL14A1";
-	}
-	2214
-	{
-		title = "Cat";
-		sprite = "FL15A1";
-	}
-	2215
-	{
-		title = "Canary";
-		sprite = "FL16A1";
-	}
-	2216
-	{
-		title = "Spider";
-		sprite = "FS01A1";
-	}
-	2217
-	{
-		title = "Bat";
-		sprite = "FS02A0";
-	}
-}
\ No newline at end of file
diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg
index ec318321d75fcb1b100f67c80d93c8750cb06282..ec030b32f276d5da59b4e8674043888a4ba80f09 100644
--- a/extras/conf/SRB2-22.cfg
+++ b/extras/conf/SRB2-22.cfg
@@ -435,7 +435,7 @@ sectortypes
 	112 = "Trigger Line Ex. (NiGHTS Mare)";
 	128 = "Check for Linedef Executor on FOFs";
 	144 = "Egg Capsule";
-	160 = "Special Stage Time/Rings Parameters";
+	160 = "Special Stage Time/Spheres Parameters";
 	176 = "Custom Global Gravity";
 	512 = "Wind/Current";
 	1024 = "Conveyor Belt";
@@ -490,7 +490,7 @@ gen_sectortypes
 		112 = "Trigger Line Ex. (NiGHTS Mare)";
 		128 = "Check for Linedef Executor on FOFs";
 		144 = "Egg Capsule";
-		160 = "Special Stage Time/Rings Parameters";
+		160 = "Special Stage Time/Spheres Parameters";
 		176 = "Custom Global Gravity";
 	}
 
@@ -766,6 +766,7 @@ linedeftypes
 		{
 			title = "Parameters";
 			prefix = "(22)";
+			flags32text = "[5] Render outer sides only";
 			flags64text = "[6] Trigger linedef executor";
 			flags128text = "[7] Intangible";
 			flags256text = "[8] Stopped by pushables";
@@ -788,7 +789,6 @@ linedeftypes
 		{
 			title = "Angular Displacement by Front Sector";
 			prefix = "(32)";
-			flags8text = "[3] Set delay by backside sector";
 			flags64text = "[6] Don't turn players";
 			flags512text = "[9] Turn all objects";
 		}
@@ -1136,7 +1136,6 @@ linedeftypes
 		{
 			title = "Goo Water, Translucent, No Sides";
 			prefix = "(125)";
-			flags8text = "[3] Slope skew sides";
 			flags64text = "[6] Use two light levels";
 			flags512text = "[9] Use target light level";
 			flags1024text = "[10] Ripple effect";
@@ -1227,6 +1226,18 @@ linedeftypes
 			3dfloorflags = "19F";
 		}
 
+		153
+		{
+			title = "Dynamically Sinking Platform";
+			prefix = "(153)";
+			flags8text = "[3] Slope skew sides";
+			flags32text = "[5] Only block player";
+			flags64text = "[6] Spindash to move";
+			flags128text = "[7] Only block non-players";
+			3dfloor = true;
+			3dfloorflags = "19F";
+		}
+
 		160
 		{
 			title = "Floating, Bobbing";
@@ -1282,7 +1293,6 @@ linedeftypes
 			title = "Rising Platform, Solid, Invisible";
 			prefix = "(193)";
 			flags2text = "[1] Sink when stepped on";
-			flags8text = "[3] Slope skew sides";
 			flags32text = "[5] Only block player";
 			flags64text = "[6] Spindash to move";
 			flags128text = "[7] Only block non-players";
@@ -1488,16 +1498,22 @@ linedeftypes
 		{
 			title = "Mario Block";
 			prefix = "(250)";
+			flags8text = "[3] Slope skew sides";
 			flags32text = "[5] Invisible block";
 			flags64text = "[6] Brick block";
 			3dfloor = true;
 			3dfloorflags = "40019F";
+			flags323dfloorflagsremove = "19E";
+			flags643dfloorflagsadd = "200000";
 		}
 
 		251
 		{
 			title = "Thwomp Block";
 			prefix = "(251)";
+			flags8text = "[3] Slope skew sides";
+			flags32text = "[5] Only block player";
+			flags128text = "[7] Only block non-players";
 			flags512text = "[9] Custom crushing sound";
 			flags1024text = "[10] Custom speed";
 			3dfloor = true;
@@ -1513,8 +1529,8 @@ linedeftypes
 			flags512text = "[9] Shattered by pushables";
 			flags1024text = "[10] Trigger linedef executor";
 			3dfloor = true;
-			3dfloorflags = "8800019";
-			flags643dfloorflagsadd = "200006";
+			3dfloorflags = "880001D";
+			flags643dfloorflagsadd = "200002";
 		}
 
 		253
@@ -1525,7 +1541,7 @@ linedeftypes
 			flags512text = "[9] Shattered by pushables";
 			flags1024text = "[10] Trigger linedef executor";
 			3dfloor = true;
-			3dfloorflags = "8801019";
+			3dfloorflags = "880101D";
 		}
 
 		254
@@ -1533,6 +1549,7 @@ linedeftypes
 			title = "Bustable Block";
 			prefix = "(254)";
 			flags8text = "[3] Slope skew sides";
+			flags32text = "[5] Only block player";
 			flags64text = "[6] Strong characters only";
 			flags128text = "[7] Only block non-players";
 			flags512text = "[9] Shattered by pushables";
@@ -1593,6 +1610,7 @@ linedeftypes
 		{
 			title = "Custom FOF";
 			prefix = "(259)";
+			flags8text = "[3] Slope skew sides";
 			flags32text = "[5] Only block player";
 			flags128text = "[7] Only block non-players";
 			flags512text = "[9] Shattered by pushables";
@@ -2161,6 +2179,14 @@ linedeftypes
 			flags8text = "[3] Set delay by backside sector";
 		}
 
+		449
+		{
+			title = "Enable Bosses with Parameter";
+			prefix = "(449)";
+			flags8text = "[3] Set delay by backside sector";
+			flags64text = "[6] Disable bosses";
+		}
+
 		457
 		{
 			title = "Track Object's Angle";
@@ -2180,12 +2206,14 @@ linedeftypes
 		{
 			title = "Award Rings";
 			prefix = "(460)";
+			flags8text = "[3] Set delay by backside sector";
 		}
 
 		461
 		{
 			title = "Spawn Object";
 			prefix = "(461)";
+			flags8text = "[3] Set delay by backside sector";
 			flags64text = "[6] Spawn inside a range";
 		}
 
@@ -2193,6 +2221,7 @@ linedeftypes
 		{
 			title = "Stop Timer/Exit Stage in Record Attack";
 			prefix = "(462)";
+			flags8text = "[3] Set delay by backside sector";
 		}
 	}
 
@@ -2206,7 +2235,7 @@ linedeftypes
 			prefix = "(413)";
 			flags2text = "[1] Keep after death";
 			flags8text = "[3] Set delay by backside sector";
-			flags32text = "[5] Seek to current song position";
+			flags32text = "[5] Seek from current position";
 			flags64text = "[6] For everyone";
 			flags128text = "[7] Fade to custom volume";
 			flags512text = "[9] Don't loop";
@@ -2220,7 +2249,7 @@ linedeftypes
 			flags2text = "[1] From calling sector";
 			flags8text = "[3] Set delay by backside sector";
 			flags64text = "[6] From nowhere for triggerer";
-			flags512text = "[9] For everyone";
+			flags512text = "[9] From nowhere for everyone";
 			flags1024text = "[10] From tagged sectors";
 		}
 
@@ -2298,7 +2327,6 @@ linedeftypes
 			flags8text = "[3] Set delay by backside sector";
 		}
 
-
 		445
 		{
 			title = "Make FOF Disappear/Reappear";
@@ -2325,8 +2353,8 @@ linedeftypes
 			flags32text = "[5] Subtract Red value";
 			flags64text = "[6] Subtract Green value";
 			flags128text = "[7] Subtract Blue value";
-			flags256text = "[8] Calc relative values";
-			flags32768text = "[15] Use back side colormap";
+			flags256text = "[8] Set relative to current";
+			flags32768text = "[15] Use backside colormap";
 		}
 
 		448
@@ -2359,7 +2387,7 @@ linedeftypes
 			prefix = "(452)";
 			flags8text = "[3] Set delay by backside sector";
 			flags64text = "[6] Do not handle FF_TRANS";
-			flags256text = "[8] Set relative to current val";
+			flags256text = "[8] Set relative to current";
 		}
 
 		453
@@ -2371,7 +2399,7 @@ linedeftypes
 			flags32text = "[5] No collision during fade";
 			flags64text = "[6] Do not handle FF_TRANS";
 			flags128text = "[7] Do not handle lighting";
-			flags256text = "[8] Set relative to current val";
+			flags256text = "[8] Set relative to current";
 			flags512text = "[9] Speed = Tic Duration";
 			flags1024text = "[10] Override existing fade";
 			flags16384text = "[14] Do not handle collision";
@@ -2395,11 +2423,11 @@ linedeftypes
 			flags32text = "[5] Subtract Red value";
 			flags64text = "[6] Subtract Green value";
 			flags128text = "[7] Subtract Blue value";
-			flags256text = "[8] Calc relative values";
+			flags256text = "[8] Set relative to current";
 			flags512text = "[9] Speed = Tic Duration";
 			flags1024text = "[10] Override existing fade";
 			flags16384text = "[14] Fade from invisible black";
-			flags32768text = "[15] Use back side colormap";
+			flags32768text = "[15] Use backside colormap";
 		}
 
 		456
@@ -2416,9 +2444,7 @@ linedeftypes
 			flags2text = "[1] Close text prompt";
 			flags8text = "[3] Set delay by backside sector";
 			flags32text = "[5] Run executor tag on close";
-			flags64text = "[6] For everyone";
-			flags128text = "[7] Do not block controls";
-			flags256text = "[8] Do not freeze time";
+			flags128text = "[7] Don't disable controls";
 			flags32768text = "[15] Find prompt by name";
 		}
 	}
@@ -2524,7 +2550,7 @@ linedeftypes
 			prefix = "(491)";
 			flags8text = "[3] Set delay by backside sector";
 			flags16text = "[4] Set raw alpha by Front X";
-			flags256text = "[8] Calc relative values";
+			flags256text = "[8] Set relative to current";
 		}
 
 		492
@@ -2534,7 +2560,7 @@ linedeftypes
 			flags8text = "[3] Set delay by backside sector";
 			flags16text = "[4] Set raw alpha by Front X";
 			flags32text = "[5] No collision during fade";
-			flags256text = "[8] Calc relative values";
+			flags256text = "[8] Set relative to current";
 			flags512text = "[9] Speed = Tic Duration";
 			flags1024text = "[10] Override existing fade";
 			flags16384text = "[14] Do not handle collision";
@@ -2632,76 +2658,84 @@ linedeftypes
 		{
 			title = "Carry Objects on Floor";
 			prefix = "(520)";
+			flags64text = "[6] Exclusive";
 		}
 
 		521
 		{
 			title = "Carry Objects on Floor (Accelerative)";
 			prefix = "(521)";
-			flags64text = "[6] Even across edges";
+			flags64text = "[6] Exclusive";
 		}
 
 		522
 		{
 			title = "Carry Objects on Floor (Displacement)";
 			prefix = "(522)";
+			flags64text = "[6] Exclusive";
 		}
 
 		523
 		{
 			title = "Carry Objects on Ceiling";
 			prefix = "(523)";
-			flags64text = "[6] Even across edges";
+			flags64text = "[6] Exclusive";
 		}
 
 		524
 		{
 			title = "Carry Objects on Ceiling (Accelerative)";
 			prefix = "(524)";
+			flags64text = "[6] Exclusive";
 		}
 
 		525
 		{
 			title = "Carry Objects on Ceiling (Displacement)";
 			prefix = "(525)";
+			flags64text = "[6] Exclusive";
 		}
 
 		530
 		{
 			title = "Scroll Floor Texture and Carry Objects";
 			prefix = "(530)";
-			flags64text = "[6] Even across edges";
+			flags64text = "[6] Exclusive";
 		}
 
 		531
 		{
 			title = "Scroll Floor Texture and Carry Objects (Accelerative)";
 			prefix = "(531)";
+			flags64text = "[6] Exclusive";
 		}
 
 		532
 		{
 			title = "Scroll Floor Texture and Carry Objects (Displacement)";
 			prefix = "(532)";
+			flags64text = "[6] Exclusive";
 		}
 
 		533
 		{
 			title = "Scroll Ceiling Texture and Carry Objects";
 			prefix = "(533)";
-			flags64text = "[6] Even across edges";
+			flags64text = "[6] Exclusive";
 		}
 
 		534
 		{
 			title = "Scroll Ceiling Texture and Carry Objects (Accelerative)";
 			prefix = "(534)";
+			flags64text = "[6] Exclusive";
 		}
 
 		535
 		{
 			title = "Scroll Ceiling Texture and Carry Objects (Displacement)";
 			prefix = "(535)";
+			flags64text = "[6] Exclusive";
 		}
 	}
 
@@ -2714,7 +2748,7 @@ linedeftypes
 			title = "Wind";
 			prefix = "(541)";
 			flags512text = "[9] Player slides";
-			flags64text = "[6] Even across edges";
+			flags64text = "[6] Exclusive";
 		}
 
 		542
@@ -2722,7 +2756,7 @@ linedeftypes
 			title = "Upwards Wind";
 			prefix = "(542)";
 			flags512text = "[9] Player slides";
-			flags64text = "[6] Even across edges";
+			flags64text = "[6] Exclusive";
 		}
 
 		543
@@ -2730,7 +2764,7 @@ linedeftypes
 			title = "Downwards Wind";
 			prefix = "(543)";
 			flags512text = "[9] Player slides";
-			flags64text = "[6] Even across edges";
+			flags64text = "[6] Exclusive";
 		}
 
 		544
@@ -2738,7 +2772,7 @@ linedeftypes
 			title = "Current";
 			prefix = "(544)";
 			flags512text = "[9] Player slides";
-			flags64text = "[6] Even across edges";
+			flags64text = "[6] Exclusive";
 		}
 
 		545
@@ -2746,7 +2780,7 @@ linedeftypes
 			title = "Upwards Current";
 			prefix = "(545)";
 			flags512text = "[9] Player slides";
-			flags64text = "[6] Even across edges";
+			flags64text = "[6] Exclusive";
 		}
 
 		546
@@ -2754,13 +2788,14 @@ linedeftypes
 			title = "Downwards Current";
 			prefix = "(546)";
 			flags512text = "[9] Player slides";
-			flags64text = "[6] Even across edges";
+			flags64text = "[6] Exclusive";
 		}
 
 		547
 		{
 			title = "Push/Pull";
 			prefix = "(547)";
+			flags64text = "[6] Exclusive";
 		}
 	}
 
@@ -3407,8 +3442,8 @@ thingtypes
 			sprite = "ESHIA1";
 			width = 16;
 			height = 48;
-			flags1text = "[1] 90 degrees counter-clockwise";
-			flags4text = "[4] 90 degrees clockwise";
+			flags1text = "[1] 90 degrees clockwise";
+			flags4text = "[4] 90 degrees counter-clockwise";
 			flags8text = "[8] Double speed";
 		}
 		115
@@ -3897,9 +3932,10 @@ thingtypes
 		title = "Monitors";
 		width = 18;
 		height = 40;
-		flags1text = "[1] Run Linedef Executor on pop";
+		flags1text = "[1] Run linedef executor on pop";
 		flags4text = "[4] Random (Strong)";
 		flags8text = "[8] Random (Weak)";
+		angletext = "Tag";
 
 		400
 		{
@@ -4029,7 +4065,8 @@ thingtypes
 		title = "Monitors (Respawning)";
 		width = 20;
 		height = 44;
-		flags1text = "[1] Run Linedef Executor on pop";
+		flags1text = "[1] Run linedef executor on pop";
+		angletext = "Tag";
 
 		431
 		{
@@ -4125,7 +4162,9 @@ thingtypes
 			sprite = "STPTA0M0";
 			width = 64;
 			height = 128;
+			flags4text = "[4] Respawn at center";
 			angletext = "Angle/Order";
+			parametertext = "Order";
 		}
 		520
 		{
@@ -4152,6 +4191,7 @@ thingtypes
 			sprite = "WSPKALAR";
 			width = 16;
 			height = 14;
+			arrow = 1;
 			flags1text = "[1] Start retracted";
 			flags4text = "[4] Retractable";
 			flags8text = "[8] Intangible";
@@ -4558,6 +4598,7 @@ thingtypes
 			sprite = "TOADA0";
 			width = 32;
 			height = 16;
+			angletext = "Tag";
 		}
 		757
 		{
@@ -5832,7 +5873,7 @@ thingtypes
 			sprite = "CAPSA0";
 			width = 72;
 			height = 144;
-			angletext = "Rings";
+			angletext = "Spheres";
 			parametertext = "Mare";
 		}
 	}
@@ -6273,7 +6314,7 @@ thingtypes
 			sprite = "PUMKA0";
 			width = 16;
 			height = 40;
-			flags1text = "Don't flicker";
+			flags1text = "[1] Don't flicker";
 		}
 		2007
 		{
@@ -6281,7 +6322,7 @@ thingtypes
 			sprite = "PUMKB0";
 			width = 16;
 			height = 40;
-			flags1text = "Don't flicker";
+			flags1text = "[1] Don't flicker";
 		}
 		2008
 		{
@@ -6289,7 +6330,7 @@ thingtypes
 			sprite = "PUMKC0";
 			width = 16;
 			height = 40;
-			flags1text = "Don't flicker";
+			flags1text = "[1] Don't flicker";
 		}
 		2009
 		{
diff --git a/extras/conf/SRB2_22Doom.cfg b/extras/conf/SRB2_22Doom.cfg
deleted file mode 100644
index 65e49d3871be87df0c3eb20831543a3304191d1d..0000000000000000000000000000000000000000
--- a/extras/conf/SRB2_22Doom.cfg
+++ /dev/null
@@ -1,38 +0,0 @@
-/************************************************************************\
-	Zone Builder Game Configuration for Sonic Robo Blast 2 Version 2.2
-\************************************************************************/
-
-// This is required to prevent accidental use of a different configuration
-type = "Doom Builder 2 Game Configuration";
-
-// This is the title to show for this game
-game = "Sonic Robo Blast 2 - 2.2 (Doom format)";
-
-// This is the simplified game engine/sourceport name
-engine = "zdoom";
-
-// Settings common to all games and all map formats
-include("Includes\\SRB222_common.cfg", "common");
-
-// Settings common to Doom map format
-include("Includes\\SRB222_common.cfg", "mapformat_doom");
-
-include("Includes\\Game_SRB222.cfg");
-
-// Script lumps detection
-scriptlumpnames
-{
-	include("Includes\\SRB222_misc.cfg", "scriptlumpnames");
-}
-
-// THING TYPES
-thingtypes
-{
-	include("Includes\\SRB222_things.cfg");
-}
-
-//Default things filters
-thingsfilters
-{
-	include("Includes\\SRB222_misc.cfg", "thingsfilters");
-}
\ No newline at end of file
diff --git a/extras/conf/SRB2_22UDMF.cfg b/extras/conf/SRB2_22UDMF.cfg
deleted file mode 100644
index 52104ed090b766914ee69d350c16799b1272d0d2..0000000000000000000000000000000000000000
--- a/extras/conf/SRB2_22UDMF.cfg
+++ /dev/null
@@ -1,47 +0,0 @@
-/************************************************************************\
-	Zone Builder Game Configuration for Sonic Robo Blast 2 Version 2.2
-\************************************************************************/
-
-// This is required to prevent accidental use of a different configuration
-type = "Doom Builder 2 Game Configuration";
-
-// This is the title to show for this game
-game = "Sonic Robo Blast 2 - 2.2 (UDMF)";
-
-// This is the simplified game engine/sourceport name
-engine = "zdoom";
-
-// Settings common to all games and all map formats
-include("Includes\\SRB222_common.cfg", "common");
-
-// Settings common to Doom map format
-include("Includes\\SRB222_common.cfg", "mapformat_udmf");
-
-include("Includes\\Game_SRB222.cfg");
-
-// Script lumps detection
-scriptlumpnames
-{
-	include("Includes\\SRB222_misc.cfg", "scriptlumpnames");
-}
-
-// THING TYPES
-thingtypes
-{
-	include("Includes\\SRB222_things.cfg");
-}
-
-//Default things filters
-thingsfilters
-{
-	include("Includes\\SRB222_misc.cfg", "thingsfilters");
-}
-
-// ENUMERATIONS
-// Each engine has its own additional thing types
-// These are enumerated lists for linedef types and UDMF fields.
-enums
-{
-	// Basic game enums
-	include("Includes\\SRB222_misc.cfg", "enums");
-}
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e8c9c31820c3ba1fcf46691cff5f4476df98220c..bc4a6114ecf1187a9cd191cc21d77eec40c6e5f0 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -120,6 +120,7 @@ set(SRB2_CORE_RENDER_SOURCES
 	r_main.c
 	r_plane.c
 	r_segs.c
+	r_skins.c
 	r_sky.c
 	r_splats.c
 	r_things.c
@@ -134,6 +135,7 @@ set(SRB2_CORE_RENDER_SOURCES
 	r_main.h
 	r_plane.h
 	r_segs.h
+	r_skins.h
 	r_sky.h
 	r_splats.h
 	r_state.h
diff --git a/src/Makefile b/src/Makefile
index 343b8d14309deb854ad03d853c5b630c07478724..6c46671a2ebb1dab97d95844e059150b20a743a4 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -466,6 +466,7 @@ OBJS:=$(i_main_o) \
 		$(OBJDIR)/r_main.o   \
 		$(OBJDIR)/r_plane.o  \
 		$(OBJDIR)/r_segs.o   \
+		$(OBJDIR)/r_skins.o  \
 		$(OBJDIR)/r_sky.o    \
 		$(OBJDIR)/r_splats.o \
 		$(OBJDIR)/r_things.o \
diff --git a/src/android/i_video.c b/src/android/i_video.c
index b8bb4fefbf408970af9c23ace95f5217548dc43e..1909cd71afbb5e2acf1efdfd5a218b44cef09316 100644
--- a/src/android/i_video.c
+++ b/src/android/i_video.c
@@ -19,10 +19,10 @@ boolean allow_fullscreen = false;
 consvar_t cv_vidwait = {"vid_wait", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 void I_StartupGraphics(void){}
-void I_StartupHardwareGraphics(void){}
-
 void I_ShutdownGraphics(void){}
 
+void VID_StartupOpenGL(void){}
+
 void I_SetPalette(RGBA_t *palette)
 {
   (void)palette;
@@ -52,10 +52,8 @@ INT32 VID_SetMode(INT32 modenum)
   return 0;
 }
 
-void VID_CheckRenderer(void)
-{
-	// ..............
-}
+void VID_CheckRenderer(void) {}
+void VID_CheckGLLoaded(rendermode_t oldrender) {}
 
 const char *VID_GetModeName(INT32 modenum)
 {
diff --git a/src/command.c b/src/command.c
index d1eea6052d0844f98472b4ad53e700f82e72aef7..abe6bcedf2bd8c4d36c39560e3a7e05f6909f55b 100644
--- a/src/command.c
+++ b/src/command.c
@@ -80,7 +80,7 @@ static boolean joyaxis2_default = false;
 static INT32 joyaxis_count = 0;
 static INT32 joyaxis2_count = 0;
 
-#define COM_BUF_SIZE 8192 // command buffer size
+#define COM_BUF_SIZE (32<<10) // command buffer size
 #define MAX_ALIAS_RECURSION 100 // max recursion allowed for aliases
 
 static INT32 com_wait; // one command per frame (for cmd sequences)
diff --git a/src/console.c b/src/console.c
index f92868e4ce431f1c913dc7713d57b78119749438..a172aa412418341a073bdcbcf58283816610de6f 100644
--- a/src/console.c
+++ b/src/console.c
@@ -97,6 +97,7 @@ static void CON_InputInit(void);
 static void CON_RecalcSize(void);
 static void CON_ChangeHeight(void);
 
+static void CON_DrawBackpic(void);
 static void CONS_hudlines_Change(void);
 static void CONS_backcolor_Change(void);
 
@@ -1530,6 +1531,51 @@ static void CON_DrawHudlines(void)
 	con_clearlines = y; // this is handled by HU_Erase();
 }
 
+// Lactozilla: Draws the console's background picture.
+static void CON_DrawBackpic(void)
+{
+	patch_t *con_backpic;
+	lumpnum_t piclump;
+	int x, w, h;
+
+	// Get the lumpnum for CONSBACK, or fallback into MISSING.
+	piclump = W_CheckNumForName("CONSBACK");
+	if (piclump == LUMPERROR)
+		piclump = W_GetNumForName("MISSING");
+
+	// Cache the Software patch.
+	con_backpic = W_CacheSoftwarePatchNum(piclump, PU_PATCH);
+
+	// Center the backpic, and draw a vertically cropped patch.
+	w = (con_backpic->width * vid.dupx);
+	x = (vid.width / 2) - (w / 2);
+	h = con_curlines/vid.dupy;
+
+	// If the patch doesn't fill the entire screen,
+	// then fill the sides with a solid color.
+	if (x > 0)
+	{
+		column_t *column = (column_t *)((UINT8 *)(con_backpic) + LONG(con_backpic->columnofs[0]));
+		if (!column->topdelta)
+		{
+			UINT8 *source = (UINT8 *)(column) + 3;
+			INT32 color = (source[0] | V_NOSCALESTART);
+			// left side
+			V_DrawFill(0, 0, x, con_curlines, color);
+			// right side
+			V_DrawFill((x + w), 0, (vid.width - w), con_curlines, color);
+		}
+	}
+
+	// Cache the patch normally.
+	con_backpic = W_CachePatchNum(piclump, PU_PATCH);
+	V_DrawCroppedPatch(x << FRACBITS, 0, FRACUNIT, V_NOSCALESTART, con_backpic,
+			0, ( BASEVIDHEIGHT - h ), BASEVIDWIDTH, h);
+
+	// Unlock the cached patch.
+	W_UnlockCachedPatch(con_backpic);
+}
+
 // draw the console background, text, and prompt if enough place
 //
 static void CON_DrawConsole(void)
@@ -1551,19 +1597,7 @@ static void CON_DrawConsole(void)
 
 	// draw console background
 	if (cons_backpic.value || con_forcepic)
-	{
-		patch_t *con_backpic = W_CachePatchName("CONSBACK", PU_PATCH);
-		int h;
-
-		h = con_curlines/vid.dupy;
-
-		// Jimita: CON_DrawBackpic just called V_DrawScaledPatch
-		//V_DrawScaledPatch(0, 0, 0, con_backpic);
-		V_DrawCroppedPatch(0, 0, FRACUNIT, 0, con_backpic,
-				0, ( BASEVIDHEIGHT - h ), BASEVIDWIDTH, h);
-
-		W_UnlockCachedPatch(con_backpic);
-	}
+		CON_DrawBackpic();
 	else
 	{
 		// inu: no more width (was always 0 and vid.width)
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 71e32977a69b07209cdd292f9ee371186ce26c89..92602d68a92db9a8b9a6813f7da1fff29bcf62a8 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -4855,7 +4855,8 @@ static inline void PingUpdate(void)
 	{
 		for (i = 1; i < MAXPLAYERS; i++)
 		{
-			if (playeringame[i] && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value))
+			if (playeringame[i] && !players[i].quittime
+			&& (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value))
 			{
 				if (players[i].jointime > 30 * TICRATE)
 					laggers[i] = true;
@@ -4874,8 +4875,8 @@ static inline void PingUpdate(void)
 				if (playeringame[i] && laggers[i])
 				{
 					pingtimeout[i]++;
+					// ok your net has been bad for too long, you deserve to die.
 					if (pingtimeout[i] > cv_pingtimeout.value)
-// ok your net has been bad for too long, you deserve to die.
 					{
 						pingtimeout[i] = 0;
 						SendKick(i, KICK_MSG_PING_HIGH | KICK_MSG_KEEP_BODY);
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index 10a1d714df22435f2bb08c1bcf7815bb874df4bc..2ddebadbadbfbb651b1c3fde53d2b272e7d31786 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -20,12 +20,9 @@
 #include "d_player.h"
 
 /*
-The 'packet version' may be used with packets whose
-format is expected to change between versions.
-
-This version is independent of the mod name, and standard
-version and subversion. It should only account for the
-basic fields of the packet, and change infrequently.
+The 'packet version' is used to distinguish packet formats.
+This version is independent of VERSION and SUBVERSION. Different
+applications may follow different packet versions.
 */
 #define PACKETVERSION 2
 
diff --git a/src/d_main.c b/src/d_main.c
index ef2ed63223125db698a9fd076bd867f1dce90ab7..c0a8eacec4cc6c49ba521a74a03c0358aee00768 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -881,6 +881,40 @@ static inline void D_CleanFile(void)
 	}
 }
 
+///\brief Checks if a netgame URL is being handled, and changes working directory to the EXE's if so.
+///       Done because browsers (at least, Firefox on Windows) launch the game from the browser's directory, which causes problems.
+static void ChangeDirForUrlHandler(void)
+{
+	// URL handlers are opened by web browsers (at least Firefox) from the browser's working directory, not the game's stored directory,
+	// so chdir to that directory unless overridden.
+	if (M_GetUrlProtocolArg() != NULL && !M_CheckParm("-nochdir"))
+	{
+		size_t i;
+
+		CONS_Printf("%s connect links load game files from the SRB2 application's stored directory. Switching to ", SERVER_URL_PROTOCOL);
+		strlcpy(srb2path, myargv[0], sizeof(srb2path));
+
+		// Get just the directory, minus the EXE name
+		for (i = strlen(srb2path)-1; i > 0; i--)
+		{
+			if (srb2path[i] == '/' || srb2path[i] == '\\')
+			{
+				srb2path[i] = '\0';
+				break;
+			}
+		}
+
+		CONS_Printf("%s\n", srb2path);
+
+#if defined (_WIN32)
+		SetCurrentDirectoryA(srb2path);
+#else
+		if (chdir(srb2path) == -1)
+			I_OutputMsg("Couldn't change working directory\n");
+#endif
+	}
+}
+
 // ==========================================================================
 // Identify the SRB2 version, and IWAD file to use.
 // ==========================================================================
@@ -1069,6 +1103,9 @@ void D_SRB2Main(void)
 	// Test Dehacked lists
 	DEH_Check();
 
+	// Netgame URL special case: change working dir to EXE folder.
+	ChangeDirForUrlHandler();
+
 	// identify the main IWAD file to use
 	IdentifyVersion();
 
@@ -1151,9 +1188,15 @@ void D_SRB2Main(void)
 	if (M_CheckParm("-password") && M_IsNextParm())
 		D_SetPassword(M_GetNextParm());
 
+	CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n");
+	Z_Init();
+
+	// Do this up here so that WADs loaded through the command line can use ExecCfg
+	COM_Init();
+
 	// add any files specified on the command line with -file wadfile
 	// to the wad list
-	if (!(M_CheckParm("-connect") && !M_CheckParm("-server")))
+	if (!((M_GetUrlProtocolArg() || M_CheckParm("-connect")) && !M_CheckParm("-server")))
 	{
 		if (M_CheckParm("-file"))
 		{
@@ -1178,9 +1221,6 @@ void D_SRB2Main(void)
 	if (M_CheckParm("-server") || dedicated)
 		netgame = server = true;
 
-	CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n");
-	Z_Init();
-
 	// adapt tables to SRB2's needs, including extra slots for dehacked file support
 	P_PatchInfoTables();
 
@@ -1188,7 +1228,7 @@ void D_SRB2Main(void)
 	M_InitMenuPresTables();
 
 	// init title screen display params
-	if (M_CheckParm("-connect"))
+	if (M_GetUrlProtocolArg() || M_CheckParm("-connect"))
 		F_InitMenuPresValues();
 
 	//---------------------------------------------------- READY TIME
@@ -1252,7 +1292,6 @@ void D_SRB2Main(void)
 	CONS_Printf("HU_Init(): Setting up heads up display.\n");
 	HU_Init();
 
-	COM_Init();
 	CON_Init();
 
 	D_RegisterServerCommands();
@@ -1286,11 +1325,10 @@ void D_SRB2Main(void)
 
 		// Set cv_renderer to the new render mode
 		VID_CheckRenderer();
-		SCR_ChangeRendererCVars(setrenderneeded);
+		SCR_ChangeRendererCVars(rendermode);
 
-		// check the renderer's state, and then clear setrenderneeded
+		// check the renderer's state
 		D_CheckRendererState();
-		setrenderneeded = 0;
 	}
 
 	wipegamestate = gamestate;
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index c25929929a2e46fe840253dcc965b48f973d4a4e..a55e702875ade5d54066f5cb987193854dc34dc1 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -22,7 +22,7 @@
 #include "g_input.h"
 #include "m_menu.h"
 #include "r_local.h"
-#include "r_things.h"
+#include "r_skins.h"
 #include "p_local.h"
 #include "p_setup.h"
 #include "s_sound.h"
diff --git a/src/dehacked.c b/src/dehacked.c
index 5a151ce3efb5dd0ce91f319a5e4c395e54f20b2f..71e2e2f549a0f68c506010a2327940d4c8da3c57 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -31,6 +31,7 @@
 #include "r_data.h"
 #include "r_draw.h"
 #include "r_patch.h"
+#include "r_things.h" // R_Char2Frame
 #include "r_sky.h"
 #include "fastcmp.h"
 #include "lua_script.h"
@@ -3889,7 +3890,26 @@ static void readmaincfg(MYFILE *f)
 			value = atoi(word2); // used for numerical settings
 
 			if (fastcmp(word, "EXECCFG"))
-				COM_BufAddText(va("exec %s\n", word2));
+			{
+				if (strchr(word2, '.'))
+					COM_BufAddText(va("exec %s\n", word2));
+				else
+				{
+					lumpnum_t lumpnum;
+					char newname[9];
+
+					strncpy(newname, word2, 8);
+
+					newname[8] = '\0';
+
+					lumpnum = W_CheckNumForName(newname);
+
+					if (lumpnum == LUMPERROR || W_LumpLength(lumpnum) == 0)
+						CONS_Debug(DBG_SETUP, "SOC Error: script lump %s not found/not valid.\n", newname);
+					else
+						COM_BufInsertText(W_CacheLumpNum(lumpnum, PU_CACHE));
+				}
+			}
 
 			else if (fastcmp(word, "SPSTAGE_START"))
 			{
@@ -7477,7 +7497,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 
 	// Got Flag Sign
 	"S_GOTFLAG",
-	
+
 	// Finish flag
 	"S_FINISHFLAG",
 
diff --git a/src/djgppdos/i_video.c b/src/djgppdos/i_video.c
index 02c7a842bc2c0aa77fb7d8d7180a04d9029878b5..f525b96ca6b19475148b8c22b213e21e88b3c8b0 100644
--- a/src/djgppdos/i_video.c
+++ b/src/djgppdos/i_video.c
@@ -339,7 +339,4 @@ void I_StartupGraphics(void)
 
 }
 
-void I_StartupHardwareGraphics(void)
-{
-	// oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo y
-}
+void VID_StartupOpenGL(void) {}
diff --git a/src/djgppdos/vid_vesa.c b/src/djgppdos/vid_vesa.c
index c8ce7dae52e645372455b76cbad40ffd03c53a0e..61ed18e4b6858eb8a9374b7edfe957f06975cce0 100644
--- a/src/djgppdos/vid_vesa.c
+++ b/src/djgppdos/vid_vesa.c
@@ -378,10 +378,8 @@ INT32 VID_SetMode (INT32 modenum)  //, UINT8 *palette)
 	return 1;
 }
 
-void VID_CheckRenderer(void)
-{
-	// ..............
-}
+void VID_CheckRenderer(void) {}
+void VID_CheckGLLoaded(rendermode_t oldrender) {}
 
 
 
diff --git a/src/doomdef.h b/src/doomdef.h
index 3d4a116beff648d06fa713591c84ed715f973b83..1d051c385f8adfbe9ffca87be1316bb6436e87a4 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -150,6 +150,9 @@ extern char logfilename[1024];
 // Otherwise we can't force updates!
 #endif
 
+/* A custom URL protocol for server links. */
+#define SERVER_URL_PROTOCOL "srb2://"
+
 // Does this version require an added patch file?
 // Comment or uncomment this as necessary.
 #define USE_PATCH_DTA
diff --git a/src/dummy/i_video.c b/src/dummy/i_video.c
index fafeee0001400ef868b6c8d91042870c6c2e3773..56ead3672ae8ded9510814b20c766061a5d1d668 100644
--- a/src/dummy/i_video.c
+++ b/src/dummy/i_video.c
@@ -11,10 +11,10 @@ boolean allow_fullscreen = false;
 consvar_t cv_vidwait = {"vid_wait", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 void I_StartupGraphics(void){}
-void I_StartupHardwareGraphics(void){}
-
 void I_ShutdownGraphics(void){}
 
+void VID_StartupOpenGL(void){}
+
 void I_SetPalette(RGBA_t *palette)
 {
 	(void)palette;
@@ -40,10 +40,8 @@ INT32 VID_SetMode(INT32 modenum)
 	return 0;
 }
 
-void VID_CheckRenderer(void)
-{
-	// ..............
-}
+void VID_CheckRenderer(void) {}
+void VID_CheckGLLoaded(rendermode_t oldrender) {}
 
 const char *VID_GetModeName(INT32 modenum)
 {
diff --git a/src/f_wipe.c b/src/f_wipe.c
index 8d12262efb2d6377395ac06c7c6d37d2f6ed48a5..0fd6c1431c099877710e3e39ec74282cf7fb4b0e 100644
--- a/src/f_wipe.c
+++ b/src/f_wipe.c
@@ -16,6 +16,7 @@
 #include "i_video.h"
 #include "v_video.h"
 
+#include "r_state.h" // fadecolormap
 #include "r_draw.h" // transtable
 #include "p_pspr.h" // tr_transxxx
 #include "p_local.h"
diff --git a/src/g_game.c b/src/g_game.c
index 08192bfb8b82247a0f3c391fb97a143a32f5eb2b..58f7795b6cb863a4745c7c8ae68a145b7672eda8 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -38,7 +38,7 @@
 #include "byteptr.h"
 #include "i_joy.h"
 #include "r_local.h"
-#include "r_things.h"
+#include "r_skins.h"
 #include "y_inter.h"
 #include "v_video.h"
 #include "dehacked.h" // get_number (for ghost thok)
@@ -1044,18 +1044,17 @@ static INT32 G_BasicDeadZoneCalculation(INT32 magnitude, fixed_t deadZone)
 {
 	const INT32 jdeadzone = (JOYAXISRANGE * deadZone) / FRACUNIT;
 	INT32 deadzoneAppliedValue = 0;
+	INT32 adjustedMagnitude = abs(magnitude);
 
-	if (jdeadzone > 0)
+	if (jdeadzone >= JOYAXISRANGE && adjustedMagnitude >= JOYAXISRANGE) // If the deadzone and magnitude are both 100%...
+		return JOYAXISRANGE; // ...return 100% input directly, to avoid dividing by 0
+	else if (adjustedMagnitude > jdeadzone) // Otherwise, calculate how much the magnitude exceeds the deadzone
 	{
-		if (magnitude > jdeadzone)
-		{
-			INT32 adjustedMagnitude = abs(magnitude);
-			adjustedMagnitude = min(adjustedMagnitude, JOYAXISRANGE);
+		adjustedMagnitude = min(adjustedMagnitude, JOYAXISRANGE);
 
-			adjustedMagnitude -= jdeadzone;
+		adjustedMagnitude -= jdeadzone;
 
-			deadzoneAppliedValue = (adjustedMagnitude * JOYAXISRANGE) / (JOYAXISRANGE - jdeadzone);
-		}
+		deadzoneAppliedValue = (adjustedMagnitude * JOYAXISRANGE) / (JOYAXISRANGE - jdeadzone);
 	}
 
 	return deadzoneAppliedValue;
diff --git a/src/hardware/hw3sound.c b/src/hardware/hw3sound.c
index 344d8b4c14b2cea0629a4575ab42e61fc94007ef..81f1d8e68fadf94e69c97e02daa65e3ecccf36ab 100644
--- a/src/hardware/hw3sound.c
+++ b/src/hardware/hw3sound.c
@@ -21,7 +21,7 @@
 #include "../tables.h"
 #include "../sounds.h"
 #include "../r_main.h"
-#include "../r_things.h"
+#include "../r_skins.h"
 #include "../m_random.h"
 #include "../p_local.h"
 #include "hw3dsdrv.h"
diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c
index 5dc02e00b8407762aae6570128eb1baf240f1e2a..a64feab087517d82de638d773b5e0e36750fc11f 100644
--- a/src/hardware/hw_cache.c
+++ b/src/hardware/hw_cache.c
@@ -224,11 +224,11 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block,
 			if (mipmap->colormap)
 				texel = mipmap->colormap[texel];
 
-			// transparent pixel
-			if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX)
+			// If the mipmap is chromakeyed, check if the texel's color
+			// is equivalent to the chroma key's color index.
+			alpha = 0xff;
+			if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX))
 				alpha = 0x00;
-			else
-				alpha = 0xff;
 
 			// hope compiler will get this switch out of the loops (dreams...)
 			// gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?)
diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c
index d2dcec1810105bed63a92f00bfbd39413c7eb906..5d58d4b203d149325ce9314493c97d97ffba3f67 100644
--- a/src/hardware/hw_draw.c
+++ b/src/hardware/hw_draw.c
@@ -280,7 +280,7 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t
 			if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT)
 			{
 				// Need to temporarily cache the real patch to get the colour of the top left pixel
-				patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
+				patch_t *realpatch = W_CacheSoftwarePatchNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
 				const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0]));
 				if (!column->topdelta)
 				{
@@ -439,7 +439,7 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal
 			if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT)
 			{
 				// Need to temporarily cache the real patch to get the colour of the top left pixel
-				patch_t *realpatch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
+				patch_t *realpatch = W_CacheSoftwarePatchNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
 				const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0]));
 				if (!column->topdelta)
 				{
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index ede76ed9791f321a26c7b02dcb6f18c1fd4510f0..6fe0d407880de5602acbf0c21335f87f4d800d3d 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -322,9 +322,10 @@ static FUINT HWR_CalcSlopeLight(FUINT lightnum, angle_t dir, fixed_t delta)
 
 #ifdef DOPLANES
 
-// HWR_RenderPlane
-// Render a floor or ceiling convex polygon
-static void HWR_RenderPlane(extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, FBITFIELD PolyFlags, INT32 lightlevel, levelflat_t *levelflat, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap)
+// -----------------+
+// HWR_RenderPlane  : Render a floor or ceiling convex polygon
+// -----------------+
+static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, FBITFIELD PolyFlags, INT32 lightlevel, levelflat_t *levelflat, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap)
 {
 	polyvertex_t *  pv;
 	float           height; //constant y for all points on the convex flat polygon
@@ -438,8 +439,6 @@ static void HWR_RenderPlane(extrasubsector_t *xsub, boolean isceiling, fixed_t f
 	flatyref = (float)(((fixed_t)pv->y & (~flatflag)) / fflatheight);
 
 	// transform
-	v3d = planeVerts;
-
 	if (FOFsector != NULL)
 	{
 		if (!isceiling) // it's a floor
@@ -491,47 +490,43 @@ static void HWR_RenderPlane(extrasubsector_t *xsub, boolean isceiling, fixed_t f
 		flatyref = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));
 	}
 
+#define SETUP3DVERT(vert, vx, vy) {\
+		/* Hurdler: add scrolling texture on floor/ceiling */\
+		if (texflat)\
+		{\
+			vert->s = (float)((vx) / fflatwidth) + scrollx;\
+			vert->t = -(float)((vy) / fflatheight) + scrolly;\
+		}\
+		else\
+		{\
+			vert->s = (float)(((vx) / fflatwidth) - flatxref + scrollx);\
+			vert->t = (float)(flatyref - ((vy) / fflatheight) + scrolly);\
+		}\
+\
+		/* Need to rotate before translate */\
+		if (angle) /* Only needs to be done if there's an altered angle */\
+		{\
+			tempxsow = FLOAT_TO_FIXED(vert->s);\
+			tempytow = FLOAT_TO_FIXED(vert->t);\
+			if (texflat)\
+				tempytow = -tempytow;\
+			vert->s = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));\
+			vert->t = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));\
+		}\
+\
+		vert->x = (vx);\
+		vert->y = height;\
+		vert->z = (vy);\
+\
+		if (slope)\
+		{\
+			fixedheight = P_GetZAt(slope, FLOAT_TO_FIXED((vx)), FLOAT_TO_FIXED((vy)));\
+			vert->y = FIXED_TO_FLOAT(fixedheight);\
+		}\
+}
 
-	for (i = 0; i < nrPlaneVerts; i++,v3d++,pv++)
-	{
-		// Hurdler: add scrolling texture on floor/ceiling
-		if (texflat)
-		{
-			v3d->s = (float)(pv->x / fflatwidth) + scrollx;
-			v3d->t = -(float)(pv->y / fflatheight) + scrolly;
-		}
-		else
-		{
-			v3d->s = (float)((pv->x / fflatwidth) - flatxref + scrollx);
-			v3d->t = (float)(flatyref - (pv->y / fflatheight) + scrolly);
-		}
-
-		// Need to rotate before translate
-		if (angle) // Only needs to be done if there's an altered angle
-		{
-			tempxsow = FLOAT_TO_FIXED(v3d->s);
-			tempytow = FLOAT_TO_FIXED(v3d->t);
-			if (texflat)
-				tempytow = -tempytow;
-			v3d->s = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));
-			v3d->t = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));
-		}
-
-		//v3d->s = (float)(v3d->s - flatxref + scrollx);
-		//v3d->t = (float)(flatyref - v3d->t + scrolly);
-
-		v3d->x = pv->x;
-		v3d->y = height;
-		v3d->z = pv->y;
-
-#ifdef ESLOPE
-		if (slope)
-		{
-			fixedheight = P_GetZAt(slope, FLOAT_TO_FIXED(pv->x), FLOAT_TO_FIXED(pv->y));
-			v3d->y = FIXED_TO_FLOAT(fixedheight);
-		}
-#endif
-	}
+	for (i = 0, v3d = planeVerts; i < nrPlaneVerts; i++,v3d++,pv++)
+		SETUP3DVERT(v3d, pv->x, pv->y);
 
 #ifdef ESLOPE
 	if (slope)
@@ -557,6 +552,79 @@ static void HWR_RenderPlane(extrasubsector_t *xsub, boolean isceiling, fixed_t f
 
 	HWD.pfnDrawPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags);
 
+	if (subsector)
+	{
+		// Horizon lines
+		FOutVector horizonpts[6];
+		float dist, vx, vy;
+		float x1, y1, xd, yd;
+		UINT8 numplanes, j;
+		vertex_t v; // For determining the closest distance from the line to the camera, to split render planes for minimum distortion;
+
+		const float renderdist = 27000.0f; // How far out to properly render the plane
+		const float farrenderdist = 32768.0f; // From here, raise plane to horizon level to fill in the line with some texture distortion
+
+		seg_t *line = &segs[subsector->firstline];
+
+		for (i = 0; i < subsector->numlines; i++, line++)
+		{
+			if (!line->glseg && line->linedef->special == HORIZONSPECIAL && R_PointOnSegSide(dup_viewx, dup_viewy, line) == 0)
+			{
+				P_ClosestPointOnLine(viewx, viewy, line->linedef, &v);
+				dist = FIXED_TO_FLOAT(R_PointToDist(v.x, v.y));
+
+				x1 = ((polyvertex_t *)line->pv1)->x;
+				y1 = ((polyvertex_t *)line->pv1)->y;
+				xd = ((polyvertex_t *)line->pv2)->x - x1;
+				yd = ((polyvertex_t *)line->pv2)->y - y1;
+
+				// Based on the seg length and the distance from the line, split horizon into multiple poly sets to reduce distortion
+				dist = sqrtf((xd*xd) + (yd*yd)) / dist / 16.0f;
+				if (dist > 100.0f)
+					numplanes = 100;
+				else
+					numplanes = (UINT8)dist + 1;
+
+				for (j = 0; j < numplanes; j++)
+				{
+					// Left side
+					vx = x1 + xd * j / numplanes;
+					vy = y1 + yd * j / numplanes;
+					SETUP3DVERT((&horizonpts[1]), vx, vy);
+
+					dist = sqrtf(powf(vx - gr_viewx, 2) + powf(vy - gr_viewy, 2));
+					vx = (vx - gr_viewx) * renderdist / dist + gr_viewx;
+					vy = (vy - gr_viewy) * renderdist / dist + gr_viewy;
+					SETUP3DVERT((&horizonpts[0]), vx, vy);
+
+					// Right side
+					vx = x1 + xd * (j+1) / numplanes;
+					vy = y1 + yd * (j+1) / numplanes;
+					SETUP3DVERT((&horizonpts[2]), vx, vy);
+
+					dist = sqrtf(powf(vx - gr_viewx, 2) + powf(vy - gr_viewy, 2));
+					vx = (vx - gr_viewx) * renderdist / dist + gr_viewx;
+					vy = (vy - gr_viewy) * renderdist / dist + gr_viewy;
+					SETUP3DVERT((&horizonpts[3]), vx, vy);
+
+					// Horizon fills
+					vx = (horizonpts[0].x - gr_viewx) * farrenderdist / renderdist + gr_viewx;
+					vy = (horizonpts[0].z - gr_viewy) * farrenderdist / renderdist + gr_viewy;
+					SETUP3DVERT((&horizonpts[5]), vx, vy);
+					horizonpts[5].y = gr_viewz;
+
+					vx = (horizonpts[3].x - gr_viewx) * farrenderdist / renderdist + gr_viewx;
+					vy = (horizonpts[3].z - gr_viewy) * farrenderdist / renderdist + gr_viewy;
+					SETUP3DVERT((&horizonpts[4]), vx, vy);
+					horizonpts[4].y = gr_viewz;
+
+					// Draw
+					HWD.pfnDrawPolygon(&Surf, horizonpts, 6, PolyFlags);
+				}
+			}
+		}
+	}
+
 #ifdef ALAM_LIGHTING
 	// add here code for dynamic lighting on planes
 	HWR_PlaneLighting(planeVerts, nrPlaneVerts);
@@ -3235,7 +3303,7 @@ static void HWR_Subsector(size_t num)
 			if (sub->validcount != validcount)
 			{
 				HWR_GetLevelFlat(&levelflats[gr_frontsector->floorpic]);
-				HWR_RenderPlane(&extrasubsectors[num], false,
+				HWR_RenderPlane(sub, &extrasubsectors[num], false,
 					// Hack to make things continue to work around slopes.
 					locFloorHeight == cullFloorHeight ? locFloorHeight : gr_frontsector->floorheight,
 					// We now return you to your regularly scheduled rendering.
@@ -3257,7 +3325,7 @@ static void HWR_Subsector(size_t num)
 			if (sub->validcount != validcount)
 			{
 				HWR_GetLevelFlat(&levelflats[gr_frontsector->ceilingpic]);
-				HWR_RenderPlane(&extrasubsectors[num], true,
+				HWR_RenderPlane(sub, &extrasubsectors[num], true,
 					// Hack to make things continue to work around slopes.
 					locCeilingHeight == cullCeilingHeight ? locCeilingHeight : gr_frontsector->ceilingheight,
 					// We now return you to your regularly scheduled rendering.
@@ -3340,7 +3408,7 @@ static void HWR_Subsector(size_t num)
 				{
 					HWR_GetLevelFlat(&levelflats[*rover->bottompic]);
 					light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
-					HWR_RenderPlane(&extrasubsectors[num], false, *rover->bottomheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, &levelflats[*rover->bottompic],
+					HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, &levelflats[*rover->bottompic],
 					                rover->master->frontsector, 255, *gr_frontsector->lightlist[light].extra_colormap);
 				}
 			}
@@ -3392,7 +3460,7 @@ static void HWR_Subsector(size_t num)
 				{
 					HWR_GetLevelFlat(&levelflats[*rover->toppic]);
 					light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
-					HWR_RenderPlane(&extrasubsectors[num], true, *rover->topheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, &levelflats[*rover->toppic],
+					HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, &levelflats[*rover->toppic],
 					                  rover->master->frontsector, 255, *gr_frontsector->lightlist[light].extra_colormap);
 				}
 			}
@@ -4025,7 +4093,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
 		if (h <= temp)
 		{
 			if (!(spr->mobj->frame & FF_FULLBRIGHT))
-				lightlevel = *list[i-1].lightlevel;
+				lightlevel = *list[i-1].lightlevel > 255 ? 255 : *list[i-1].lightlevel;
 			colormap = *list[i-1].extra_colormap;
 			break;
 		}
@@ -4033,7 +4101,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
 #else
 	i = R_GetPlaneLight(sector, temp, false);
 	if (!(spr->mobj->frame & FF_FULLBRIGHT))
-		lightlevel = *list[i].lightlevel;
+		lightlevel = *list[i].lightlevel > 255 ? 255 : *list[i].lightlevel;
 	colormap = *list[i].extra_colormap;
 #endif
 
@@ -4049,7 +4117,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
 		if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES))
 		{
 			if (!(spr->mobj->frame & FF_FULLBRIGHT))
-				lightlevel = *list[i].lightlevel;
+				lightlevel = *list[i].lightlevel > 255 ? 255 : *list[i].lightlevel;
 			colormap = *list[i].extra_colormap;
 		}
 
@@ -4322,7 +4390,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
 		extracolormap_t *colormap = sector->extra_colormap;
 
 		if (!(spr->mobj->frame & FF_FULLBRIGHT))
-			lightlevel = sector->lightlevel;
+			lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel;
 
 		HWR_Lighting(&Surf, lightlevel, colormap);
 	}
@@ -4417,7 +4485,7 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
 			light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
 
 			if (!(spr->mobj->frame & FF_FULLBRIGHT))
-				lightlevel = *sector->lightlist[light].lightlevel;
+				lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel;
 
 			if (*sector->lightlist[light].extra_colormap)
 				colormap = *sector->lightlist[light].extra_colormap;
@@ -4425,7 +4493,7 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
 		else
 		{
 			if (!(spr->mobj->frame & FF_FULLBRIGHT))
-				lightlevel = sector->lightlevel;
+				lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel;
 
 			if (sector->extra_colormap)
 				colormap = sector->extra_colormap;
@@ -4837,7 +4905,7 @@ static void HWR_CreateDrawNodes(void)
 
 			if (!(sortnode[sortindex[i]].plane->blend & PF_NoTexture))
 				HWR_GetLevelFlat(sortnode[sortindex[i]].plane->levelflat);
-			HWR_RenderPlane(sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->isceiling, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel,
+			HWR_RenderPlane(NULL, sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->isceiling, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel,
 				sortnode[sortindex[i]].plane->levelflat, sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->alpha, sortnode[sortindex[i]].plane->planecolormap);
 		}
 		else if (sortnode[sortindex[i]].polyplane)
@@ -6155,7 +6223,6 @@ void HWR_Shutdown(void)
 	CONS_Printf("HWR_Shutdown()\n");
 	HWR_FreeExtraSubsectors();
 	HWR_FreePolyPool();
-	HWR_FreeMipmapCache();
 	HWR_FreeTextureCache();
 	HWD.pfnFlushScreenTextures();
 }
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index e130373d21db767b7872528942d959d315ec2dce..35932bcc0e04559981faa54f4e4865c1675c2328 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -1207,7 +1207,7 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
 			light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
 
 			if (!(spr->mobj->frame & FF_FULLBRIGHT))
-				lightlevel = *sector->lightlist[light].lightlevel;
+				lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel;
 
 			if (*sector->lightlist[light].extra_colormap)
 				colormap = *sector->lightlist[light].extra_colormap;
@@ -1215,7 +1215,7 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
 		else
 		{
 			if (!(spr->mobj->frame & FF_FULLBRIGHT))
-				lightlevel = sector->lightlevel;
+				lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel;
 
 			if (sector->extra_colormap)
 				colormap = sector->extra_colormap;
@@ -1461,7 +1461,7 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
 
 			// rotation pivot
 			p.centerx = FIXED_TO_FLOAT(spr->mobj->radius/2);
-			p.centery = FIXED_TO_FLOAT(spr->mobj->height/2);
+			p.centery = FIXED_TO_FLOAT(spr->mobj->height/(flip ? -2 : 2));
 
 			// rotation axis
 			if (sprinfo->available)
@@ -1473,6 +1473,9 @@ boolean HWR_DrawModel(gr_vissprite_t *spr)
 				p.rollflip = 1;
 			else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
 				p.rollflip = -1;
+
+			if (flip)
+				p.rollflip *= -1;
 		}
 
 		p.anglex = 0.0f;
diff --git a/src/i_tcp.c b/src/i_tcp.c
index 34cad1765df8225cb86fb93d1b781191cd506f2f..373ea1bd03836514cd219030fd72fb1431791126 100644
--- a/src/i_tcp.c
+++ b/src/i_tcp.c
@@ -1423,6 +1423,7 @@ static void SOCK_ClearBans(void)
 boolean I_InitTcpNetwork(void)
 {
 	char serverhostname[255];
+	const char *urlparam = NULL;
 	boolean ret = false;
 	// initilize the OS's TCP/IP stack
 	if (!I_InitTcpDriver())
@@ -1476,10 +1477,12 @@ boolean I_InitTcpNetwork(void)
 
 		ret = true;
 	}
-	else if (M_CheckParm("-connect"))
+	else if ((urlparam = M_GetUrlProtocolArg()) != NULL || M_CheckParm("-connect"))
 	{
-		if (M_IsNextParm())
-			strcpy(serverhostname, M_GetNextParm());
+		if (urlparam != NULL)
+			strlcpy(serverhostname, urlparam, sizeof(serverhostname));
+		else if (M_IsNextParm())
+			strlcpy(serverhostname, M_GetNextParm(), sizeof(serverhostname));
 		else
 			serverhostname[0] = 0; // assuming server in the LAN, use broadcast to detect it
 
diff --git a/src/i_video.h b/src/i_video.h
index bdc10c9c5d2aab8a2eaa8eceff5a1b2db7411cd5..98ed7f38a18822d8038ec0973ef3c680572c2d89 100644
--- a/src/i_video.h
+++ b/src/i_video.h
@@ -36,10 +36,10 @@ typedef enum
 */
 extern rendermode_t rendermode;
 
-/**	\brief hardware renderer loaded
+/**	\brief OpenGL state
 	0 = never loaded, 1 = loaded successfully, -1 = failed loading
 */
-extern INT32 hwrenderloaded;
+extern INT32 vid_opengl_state;
 
 /**	\brief use highcolor modes if true
 */
@@ -49,11 +49,7 @@ extern boolean highcolor;
 */
 void I_StartupGraphics(void);
 
-/**	\brief setup hardware mode
-*/
-void I_StartupHardwareGraphics(void);
-
-/**	\brief restore old video mode
+/**	\brief shutdown video mode
 */
 void I_ShutdownGraphics(void);
 
@@ -97,6 +93,14 @@ INT32 VID_SetMode(INT32 modenum);
 */
 void VID_CheckRenderer(void);
 
+/**	\brief Load OpenGL mode
+*/
+void VID_StartupOpenGL(void);
+
+/**	\brief Checks if OpenGL loaded
+*/
+void VID_CheckGLLoaded(rendermode_t oldrender);
+
 /**	\brief	The VID_GetModeName function
 
 	\param	modenum	video mode number
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 03f14244614e73c2d9e35085f637424c41ed2d84..d001408be805b952c18cf94482fc52ee73393850 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -21,7 +21,7 @@
 #include "z_zone.h"
 #include "r_main.h"
 #include "r_draw.h"
-#include "r_things.h"
+#include "r_things.h" // R_Frame2Char etc
 #include "m_random.h"
 #include "s_sound.h"
 #include "g_game.h"
diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c
index efed9adb7b7e61b2a230ceef184991e5de0d7051..92080e8eda16674593f9ea0f745c5370ce9b2e15 100644
--- a/src/lua_hooklib.c
+++ b/src/lua_hooklib.c
@@ -15,7 +15,7 @@
 #include "doomstat.h"
 #include "p_mobj.h"
 #include "g_game.h"
-#include "r_things.h"
+#include "r_skins.h"
 #include "b_bot.h"
 #include "z_zone.h"
 
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index a7bd8da940adb8d574e641b7651f68fb214d99de..9e46344cf5472780cbebda2d73eba51b31406ae3 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -13,7 +13,7 @@
 #include "doomdef.h"
 #ifdef HAVE_BLUA
 #include "fastcmp.h"
-#include "r_things.h"
+#include "r_skins.h"
 #include "p_local.h"
 #include "g_game.h"
 #include "p_setup.h"
diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c
index 3ade06042efc9f2183c0c3107d9e795f67713a50..f26aed2f0fd82a8bb39d2a56cf36f1c58dc6df01 100644
--- a/src/lua_skinlib.c
+++ b/src/lua_skinlib.c
@@ -13,7 +13,7 @@
 #include "doomdef.h"
 #ifdef HAVE_BLUA
 #include "fastcmp.h"
-#include "r_things.h"
+#include "r_skins.h"
 #include "sounds.h"
 
 #include "lua_script.h"
diff --git a/src/m_argv.c b/src/m_argv.c
index acb74cff415d2d84058ce5cc81e74a548c0ee936..7d43d96bc62f0c20c2b1f1485809defab2bdda0a 100644
--- a/src/m_argv.c
+++ b/src/m_argv.c
@@ -34,6 +34,25 @@ boolean myargmalloc = false;
 */
 static INT32 found;
 
+/**	\brief Parses a server URL (such as srb2://127.0.0.1) as may be passed to the game via a web browser, etc.
+
+	\return the contents of the URL after the protocol (a server to join), or NULL if not found
+*/
+const char *M_GetUrlProtocolArg(void)
+{
+	INT32 i;
+	const size_t len = strlen(SERVER_URL_PROTOCOL);
+
+	for (i = 1; i < myargc; i++)
+	{
+		if (strlen(myargv[i]) > len && !strnicmp(myargv[i], SERVER_URL_PROTOCOL, len))
+		{
+			return &myargv[i][len];
+		}
+	}
+
+	return NULL;
+}
 
 /**	\brief	The M_CheckParm function
 
diff --git a/src/m_argv.h b/src/m_argv.h
index ca97d9b126106e1e2a6a2d70271acc7ee40ab380..92770f4e9e9b0c58b3a32ad8b752e62cca65b236 100644
--- a/src/m_argv.h
+++ b/src/m_argv.h
@@ -21,6 +21,9 @@ extern INT32 myargc;
 extern char **myargv;
 extern boolean myargmalloc;
 
+// Looks for an srb2:// (or similar) URL passed in as an argument and returns the IP to connect to if found.
+const char *M_GetUrlProtocolArg(void);
+
 // Returns the position of the given parameter in the arg list (0 if not found).
 INT32 M_CheckParm(const char *check);
 
diff --git a/src/m_cond.c b/src/m_cond.c
index 89058a488ae1833167caea247b60bc1391e62c15..0abc7adf88c7ace2907b69ea4c8277a500549b99 100644
--- a/src/m_cond.c
+++ b/src/m_cond.c
@@ -18,7 +18,7 @@
 #include "v_video.h" // video flags
 
 #include "g_game.h" // record info
-#include "r_things.h" // numskins
+#include "r_skins.h" // numskins
 #include "r_draw.h" // R_GetColorByName
 
 // Map triggers for linedef executors
diff --git a/src/m_fixed.h b/src/m_fixed.h
index 7fdb9ad0a014e05828c289d67bb0342039208d19..cc54c1aea257d5d0ef8180fe3ef15d25b392afb6 100644
--- a/src/m_fixed.h
+++ b/src/m_fixed.h
@@ -38,8 +38,20 @@ typedef INT32 fixed_t;
 /*!
   \brief convert fixed_t into floating number
 */
-#define FIXED_TO_FLOAT(x) (((float)(x)) / ((float)FRACUNIT))
-#define FLOAT_TO_FIXED(f) (fixed_t)((f) * ((float)FRACUNIT))
+
+FUNCMATH FUNCINLINE static ATTRINLINE float FixedToFloat(fixed_t x)
+{
+	return x / (float)FRACUNIT;
+}
+
+FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FloatToFixed(float f)
+{
+	return (fixed_t)(f * FRACUNIT);
+}
+
+// for backwards compat
+#define FIXED_TO_FLOAT(x) FixedToFloat(x) // (((float)(x)) / ((float)FRACUNIT))
+#define FLOAT_TO_FIXED(f) FloatToFixed(f) // (fixed_t)((f) * ((float)FRACUNIT))
 
 
 #if defined (__WATCOMC__) && FRACBITS == 16
diff --git a/src/m_menu.c b/src/m_menu.c
index 858c19f645b57174edf2d8796df0fae030e57745..63846b5e110c972649ea29b350b122501ac7f903 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -519,6 +519,8 @@ static menuitem_t MISC_AddonsMenu[] =
 // ---------------------------------
 static menuitem_t MAPauseMenu[] =
 {
+	{IT_CALL | IT_STRING,    NULL, "Emblem Hints...",      M_EmblemHints,         32},
+
 	{IT_CALL | IT_STRING,    NULL, "Continue",             M_SelectableClearMenus,48},
 	{IT_CALL | IT_STRING,    NULL, "Retry",                M_ModeAttackRetry,     56},
 	{IT_CALL | IT_STRING,    NULL, "Abort",                M_ModeAttackEndGame,   64},
@@ -526,6 +528,7 @@ static menuitem_t MAPauseMenu[] =
 
 typedef enum
 {
+	mapause_hints,
 	mapause_continue,
 	mapause_retry,
 	mapause_abort
@@ -727,9 +730,9 @@ static menuitem_t SR_SoundTestMenu[] =
 
 static menuitem_t SR_EmblemHintMenu[] =
 {
-	{IT_STRING | IT_ARROWS,       NULL, "Page", M_HandleEmblemHints, 10},
-	{IT_STRING|IT_CVAR,         NULL, "Emblem Radar", &cv_itemfinder, 20},
-	{IT_WHITESTRING|IT_SUBMENU, NULL, "Back",         &SPauseDef,     30}
+	{IT_STRING | IT_ARROWS,  NULL, "Page",    M_HandleEmblemHints, 10},
+	{IT_STRING|IT_CVAR,      NULL, "Emblem Radar", &cv_itemfinder, 20},
+	{IT_WHITESTRING|IT_CALL, NULL, "Back",         M_GoBack,       30}
 };
 
 // --------------------------------
@@ -2089,7 +2092,7 @@ static void M_VideoOptions(INT32 choice)
 {
 	(void)choice;
 #ifdef HWRENDER
-	if (hwrenderloaded == -1)
+	if (vid_opengl_state == -1)
 	{
 		OP_VideoOptionsMenu[op_video_renderer].status = (IT_TRANSTEXT | IT_PAIR);
 		OP_VideoOptionsMenu[op_video_renderer].patch = "Renderer";
@@ -2184,7 +2187,7 @@ menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE(
 menu_t OP_ScreenshotOptionsDef =
 {
 	MN_OP_MAIN + (MN_OP_DATA << 6) + (MN_OP_SCREENSHOTS << 12),
-	"M_DATA",
+	"M_SCREEN",
 	sizeof (OP_ScreenshotOptionsMenu)/sizeof (menuitem_t),
 	&OP_DataOptionsDef,
 	OP_ScreenshotOptionsMenu,
@@ -3614,6 +3617,7 @@ void M_StartControlPanel(void)
 	else if (modeattacking)
 	{
 		currentMenu = &MAPauseDef;
+		MAPauseMenu[mapause_hints].status = (M_SecretUnlocked(SECRET_EMBLEMHINTS)) ? (IT_STRING | IT_CALL) : (IT_DISABLED);
 		itemOn = mapause_continue;
 	}
 	else if (!(netgame || multiplayer)) // Single Player
@@ -5054,6 +5058,17 @@ static boolean M_SetNextMapOnPlatter(void)
 }
 #endif
 
+static boolean M_GametypeHasLevels(INT32 gt)
+{
+	INT32 mapnum;
+
+	for (mapnum = 0; mapnum < NUMMAPS; mapnum++)
+		if (M_CanShowLevelOnPlatter(mapnum, gt))
+			return true;
+
+	return false;
+}
+
 static INT32 M_CountRowsToShowOnPlatter(INT32 gt)
 {
 	INT32 mapnum = 0, prevmapnum = 0, col = 0, rows = 0;
@@ -5371,7 +5386,10 @@ static void M_HandleLevelPlatter(INT32 choice)
 		case KEY_RIGHTARROW:
 			if (levellistmode == LLM_CREATESERVER && !lsrow)
 			{
-				CV_AddValue(&cv_newgametype, 1);
+				INT32 startinggametype = cv_newgametype.value;
+				do
+					CV_AddValue(&cv_newgametype, 1);
+				while (cv_newgametype.value != startinggametype && !M_GametypeHasLevels(cv_newgametype.value));
 				S_StartSound(NULL,sfx_menu1);
 				lscol = 0;
 
@@ -5400,7 +5418,10 @@ static void M_HandleLevelPlatter(INT32 choice)
 		case KEY_LEFTARROW:
 			if (levellistmode == LLM_CREATESERVER && !lsrow)
 			{
-				CV_AddValue(&cv_newgametype, -1);
+				INT32 startinggametype = cv_newgametype.value;
+				do
+					CV_AddValue(&cv_newgametype, -1);
+				while (cv_newgametype.value != startinggametype && !M_GametypeHasLevels(cv_newgametype.value));
 				S_StartSound(NULL,sfx_menu1);
 				lscol = 0;
 
@@ -5720,6 +5741,8 @@ static void M_DrawNightsAttackSuperSonic(void)
 	const UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_YELLOW, GTC_CACHE);
 	INT32 timer = (ntsatkdrawtimer/4) % 2;
 	angle_t fa = (FixedAngle(((ntsatkdrawtimer * 4) % 360)<<FRACBITS)>>ANGLETOFINESHIFT) & FINEMASK;
+	ntssupersonic[0] = W_CachePatchName("NTSSONC1", PU_PATCH);
+	ntssupersonic[1] = W_CachePatchName("NTSSONC2", PU_PATCH);
 	V_DrawFixedPatch(235<<FRACBITS, (120<<FRACBITS) - (8*FINESINE(fa)), FRACUNIT, 0, ntssupersonic[timer], colormap);
 }
 
@@ -7271,6 +7294,7 @@ static void M_EmblemHints(INT32 choice)
 	SR_EmblemHintMenu[0].status = (local > NUMHINTS*2) ? (IT_STRING | IT_ARROWS) : (IT_DISABLED);
 	SR_EmblemHintMenu[1].status = (M_SecretUnlocked(SECRET_ITEMFINDER)) ? (IT_CVAR|IT_STRING) : (IT_SECRET);
 	hintpage = 1;
+	SR_EmblemHintDef.prevMenu = currentMenu;
 	M_SetupNextMenu(&SR_EmblemHintDef);
 	itemOn = 2; // always start on back.
 }
@@ -7951,12 +7975,20 @@ static void M_CustomLevelSelect(INT32 choice)
 static void M_SinglePlayerMenu(INT32 choice)
 {
 	(void)choice;
-	SP_MainMenu[sptutorial].status =
-		tutorialmap ? IT_CALL|IT_STRING : IT_NOTHING|IT_DISABLED;
-	SP_MainMenu[sprecordattack].status =
-		(M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET;
-	SP_MainMenu[spnightsmode].status =
-		(M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET;
+
+	levellistmode = LLM_RECORDATTACK;
+	if (M_GametypeHasLevels(-1))
+		SP_MainMenu[sprecordattack].status = (M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET;
+	else
+		SP_MainMenu[sprecordattack].status = IT_NOTHING|IT_DISABLED;
+
+	levellistmode = LLM_NIGHTSATTACK;
+	if (M_GametypeHasLevels(-1))
+		SP_MainMenu[spnightsmode].status = (M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET;
+	else
+		SP_MainMenu[spnightsmode].status = IT_NOTHING|IT_DISABLED;
+
+	SP_MainMenu[sptutorial].status = tutorialmap ? IT_CALL|IT_STRING : IT_NOTHING|IT_DISABLED;
 
 	M_SetupNextMenu(&SP_MainDef);
 }
@@ -9958,9 +9990,6 @@ static void M_NightsAttack(INT32 choice)
 	// This is really just to make sure Sonic is the played character, just in case
 	M_PatchSkinNameTable();
 
-	ntssupersonic[0] = W_CachePatchName("NTSSONC1", PU_PATCH);
-	ntssupersonic[1] = W_CachePatchName("NTSSONC2", PU_PATCH);
-
 	G_SetGamestate(GS_TIMEATTACK); // do this before M_SetupNextMenu so that menu meta state knows that we're switching
 	titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please
 	M_SetupNextMenu(&SP_NightsAttackDef);
@@ -10080,13 +10109,13 @@ static void M_ReplayTimeAttack(INT32 choice)
 static void M_EraseGuest(INT32 choice)
 {
 	const char *rguest = va("%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s-guest.lmp", srb2home, timeattackfolder, G_BuildMapName(cv_nextmap.value));
-	(void)choice;
-	if (FIL_FileExists(rguest))
-		remove(rguest);
-	if (currentMenu == &SP_NightsGuestReplayDef)
-		M_SetupNextMenu(&SP_NightsAttackDef);
-	else
-		M_SetupNextMenu(&SP_TimeAttackDef);
+
+	if (choice == 'y' || choice == KEY_ENTER)
+	{
+		if (FIL_FileExists(rguest))
+			remove(rguest);
+	}
+	M_SetupNextMenu(currentMenu->prevMenu->prevMenu);
 	Nextmap_OnChange();
 	M_StartMessage(M_GetText("Guest replay data erased.\n"),NULL,MM_NOTHING);
 }
diff --git a/src/m_menu.h b/src/m_menu.h
index 698790a0badfbb86b7c5ac0d1c37a0b127ecc673..b537911e379b1589bc0bc8abcaa731911b011306 100644
--- a/src/m_menu.h
+++ b/src/m_menu.h
@@ -15,9 +15,10 @@
 #ifndef __X_MENU__
 #define __X_MENU__
 
+#include "doomstat.h" // for NUMGAMETYPES
 #include "d_event.h"
 #include "command.h"
-#include "r_things.h" // for SKINNAMESIZE
+#include "r_skins.h" // for SKINNAMESIZE
 #include "f_finale.h" // for ttmode_enum
 
 //
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 5d067ebc3c24f0af29b4bda036ea14c103a99b18..14e5c4d3e5050a00e21ff6e7453ca76824a99e8f 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -21,7 +21,7 @@
 #include "s_sound.h"
 #include "m_random.h"
 #include "m_misc.h"
-#include "r_things.h"
+#include "r_skins.h"
 #include "i_video.h"
 #include "z_zone.h"
 #include "lua_hook.h"
diff --git a/src/p_mobj.c b/src/p_mobj.c
index faee245d3b9e2f63e39eeedda617d20134c7ddd5..9194cf9f7e2dfbbf2b14e8e32f7f66348cfb2bb9 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -19,7 +19,7 @@
 #include "p_local.h"
 #include "p_setup.h"
 #include "r_main.h"
-#include "r_things.h"
+#include "r_skins.h"
 #include "r_sky.h"
 #include "r_splats.h"
 #include "s_sound.h"
diff --git a/src/p_saveg.c b/src/p_saveg.c
index fc8d9d4ee82b9a9b21ccc5316ea6d1521c5a1415..e6c7d07fdf58da4d264b578fcc03ce056cb1b5a0 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -22,7 +22,7 @@
 #include "p_setup.h"
 #include "p_saveg.h"
 #include "r_data.h"
-#include "r_things.h"
+#include "r_skins.h"
 #include "r_state.h"
 #include "w_wad.h"
 #include "y_inter.h"
diff --git a/src/p_setup.c b/src/p_setup.c
index 7b4c6773b07a0bef06905839fbfc62317744881a..857bb1d43a70c21e163c8092a4feeca06c49ce62 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -27,7 +27,7 @@
 #include "i_system.h"
 
 #include "r_data.h"
-#include "r_things.h"
+#include "r_things.h" // for R_AddSpriteDefs
 #include "r_patch.h"
 #include "r_sky.h"
 #include "r_draw.h"
diff --git a/src/p_spec.c b/src/p_spec.c
index d9bbab246ea4b8327666e0695f14776aa2ba86b8..aecdb3b98f75583a2bb7492442085645f4517720 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -36,7 +36,7 @@
 #include "m_cond.h" //unlock triggers
 #include "lua_hook.h" // LUAh_LinedefExecute
 #include "f_finale.h" // control text prompt
-#include "r_things.h" // skins
+#include "r_skins.h" // skins
 
 #ifdef HW3SOUND
 #include "hardware/hw3sound.h"
diff --git a/src/p_user.c b/src/p_user.c
index 5dd6fe0576343b4dffe0992edac179482e1e1ca9..01584eee9f7721bd8c404d69052eeac9bf776fa9 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -22,7 +22,7 @@
 #include "p_local.h"
 #include "r_main.h"
 #include "s_sound.h"
-#include "r_things.h"
+#include "r_skins.h"
 #include "d_think.h"
 #include "r_sky.h"
 #include "p_setup.h"
diff --git a/src/r_segs.c b/src/r_segs.c
index 0233b1161bd93137a7cbf5e1a1bd7bc71a13f9be..32a9221474bc69d8bf105a90cc5b9e390988e0ab 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -240,14 +240,13 @@ static void R_DrawWallSplats(void)
 //  way we don't have to store extra post_t info with each column for
 //  multi-patch textures. They are not normally needed as multi-patch
 //  textures don't have holes in it. At least not for now.
-static INT32 column2s_length; // column->length : for multi-patch on 2sided wall = texture->height
 
 static void R_Render2sidedMultiPatchColumn(column_t *column)
 {
 	INT32 topscreen, bottomscreen;
 
 	topscreen = sprtopscreen; // + spryscale*column->topdelta;  topdelta is 0 for the wall
-	bottomscreen = topscreen + spryscale * column2s_length;
+	bottomscreen = topscreen + spryscale * lengthcol;
 
 	dc_yl = (sprtopscreen+FRACUNIT-1)>>FRACBITS;
 	dc_yh = (bottomscreen-1)>>FRACBITS;
@@ -279,13 +278,6 @@ static void R_Render2sidedMultiPatchColumn(column_t *column)
 	}
 }
 
-// quick wrapper for R_DrawFlippedMaskedColumn so it can be set as a colfunc_2s value
-// uses column2s_length for texture->height as above
-static void R_DrawFlippedMaskedSegColumn(column_t *column)
-{
-	R_DrawFlippedMaskedColumn(column, column2s_length);
-}
-
 void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 {
 	size_t pindex;
@@ -364,8 +356,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 	{
 		if (textures[texnum]->flip & 2) // vertically flipped?
 		{
-			colfunc_2s = R_DrawFlippedMaskedSegColumn;
-			column2s_length = textures[texnum]->height;
+			colfunc_2s = R_DrawFlippedMaskedColumn;
+			lengthcol = textures[texnum]->height;
 		}
 		else
 			colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture
@@ -373,7 +365,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 	else
 	{
 		colfunc_2s = R_Render2sidedMultiPatchColumn; // render multipatch with no holes (no post_t info)
-		column2s_length = textures[texnum]->height;
+		lengthcol = textures[texnum]->height;
 	}
 
 	// Setup lighting based on the presence/lack-of 3D floors.
@@ -733,7 +725,7 @@ static void R_DrawRepeatMaskedColumn(column_t *col)
 static void R_DrawRepeatFlippedMaskedColumn(column_t *col)
 {
 	do {
-		R_DrawFlippedMaskedColumn(col, column2s_length);
+		R_DrawFlippedMaskedColumn(col);
 		sprtopscreen += dc_texheight*spryscale;
 	} while (sprtopscreen < sprbotscreen);
 }
@@ -1065,7 +1057,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 		if (textures[texnum]->flip & 2) // vertically flipped?
 		{
 			colfunc_2s = R_DrawRepeatFlippedMaskedColumn;
-			column2s_length = textures[texnum]->height;
+			lengthcol = textures[texnum]->height;
 		}
 		else
 			colfunc_2s = R_DrawRepeatMaskedColumn; // render the usual 2sided single-patch packed texture
@@ -1073,7 +1065,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	else
 	{
 		colfunc_2s = R_Render2sidedMultiPatchColumn;        //render multipatch with no holes (no post_t info)
-		column2s_length = textures[texnum]->height;
+		lengthcol = textures[texnum]->height;
 	}
 
 #ifdef ESLOPE
diff --git a/src/r_skins.c b/src/r_skins.c
new file mode 100644
index 0000000000000000000000000000000000000000..2e9548bd7cd0831469b3169f6618d726996ab4c6
--- /dev/null
+++ b/src/r_skins.c
@@ -0,0 +1,825 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 1993-1996 by id Software, Inc.
+// Copyright (C) 1998-2000 by DooM Legacy Team.
+// Copyright (C) 1999-2020 by Sonic Team Junior.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+/// \file  r_skins.c
+/// \brief Loading skins
+
+#include "doomdef.h"
+#include "console.h"
+#include "g_game.h"
+#include "r_local.h"
+#include "st_stuff.h"
+#include "w_wad.h"
+#include "z_zone.h"
+#include "m_misc.h"
+#include "info.h" // spr2names
+#include "i_video.h" // rendermode
+#include "i_system.h"
+#include "r_things.h"
+#include "r_skins.h"
+#include "p_local.h"
+#include "dehacked.h" // get_number (for thok)
+#include "m_cond.h"
+#ifdef HWRENDER
+#include "hardware/hw_md2.h"
+#endif
+
+#ifdef PC_DOS
+#include <stdio.h> // for snprintf
+int	snprintf(char *str, size_t n, const char *fmt, ...);
+//int	vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
+#endif
+
+INT32 numskins = 0;
+skin_t skins[MAXSKINS];
+
+// FIXTHIS: don't work because it must be inistilised before the config load
+//#define SKINVALUES
+#ifdef SKINVALUES
+CV_PossibleValue_t skin_cons_t[MAXSKINS+1];
+#endif
+
+//
+// P_GetSkinSprite2
+// For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
+// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
+//
+
+UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
+{
+	UINT8 super = 0, i = 0;
+
+	if (!skin)
+		return 0;
+
+	if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2)
+		return 0;
+
+	while (!skin->sprites[spr2].numframes
+		&& spr2 != SPR2_STND
+		&& ++i < 32) // recursion limiter
+	{
+		if (spr2 & FF_SPR2SUPER)
+		{
+			super = FF_SPR2SUPER;
+			spr2 &= ~FF_SPR2SUPER;
+			continue;
+		}
+
+		switch(spr2)
+		{
+		// Normal special cases.
+		case SPR2_JUMP:
+			spr2 = ((player
+					? player->charflags
+					: skin->flags)
+					& SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL;
+			break;
+		case SPR2_TIRE:
+			spr2 = ((player
+					? player->charability
+					: skin->ability)
+					== CA_SWIM) ? SPR2_SWIM : SPR2_FLY;
+			break;
+		// Use the handy list, that's what it's there for!
+		default:
+			spr2 = spr2defaults[spr2];
+			break;
+		}
+
+		spr2 |= super;
+	}
+
+	if (i >= 32) // probably an infinite loop...
+		return 0;
+
+	return spr2;
+}
+
+static void Sk_SetDefaultValue(skin_t *skin)
+{
+	INT32 i;
+	//
+	// set default skin values
+	//
+	memset(skin, 0, sizeof (skin_t));
+	snprintf(skin->name,
+		sizeof skin->name, "skin %u", (UINT32)(skin-skins));
+	skin->name[sizeof skin->name - 1] = '\0';
+	skin->wadnum = INT16_MAX;
+
+	skin->flags = 0;
+
+	strcpy(skin->realname, "Someone");
+	strcpy(skin->hudname, "???");
+
+	skin->starttranscolor = 96;
+	skin->prefcolor = SKINCOLOR_GREEN;
+	skin->supercolor = SKINCOLOR_SUPERGOLD1;
+	skin->prefoppositecolor = 0; // use tables
+
+	skin->normalspeed = 36<<FRACBITS;
+	skin->runspeed = 28<<FRACBITS;
+	skin->thrustfactor = 5;
+	skin->accelstart = 96;
+	skin->acceleration = 40;
+
+	skin->ability = CA_NONE;
+	skin->ability2 = CA2_SPINDASH;
+	skin->jumpfactor = FRACUNIT;
+	skin->actionspd = 30<<FRACBITS;
+	skin->mindash = 15<<FRACBITS;
+	skin->maxdash = 70<<FRACBITS;
+
+	skin->radius = mobjinfo[MT_PLAYER].radius;
+	skin->height = mobjinfo[MT_PLAYER].height;
+	skin->spinheight = FixedMul(skin->height, 2*FRACUNIT/3);
+
+	skin->shieldscale = FRACUNIT;
+	skin->camerascale = FRACUNIT;
+
+	skin->thokitem = -1;
+	skin->spinitem = -1;
+	skin->revitem = -1;
+	skin->followitem = 0;
+
+	skin->highresscale = FRACUNIT;
+	skin->contspeed = 17;
+	skin->contangle = 0;
+
+	skin->availability = 0;
+
+	for (i = 0; i < sfx_skinsoundslot0; i++)
+		if (S_sfx[i].skinsound != -1)
+			skin->soundsid[S_sfx[i].skinsound] = i;
+}
+
+//
+// Initialize the basic skins
+//
+void R_InitSkins(void)
+{
+#ifdef SKINVALUES
+	INT32 i;
+
+	for (i = 0; i <= MAXSKINS; i++)
+	{
+		skin_cons_t[i].value = 0;
+		skin_cons_t[i].strvalue = NULL;
+	}
+#endif
+
+	// no default skin!
+	numskins = 0;
+}
+
+UINT32 R_GetSkinAvailabilities(void)
+{
+	INT32 s;
+	UINT32 response = 0;
+
+	for (s = 0; s < MAXSKINS; s++)
+	{
+		if (skins[s].availability && unlockables[skins[s].availability - 1].unlocked)
+			response |= (1 << s);
+	}
+	return response;
+}
+
+// returns true if available in circumstances, otherwise nope
+// warning don't use with an invalid skinnum other than -1 which always returns true
+boolean R_SkinUsable(INT32 playernum, INT32 skinnum)
+{
+	return ((skinnum == -1) // Simplifies things elsewhere, since there's already plenty of checks for less-than-0...
+		|| (!skins[skinnum].availability)
+		|| (((netgame || multiplayer) && playernum != -1) ? (players[playernum].availabilities & (1 << skinnum)) : (unlockables[skins[skinnum].availability - 1].unlocked))
+		|| (modeattacking) // If you have someone else's run you might as well take a look
+		|| (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum)) // Force 1.
+		|| (netgame && (cv_forceskin.value == skinnum)) // Force 2.
+		|| (metalrecording && skinnum == 5) // Force 3.
+		);
+}
+
+// returns true if the skin name is found (loaded from pwad)
+// warning return -1 if not found
+INT32 R_SkinAvailable(const char *name)
+{
+	INT32 i;
+
+	for (i = 0; i < numskins; i++)
+	{
+		// search in the skin list
+		if (stricmp(skins[i].name,name)==0)
+			return i;
+	}
+	return -1;
+}
+
+// network code calls this when a 'skin change' is received
+void SetPlayerSkin(INT32 playernum, const char *skinname)
+{
+	INT32 i = R_SkinAvailable(skinname);
+	player_t *player = &players[playernum];
+
+	if ((i != -1) && R_SkinUsable(playernum, i))
+	{
+		SetPlayerSkinByNum(playernum, i);
+		return;
+	}
+
+	if (P_IsLocalPlayer(player))
+		CONS_Alert(CONS_WARNING, M_GetText("Skin '%s' not found.\n"), skinname);
+	else if(server || IsPlayerAdmin(consoleplayer))
+		CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) skin '%s' not found\n"), playernum, player_names[playernum], skinname);
+
+	SetPlayerSkinByNum(playernum, 0);
+}
+
+// Same as SetPlayerSkin, but uses the skin #.
+// network code calls this when a 'skin change' is received
+void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
+{
+	player_t *player = &players[playernum];
+	skin_t *skin = &skins[skinnum];
+	UINT8 newcolor = 0;
+
+	if (skinnum >= 0 && skinnum < numskins && R_SkinUsable(playernum, skinnum)) // Make sure it exists!
+	{
+		player->skin = skinnum;
+
+		player->camerascale = skin->camerascale;
+		player->shieldscale = skin->shieldscale;
+
+		player->charability = (UINT8)skin->ability;
+		player->charability2 = (UINT8)skin->ability2;
+
+		player->charflags = (UINT32)skin->flags;
+
+		player->thokitem = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem;
+		player->spinitem = skin->spinitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].damage : (UINT32)skin->spinitem;
+		player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem;
+		player->followitem = skin->followitem;
+
+		if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->revitem == MT_LHRT || player->spinitem == MT_LHRT || player->thokitem == MT_LHRT)) // Healers can't keep their buff.
+			player->powers[pw_shield] &= SH_STACK;
+
+		player->actionspd = skin->actionspd;
+		player->mindash = skin->mindash;
+		player->maxdash = skin->maxdash;
+
+		player->normalspeed = skin->normalspeed;
+		player->runspeed = skin->runspeed;
+		player->thrustfactor = skin->thrustfactor;
+		player->accelstart = skin->accelstart;
+		player->acceleration = skin->acceleration;
+
+		player->jumpfactor = skin->jumpfactor;
+
+		player->height = skin->height;
+		player->spinheight = skin->spinheight;
+
+		if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback))
+		{
+			if (playernum == consoleplayer)
+				CV_StealthSetValue(&cv_playercolor, skin->prefcolor);
+			else if (playernum == secondarydisplayplayer)
+				CV_StealthSetValue(&cv_playercolor2, skin->prefcolor);
+			player->skincolor = newcolor = skin->prefcolor;
+		}
+
+		if (player->followmobj)
+		{
+			P_RemoveMobj(player->followmobj);
+			P_SetTarget(&player->followmobj, NULL);
+		}
+
+		if (player->mo)
+		{
+			fixed_t radius = FixedMul(skin->radius, player->mo->scale);
+			if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (skin->sprites[SPR2_NFLY].numframes == 0)) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
+			{
+				skin = &skins[DEFAULTNIGHTSSKIN];
+				player->followitem = skin->followitem;
+				if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback))
+					newcolor = skin->prefcolor; // will be updated in thinker to flashing
+			}
+			player->mo->skin = skin;
+			if (newcolor)
+				player->mo->color = newcolor;
+			P_SetScale(player->mo, player->mo->scale);
+			player->mo->radius = radius;
+
+			P_SetPlayerMobjState(player->mo, player->mo->state-states); // Prevent visual errors when switching between skins with differing number of frames
+		}
+		return;
+	}
+
+	if (P_IsLocalPlayer(player))
+		CONS_Alert(CONS_WARNING, M_GetText("Requested skin %d not found\n"), skinnum);
+	else if(server || IsPlayerAdmin(consoleplayer))
+		CONS_Alert(CONS_WARNING, "Player %d (%s) skin %d not found\n", playernum, player_names[playernum], skinnum);
+	SetPlayerSkinByNum(playernum, 0); // not found put the sonic skin
+}
+
+//
+// Add skins from a pwad, each skin preceded by 'S_SKIN' marker
+//
+
+// Does the same is in w_wad, but check only for
+// the first 6 characters (this is so we can have S_SKIN1, S_SKIN2..
+// for wad editors that don't like multiple resources of the same name)
+//
+static UINT16 W_CheckForSkinMarkerInPwad(UINT16 wadid, UINT16 startlump)
+{
+	UINT16 i;
+	const char *S_SKIN = "S_SKIN";
+	lumpinfo_t *lump_p;
+
+	// scan forward, start at <startlump>
+	if (startlump < wadfiles[wadid]->numlumps)
+	{
+		lump_p = wadfiles[wadid]->lumpinfo + startlump;
+		for (i = startlump; i < wadfiles[wadid]->numlumps; i++, lump_p++)
+			if (memcmp(lump_p->name,S_SKIN,6)==0)
+				return i;
+	}
+	return INT16_MAX; // not found
+}
+
+#define HUDNAMEWRITE(value) STRBUFCPY(skin->hudname, value)
+
+// turn _ into spaces and . into katana dot
+#define SYMBOLCONVERT(name) for (value = name; *value; value++)\
+					{\
+						if (*value == '_') *value = ' ';\
+						else if (*value == '.') *value = '\x1E';\
+					}
+
+//
+// Patch skins from a pwad, each skin preceded by 'P_SKIN' marker
+//
+
+// Does the same is in w_wad, but check only for
+// the first 6 characters (this is so we can have P_SKIN1, P_SKIN2..
+// for wad editors that don't like multiple resources of the same name)
+//
+static UINT16 W_CheckForPatchSkinMarkerInPwad(UINT16 wadid, UINT16 startlump)
+{
+	UINT16 i;
+	const char *P_SKIN = "P_SKIN";
+	lumpinfo_t *lump_p;
+
+	// scan forward, start at <startlump>
+	if (startlump < wadfiles[wadid]->numlumps)
+	{
+		lump_p = wadfiles[wadid]->lumpinfo + startlump;
+		for (i = startlump; i < wadfiles[wadid]->numlumps; i++, lump_p++)
+			if (memcmp(lump_p->name,P_SKIN,6)==0)
+				return i;
+	}
+	return INT16_MAX; // not found
+}
+
+static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin)
+{
+	UINT16 newlastlump;
+	UINT8 sprite2;
+
+	*lump += 1; // start after S_SKIN
+	*lastlump = W_CheckNumForNamePwad("S_END",wadnum,*lump); // stop at S_END
+
+	// old wadding practices die hard -- stop at S_SKIN (or P_SKIN) or S_START if they come before S_END.
+	newlastlump = W_CheckForSkinMarkerInPwad(wadnum,*lump);
+	if (newlastlump < *lastlump) *lastlump = newlastlump;
+	newlastlump = W_CheckForPatchSkinMarkerInPwad(wadnum,*lump);
+	if (newlastlump < *lastlump) *lastlump = newlastlump;
+	newlastlump = W_CheckNumForNamePwad("S_START",wadnum,*lump);
+	if (newlastlump < *lastlump) *lastlump = newlastlump;
+
+	// ...and let's handle super, too
+	newlastlump = W_CheckNumForNamePwad("S_SUPER",wadnum,*lump);
+	if (newlastlump < *lastlump)
+	{
+		newlastlump++;
+		// load all sprite sets we are aware of... for super!
+		for (sprite2 = 0; sprite2 < free_spr2; sprite2++)
+			R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[FF_SPR2SUPER|sprite2], wadnum, newlastlump, *lastlump);
+
+		newlastlump--;
+		*lastlump = newlastlump; // okay, make the normal sprite set loading end there
+	}
+
+	// load all sprite sets we are aware of... for normal stuff.
+	for (sprite2 = 0; sprite2 < free_spr2; sprite2++)
+		R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump);
+
+	if (skin->sprites[0].numframes == 0)
+		I_Error("R_LoadSkinSprites: no frames found for sprite SPR2_%s\n", spr2names[0]);
+}
+
+// returns whether found appropriate property
+static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
+{
+	// custom translation table
+	if (!stricmp(stoken, "startcolor"))
+		skin->starttranscolor = atoi(value);
+
+#define FULLPROCESS(field) else if (!stricmp(stoken, #field)) skin->field = get_number(value);
+	// character type identification
+	FULLPROCESS(flags)
+	FULLPROCESS(ability)
+	FULLPROCESS(ability2)
+
+	FULLPROCESS(thokitem)
+	FULLPROCESS(spinitem)
+	FULLPROCESS(revitem)
+	FULLPROCESS(followitem)
+#undef FULLPROCESS
+
+#define GETFRACBITS(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value)<<FRACBITS;
+	GETFRACBITS(normalspeed)
+	GETFRACBITS(runspeed)
+
+	GETFRACBITS(mindash)
+	GETFRACBITS(maxdash)
+	GETFRACBITS(actionspd)
+
+	GETFRACBITS(radius)
+	GETFRACBITS(height)
+	GETFRACBITS(spinheight)
+#undef GETFRACBITS
+
+#define GETINT(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value);
+	GETINT(thrustfactor)
+	GETINT(accelstart)
+	GETINT(acceleration)
+	GETINT(contspeed)
+	GETINT(contangle)
+#undef GETINT
+
+#define GETSKINCOLOR(field) else if (!stricmp(stoken, #field)) skin->field = R_GetColorByName(value);
+	GETSKINCOLOR(prefcolor)
+	GETSKINCOLOR(prefoppositecolor)
+#undef GETSKINCOLOR
+	else if (!stricmp(stoken, "supercolor"))
+		skin->supercolor = R_GetSuperColorByName(value);
+
+#define GETFLOAT(field) else if (!stricmp(stoken, #field)) skin->field = FLOAT_TO_FIXED(atof(value));
+	GETFLOAT(jumpfactor)
+	GETFLOAT(highresscale)
+	GETFLOAT(shieldscale)
+	GETFLOAT(camerascale)
+#undef GETFLOAT
+
+#define GETFLAG(field) else if (!stricmp(stoken, #field)) { \
+	strupr(value); \
+	if (atoi(value) || value[0] == 'T' || value[0] == 'Y') \
+		skin->flags |= (SF_##field); \
+	else \
+		skin->flags &= ~(SF_##field); \
+}
+	// parameters for individual character flags
+	// these are uppercase so they can be concatenated with SF_
+	// 1, true, yes are all valid values
+	GETFLAG(SUPER)
+	GETFLAG(NOSUPERSPIN)
+	GETFLAG(NOSPINDASHDUST)
+	GETFLAG(HIRES)
+	GETFLAG(NOSKID)
+	GETFLAG(NOSPEEDADJUST)
+	GETFLAG(RUNONWATER)
+	GETFLAG(NOJUMPSPIN)
+	GETFLAG(NOJUMPDAMAGE)
+	GETFLAG(STOMPDAMAGE)
+	GETFLAG(MARIODAMAGE)
+	GETFLAG(MACHINE)
+	GETFLAG(DASHMODE)
+	GETFLAG(FASTEDGE)
+	GETFLAG(MULTIABILITY)
+	GETFLAG(NONIGHTSROTATION)
+#undef GETFLAG
+
+	else // let's check if it's a sound, otherwise error out
+	{
+		boolean found = false;
+		sfxenum_t i;
+		size_t stokenadjust;
+
+		// Remove the prefix. (We need to affect an adjusting variable so that we can print error messages if it's not actually a sound.)
+		if ((stoken[0] == 'D' || stoken[0] == 'd') && (stoken[1] == 'S' || stoken[1] == 's')) // DS*
+			stokenadjust = 2;
+		else // sfx_*
+			stokenadjust = 4;
+
+		// Remove the prefix. (We can affect this directly since we're not going to use it again.)
+		if ((value[0] == 'D' || value[0] == 'd') && (value[1] == 'S' || value[1] == 's')) // DS*
+			value += 2;
+		else // sfx_*
+			value += 4;
+
+		// copy name of sounds that are remapped
+		// for this skin
+		for (i = 0; i < sfx_skinsoundslot0; i++)
+		{
+			if (!S_sfx[i].name)
+				continue;
+			if (S_sfx[i].skinsound != -1
+				&& !stricmp(S_sfx[i].name,
+					stoken + stokenadjust))
+			{
+				skin->soundsid[S_sfx[i].skinsound] =
+					S_AddSoundFx(value, S_sfx[i].singularity, S_sfx[i].pitch, true);
+				found = true;
+			}
+		}
+		return found;
+	}
+	return true;
+}
+
+//
+// Find skin sprites, sounds & optional status bar face, & add them
+//
+void R_AddSkins(UINT16 wadnum)
+{
+	UINT16 lump, lastlump = 0;
+	char *buf;
+	char *buf2;
+	char *stoken;
+	char *value;
+	size_t size;
+	skin_t *skin;
+	boolean hudname, realname;
+
+	//
+	// search for all skin markers in pwad
+	//
+
+	while ((lump = W_CheckForSkinMarkerInPwad(wadnum, lastlump)) != INT16_MAX)
+	{
+		// advance by default
+		lastlump = lump + 1;
+
+		if (numskins >= MAXSKINS)
+		{
+			CONS_Debug(DBG_RENDER, "ignored skin (%d skins maximum)\n", MAXSKINS);
+			continue; // so we know how many skins couldn't be added
+		}
+		buf = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE);
+		size = W_LumpLengthPwad(wadnum, lump);
+
+		// for strtok
+		buf2 = malloc(size+1);
+		if (!buf2)
+			I_Error("R_AddSkins: No more free memory\n");
+		M_Memcpy(buf2,buf,size);
+		buf2[size] = '\0';
+
+		// set defaults
+		skin = &skins[numskins];
+		Sk_SetDefaultValue(skin);
+		skin->wadnum = wadnum;
+		hudname = realname = false;
+		// parse
+		stoken = strtok (buf2, "\r\n= ");
+		while (stoken)
+		{
+			if ((stoken[0] == '/' && stoken[1] == '/')
+				|| (stoken[0] == '#'))// skip comments
+			{
+				stoken = strtok(NULL, "\r\n"); // skip end of line
+				goto next_token;              // find the real next token
+			}
+
+			value = strtok(NULL, "\r\n= ");
+
+			if (!value)
+				I_Error("R_AddSkins: syntax error in S_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename);
+
+			// Some of these can't go in R_ProcessPatchableFields because they have side effects for future lines.
+			// Others can't go in there because we don't want them to be patchable.
+			if (!stricmp(stoken, "name"))
+			{
+				INT32 skinnum = R_SkinAvailable(value);
+				strlwr(value);
+				if (skinnum == -1)
+					STRBUFCPY(skin->name, value);
+				// the skin name must uniquely identify a single skin
+				// if the name is already used I make the name 'namex'
+				// using the default skin name's number set above
+				else
+				{
+					const size_t stringspace =
+						strlen(value) + sizeof (numskins) + 1;
+					char *value2 = Z_Malloc(stringspace, PU_STATIC, NULL);
+					snprintf(value2, stringspace,
+						"%s%d", value, numskins);
+					value2[stringspace - 1] = '\0';
+					if (R_SkinAvailable(value2) == -1)
+						// I'm lazy so if NEW name is already used I leave the 'skin x'
+						// default skin name set in Sk_SetDefaultValue
+						STRBUFCPY(skin->name, value2);
+					Z_Free(value2);
+				}
+
+				// copy to hudname and fullname as a default.
+				if (!realname)
+				{
+					STRBUFCPY(skin->realname, skin->name);
+					for (value = skin->realname; *value; value++)
+					{
+						if (*value == '_') *value = ' '; // turn _ into spaces.
+						else if (*value == '.') *value = '\x1E'; // turn . into katana dot.
+					}
+				}
+				if (!hudname)
+				{
+					HUDNAMEWRITE(skin->name);
+					strupr(skin->hudname);
+					SYMBOLCONVERT(skin->hudname)
+				}
+			}
+			else if (!stricmp(stoken, "realname"))
+			{ // Display name (eg. "Knuckles")
+				realname = true;
+				STRBUFCPY(skin->realname, value);
+				SYMBOLCONVERT(skin->realname)
+				if (!hudname)
+					HUDNAMEWRITE(skin->realname);
+			}
+			else if (!stricmp(stoken, "hudname"))
+			{ // Life icon name (eg. "K.T.E")
+				hudname = true;
+				HUDNAMEWRITE(value);
+				SYMBOLCONVERT(skin->hudname)
+				if (!realname)
+					STRBUFCPY(skin->realname, skin->hudname);
+			}
+			else if (!stricmp(stoken, "availability"))
+			{
+				skin->availability = atoi(value);
+				if (skin->availability >= MAXUNLOCKABLES)
+					skin->availability = 0;
+			}
+			else if (!R_ProcessPatchableFields(skin, stoken, value))
+				CONS_Debug(DBG_SETUP, "R_AddSkins: Unknown keyword '%s' in S_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename);
+
+next_token:
+			stoken = strtok(NULL, "\r\n= ");
+		}
+		free(buf2);
+
+		// Add sprites
+		R_LoadSkinSprites(wadnum, &lump, &lastlump, skin);
+		//ST_LoadFaceGraphics(numskins); -- nah let's do this elsewhere
+
+		R_FlushTranslationColormapCache();
+
+		if (!skin->availability) // Safe to print...
+			CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name);
+#ifdef SKINVALUES
+		skin_cons_t[numskins].value = numskins;
+		skin_cons_t[numskins].strvalue = skin->name;
+#endif
+
+#ifdef HWRENDER
+		if (rendermode == render_opengl)
+			HWR_AddPlayerModel(numskins);
+#endif
+
+		numskins++;
+	}
+	return;
+}
+
+//
+// Patch skin sprites
+//
+void R_PatchSkins(UINT16 wadnum)
+{
+	UINT16 lump, lastlump = 0;
+	char *buf;
+	char *buf2;
+	char *stoken;
+	char *value;
+	size_t size;
+	skin_t *skin;
+	boolean noskincomplain, realname, hudname;
+
+	//
+	// search for all skin patch markers in pwad
+	//
+
+	while ((lump = W_CheckForPatchSkinMarkerInPwad(wadnum, lastlump)) != INT16_MAX)
+	{
+		INT32 skinnum = 0;
+
+		// advance by default
+		lastlump = lump + 1;
+
+		buf = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE);
+		size = W_LumpLengthPwad(wadnum, lump);
+
+		// for strtok
+		buf2 = malloc(size+1);
+		if (!buf2)
+			I_Error("R_PatchSkins: No more free memory\n");
+		M_Memcpy(buf2,buf,size);
+		buf2[size] = '\0';
+
+		skin = NULL;
+		noskincomplain = realname = hudname = false;
+
+		/*
+		Parse. Has more phases than the parser in R_AddSkins because it needs to have the patching name first (no default skin name is acceptible for patching, unlike skin creation)
+		*/
+
+		stoken = strtok(buf2, "\r\n= ");
+		while (stoken)
+		{
+			if ((stoken[0] == '/' && stoken[1] == '/')
+				|| (stoken[0] == '#'))// skip comments
+			{
+				stoken = strtok(NULL, "\r\n"); // skip end of line
+				goto next_token;              // find the real next token
+			}
+
+			value = strtok(NULL, "\r\n= ");
+
+			if (!value)
+				I_Error("R_PatchSkins: syntax error in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename);
+
+			if (!skin) // Get the name!
+			{
+				if (!stricmp(stoken, "name"))
+				{
+					strlwr(value);
+					skinnum = R_SkinAvailable(value);
+					if (skinnum != -1)
+						skin = &skins[skinnum];
+					else
+					{
+						CONS_Debug(DBG_SETUP, "R_PatchSkins: unknown skin name in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename);
+						noskincomplain = true;
+					}
+				}
+			}
+			else // Get the properties!
+			{
+				// Some of these can't go in R_ProcessPatchableFields because they have side effects for future lines.
+				if (!stricmp(stoken, "realname"))
+				{ // Display name (eg. "Knuckles")
+					realname = true;
+					STRBUFCPY(skin->realname, value);
+					SYMBOLCONVERT(skin->realname)
+					if (!hudname)
+						HUDNAMEWRITE(skin->realname);
+				}
+				else if (!stricmp(stoken, "hudname"))
+				{ // Life icon name (eg. "K.T.E")
+					hudname = true;
+					HUDNAMEWRITE(value);
+					SYMBOLCONVERT(skin->hudname)
+					if (!realname)
+						STRBUFCPY(skin->realname, skin->hudname);
+				}
+				else if (!R_ProcessPatchableFields(skin, stoken, value))
+					CONS_Debug(DBG_SETUP, "R_PatchSkins: Unknown keyword '%s' in P_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename);
+			}
+
+			if (!skin)
+				break;
+
+next_token:
+			stoken = strtok(NULL, "\r\n= ");
+		}
+		free(buf2);
+
+		if (!skin) // Didn't include a name parameter? What a waste.
+		{
+			if (!noskincomplain)
+				CONS_Debug(DBG_SETUP, "R_PatchSkins: no skin name given in P_SKIN lump #%d (WAD %s)\n", lump, wadfiles[wadnum]->filename);
+			continue;
+		}
+
+		// Patch sprites
+		R_LoadSkinSprites(wadnum, &lump, &lastlump, skin);
+		//ST_LoadFaceGraphics(skinnum); -- nah let's do this elsewhere
+
+		R_FlushTranslationColormapCache();
+
+		if (!skin->availability) // Safe to print...
+			CONS_Printf(M_GetText("Patched skin '%s'\n"), skin->name);
+	}
+	return;
+}
+
+#undef HUDNAMEWRITE
+#undef SYMBOLCONVERT
diff --git a/src/r_skins.h b/src/r_skins.h
new file mode 100644
index 0000000000000000000000000000000000000000..96697b4220038c1bdbe491cbd4943b2b4127113b
--- /dev/null
+++ b/src/r_skins.h
@@ -0,0 +1,103 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 1993-1996 by id Software, Inc.
+// Copyright (C) 1998-2000 by DooM Legacy Team.
+// Copyright (C) 1999-2020 by Sonic Team Junior.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+/// \file  r_skins.h
+/// \brief Skins stuff
+
+#ifndef __R_SKINS__
+#define __R_SKINS__
+
+#include "info.h"
+#include "sounds.h"
+#include "d_player.h" // skinflags
+#include "r_patch.h" // spriteinfo_t
+#include "r_defs.h" // spritedef_t
+
+/// Defaults
+#define SKINNAMESIZE 16
+// should be all lowercase!! S_SKIN processing does a strlwr
+#define DEFAULTSKIN "sonic"
+#define DEFAULTSKIN2 "tails" // secondary player
+#define DEFAULTNIGHTSSKIN 0
+
+/// The skin_t struct
+typedef struct
+{
+	char name[SKINNAMESIZE+1]; // INT16 descriptive name of the skin
+	UINT16 wadnum;
+	skinflags_t flags;
+
+	char realname[SKINNAMESIZE+1]; // Display name for level completion.
+	char hudname[SKINNAMESIZE+1]; // HUD name to display (officially exactly 5 characters long)
+
+	UINT8 ability; // ability definition
+	UINT8 ability2; // secondary ability definition
+	INT32 thokitem;
+	INT32 spinitem;
+	INT32 revitem;
+	INT32 followitem;
+	fixed_t actionspd;
+	fixed_t mindash;
+	fixed_t maxdash;
+
+	fixed_t normalspeed; // Normal ground
+	fixed_t runspeed; // Speed that you break into your run animation
+
+	UINT8 thrustfactor; // Thrust = thrustfactor * acceleration
+	UINT8 accelstart; // Acceleration if speed = 0
+	UINT8 acceleration; // Acceleration
+
+	fixed_t jumpfactor; // multiple of standard jump height
+
+	fixed_t radius; // Bounding box changes.
+	fixed_t height;
+	fixed_t spinheight;
+
+	fixed_t shieldscale; // no change to bounding box, but helps set the shield's sprite size
+	fixed_t camerascale;
+
+	// Definable color translation table
+	UINT8 starttranscolor;
+	UINT8 prefcolor;
+	UINT8 supercolor;
+	UINT8 prefoppositecolor; // if 0 use tables instead
+
+	fixed_t highresscale; // scale of highres, default is 0.5
+	UINT8 contspeed; // continue screen animation speed
+	UINT8 contangle; // initial angle on continue screen
+
+	// specific sounds per skin
+	sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table
+
+	// contains super versions too
+	spritedef_t sprites[NUMPLAYERSPRITES*2];
+	spriteinfo_t sprinfo[NUMPLAYERSPRITES*2];
+
+	UINT8 availability; // lock?
+} skin_t;
+
+/// Externs
+extern INT32 numskins;
+extern skin_t skins[MAXSKINS];
+
+/// Function prototypes
+void R_InitSkins(void);
+
+void SetPlayerSkin(INT32 playernum,const char *skinname);
+void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002
+boolean R_SkinUsable(INT32 playernum, INT32 skinnum);
+UINT32 R_GetSkinAvailabilities(void);
+INT32 R_SkinAvailable(const char *name);
+void R_PatchSkins(UINT16 wadnum);
+void R_AddSkins(UINT16 wadnum);
+
+UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player);
+
+#endif //__R_SKINS__
diff --git a/src/r_things.c b/src/r_things.c
index 953825d0f3aaf3d2e38f8245d4b5ffafe3dd1ceb..d2f3b49021d262b5576ff0319d34f0fd4794b24d 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -30,11 +30,8 @@
 #include "p_tick.h"
 #include "p_local.h"
 #include "p_slopes.h"
-#include "dehacked.h" // get_number (for thok)
 #include "d_netfil.h" // blargh. for nameonly().
 #include "m_cheat.h" // objectplace
-#include "m_cond.h"
-#include "fastcmp.h"
 #ifdef HWRENDER
 #include "hardware/hw_md2.h"
 #include "hardware/hw_glob.h"
@@ -42,14 +39,6 @@
 #include "hardware/hw_drv.h"
 #endif
 
-#ifdef PC_DOS
-#include <stdio.h> // for snprintf
-int	snprintf(char *str, size_t n, const char *fmt, ...);
-//int	vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
-#endif
-
-static void R_InitSkins(void);
-
 #define MINZ (FRACUNIT*4)
 #define BASEYCENTER (BASEVIDHEIGHT/2)
 
@@ -233,7 +222,7 @@ static void R_InstallSpriteLump(UINT16 wad,            // graphics patch
 //
 // Returns true if the sprite was succesfully added
 //
-static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump)
+boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump)
 {
 	UINT16 l;
 	UINT8 frame;
@@ -245,6 +234,8 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
 	memset(sprtemp,0xFF, sizeof (sprtemp));
 	maxframe = (size_t)-1;
 
+	spritename = sprname;
+
 	// are we 'patching' a sprite already loaded ?
 	// if so, it might patch only certain frames, not all
 	if (spritedef->numframes) // (then spriteframes is not null)
@@ -476,11 +467,10 @@ void R_AddSpriteDefs(UINT16 wadnum)
 	//
 	for (i = 0; i < numsprites; i++)
 	{
-		spritename = sprnames[i];
-		if (spritename[4] && wadnum >= (UINT16)spritename[4])
+		if (sprnames[i][4] && wadnum >= (UINT16)sprnames[i][4])
 			continue;
 
-		if (R_AddSingleSpriteDef(spritename, &sprites[i], wadnum, start, end))
+		if (R_AddSingleSpriteDef(sprnames[i], &sprites[i], wadnum, start, end))
 		{
 #ifdef HWRENDER
 			if (rendermode == render_opengl)
@@ -489,7 +479,7 @@ void R_AddSpriteDefs(UINT16 wadnum)
 			// if a new sprite was added (not just replaced)
 			addsprites++;
 #ifndef ZDEBUG
-			CONS_Debug(DBG_SETUP, "sprite %s set in pwad %d\n", spritename, wadnum);
+			CONS_Debug(DBG_SETUP, "sprite %s set in pwad %d\n", sprnames[i], wadnum);
 #endif
 		}
 	}
@@ -651,10 +641,10 @@ void R_DrawMaskedColumn(column_t *column)
 			dc_yl = mceilingclip[dc_x]+1;
 		if (dc_yl < 0)
 			dc_yl = 0;
-		if (dc_yh >= vid.height)
+		if (dc_yh >= vid.height) // dc_yl must be < vid.height, so reduces number of checks in tight loop
 			dc_yh = vid.height - 1;
 
-		if (dc_yl <= dc_yh && dc_yl < vid.height && dc_yh > 0)
+		if (dc_yl <= dc_yh && dc_yh > 0)
 		{
 			dc_source = (UINT8 *)column + 3;
 			dc_texturemid = basetexturemid - (topdelta<<FRACBITS);
@@ -665,15 +655,10 @@ void R_DrawMaskedColumn(column_t *column)
 			// quick fix... something more proper should be done!!!
 			if (ylookup[dc_yl])
 				colfunc();
-			else if (colfunc == colfuncs[COLDRAWFUNC_BASE])
-			{
-				static INT32 first = 1;
-				if (first)
-				{
-					CONS_Debug(DBG_RENDER, "WARNING: avoiding a crash in %s %d\n", __FILE__, __LINE__);
-					first = 0;
-				}
-			}
+#ifdef PARANOIA
+			else
+				I_Error("R_DrawMaskedColumn: Invalid ylookup for dc_yl %d", dc_yl);
+#endif
 		}
 		column = (column_t *)((UINT8 *)column + column->length + 4);
 	}
@@ -681,7 +666,9 @@ void R_DrawMaskedColumn(column_t *column)
 	dc_texturemid = basetexturemid;
 }
 
-void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight)
+INT32 lengthcol; // column->length : for flipped column function pointers and multi-patch on 2sided wall = texture->height
+
+void R_DrawFlippedMaskedColumn(column_t *column)
 {
 	INT32 topscreen;
 	INT32 bottomscreen;
@@ -697,7 +684,7 @@ void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight)
 		if (topdelta <= prevdelta)
 			topdelta += prevdelta;
 		prevdelta = topdelta;
-		topdelta = texheight-column->length-topdelta;
+		topdelta = lengthcol-column->length-topdelta;
 		topscreen = sprtopscreen + spryscale*topdelta;
 		bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*column->length
 		                                      : sprbotscreen + spryscale*column->length;
@@ -719,10 +706,10 @@ void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight)
 			dc_yl = mceilingclip[dc_x]+1;
 		if (dc_yl < 0)
 			dc_yl = 0;
-		if (dc_yh >= vid.height)
+		if (dc_yh >= vid.height) // dc_yl must be < vid.height, so reduces number of checks in tight loop
 			dc_yh = vid.height - 1;
 
-		if (dc_yl <= dc_yh && dc_yl < vid.height && dc_yh > 0)
+		if (dc_yl <= dc_yh && dc_yh > 0)
 		{
 			dc_source = ZZ_Alloc(column->length);
 			for (s = (UINT8 *)column+2+column->length, d = dc_source; d < dc_source+column->length; --s)
@@ -732,15 +719,10 @@ void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight)
 			// Still drawn by R_DrawColumn.
 			if (ylookup[dc_yl])
 				colfunc();
-			else if (colfunc == colfuncs[COLDRAWFUNC_BASE])
-			{
-				static INT32 first = 1;
-				if (first)
-				{
-					CONS_Debug(DBG_RENDER, "WARNING: avoiding a crash in %s %d\n", __FILE__, __LINE__);
-					first = 0;
-				}
-			}
+#ifdef PARANOIA
+			else
+				I_Error("R_DrawMaskedColumn: Invalid ylookup for dc_yl %d", dc_yl);
+#endif
 			Z_Free(dc_source);
 		}
 		column = (column_t *)((UINT8 *)column + column->length + 4);
@@ -756,7 +738,9 @@ void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight)
 static void R_DrawVisSprite(vissprite_t *vis)
 {
 	column_t *column;
+	void (*localcolfunc)(column_t *);
 	INT32 texturecolumn;
+	INT32 pwidth;
 	fixed_t frac;
 	patch_t *patch = vis->patch;
 	fixed_t this_scale = vis->mobj->scale;
@@ -905,50 +889,52 @@ static void R_DrawVisSprite(vissprite_t *vis)
 	if (vis->x2 >= vid.width)
 		vis->x2 = vid.width-1;
 
+	localcolfunc = (vis->cut & SC_VFLIP) ? R_DrawFlippedMaskedColumn : R_DrawMaskedColumn;
+	lengthcol = patch->height;
+
 	// Split drawing loops for paper and non-paper to reduce conditional checks per sprite
 	if (vis->scalestep)
 	{
-		// Papersprite drawing loop
+		pwidth = SHORT(patch->width);
 
+		// Papersprite drawing loop
 		for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, spryscale += vis->scalestep)
 		{
 			angle_t angle = ((vis->centerangle + xtoviewangle[dc_x]) >> ANGLETOFINESHIFT) & 0xFFF;
 			texturecolumn = (vis->paperoffset - FixedMul(FINETANGENT(angle), vis->paperdistance)) / this_scale;
 
-			if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
+			if (texturecolumn < 0 || texturecolumn >= pwidth)
 				continue;
 
 			if (vis->xiscale < 0) // Flipped sprite
-				texturecolumn = SHORT(patch->width) - 1 - texturecolumn;
+				texturecolumn = pwidth - 1 - texturecolumn;
 
 			sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale));
 			dc_iscale = (0xffffffffu / (unsigned)spryscale);
 
 			column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn]));
 
-			if (vis->cut & SC_VFLIP)
-				R_DrawFlippedMaskedColumn(column, patch->height);
-			else
-				R_DrawMaskedColumn(column);
+			localcolfunc (column);
 		}
 	}
 	else
 	{
+#ifdef RANGECHECK
+		pwidth = SHORT(patch->width);
+#endif
+
 		// Non-paper drawing loop
 		for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale, sprtopscreen += vis->shear.tan)
 		{
 #ifdef RANGECHECK
 			texturecolumn = frac>>FRACBITS;
-			if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
+			if (texturecolumn < 0 || texturecolumn >= pwidth)
 				I_Error("R_DrawSpriteRange: bad texturecolumn at %d from end", vis->x2 - dc_x);
 			column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn]));
 #else
 			column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS]));
 #endif
-			if (vis->cut & SC_VFLIP)
-				R_DrawFlippedMaskedColumn(column, patch->height);
-			else
-				R_DrawMaskedColumn(column);
+			localcolfunc (column);
 		}
 	}
 
@@ -2964,795 +2950,3 @@ void R_DrawMasked(maskcount_t* masks, UINT8 nummasks)
 
 	free(heads);
 }
-
-// ==========================================================================
-//
-//                              SKINS CODE
-//
-// ==========================================================================
-
-INT32 numskins = 0;
-skin_t skins[MAXSKINS];
-// FIXTHIS: don't work because it must be inistilised before the config load
-//#define SKINVALUES
-#ifdef SKINVALUES
-CV_PossibleValue_t skin_cons_t[MAXSKINS+1];
-#endif
-
-//
-// P_GetSkinSprite2
-// For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing.
-// For super players, does the same as above - but tries the super equivalent for each sprite2 before the non-super version.
-//
-
-UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
-{
-	UINT8 super = 0, i = 0;
-
-	if (!skin)
-		return 0;
-
-	if ((playersprite_t)(spr2 & ~FF_SPR2SUPER) >= free_spr2)
-		return 0;
-
-	while (!skin->sprites[spr2].numframes
-		&& spr2 != SPR2_STND
-		&& ++i < 32) // recursion limiter
-	{
-		if (spr2 & FF_SPR2SUPER)
-		{
-			super = FF_SPR2SUPER;
-			spr2 &= ~FF_SPR2SUPER;
-			continue;
-		}
-
-		switch(spr2)
-		{
-		// Normal special cases.
-		case SPR2_JUMP:
-			spr2 = ((player
-					? player->charflags
-					: skin->flags)
-					& SF_NOJUMPSPIN) ? SPR2_SPNG : SPR2_ROLL;
-			break;
-		case SPR2_TIRE:
-			spr2 = ((player
-					? player->charability
-					: skin->ability)
-					== CA_SWIM) ? SPR2_SWIM : SPR2_FLY;
-			break;
-		// Use the handy list, that's what it's there for!
-		default:
-			spr2 = spr2defaults[spr2];
-			break;
-		}
-
-		spr2 |= super;
-	}
-
-	if (i >= 32) // probably an infinite loop...
-		return 0;
-
-	return spr2;
-}
-
-static void Sk_SetDefaultValue(skin_t *skin)
-{
-	INT32 i;
-	//
-	// set default skin values
-	//
-	memset(skin, 0, sizeof (skin_t));
-	snprintf(skin->name,
-		sizeof skin->name, "skin %u", (UINT32)(skin-skins));
-	skin->name[sizeof skin->name - 1] = '\0';
-	skin->wadnum = INT16_MAX;
-
-	skin->flags = 0;
-
-	strcpy(skin->realname, "Someone");
-	strcpy(skin->hudname, "???");
-
-	skin->starttranscolor = 96;
-	skin->prefcolor = SKINCOLOR_GREEN;
-	skin->supercolor = SKINCOLOR_SUPERGOLD1;
-	skin->prefoppositecolor = 0; // use tables
-
-	skin->normalspeed = 36<<FRACBITS;
-	skin->runspeed = 28<<FRACBITS;
-	skin->thrustfactor = 5;
-	skin->accelstart = 96;
-	skin->acceleration = 40;
-
-	skin->ability = CA_NONE;
-	skin->ability2 = CA2_SPINDASH;
-	skin->jumpfactor = FRACUNIT;
-	skin->actionspd = 30<<FRACBITS;
-	skin->mindash = 15<<FRACBITS;
-	skin->maxdash = 70<<FRACBITS;
-
-	skin->radius = mobjinfo[MT_PLAYER].radius;
-	skin->height = mobjinfo[MT_PLAYER].height;
-	skin->spinheight = FixedMul(skin->height, 2*FRACUNIT/3);
-
-	skin->shieldscale = FRACUNIT;
-	skin->camerascale = FRACUNIT;
-
-	skin->thokitem = -1;
-	skin->spinitem = -1;
-	skin->revitem = -1;
-	skin->followitem = 0;
-
-	skin->highresscale = FRACUNIT;
-	skin->contspeed = 17;
-	skin->contangle = 0;
-
-	skin->availability = 0;
-
-	for (i = 0; i < sfx_skinsoundslot0; i++)
-		if (S_sfx[i].skinsound != -1)
-			skin->soundsid[S_sfx[i].skinsound] = i;
-}
-
-//
-// Initialize the basic skins
-//
-void R_InitSkins(void)
-{
-#ifdef SKINVALUES
-	INT32 i;
-
-	for (i = 0; i <= MAXSKINS; i++)
-	{
-		skin_cons_t[i].value = 0;
-		skin_cons_t[i].strvalue = NULL;
-	}
-#endif
-
-	// no default skin!
-	numskins = 0;
-}
-
-UINT32 R_GetSkinAvailabilities(void)
-{
-	INT32 s;
-	UINT32 response = 0;
-
-	for (s = 0; s < MAXSKINS; s++)
-	{
-		if (skins[s].availability && unlockables[skins[s].availability - 1].unlocked)
-			response |= (1 << s);
-	}
-	return response;
-}
-
-// returns true if available in circumstances, otherwise nope
-// warning don't use with an invalid skinnum other than -1 which always returns true
-boolean R_SkinUsable(INT32 playernum, INT32 skinnum)
-{
-	return ((skinnum == -1) // Simplifies things elsewhere, since there's already plenty of checks for less-than-0...
-		|| (!skins[skinnum].availability)
-		|| (((netgame || multiplayer) && playernum != -1) ? (players[playernum].availabilities & (1 << skinnum)) : (unlockables[skins[skinnum].availability - 1].unlocked))
-		|| (modeattacking) // If you have someone else's run you might as well take a look
-		|| (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum)) // Force 1.
-		|| (netgame && (cv_forceskin.value == skinnum)) // Force 2.
-		|| (metalrecording && skinnum == 5) // Force 3.
-		);
-}
-
-// returns true if the skin name is found (loaded from pwad)
-// warning return -1 if not found
-INT32 R_SkinAvailable(const char *name)
-{
-	INT32 i;
-
-	for (i = 0; i < numskins; i++)
-	{
-		// search in the skin list
-		if (stricmp(skins[i].name,name)==0)
-			return i;
-	}
-	return -1;
-}
-
-// network code calls this when a 'skin change' is received
-void SetPlayerSkin(INT32 playernum, const char *skinname)
-{
-	INT32 i = R_SkinAvailable(skinname);
-	player_t *player = &players[playernum];
-
-	if ((i != -1) && R_SkinUsable(playernum, i))
-	{
-		SetPlayerSkinByNum(playernum, i);
-		return;
-	}
-
-	if (P_IsLocalPlayer(player))
-		CONS_Alert(CONS_WARNING, M_GetText("Skin '%s' not found.\n"), skinname);
-	else if(server || IsPlayerAdmin(consoleplayer))
-		CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) skin '%s' not found\n"), playernum, player_names[playernum], skinname);
-
-	SetPlayerSkinByNum(playernum, 0);
-}
-
-// Same as SetPlayerSkin, but uses the skin #.
-// network code calls this when a 'skin change' is received
-void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
-{
-	player_t *player = &players[playernum];
-	skin_t *skin = &skins[skinnum];
-	UINT8 newcolor = 0;
-
-	if (skinnum >= 0 && skinnum < numskins && R_SkinUsable(playernum, skinnum)) // Make sure it exists!
-	{
-		player->skin = skinnum;
-
-		player->camerascale = skin->camerascale;
-		player->shieldscale = skin->shieldscale;
-
-		player->charability = (UINT8)skin->ability;
-		player->charability2 = (UINT8)skin->ability2;
-
-		player->charflags = (UINT32)skin->flags;
-
-		player->thokitem = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem;
-		player->spinitem = skin->spinitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].damage : (UINT32)skin->spinitem;
-		player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem;
-		player->followitem = skin->followitem;
-
-		if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->revitem == MT_LHRT || player->spinitem == MT_LHRT || player->thokitem == MT_LHRT)) // Healers can't keep their buff.
-			player->powers[pw_shield] &= SH_STACK;
-
-		player->actionspd = skin->actionspd;
-		player->mindash = skin->mindash;
-		player->maxdash = skin->maxdash;
-
-		player->normalspeed = skin->normalspeed;
-		player->runspeed = skin->runspeed;
-		player->thrustfactor = skin->thrustfactor;
-		player->accelstart = skin->accelstart;
-		player->acceleration = skin->acceleration;
-
-		player->jumpfactor = skin->jumpfactor;
-
-		player->height = skin->height;
-		player->spinheight = skin->spinheight;
-
-		if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback))
-		{
-			if (playernum == consoleplayer)
-				CV_StealthSetValue(&cv_playercolor, skin->prefcolor);
-			else if (playernum == secondarydisplayplayer)
-				CV_StealthSetValue(&cv_playercolor2, skin->prefcolor);
-			player->skincolor = newcolor = skin->prefcolor;
-		}
-
-		if (player->followmobj)
-		{
-			P_RemoveMobj(player->followmobj);
-			P_SetTarget(&player->followmobj, NULL);
-		}
-
-		if (player->mo)
-		{
-			fixed_t radius = FixedMul(skin->radius, player->mo->scale);
-			if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (skin->sprites[SPR2_NFLY].numframes == 0)) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
-			{
-				skin = &skins[DEFAULTNIGHTSSKIN];
-				player->followitem = skin->followitem;
-				if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback))
-					newcolor = skin->prefcolor; // will be updated in thinker to flashing
-			}
-			player->mo->skin = skin;
-			if (newcolor)
-				player->mo->color = newcolor;
-			P_SetScale(player->mo, player->mo->scale);
-			player->mo->radius = radius;
-
-			P_SetPlayerMobjState(player->mo, player->mo->state-states); // Prevent visual errors when switching between skins with differing number of frames
-		}
-		return;
-	}
-
-	if (P_IsLocalPlayer(player))
-		CONS_Alert(CONS_WARNING, M_GetText("Requested skin %d not found\n"), skinnum);
-	else if(server || IsPlayerAdmin(consoleplayer))
-		CONS_Alert(CONS_WARNING, "Player %d (%s) skin %d not found\n", playernum, player_names[playernum], skinnum);
-	SetPlayerSkinByNum(playernum, 0); // not found put the sonic skin
-}
-
-//
-// Add skins from a pwad, each skin preceded by 'S_SKIN' marker
-//
-
-// Does the same is in w_wad, but check only for
-// the first 6 characters (this is so we can have S_SKIN1, S_SKIN2..
-// for wad editors that don't like multiple resources of the same name)
-//
-static UINT16 W_CheckForSkinMarkerInPwad(UINT16 wadid, UINT16 startlump)
-{
-	UINT16 i;
-	const char *S_SKIN = "S_SKIN";
-	lumpinfo_t *lump_p;
-
-	// scan forward, start at <startlump>
-	if (startlump < wadfiles[wadid]->numlumps)
-	{
-		lump_p = wadfiles[wadid]->lumpinfo + startlump;
-		for (i = startlump; i < wadfiles[wadid]->numlumps; i++, lump_p++)
-			if (memcmp(lump_p->name,S_SKIN,6)==0)
-				return i;
-	}
-	return INT16_MAX; // not found
-}
-
-#define HUDNAMEWRITE(value) STRBUFCPY(skin->hudname, value)
-
-// turn _ into spaces and . into katana dot
-#define SYMBOLCONVERT(name) for (value = name; *value; value++)\
-					{\
-						if (*value == '_') *value = ' ';\
-						else if (*value == '.') *value = '\x1E';\
-					}
-
-//
-// Patch skins from a pwad, each skin preceded by 'P_SKIN' marker
-//
-
-// Does the same is in w_wad, but check only for
-// the first 6 characters (this is so we can have P_SKIN1, P_SKIN2..
-// for wad editors that don't like multiple resources of the same name)
-//
-static UINT16 W_CheckForPatchSkinMarkerInPwad(UINT16 wadid, UINT16 startlump)
-{
-	UINT16 i;
-	const char *P_SKIN = "P_SKIN";
-	lumpinfo_t *lump_p;
-
-	// scan forward, start at <startlump>
-	if (startlump < wadfiles[wadid]->numlumps)
-	{
-		lump_p = wadfiles[wadid]->lumpinfo + startlump;
-		for (i = startlump; i < wadfiles[wadid]->numlumps; i++, lump_p++)
-			if (memcmp(lump_p->name,P_SKIN,6)==0)
-				return i;
-	}
-	return INT16_MAX; // not found
-}
-
-static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, skin_t *skin)
-{
-	UINT16 newlastlump;
-	UINT8 sprite2;
-
-	*lump += 1; // start after S_SKIN
-	*lastlump = W_CheckNumForNamePwad("S_END",wadnum,*lump); // stop at S_END
-
-	// old wadding practices die hard -- stop at S_SKIN (or P_SKIN) or S_START if they come before S_END.
-	newlastlump = W_CheckForSkinMarkerInPwad(wadnum,*lump);
-	if (newlastlump < *lastlump) *lastlump = newlastlump;
-	newlastlump = W_CheckForPatchSkinMarkerInPwad(wadnum,*lump);
-	if (newlastlump < *lastlump) *lastlump = newlastlump;
-	newlastlump = W_CheckNumForNamePwad("S_START",wadnum,*lump);
-	if (newlastlump < *lastlump) *lastlump = newlastlump;
-
-	// ...and let's handle super, too
-	newlastlump = W_CheckNumForNamePwad("S_SUPER",wadnum,*lump);
-	if (newlastlump < *lastlump)
-	{
-		newlastlump++;
-		// load all sprite sets we are aware of... for super!
-		for (sprite2 = 0; sprite2 < free_spr2; sprite2++)
-			R_AddSingleSpriteDef((spritename = spr2names[sprite2]), &skin->sprites[FF_SPR2SUPER|sprite2], wadnum, newlastlump, *lastlump);
-
-		newlastlump--;
-		*lastlump = newlastlump; // okay, make the normal sprite set loading end there
-	}
-
-	// load all sprite sets we are aware of... for normal stuff.
-	for (sprite2 = 0; sprite2 < free_spr2; sprite2++)
-		R_AddSingleSpriteDef((spritename = spr2names[sprite2]), &skin->sprites[sprite2], wadnum, *lump, *lastlump);
-
-	if (skin->sprites[0].numframes == 0)
-		I_Error("R_LoadSkinSprites: no frames found for sprite SPR2_%s\n", spr2names[0]);
-}
-
-// returns whether found appropriate property
-static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
-{
-	// custom translation table
-	if (!stricmp(stoken, "startcolor"))
-		skin->starttranscolor = atoi(value);
-
-#define FULLPROCESS(field) else if (!stricmp(stoken, #field)) skin->field = get_number(value);
-	// character type identification
-	FULLPROCESS(flags)
-	FULLPROCESS(ability)
-	FULLPROCESS(ability2)
-
-	FULLPROCESS(thokitem)
-	FULLPROCESS(spinitem)
-	FULLPROCESS(revitem)
-	FULLPROCESS(followitem)
-#undef FULLPROCESS
-
-#define GETFRACBITS(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value)<<FRACBITS;
-	GETFRACBITS(normalspeed)
-	GETFRACBITS(runspeed)
-
-	GETFRACBITS(mindash)
-	GETFRACBITS(maxdash)
-	GETFRACBITS(actionspd)
-
-	GETFRACBITS(radius)
-	GETFRACBITS(height)
-	GETFRACBITS(spinheight)
-#undef GETFRACBITS
-
-#define GETINT(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value);
-	GETINT(thrustfactor)
-	GETINT(accelstart)
-	GETINT(acceleration)
-	GETINT(contspeed)
-	GETINT(contangle)
-#undef GETINT
-
-#define GETSKINCOLOR(field) else if (!stricmp(stoken, #field)) skin->field = R_GetColorByName(value);
-	GETSKINCOLOR(prefcolor)
-	GETSKINCOLOR(prefoppositecolor)
-#undef GETSKINCOLOR
-	else if (!stricmp(stoken, "supercolor"))
-		skin->supercolor = R_GetSuperColorByName(value);
-
-#define GETFLOAT(field) else if (!stricmp(stoken, #field)) skin->field = FLOAT_TO_FIXED(atof(value));
-	GETFLOAT(jumpfactor)
-	GETFLOAT(highresscale)
-	GETFLOAT(shieldscale)
-	GETFLOAT(camerascale)
-#undef GETFLOAT
-
-#define GETFLAG(field) else if (!stricmp(stoken, #field)) { \
-	strupr(value); \
-	if (atoi(value) || value[0] == 'T' || value[0] == 'Y') \
-		skin->flags |= (SF_##field); \
-	else \
-		skin->flags &= ~(SF_##field); \
-}
-	// parameters for individual character flags
-	// these are uppercase so they can be concatenated with SF_
-	// 1, true, yes are all valid values
-	GETFLAG(SUPER)
-	GETFLAG(NOSUPERSPIN)
-	GETFLAG(NOSPINDASHDUST)
-	GETFLAG(HIRES)
-	GETFLAG(NOSKID)
-	GETFLAG(NOSPEEDADJUST)
-	GETFLAG(RUNONWATER)
-	GETFLAG(NOJUMPSPIN)
-	GETFLAG(NOJUMPDAMAGE)
-	GETFLAG(STOMPDAMAGE)
-	GETFLAG(MARIODAMAGE)
-	GETFLAG(MACHINE)
-	GETFLAG(DASHMODE)
-	GETFLAG(FASTEDGE)
-	GETFLAG(MULTIABILITY)
-	GETFLAG(NONIGHTSROTATION)
-#undef GETFLAG
-
-	else // let's check if it's a sound, otherwise error out
-	{
-		boolean found = false;
-		sfxenum_t i;
-		size_t stokenadjust;
-
-		// Remove the prefix. (We need to affect an adjusting variable so that we can print error messages if it's not actually a sound.)
-		if ((stoken[0] == 'D' || stoken[0] == 'd') && (stoken[1] == 'S' || stoken[1] == 's')) // DS*
-			stokenadjust = 2;
-		else // sfx_*
-			stokenadjust = 4;
-
-		// Remove the prefix. (We can affect this directly since we're not going to use it again.)
-		if ((value[0] == 'D' || value[0] == 'd') && (value[1] == 'S' || value[1] == 's')) // DS*
-			value += 2;
-		else // sfx_*
-			value += 4;
-
-		// copy name of sounds that are remapped
-		// for this skin
-		for (i = 0; i < sfx_skinsoundslot0; i++)
-		{
-			if (!S_sfx[i].name)
-				continue;
-			if (S_sfx[i].skinsound != -1
-				&& !stricmp(S_sfx[i].name,
-					stoken + stokenadjust))
-			{
-				skin->soundsid[S_sfx[i].skinsound] =
-					S_AddSoundFx(value, S_sfx[i].singularity, S_sfx[i].pitch, true);
-				found = true;
-			}
-		}
-		return found;
-	}
-	return true;
-}
-
-//
-// Find skin sprites, sounds & optional status bar face, & add them
-//
-void R_AddSkins(UINT16 wadnum)
-{
-	UINT16 lump, lastlump = 0;
-	char *buf;
-	char *buf2;
-	char *stoken;
-	char *value;
-	size_t size;
-	skin_t *skin;
-	boolean hudname, realname;
-
-	//
-	// search for all skin markers in pwad
-	//
-
-	while ((lump = W_CheckForSkinMarkerInPwad(wadnum, lastlump)) != INT16_MAX)
-	{
-		// advance by default
-		lastlump = lump + 1;
-
-		if (numskins >= MAXSKINS)
-		{
-			CONS_Debug(DBG_RENDER, "ignored skin (%d skins maximum)\n", MAXSKINS);
-			continue; // so we know how many skins couldn't be added
-		}
-		buf = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE);
-		size = W_LumpLengthPwad(wadnum, lump);
-
-		// for strtok
-		buf2 = malloc(size+1);
-		if (!buf2)
-			I_Error("R_AddSkins: No more free memory\n");
-		M_Memcpy(buf2,buf,size);
-		buf2[size] = '\0';
-
-		// set defaults
-		skin = &skins[numskins];
-		Sk_SetDefaultValue(skin);
-		skin->wadnum = wadnum;
-		hudname = realname = false;
-		// parse
-		stoken = strtok (buf2, "\r\n= ");
-		while (stoken)
-		{
-			if ((stoken[0] == '/' && stoken[1] == '/')
-				|| (stoken[0] == '#'))// skip comments
-			{
-				stoken = strtok(NULL, "\r\n"); // skip end of line
-				goto next_token;              // find the real next token
-			}
-
-			value = strtok(NULL, "\r\n= ");
-
-			if (!value)
-				I_Error("R_AddSkins: syntax error in S_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename);
-
-			// Some of these can't go in R_ProcessPatchableFields because they have side effects for future lines.
-			// Others can't go in there because we don't want them to be patchable.
-			if (!stricmp(stoken, "name"))
-			{
-				INT32 skinnum = R_SkinAvailable(value);
-				strlwr(value);
-				if (skinnum == -1)
-					STRBUFCPY(skin->name, value);
-				// the skin name must uniquely identify a single skin
-				// if the name is already used I make the name 'namex'
-				// using the default skin name's number set above
-				else
-				{
-					const size_t stringspace =
-						strlen(value) + sizeof (numskins) + 1;
-					char *value2 = Z_Malloc(stringspace, PU_STATIC, NULL);
-					snprintf(value2, stringspace,
-						"%s%d", value, numskins);
-					value2[stringspace - 1] = '\0';
-					if (R_SkinAvailable(value2) == -1)
-						// I'm lazy so if NEW name is already used I leave the 'skin x'
-						// default skin name set in Sk_SetDefaultValue
-						STRBUFCPY(skin->name, value2);
-					Z_Free(value2);
-				}
-
-				// copy to hudname and fullname as a default.
-				if (!realname)
-				{
-					STRBUFCPY(skin->realname, skin->name);
-					for (value = skin->realname; *value; value++)
-					{
-						if (*value == '_') *value = ' '; // turn _ into spaces.
-						else if (*value == '.') *value = '\x1E'; // turn . into katana dot.
-					}
-				}
-				if (!hudname)
-				{
-					HUDNAMEWRITE(skin->name);
-					strupr(skin->hudname);
-					SYMBOLCONVERT(skin->hudname)
-				}
-			}
-			else if (!stricmp(stoken, "realname"))
-			{ // Display name (eg. "Knuckles")
-				realname = true;
-				STRBUFCPY(skin->realname, value);
-				SYMBOLCONVERT(skin->realname)
-				if (!hudname)
-					HUDNAMEWRITE(skin->realname);
-			}
-			else if (!stricmp(stoken, "hudname"))
-			{ // Life icon name (eg. "K.T.E")
-				hudname = true;
-				HUDNAMEWRITE(value);
-				SYMBOLCONVERT(skin->hudname)
-				if (!realname)
-					STRBUFCPY(skin->realname, skin->hudname);
-			}
-			else if (!stricmp(stoken, "availability"))
-			{
-				skin->availability = atoi(value);
-				if (skin->availability >= MAXUNLOCKABLES)
-					skin->availability = 0;
-			}
-			else if (!R_ProcessPatchableFields(skin, stoken, value))
-				CONS_Debug(DBG_SETUP, "R_AddSkins: Unknown keyword '%s' in S_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename);
-
-next_token:
-			stoken = strtok(NULL, "\r\n= ");
-		}
-		free(buf2);
-
-		// Add sprites
-		R_LoadSkinSprites(wadnum, &lump, &lastlump, skin);
-		//ST_LoadFaceGraphics(numskins); -- nah let's do this elsewhere
-
-		R_FlushTranslationColormapCache();
-
-		if (!skin->availability) // Safe to print...
-			CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name);
-#ifdef SKINVALUES
-		skin_cons_t[numskins].value = numskins;
-		skin_cons_t[numskins].strvalue = skin->name;
-#endif
-
-#ifdef HWRENDER
-		if (rendermode == render_opengl)
-			HWR_AddPlayerModel(numskins);
-#endif
-
-		numskins++;
-	}
-	return;
-}
-
-//
-// Patch skin sprites
-//
-void R_PatchSkins(UINT16 wadnum)
-{
-	UINT16 lump, lastlump = 0;
-	char *buf;
-	char *buf2;
-	char *stoken;
-	char *value;
-	size_t size;
-	skin_t *skin;
-	boolean noskincomplain, realname, hudname;
-
-	//
-	// search for all skin patch markers in pwad
-	//
-
-	while ((lump = W_CheckForPatchSkinMarkerInPwad(wadnum, lastlump)) != INT16_MAX)
-	{
-		INT32 skinnum = 0;
-
-		// advance by default
-		lastlump = lump + 1;
-
-		buf = W_CacheLumpNumPwad(wadnum, lump, PU_CACHE);
-		size = W_LumpLengthPwad(wadnum, lump);
-
-		// for strtok
-		buf2 = malloc(size+1);
-		if (!buf2)
-			I_Error("R_PatchSkins: No more free memory\n");
-		M_Memcpy(buf2,buf,size);
-		buf2[size] = '\0';
-
-		skin = NULL;
-		noskincomplain = realname = hudname = false;
-
-		/*
-		Parse. Has more phases than the parser in R_AddSkins because it needs to have the patching name first (no default skin name is acceptible for patching, unlike skin creation)
-		*/
-
-		stoken = strtok(buf2, "\r\n= ");
-		while (stoken)
-		{
-			if ((stoken[0] == '/' && stoken[1] == '/')
-				|| (stoken[0] == '#'))// skip comments
-			{
-				stoken = strtok(NULL, "\r\n"); // skip end of line
-				goto next_token;              // find the real next token
-			}
-
-			value = strtok(NULL, "\r\n= ");
-
-			if (!value)
-				I_Error("R_PatchSkins: syntax error in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename);
-
-			if (!skin) // Get the name!
-			{
-				if (!stricmp(stoken, "name"))
-				{
-					strlwr(value);
-					skinnum = R_SkinAvailable(value);
-					if (skinnum != -1)
-						skin = &skins[skinnum];
-					else
-					{
-						CONS_Debug(DBG_SETUP, "R_PatchSkins: unknown skin name in P_SKIN lump# %d(%s) in WAD %s\n", lump, W_CheckNameForNumPwad(wadnum,lump), wadfiles[wadnum]->filename);
-						noskincomplain = true;
-					}
-				}
-			}
-			else // Get the properties!
-			{
-				// Some of these can't go in R_ProcessPatchableFields because they have side effects for future lines.
-				if (!stricmp(stoken, "realname"))
-				{ // Display name (eg. "Knuckles")
-					realname = true;
-					STRBUFCPY(skin->realname, value);
-					SYMBOLCONVERT(skin->realname)
-					if (!hudname)
-						HUDNAMEWRITE(skin->realname);
-				}
-				else if (!stricmp(stoken, "hudname"))
-				{ // Life icon name (eg. "K.T.E")
-					hudname = true;
-					HUDNAMEWRITE(value);
-					SYMBOLCONVERT(skin->hudname)
-					if (!realname)
-						STRBUFCPY(skin->realname, skin->hudname);
-				}
-				else if (!R_ProcessPatchableFields(skin, stoken, value))
-					CONS_Debug(DBG_SETUP, "R_PatchSkins: Unknown keyword '%s' in P_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename);
-			}
-
-			if (!skin)
-				break;
-
-next_token:
-			stoken = strtok(NULL, "\r\n= ");
-		}
-		free(buf2);
-
-		if (!skin) // Didn't include a name parameter? What a waste.
-		{
-			if (!noskincomplain)
-				CONS_Debug(DBG_SETUP, "R_PatchSkins: no skin name given in P_SKIN lump #%d (WAD %s)\n", lump, wadfiles[wadnum]->filename);
-			continue;
-		}
-
-		// Patch sprites
-		R_LoadSkinSprites(wadnum, &lump, &lastlump, skin);
-		//ST_LoadFaceGraphics(skinnum); -- nah let's do this elsewhere
-
-		R_FlushTranslationColormapCache();
-
-		if (!skin->availability) // Safe to print...
-			CONS_Printf(M_GetText("Patched skin '%s'\n"), skin->name);
-	}
-	return;
-}
-
-#undef HUDNAMEWRITE
-#undef SYMBOLCONVERT
diff --git a/src/r_things.h b/src/r_things.h
index bd6271b60eaa2333662ddd0582f3677b7466145a..7a0fe3a60ee557bc358e95e75c49dc5f53d6ef3f 100644
--- a/src/r_things.h
+++ b/src/r_things.h
@@ -14,26 +14,27 @@
 #ifndef __R_THINGS__
 #define __R_THINGS__
 
-#include "sounds.h"
 #include "r_plane.h"
 #include "r_patch.h"
 #include "r_portal.h"
 #include "r_defs.h"
+#include "r_skins.h"
 
-// number of sprite lumps for spritewidth,offset,topoffset lookup tables
-// Fab: this is a hack : should allocate the lookup tables per sprite
-#define MAXVISSPRITES 2048 // added 2-2-98 was 128
-
-#define VISSPRITECHUNKBITS 6	// 2^6 = 64 sprites per chunk
-#define VISSPRITESPERCHUNK (1 << VISSPRITECHUNKBITS)
-#define VISSPRITEINDEXMASK (VISSPRITESPERCHUNK - 1)
+// --------------
+// SPRITE LOADING
+// --------------
 
 #define FEETADJUST (4<<FRACBITS) // R_AddSingleSpriteDef
 
-// Constant arrays used for psprite clipping
-//  and initializing clipping.
-extern INT16 negonearray[MAXVIDWIDTH];
-extern INT16 screenheightarray[MAXVIDWIDTH];
+boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump);
+
+//faB: find sprites in wadfile, replace existing, add new ones
+//     (only sprites from namelist are added or replaced)
+void R_AddSpriteDefs(UINT16 wadnum);
+
+// ---------------------
+// MASKED COLUMN DRAWING
+// ---------------------
 
 // vars for R_DrawMaskedColumn
 extern INT16 *mfloorclip;
@@ -43,13 +44,19 @@ extern fixed_t sprtopscreen;
 extern fixed_t sprbotscreen;
 extern fixed_t windowtop;
 extern fixed_t windowbottom;
+extern INT32 lengthcol;
 
 void R_DrawMaskedColumn(column_t *column);
-void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight);
+void R_DrawFlippedMaskedColumn(column_t *column);
 
-//faB: find sprites in wadfile, replace existing, add new ones
-//     (only sprites from namelist are added or replaced)
-void R_AddSpriteDefs(UINT16 wadnum);
+// ----------------
+// SPRITE RENDERING
+// ----------------
+
+// Constant arrays used for psprite clipping
+//  and initializing clipping.
+extern INT16 negonearray[MAXVIDWIDTH];
+extern INT16 screenheightarray[MAXVIDWIDTH];
 
 fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope);
 
@@ -68,6 +75,9 @@ boolean R_ThingVisibleWithinDist (mobj_t *thing,
 boolean R_PrecipThingVisible (precipmobj_t *precipthing,
 		fixed_t precip_draw_dist);
 
+// --------------
+// MASKED DRAWING
+// --------------
 /** Used to count the amount of masked elements
  * per portal to later group them in separate
  * drawnode lists.
@@ -82,73 +92,18 @@ typedef struct
 
 void R_DrawMasked(maskcount_t* masks, UINT8 nummasks);
 
-// -----------
-// SKINS STUFF
-// -----------
-#define SKINNAMESIZE 16
-// should be all lowercase!! S_SKIN processing does a strlwr
-#define DEFAULTSKIN "sonic"
-#define DEFAULTSKIN2 "tails" // secondary player
-#define DEFAULTNIGHTSSKIN 0
+// ----------
+// VISSPRITES
+// ----------
+
+// number of sprite lumps for spritewidth,offset,topoffset lookup tables
+// Fab: this is a hack : should allocate the lookup tables per sprite
+#define MAXVISSPRITES 2048 // added 2-2-98 was 128
+
+#define VISSPRITECHUNKBITS 6	// 2^6 = 64 sprites per chunk
+#define VISSPRITESPERCHUNK (1 << VISSPRITECHUNKBITS)
+#define VISSPRITEINDEXMASK (VISSPRITESPERCHUNK - 1)
 
-typedef struct
-{
-	char name[SKINNAMESIZE+1]; // INT16 descriptive name of the skin
-	UINT16 wadnum;
-	skinflags_t flags;
-
-	char realname[SKINNAMESIZE+1]; // Display name for level completion.
-	char hudname[SKINNAMESIZE+1]; // HUD name to display (officially exactly 5 characters long)
-
-	UINT8 ability; // ability definition
-	UINT8 ability2; // secondary ability definition
-	INT32 thokitem;
-	INT32 spinitem;
-	INT32 revitem;
-	INT32 followitem;
-	fixed_t actionspd;
-	fixed_t mindash;
-	fixed_t maxdash;
-
-	fixed_t normalspeed; // Normal ground
-	fixed_t runspeed; // Speed that you break into your run animation
-
-	UINT8 thrustfactor; // Thrust = thrustfactor * acceleration
-	UINT8 accelstart; // Acceleration if speed = 0
-	UINT8 acceleration; // Acceleration
-
-	fixed_t jumpfactor; // multiple of standard jump height
-
-	fixed_t radius; // Bounding box changes.
-	fixed_t height;
-	fixed_t spinheight;
-
-	fixed_t shieldscale; // no change to bounding box, but helps set the shield's sprite size
-	fixed_t camerascale;
-
-	// Definable color translation table
-	UINT8 starttranscolor;
-	UINT8 prefcolor;
-	UINT8 supercolor;
-	UINT8 prefoppositecolor; // if 0 use tables instead
-
-	fixed_t highresscale; // scale of highres, default is 0.5
-	UINT8 contspeed; // continue screen animation speed
-	UINT8 contangle; // initial angle on continue screen
-
-	// specific sounds per skin
-	sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table
-
-	// contains super versions too
-	spritedef_t sprites[NUMPLAYERSPRITES*2];
-	spriteinfo_t sprinfo[NUMPLAYERSPRITES*2];
-
-	UINT8 availability; // lock?
-} skin_t;
-
-// -----------
-// NOT SKINS STUFF !
-// -----------
 typedef enum
 {
 	// actual cuts
@@ -227,6 +182,12 @@ typedef struct vissprite_s
 	INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing
 } vissprite_t;
 
+extern UINT32 visspritecount;
+
+// ----------
+// DRAW NODES
+// ----------
+
 // A drawnode is something that points to a 3D floor, 3D side, or masked
 // middle texture. This is used for sorting with sprites.
 typedef struct drawnode_s
@@ -241,23 +202,11 @@ typedef struct drawnode_s
 	struct drawnode_s *prev;
 } drawnode_t;
 
-extern INT32 numskins;
-extern skin_t skins[MAXSKINS];
-extern UINT32 visspritecount;
-
-void SetPlayerSkin(INT32 playernum,const char *skinname);
-void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002
-boolean R_SkinUsable(INT32 playernum, INT32 skinnum);
-UINT32 R_GetSkinAvailabilities(void);
-INT32 R_SkinAvailable(const char *name);
-void R_PatchSkins(UINT16 wadnum);
-void R_AddSkins(UINT16 wadnum);
-
-UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player);
-
 void R_InitDrawNodes(void);
 
-char *GetPlayerFacePic(INT32 skinnum);
+// -----------------------
+// SPRITE FRAME CHARACTERS
+// -----------------------
 
 // Functions to go from sprite character ID to frame number
 // for 2.1 compatibility this still uses the old 'A' + frame code
diff --git a/src/s_sound.c b/src/s_sound.c
index 8193fdb9b948a7fe0b7aa9fedb53e9b77f0cd516..8e9461d785b9eecef326d4238494230791425211 100644
--- a/src/s_sound.c
+++ b/src/s_sound.c
@@ -27,7 +27,7 @@ extern INT32 msg_id;
 #include "g_game.h"
 #include "m_argv.h"
 #include "r_main.h" // R_PointToAngle2() used to calc stereo sep.
-#include "r_things.h" // for skins
+#include "r_skins.h" // for skins
 #include "i_system.h"
 #include "i_sound.h"
 #include "s_sound.h"
diff --git a/src/screen.c b/src/screen.c
index 7ebe34635600eeb68d0bfcabb1ca5c81e991ef4a..011477338ac94b3f00c98d2a8503c6aa30dc84fb 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -453,7 +453,7 @@ void SCR_ActuallyChangeRenderer(void)
 
 #ifdef HWRENDER
 	// Well, it didn't even load anyway.
-	if ((hwrenderloaded == -1) && (setrenderneeded == render_opengl))
+	if ((vid_opengl_state == -1) && (setrenderneeded == render_opengl))
 	{
 		if (M_CheckParm("-nogl"))
 			CONS_Alert(CONS_ERROR, "OpenGL rendering was disabled!\n");
@@ -478,7 +478,7 @@ void SCR_ChangeRenderer(void)
 	{
 		target_renderer = cv_renderer.value;
 #ifdef HWRENDER
-		if (M_CheckParm("-opengl") && (hwrenderloaded == 1))
+		if (M_CheckParm("-opengl") && (vid_opengl_state == 1))
 			target_renderer = rendermode = render_opengl;
 		else
 #endif
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index b334f6313614b5890c9b971b07068e7c404b6cec..7e260f4c01ed5a83960bd8f65bdc1f50fbad5ee6 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -284,6 +284,7 @@
     <ClInclude Include="..\r_patch.h" />
     <ClInclude Include="..\r_portal.h" />
     <ClInclude Include="..\r_segs.h" />
+    <ClInclude Include="..\r_skins.h" />
     <ClInclude Include="..\r_sky.h" />
     <ClInclude Include="..\r_splats.h" />
     <ClInclude Include="..\r_state.h" />
@@ -446,6 +447,7 @@
 	<ClCompile Include="..\r_patch.c" />
     <ClCompile Include="..\r_portal.c" />
     <ClCompile Include="..\r_segs.c" />
+    <ClCompile Include="..\r_skins.c" />
     <ClCompile Include="..\r_sky.c" />
     <ClCompile Include="..\r_splats.c" />
     <ClCompile Include="..\r_things.c" />
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index 3f61e87098fd08e732f7c521435d93fb63ca77f9..21820551a4ad1bfcfe85765d7975fa482c646e55 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -417,6 +417,9 @@
     <ClInclude Include="..\r_segs.h">
       <Filter>R_Rend</Filter>
     </ClInclude>
+    <ClInclude Include="..\r_skins.h">
+      <Filter>R_Rend</Filter>
+    </ClInclude>
     <ClInclude Include="..\r_sky.h">
       <Filter>R_Rend</Filter>
     </ClInclude>
@@ -849,6 +852,9 @@
     <ClCompile Include="..\r_segs.c">
       <Filter>R_Rend</Filter>
     </ClCompile>
+    <ClCompile Include="..\r_skins.c">
+      <Filter>R_Rend</Filter>
+    </ClCompile>
     <ClCompile Include="..\r_sky.c">
       <Filter>R_Rend</Filter>
     </ClCompile>
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 1af4cbf73b8ab1263d3c91b46d890e0f97f2ceb4..2a129fbde2b41d593fd34359f13d6a463e4d8b94 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -104,7 +104,7 @@ static consvar_t cv_stretch = {"stretch", "Off", CV_SAVE|CV_NOSHOWHELP, CV_OnOff
 static consvar_t cv_alwaysgrabmouse = {"alwaysgrabmouse", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 UINT8 graphics_started = 0; // Is used in console.c and screen.c
-INT32 hwrenderloaded = 0;
+INT32 vid_opengl_state = 0;
 
 // To disable fullscreen at startup; is set in VID_PrepareModeList
 boolean allow_fullscreen = false;
@@ -1436,7 +1436,7 @@ static SDL_bool Impl_CreateContext(void)
 {
 	// Renderer-specific stuff
 #ifdef HWRENDER
-	if ((rendermode == render_opengl) && (hwrenderloaded != -1))
+	if ((rendermode == render_opengl) && (vid_opengl_state != -1))
 	{
 		if (!sdlglcontext)
 			sdlglcontext = SDL_GL_CreateContext(window);
@@ -1469,10 +1469,10 @@ static SDL_bool Impl_CreateContext(void)
 	return SDL_TRUE;
 }
 
-#ifdef HWRENDER
-static void VID_CheckGLLoaded(rendermode_t oldrender)
+void VID_CheckGLLoaded(rendermode_t oldrender)
 {
-	if (hwrenderloaded == -1) // Well, it didn't work the first time anyway.
+#ifdef HWRENDER
+	if (vid_opengl_state == -1) // Well, it didn't work the first time anyway.
 	{
 		CONS_Alert(CONS_ERROR, "OpenGL never loaded\n");
 		rendermode = oldrender;
@@ -1485,40 +1485,66 @@ static void VID_CheckGLLoaded(rendermode_t oldrender)
 			setrenderneeded = 0;
 		}
 	}
-}
 #endif
+}
 
 void VID_CheckRenderer(void)
 {
-	SDL_bool rendererchanged = SDL_FALSE;
+	boolean rendererchanged = false;
+	boolean contextcreated = false;
 	rendermode_t oldrenderer = rendermode;
 
 	if (dedicated)
 		return;
 
-#ifdef HWRENDER
-	if (!graphics_started)
-		VID_CheckGLLoaded(oldrenderer);
-#endif
-
 	if (setrenderneeded)
 	{
 		rendermode = setrenderneeded;
-		rendererchanged = SDL_TRUE;
+		rendererchanged = true;
 
 #ifdef HWRENDER
 		if (rendermode == render_opengl)
 		{
 			VID_CheckGLLoaded(oldrenderer);
+
 			// Initialise OpenGL before calling SDLSetMode!!!
-			if (hwrenderloaded != 1)
-				I_StartupHardwareGraphics();
-			else if (hwrenderloaded == -1)
-				rendererchanged = SDL_FALSE;
+			// This is because SDLSetMode calls OglSdlSurface.
+			if (vid_opengl_state == 0)
+			{
+				VID_StartupOpenGL();
+				// Loaded successfully!
+				if (vid_opengl_state == 1)
+				{
+					// Destroy the current window, if it exists.
+					if (window)
+					{
+						SDL_DestroyWindow(window);
+						window = NULL;
+					}
+
+					// Destroy the current window rendering context, if that also exists.
+					if (renderer)
+					{
+						SDL_DestroyRenderer(renderer);
+						renderer = NULL;
+					}
+
+					// Create a new window.
+					Impl_CreateWindow(USE_FULLSCREEN);
+
+					// From there, the OpenGL context was already created.
+					contextcreated = true;
+				}
+			}
+			else if (vid_opengl_state == -1)
+				rendererchanged = false;
 		}
 #endif
 
-		Impl_CreateContext();
+		if (!contextcreated)
+			Impl_CreateContext();
+
+		setrenderneeded = 0;
 	}
 
 	SDLSetMode(vid.width, vid.height, USE_FULLSCREEN, (rendererchanged ? SDL_FALSE : SDL_TRUE));
@@ -1531,15 +1557,25 @@ void VID_CheckRenderer(void)
 			SDL_FreeSurface(bufSurface);
 			bufSurface = NULL;
 		}
+
+		if (rendererchanged)
+		{
 #ifdef HWRENDER
-		if (hwrenderloaded == 1) // Only if OpenGL ever loaded!
-			HWR_FreeTextureCache();
+			if (vid_opengl_state == 1) // Only if OpenGL ever loaded!
+				HWR_FreeTextureCache();
 #endif
-		SCR_SetDrawFuncs();
+			SCR_SetDrawFuncs();
+		}
 	}
 #ifdef HWRENDER
 	else if (rendermode == render_opengl)
-		R_InitHardwareMode();
+	{
+		if (rendererchanged)
+		{
+			R_InitHardwareMode();
+			V_SetPalette(0);
+		}
+	}
 #else
 	(void)oldrenderer;
 #endif
@@ -1583,7 +1619,7 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
 		flags |= SDL_WINDOW_BORDERLESS;
 
 #ifdef HWRENDER
-	if (hwrenderloaded != -1)
+	if (vid_opengl_state == 1)
 		flags |= SDL_WINDOW_OPENGL;
 #endif
 
@@ -1717,11 +1753,12 @@ void I_StartupGraphics(void)
 
 	//SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY>>1,SDL_DEFAULT_REPEAT_INTERVAL<<2);
 	VID_Command_ModeList_f();
+
 #ifdef HWRENDER
 	if (M_CheckParm("-nogl"))
-		hwrenderloaded = -1; // Don't call SDL_GL_LoadLibrary
-	else
-		I_StartupHardwareGraphics();
+		vid_opengl_state = -1; // Don't startup OpenGL
+	else if (chosenrendermode == render_opengl)
+		VID_StartupOpenGL();
 #endif
 
 	// Fury: we do window initialization after GL setup to allow
@@ -1776,12 +1813,13 @@ void I_StartupGraphics(void)
 	graphics_started = true;
 }
 
-void I_StartupHardwareGraphics(void)
+void VID_StartupOpenGL(void)
 {
 #ifdef HWRENDER
 	static boolean glstartup = false;
 	if (!glstartup)
 	{
+		CONS_Printf("VID_StartupOpenGL()...\n");
 		HWD.pfnInit             = hwSym("Init",NULL);
 		HWD.pfnFinishUpdate     = NULL;
 		HWD.pfnDraw2DLine       = hwSym("Draw2DLine",NULL);
@@ -1819,7 +1857,9 @@ void I_StartupHardwareGraphics(void)
 		HWD.pfnLoadCustomShader = hwSym("LoadCustomShader",NULL);
 		HWD.pfnInitCustomShaders= hwSym("InitCustomShaders",NULL);
 
-		if (!HWD.pfnInit()) // let load the OpenGL library
+		vid_opengl_state = HWD.pfnInit() ? 1 : -1; // let load the OpenGL library
+
+		if (vid_opengl_state == -1)
 		{
 			rendermode = render_soft;
 			setrenderneeded = 0;
diff --git a/src/sounds.c b/src/sounds.c
index a9d720d5c44800ef5dddf0eb208ac3db3a918388..ca943c2d06f0fd9d86e0a3616a86c84b857f65e3 100644
--- a/src/sounds.c
+++ b/src/sounds.c
@@ -15,7 +15,7 @@
 #include "i_sound.h"
 #include "sounds.h"
 #include "r_defs.h"
-#include "r_things.h"
+#include "r_skins.h"
 #include "z_zone.h"
 #include "w_wad.h"
 #include "lua_script.h"
diff --git a/src/w_wad.c b/src/w_wad.c
index 90a3b9105c5889802a84fee8866f3064d3f8d490..f356f33fe31b88cf2fda7f5a3759a768700332ee 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -807,7 +807,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup)
 
 #ifdef HWRENDER
 	// Read shaders from file
-	if (rendermode == render_opengl && (hwrenderloaded == 1))
+	if (rendermode == render_opengl && (vid_opengl_state == 1))
 	{
 		HWR_ReadShaders(numwadfiles - 1, (type == RET_PK3));
 		HWR_LoadShaders();
@@ -1505,53 +1505,69 @@ void *W_CacheLumpName(const char *name, INT32 tag)
 // Cache a patch into heap memory, convert the patch format as necessary
 //
 
-void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
+void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
 {
-#ifdef HWRENDER
-	GLPatch_t *grPatch;
-#endif
+	lumpcache_t *lumpcache = NULL;
 
 	if (!TestValidLump(wad, lump))
 		return NULL;
 
-#ifdef HWRENDER
-	// Software-only compile cache the data without conversion
-	if (rendermode == render_soft || rendermode == render_none)
-#endif
+	lumpcache = wadfiles[wad]->patchcache;
+
+	if (!lumpcache[lump])
 	{
-		lumpcache_t *lumpcache = wadfiles[wad]->patchcache;
-		if (!lumpcache[lump])
-		{
-			size_t len = W_LumpLengthPwad(wad, lump);
-			void *ptr, *lumpdata;
+		size_t len = W_LumpLengthPwad(wad, lump);
+		void *ptr, *lumpdata;
 #ifndef NO_PNG_LUMPS
-			void *srcdata = NULL;
+		void *srcdata = NULL;
 #endif
 
-			ptr = Z_Malloc(len, tag, &lumpcache[lump]);
-			lumpdata = Z_Malloc(len, tag, NULL);
+		ptr = Z_Malloc(len, tag, &lumpcache[lump]);
+		lumpdata = Z_Malloc(len, tag, NULL);
 
-			// read the lump in full
-			W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0);
+		// read the lump in full
+		W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0);
 
 #ifndef NO_PNG_LUMPS
-			// lump is a png so convert it
-			if (R_IsLumpPNG((UINT8 *)lumpdata, len))
-			{
-				size_t newlen;
-				srcdata = R_PNGToPatch((UINT8 *)lumpdata, len, &newlen);
-				ptr = Z_Realloc(ptr, newlen, tag, &lumpcache[lump]);
-				M_Memcpy(ptr, srcdata, newlen);
-				Z_Free(srcdata);
-			}
-			else // just copy it into the patch cache
-#endif
-				M_Memcpy(ptr, lumpdata, len);
+		// lump is a png so convert it
+		if (R_IsLumpPNG((UINT8 *)lumpdata, len))
+		{
+			size_t newlen;
+			srcdata = R_PNGToPatch((UINT8 *)lumpdata, len, &newlen);
+			ptr = Z_Realloc(ptr, newlen, tag, &lumpcache[lump]);
+			M_Memcpy(ptr, srcdata, newlen);
+			Z_Free(srcdata);
 		}
-		else
-			Z_ChangeTag(lumpcache[lump], tag);
+		else // just copy it into the patch cache
+#endif
+			M_Memcpy(ptr, lumpdata, len);
+	}
+	else
+		Z_ChangeTag(lumpcache[lump], tag);
 
-		return lumpcache[lump];
+	return lumpcache[lump];
+}
+
+void *W_CacheSoftwarePatchNum(lumpnum_t lumpnum, INT32 tag)
+{
+	return W_CacheSoftwarePatchNumPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum),tag);
+}
+
+void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
+{
+#ifdef HWRENDER
+	GLPatch_t *grPatch;
+#endif
+
+	if (!TestValidLump(wad, lump))
+		return NULL;
+
+#ifdef HWRENDER
+	// Software-only compile cache the data without conversion
+	if (rendermode == render_soft || rendermode == render_none)
+#endif
+	{
+		return W_CacheSoftwarePatchNumPwad(wad, lump, tag);
 	}
 #ifdef HWRENDER
 
diff --git a/src/w_wad.h b/src/w_wad.h
index 15a5cf7fb91a0fd43167d3e4bd4e066ea3b778f2..86a0db1d40bcfc9e048afcfc8c2dfb4403e78836 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -191,8 +191,15 @@ boolean W_IsPatchCached(lumpnum_t lump, void *ptr);
 void *W_CacheLumpName(const char *name, INT32 tag);
 void *W_CachePatchName(const char *name, INT32 tag);
 
-void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag); // return a patch_t
-void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag); // return a patch_t
+// Returns either a Software patch, or an OpenGL patch.
+// Performs any necessary conversions from PNG images.
+void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag);
+void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag);
+
+// Returns a Software patch.
+// Performs any necessary conversions from PNG images.
+void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag);
+void *W_CacheSoftwarePatchNum(lumpnum_t lumpnum, INT32 tag);
 
 void W_UnlockCachedPatch(void *patch);
 
diff --git a/src/win32/win_vid.c b/src/win32/win_vid.c
index d0aab92b3e16a4d13fb4cb57039869a732bfaef1..4e7bab5696d6861350412b47f52b591352da8cde 100644
--- a/src/win32/win_vid.c
+++ b/src/win32/win_vid.c
@@ -239,10 +239,7 @@ void I_StartupGraphics(void)
 	if (!dedicated) graphics_started = true;
 }
 
-void I_StartupHardwareGraphics(void)
-{
-	// oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo yeah oh yeah woo y
-}
+void VID_StartupOpenGL(void){}
 
 // ------------------
 // I_ShutdownGraphics
@@ -951,10 +948,8 @@ INT32 VID_SetMode(INT32 modenum)
 	return 1;
 }
 
-void VID_CheckRenderer(void)
-{
-	// ..............
-}
+void VID_CheckRenderer(void) {}
+void VID_CheckGLLoaded(rendermode_t oldrender) {}
 
 // ========================================================================
 // Free the video buffer of the last video mode,
diff --git a/src/y_inter.c b/src/y_inter.c
index 36cb64d0625de2b1d3862cf85bcd0fcf6cbbe486..6f23ef1b1f6fa1f983f064ef1abc11154702f274 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -19,7 +19,7 @@
 #include "i_video.h"
 #include "p_tick.h"
 #include "r_defs.h"
-#include "r_things.h"
+#include "r_skins.h"
 #include "s_sound.h"
 #include "st_stuff.h"
 #include "v_video.h"