diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..d936721b63e3bfcf63f4760308d26daab03da40b
--- /dev/null
+++ b/extras/conf/SRB2-22.cfg
@@ -0,0 +1,6419 @@
+/*********************************************************\
+	Zone Builder Game Configuration
+	For Sonic Robo Blast 2 Version 2.2
+	Contributors (alphabetical):
+	* Foxboy
+	* JJames19119
+	* Kalaron
+	* Kristos
+	* MascaraSnake
+	* mazmazz
+	* Morpheus
+	* Neo Chaotikal
+	* Nev3r
+	* Oogaland
+	* Rob
+	* Shadow Hog
+	* Spherallic
+	* SRB2-Playah
+	* SSNTails
+	* SteelT
+	* ST218
+	* toaster
+	* Viola
+\*********************************************************/
+
+// 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";
+
+//GZDB specific. Don't try to load lumps that don't exist.
+basegame = 0;
+
+// This is the simplified game engine/sourceport name
+engine = "zdoom";
+
+// When this is set to true, sectors with the same tag will light up when a line is highlighted
+linetagindicatesectors = true;
+
+// The format interface handles the map data format - DoomMapSetIO for SRB2DB2, SRB2MapSetIO for Zone Builder
+formatinterface = "SRB2MapSetIO";
+
+//Sky textures for vanilla maps
+defaultskytextures
+{
+	SKY1 = "MAP01,MAP02,MAP03,MAP50,MAPA1,MAPA2,MAPA5,MAPA6,MAPA9,MAPAA,MAPAB,MAPAC,MAPAD,MAPAE,MAPAG,MAPAJ,MAPAK,MAPF0,MAPF1,MAPFA,MAPM0,MAPM8,MAPMA,MAPMB,MAPMC";
+	SKY4 = "MAP04,MAP06,MAP51,MAPF8,MAPM1";
+	SKY6 = "MAP05";
+	SKY7 = "MAP07,MAP08,MAP09,MAP52,MAPM2,MAPM5";
+	SKY10 = "MAP12,MAP53,MAPM3";
+	SKY11 = "MAP10,MAP11,MAP16,MAP55,MAPF2,MAPF5,MAPF6,MAPF9,MAPM7";
+	SKY13 = "MAP13,MAP54,MAPAS";
+	SKY21 = "MAPAF,MAPF7,MAPM4";
+	SKY22 = "MAP22,MAP23,MAP24,MAP25,MAP56,MAPAN,MAPAO,MAPF4,MAPM6";
+	SKY29 = "MAP58,MAPAV";
+	SKY30 = "MAP30";
+	SKY35 = "MAP41";
+	SKY40 = "MAP40";
+	SKY55 = "MAPF3,MAPM9";
+	SKY66 = "MAPAT";
+	SKY99 = "MAP57";
+	SKY103 = "MAPA3,MAPA4,MAPAU";
+	SKY107 = "MAPA7,MAPA8";
+	SKY117 = "MAPAH,MAPAI";
+	SKY127 = "MAPAR";
+	SKY132 = "MAPAW";
+}
+
+// Default lump name for new map
+defaultlumpname = "MAP01";
+
+// Default testing parameters
+testparameters = "-file \"%AP\" \"%F\" -warp %L";
+testshortpaths = true;
+
+// Default nodebuilder configurations
+defaultsavecompiler = "zennode_normal";
+defaulttestcompiler = "zennode_fast";
+
+// Skill levels
+skills
+{
+	1 = "Normal";
+}
+
+// Skins
+skins
+{
+	Sonic;
+	Tails;
+	Knuckles;
+	Metalsonic;
+	Fang;
+	Amy;
+}
+
+// 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";
+}
+
+// Special linedefs
+soundlinedefflag = 64;	// See linedefflags
+singlesidedflag = 1;	// See linedefflags
+doublesidedflag = 4;	// See linedefflags
+impassableflag = 1;
+upperunpeggedflag = 8;
+lowerunpeggedflag = 16;
+repeatmidtextureflag = 1024;
+pegmidtextureflag = 256;
+
+// Generalized actions
+generalizedlinedefs = false;
+generalizedsectors = true;
+
+// Texture loading options
+defaultwalltexture = "GFZROCK";
+defaultfloortexture = "GFZFLR01";
+defaultceilingtexture = "F_SKY1";
+mixtexturesflats = true;
+defaulttexturescale = 1.0f;
+defaultflatscale = 1.0f;
+
+// Thing number for start position in 3D Mode
+start3dmode = 3328;
+
+
+
+
+/*
+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.
+Kalaron: and now TX_START
+*/
+
+// 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";
+	}
+}
+
+
+/*
+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
+{
+	~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;
+	}
+}
+
+scriptlumpnames
+{
+	MAINCFG
+	{
+		script = "SOC.cfg";
+	}
+
+	OBJCTCFG
+	{
+		script = "SOC.cfg";
+	}
+
+	SOC_
+	{
+		script = "SOC.cfg";
+		isprefix = true;
+	}
+
+	LUA_
+	{
+		script = "Lua.cfg";
+		isprefix = true;
+	}
+}
+
+// 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;
+}
+
+// SECTOR TYPES-----------------------------------------------------------------
+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";
+}
+
+
+// GENERALISED SECTOR TYPES-----------------------------------------------------------------
+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";
+	}
+}
+
+// LINEDEF FLAGS
+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 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 = "secret";
+	64 = "blocksound";
+	128 = "dontdraw";
+	256 = "mapped";
+}
+
+// LINEDEF ACTIVATIONS
+linedefactivations
+{
+}
+
+// LINEDEF TYPES
+linedeftypes
+{
+	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 maces";
+			flags256text = "[8] Spawn mace 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] Only bustable by Knuckles";
+			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";
+		}
+	}
+
+	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)";
+		}
+	}
+}
+
+
+// THING FLAGS
+thingflags
+{
+	1 = "[1] Extra";
+	2 = "[2] Flip";
+	4 = "[4] Special";
+	8 = "[8] 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 = "skill1";
+	2 = "skill2";
+	4 = "skill3";
+	8 = "ambush";
+}
+
+// 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;
+
+
+// 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
+thingtypes
+{
+	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";
+		}
+		124
+		{
+			title = "AquaBuzz";
+			sprite = "BBUZA1";
+			width = 20;
+			height = 24;
+		}
+		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";
+		}
+		107
+		{
+			title = "Crawla Commander";
+			sprite = "CCOMA1";
+			width = 16;
+			height = 32;
+		}
+		108
+		{
+			title = "Deton";
+			sprite = "DETNA1";
+			width = 20;
+			height = 32;
+		}
+		109
+		{
+			title = "Skim";
+			sprite = "SKIMA1";
+			width = 16;
+			height = 24;
+		}
+		110
+		{
+			title = "Turret";
+			sprite = "TRETA1";
+			width = 16;
+			height = 32;
+		}
+		111
+		{
+			title = "Pop-up Turret";
+			sprite = "TURRI1";
+			width = 12;
+			height = 64;
+			angletext = "Firing delay";
+		}
+		112
+		{
+			title = "Spincushion";
+			sprite = "SHRPA1";
+			width = 16;
+			height = 24;
+		}
+		113
+		{
+			title = "Jet Jaw";
+			sprite = "JJAWA3A7";
+			width = 12;
+			height = 20;
+		}
+		114
+		{
+			title = "Snailer";
+			sprite = "SNLRA3A7";
+			width = 24;
+			height = 48;
+		}
+		115
+		{
+			title = "Bird Aircraft Strike Hazard";
+			sprite = "VLTRF1";
+			width = 12;
+			height = 24;
+		}
+		116
+		{
+			title = "Pointy";
+			sprite = "PNTYA1";
+			width = 8;
+			height = 16;
+		}
+		117
+		{
+			title = "Robo-Hood";
+			sprite = "ARCHA1";
+			width = 24;
+			height = 32;
+		}
+		118
+		{
+			title = "CastleBot FaceStabber";
+			sprite = "CBFSA1";
+			width = 32;
+			height = 72;
+		}
+		1113
+		{
+			title = "Suspicious FaceStabber 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";
+		}
+		120
+		{
+			title = "Green Snapper";
+			sprite = "GSNPA1";
+			width = 24;
+			height = 24;
+		}
+		121
+		{
+			title = "Minus";
+			sprite = "MNUSA1";
+			width = 24;
+			height = 32;
+		}
+		122
+		{
+			title = "Spring Shell (Green)";
+			sprite = "SSHLA1";
+			width = 24;
+			height = 40;
+		}
+		125
+		{
+			title = "Spring Shell (Yellow)";
+			sprite = "SSHLI1";
+			width = 24;
+			height = 40;
+		}
+		123
+		{
+			title = "Unidus";
+			sprite = "UNIDA1";
+			width = 18;
+			height = 36;
+		}
+		126
+		{
+			title = "Crushstacean";
+			sprite = "CRABA0";
+			width = 24;
+			height = 32;
+			flags8text = "[8] Move left from spawn";
+		}
+		127
+		{
+			title = "Hive Elemental";
+			sprite = "HIVEA0";
+			width = 32;
+			height = 80;
+			parametertext = "No. bees";
+		}
+		128
+		{
+			title = "Bumble Bore";
+			sprite = "BUMBA1";
+			width = 16;
+			height = 32;
+		}
+		129
+		{
+			title = "Penguinator";
+			sprite = "PENGA1";
+			width = 24;
+			height = 32;
+		}
+		130
+		{
+			title = "Pophat";
+			sprite = "POPHA1";
+			width = 24;
+			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;
+		}
+		134
+		{
+			title = "Canarivore";
+			sprite = "CANAA0";
+			width = 12;
+			height = 80;
+			hangs = 1;
+		}
+		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";
+		}
+	}
+
+	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;
+			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";
+		}
+	}
+
+	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";
+		}
+		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;
+		}
+	}
+
+	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 = 8;
+		height = 16;
+		sprite = "UNKNA0";
+
+		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;
+			flags4text = "[4] Slides when pushed";
+			flags8text = "[8] Not pushable";
+		}
+		1103
+		{
+			title = "CEZ Flower";
+			sprite = "FWR4A0";
+			width = 16;
+			height = 40;
+		}
+		1104
+		{
+			title = "Mace";
+			sprite = "SMCEA0";
+			width = 17;
+			height = 34;
+			flags4text = "[4] No sounds";
+			flags8text = "[8] Double size";
+			angletext = "Tag";
+		}
+		1105
+		{
+			title = "Chain & Maces";
+			sprite = "SMCEA0";
+			width = 17;
+			height = 34;
+			flags4text = "[4] No sounds";
+			flags8text = "[8] Double size";
+			angletext = "Tag";
+		}
+		1106
+		{
+			title = "Chained Spring";
+			sprite = "YSPBA0";
+			width = 17;
+			height = 34;
+			flags4text = "[4] No sounds";
+			flags8text = "[8] Red spring";
+			angletext = "Tag";
+		}
+		1107
+		{
+			title = "Chain";
+			sprite = "BMCHA0";
+			width = 17;
+			height = 34;
+			flags8text = "[8] Double size";
+			angletext = "Tag";
+		}
+		1108
+		{
+			arrow = 1;
+			title = "Chain (Hidden)";
+			sprite = "internal:chain3";
+			width = 17;
+			height = 34;
+			flags8text = "[8] Double size";
+		}
+		1109
+		{
+			title = "Firebar";
+			sprite = "BFBRA0";
+			width = 17;
+			height = 34;
+			flags4text = "[4] No sounds";
+			flags8text = "[8] Double size";
+			angletext = "Tag";
+		}
+		1110
+		{
+			title = "Custom Mace";
+			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 = "FaceStabber 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";
+		}
+		1472
+		{
+			title = "Palm Tree Trunk (Big)";
+			width = 16;
+			height = 160;
+			sprite = "BSZ8C0";
+		}
+		1473
+		{
+			title = "Palm Tree Leaves (Big)";
+			width = 16;
+			height = 160;
+			sprite = "BSZ8D0";
+		}
+		1474
+		{
+			title = "Palm Tree Trunk (Small)";
+			width = 8;
+			height = 80;
+			sprite = "BSZ8E0";
+		}
+		1475
+		{
+			title = "Palm Tree Leaves (Small)";
+			width = 16;
+			height = 80;
+			sprite = "BSZ8F0";
+		}
+	}
+
+	azuretemple
+	{
+		color = 10; // Green
+		title = "Azure Temple";
+
+		1500
+		{
+			arrow = 1;
+			blocking = 2;
+			title = "Trapgoyle";
+			sprite = "GARGA1";
+			width = 16;
+			height = 40;
+			flags4text = "[4] Slides when pushed";
+			flags8text = "[8] Not pushable";
+		}
+		1501
+		{
+			arrow = 1;
+			blocking = 2;
+			title = "Trapgoyle (Up)";
+			sprite = "GARGA1";
+			width = 16;
+			height = 40;
+			flags4text = "[4] Slides when pushed";
+			flags8text = "[8] Not pushable";
+		}
+		1502
+		{
+			arrow = 1;
+			blocking = 2;
+			title = "Trapgoyle (Down)";
+			sprite = "GARGA1";
+			width = 16;
+			height = 40;
+			flags4text = "[4] Slides when pushed";
+			flags8text = "[8] Not pushable";
+		}
+		1503
+		{
+			arrow = 1;
+			blocking = 2;
+			title = "Trapgoyle (Long)";
+			sprite = "GARGA1";
+			width = 16;
+			height = 40;
+			flags4text = "[4] Slides when pushed";
+			flags8text = "[8] Not pushable";
+		}
+		1504
+		{
+			title = "ATZ Target";
+			sprite = "RCRYB0";
+			width = 24;
+			height = 32;
+		}
+	}
+
+	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";
+		}
+	}
+}
+
+//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;
+		}
+
+	}
+}
\ No newline at end of file
diff --git a/libs/libopenmpt/SRB2NOTE.md b/libs/libopenmpt/SRB2NOTE.md
index d664ddd7e49930e69cdf6c81d7981568fb2e3d78..7eac9183bc1fbac89647e64404c04458ae10255a 100644
--- a/libs/libopenmpt/SRB2NOTE.md
+++ b/libs/libopenmpt/SRB2NOTE.md
@@ -1,6 +1,6 @@
 # libopenmpt mingw-w64 binary info
 
-Current built version as of 2019/05/23 is 0.4.4+r11531.pkg
+Current built version as of 2019/09/27 is 0.4.7+r12088.pkg
 
 * mingw binaries (.dll): `bin/[x86 or x86_64]/mingw`
 * mingw import libraries (.dll.a): `lib/[x86 or x86_64]/mingw`
diff --git a/libs/libopenmpt/bin/x86/libopenmpt.dll b/libs/libopenmpt/bin/x86/libopenmpt.dll
index 0fc9e7656d5681b59df4a605b5f39ffe59fd55a9..8ad64fdfd94a9ca0008c3760dd8f57904beb14a6 100644
Binary files a/libs/libopenmpt/bin/x86/libopenmpt.dll and b/libs/libopenmpt/bin/x86/libopenmpt.dll differ
diff --git a/libs/libopenmpt/bin/x86/mingw/libopenmpt.dll b/libs/libopenmpt/bin/x86/mingw/libopenmpt.dll
index 5fa3642566039530a3ddf633d45617ef9d93f9bd..945b475e62878802d824f500b127185a8be6498e 100644
Binary files a/libs/libopenmpt/bin/x86/mingw/libopenmpt.dll and b/libs/libopenmpt/bin/x86/mingw/libopenmpt.dll differ
diff --git a/libs/libopenmpt/bin/x86/openmpt-mpg123.dll b/libs/libopenmpt/bin/x86/openmpt-mpg123.dll
index 79148a40ef3cef8e0f745ff14d1ccc1ac4aab025..b068ddd0c8d7d56bcbac4ea727cdeda8b6a5de03 100644
Binary files a/libs/libopenmpt/bin/x86/openmpt-mpg123.dll and b/libs/libopenmpt/bin/x86/openmpt-mpg123.dll differ
diff --git a/libs/libopenmpt/bin/x86/openmpt-ogg.dll b/libs/libopenmpt/bin/x86/openmpt-ogg.dll
index 6b5a42e8f1fd11353588880cd36c649993eebe9e..a5b4600637793a541e61f866734ec3720fcf664a 100644
Binary files a/libs/libopenmpt/bin/x86/openmpt-ogg.dll and b/libs/libopenmpt/bin/x86/openmpt-ogg.dll differ
diff --git a/libs/libopenmpt/bin/x86/openmpt-vorbis.dll b/libs/libopenmpt/bin/x86/openmpt-vorbis.dll
index 486b30731c234696ad1feb3ca9740eebbd390668..1ebed9b0e2401648f7f85c5adb7f8fca854b0832 100644
Binary files a/libs/libopenmpt/bin/x86/openmpt-vorbis.dll and b/libs/libopenmpt/bin/x86/openmpt-vorbis.dll differ
diff --git a/libs/libopenmpt/bin/x86/openmpt-zlib.dll b/libs/libopenmpt/bin/x86/openmpt-zlib.dll
index b6e028ab4f31b40c620983e73b76b747f9f3249e..41bc22d2f554108782fee07ff564812aa705dca7 100644
Binary files a/libs/libopenmpt/bin/x86/openmpt-zlib.dll and b/libs/libopenmpt/bin/x86/openmpt-zlib.dll differ
diff --git a/libs/libopenmpt/bin/x86_64/libopenmpt.dll b/libs/libopenmpt/bin/x86_64/libopenmpt.dll
index 536492798e9167241fc526d010f6ed25e9d0686e..ffbb4b19a0224601264f85de933893aad9aae860 100644
Binary files a/libs/libopenmpt/bin/x86_64/libopenmpt.dll and b/libs/libopenmpt/bin/x86_64/libopenmpt.dll differ
diff --git a/libs/libopenmpt/bin/x86_64/mingw/libopenmpt.dll b/libs/libopenmpt/bin/x86_64/mingw/libopenmpt.dll
index 3f6bea95f72b0a8ee68a41128f8bb700918d568d..018ae827657b1c1b550d58129a09d495cbcddfd4 100644
Binary files a/libs/libopenmpt/bin/x86_64/mingw/libopenmpt.dll and b/libs/libopenmpt/bin/x86_64/mingw/libopenmpt.dll differ
diff --git a/libs/libopenmpt/bin/x86_64/openmpt-mpg123.dll b/libs/libopenmpt/bin/x86_64/openmpt-mpg123.dll
index f96d446f25c61df1368c4219324e3a2bf6138723..9a0fca8745a180ffe92ea8c05bff042665092bd4 100644
Binary files a/libs/libopenmpt/bin/x86_64/openmpt-mpg123.dll and b/libs/libopenmpt/bin/x86_64/openmpt-mpg123.dll differ
diff --git a/libs/libopenmpt/bin/x86_64/openmpt-ogg.dll b/libs/libopenmpt/bin/x86_64/openmpt-ogg.dll
index 3fd9514147973966faf77c7c2e08fb61c3fa4878..4bc1a336b89cf18fcf45b361bbabc7a13a7120f9 100644
Binary files a/libs/libopenmpt/bin/x86_64/openmpt-ogg.dll and b/libs/libopenmpt/bin/x86_64/openmpt-ogg.dll differ
diff --git a/libs/libopenmpt/bin/x86_64/openmpt-vorbis.dll b/libs/libopenmpt/bin/x86_64/openmpt-vorbis.dll
index 56047c82fbf4ff4eecc148718ed2b9fc1882a9da..ebe8ef9b3c05737e2d8bf626bd8a420a037ea29b 100644
Binary files a/libs/libopenmpt/bin/x86_64/openmpt-vorbis.dll and b/libs/libopenmpt/bin/x86_64/openmpt-vorbis.dll differ
diff --git a/libs/libopenmpt/bin/x86_64/openmpt-zlib.dll b/libs/libopenmpt/bin/x86_64/openmpt-zlib.dll
index 562d8e6a9e89b933d2ea4ef30ae2d7e500e35c97..319b646ff393aa2bbf3137fde1518da2bb9faea4 100644
Binary files a/libs/libopenmpt/bin/x86_64/openmpt-zlib.dll and b/libs/libopenmpt/bin/x86_64/openmpt-zlib.dll differ
diff --git a/libs/libopenmpt/changelog.md b/libs/libopenmpt/changelog.md
index 9847be1197908bc6962277f54d7a68f0b7d95a79..0b727955878745b2b0fdafc28e6eed682f597e12 100644
--- a/libs/libopenmpt/changelog.md
+++ b/libs/libopenmpt/changelog.md
@@ -5,6 +5,44 @@ Changelog {#changelog}
 For fully detailed change log, please see the source repository directly. This
 is just a high-level summary.
 
+### libopenmpt 0.4.7 (2019-09-23)
+
+ *  [**Bug**] Compilation fix for various platforms that do not provide
+    `std::aligned_alloc` in C++17 mode. The problematic dependency has been
+    removed. This should fix build problems on MinGW, OpenBSD, Haiku, and others
+    for good.
+
+ *  J2B: Ignore notes with non-existing instrument (fixes Ending.j2b).
+
+ *  mpg123: Update to v1.25.13 (2019-08-24).
+ *  ogg: Update to v1.3.4. (2019-08-31).
+ *  flac: Update to v1.3.3. (2019-08-04).
+
+### libopenmpt 0.4.6 (2019-08-10)
+
+ *  [**Bug**] Compilation fix for OpenBSD.
+ *  [**Bug**] Compilation fix for NO_PLUGINS being defined.
+
+ *  in_openmpt: Correct documentation. `openmpt-mpg123.dll` must be placed into
+    the Winamp directory.
+
+ *  Detect IT files unpacked with early UNMO3 versions.
+
+ *  mpg123: Update to v1.25.11 (2019-07-18).
+ *  minimp3: Update to commit 977514a6dfc4960d819a103f43b358e58ac6c28f
+    (2019-07-24).
+ *  miniz: Update to v2.1.0 (2019-05-05).
+ *  stb_vorbis: Update to v1.17 (2019-08-09).
+
+### libopenmpt 0.4.5 (2019-05-27)
+
+ *  [**Sec**] Possible crash during playback due out-of-bounds read in XM and
+    MT2 files (r11608).
+
+ *  Breaking out of a sustain loop through Note-Off sometimes didn't continue in
+    the regular sample loop.
+ *  Seeking did not stop notes playing with XM Key Off (Kxx) effect.
+
 ### libopenmpt 0.4.4 (2019-04-07)
 
  *  [**Bug**] Channel VU meters were swapped.
diff --git a/libs/libopenmpt/inc/libopenmpt/libopenmpt_version.h b/libs/libopenmpt/inc/libopenmpt/libopenmpt_version.h
index 5ca7f21d0ff4a776d8011fc72b67d140aa237b9d..4bb90278c6c903d9d62e4dbf752b79846c950307 100644
--- a/libs/libopenmpt/inc/libopenmpt/libopenmpt_version.h
+++ b/libs/libopenmpt/inc/libopenmpt/libopenmpt_version.h
@@ -19,7 +19,7 @@
 /*! \brief libopenmpt minor version number */
 #define OPENMPT_API_VERSION_MINOR 4
 /*! \brief libopenmpt patch version number */
-#define OPENMPT_API_VERSION_PATCH 4
+#define OPENMPT_API_VERSION_PATCH 7
 /*! \brief libopenmpt pre-release tag */
 #define OPENMPT_API_VERSION_PREREL ""
 /*! \brief libopenmpt pre-release flag */
diff --git a/libs/libopenmpt/lib/x86/libopenmpt.lib b/libs/libopenmpt/lib/x86/libopenmpt.lib
index 3f814528acc851cec1e764547570756c24d65225..c81c4c4edc15454f65e9f36738e17591a4ec8d15 100644
Binary files a/libs/libopenmpt/lib/x86/libopenmpt.lib and b/libs/libopenmpt/lib/x86/libopenmpt.lib differ
diff --git a/libs/libopenmpt/lib/x86/mingw/libopenmpt.dll.a b/libs/libopenmpt/lib/x86/mingw/libopenmpt.dll.a
index e3fa0c58fcd082319ea3b6365cb566dd7a3efa24..1d76372535b4a432a259ab2fc3a539b3af803c2d 100644
Binary files a/libs/libopenmpt/lib/x86/mingw/libopenmpt.dll.a and b/libs/libopenmpt/lib/x86/mingw/libopenmpt.dll.a differ
diff --git a/libs/libopenmpt/lib/x86_64/libopenmpt.lib b/libs/libopenmpt/lib/x86_64/libopenmpt.lib
index 75e3849fac966542b457684ca6f55a41237211d3..216d93b45b32cc968decb30aa240839bef2c13d6 100644
Binary files a/libs/libopenmpt/lib/x86_64/libopenmpt.lib and b/libs/libopenmpt/lib/x86_64/libopenmpt.lib differ
diff --git a/libs/libopenmpt/lib/x86_64/mingw/libopenmpt.dll.a b/libs/libopenmpt/lib/x86_64/mingw/libopenmpt.dll.a
index 72940372211829f26b413075496f7e201d5fb357..c6eda119fecb39b7f19c5c43e2c43fbeb88a0716 100644
Binary files a/libs/libopenmpt/lib/x86_64/mingw/libopenmpt.dll.a and b/libs/libopenmpt/lib/x86_64/mingw/libopenmpt.dll.a differ
diff --git a/src/b_bot.c b/src/b_bot.c
index 17211b3532d2ace7448fd3a7f1cafac82a1bef9e..651aeb03d6f1911be09114118ff034b54367d8c2 100644
--- a/src/b_bot.c
+++ b/src/b_bot.c
@@ -140,6 +140,9 @@ void B_BuildTiccmd(player_t *player, ticcmd_t *cmd)
 
 void B_KeysToTiccmd(mobj_t *mo, ticcmd_t *cmd, boolean forward, boolean backward, boolean left, boolean right, boolean strafeleft, boolean straferight, boolean jump, boolean spin)
 {
+	// don't try to do stuff if your sonic is in a minecart or something
+	if (players[consoleplayer].powers[pw_carry])
+		return;
 	// Turn the virtual keypresses into ticcmd_t.
 	if (twodlevel || mo->flags2 & MF2_TWOD) {
 		if (players[consoleplayer].climbing
@@ -218,7 +221,12 @@ boolean B_CheckRespawn(player_t *player)
 		return false;
 
 	// Low ceiling, do not want!
-	if (sonic->ceilingz - sonic->z < 2*sonic->height)
+	if (sonic->eflags & MFE_VERTICALFLIP)
+	{
+		if (sonic->z - sonic->floorz < (sonic->player->exiting ? 5 : 2)*sonic->height)
+			return false;
+	}
+	else if (sonic->ceilingz - sonic->z < (sonic->player->exiting ? 6 : 3)*sonic->height)
 		return false;
 
 	// If you're dead, wait a few seconds to respawn.
@@ -252,11 +260,11 @@ void B_RespawnBot(INT32 playernum)
 	y = sonic->y;
 	if (sonic->eflags & MFE_VERTICALFLIP) {
 		tails->eflags |= MFE_VERTICALFLIP;
-		z = sonic->z - FixedMul(512*FRACUNIT,sonic->scale);
+		z = sonic->z - (512*sonic->scale);
 		if (z < sonic->floorz)
 			z = sonic->floorz;
 	} else {
-		z = sonic->z + sonic->height + FixedMul(512*FRACUNIT,sonic->scale);
+		z = sonic->z + sonic->height + (512*sonic->scale);
 		if (z > sonic->ceilingz - sonic->height)
 			z = sonic->ceilingz - sonic->height;
 	}
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 476bb1a1ea357b36c56894a36645e474e101ef73..3234bc756c4e9ac5793f61598c889508d16f89e8 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -3841,7 +3841,7 @@ static void HandlePacketFromPlayer(SINT8 node)
 				break;
 
 			// Ignore tics from those not synched
-			if (resynch_inprogress[node])
+			if (resynch_inprogress[node] && nettics[node] == gametic)
 				break;
 
 			// To save bytes, only the low byte of tic numbers are sent
@@ -4699,7 +4699,7 @@ void TryRunTics(tic_t realtics)
 	if (player_joining)
 		return;
 
-	if (neededtic > gametic)
+	if (neededtic > gametic && !resynch_local_inprogress)
 	{
 		if (advancedemo)
 			D_StartTitle();
@@ -4853,8 +4853,13 @@ void NetUpdate(void)
 			for (i = 0; i < MAXNETNODES; ++i)
 				if (resynch_inprogress[i])
 				{
-					SV_SendResynch(i);
-					counts = -666;
+					if (!nodeingame[i] || nettics[i] == gametic)
+					{
+						SV_SendResynch(i);
+						counts = -666;
+					}
+					else
+						counts = 0; // Let the client catch up with the server
 				}
 
 			// Do not make tics while resynching
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index bd57c24810ffd25aaf379da8a51548cac315d6f7..1e69d371eaaaea84c1d38475bdf40ad77bd45cbc 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -363,7 +363,7 @@ consvar_t cv_runscripts = {"runscripts", "Yes", 0, CV_YesNo, NULL, 0, NULL, NULL
 consvar_t cv_pause = {"pausepermission", "Server", CV_NETVAR, pause_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_mute = {"mute", "Off", CV_NETVAR|CV_CALL, CV_OnOff, Mute_OnChange, 0, NULL, NULL, 0, 0, NULL};
 
-consvar_t cv_sleep = {"cpusleep", "-1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL, NULL, 0, 0, NULL};
+consvar_t cv_sleep = {"cpusleep", "1", CV_SAVE, sleeping_cons_t, NULL, -1, NULL, NULL, 0, 0, NULL};
 
 INT16 gametype = GT_COOP;
 boolean splitscreen = false;
@@ -1186,12 +1186,12 @@ static void SendNameAndColor(void)
 	&& !strcmp(cv_skin.string, skins[players[consoleplayer].skin].name))
 		return;
 
+	players[consoleplayer].availabilities = R_GetSkinAvailabilities();
+
 	// We'll handle it later if we're not playing.
 	if (!Playing())
 		return;
 
-	players[consoleplayer].availabilities = R_GetSkinAvailabilities();
-
 	// If you're not in a netgame, merely update the skin, color, and name.
 	if (!netgame)
 	{
@@ -1304,12 +1304,12 @@ static void SendNameAndColor2(void)
 			CV_StealthSet(&cv_playercolor2, cv_playercolor2.defaultvalue);
 	}
 
+	players[secondplaya].availabilities = R_GetSkinAvailabilities();
+
 	// We'll handle it later if we're not playing.
 	if (!Playing())
 		return;
 
-	players[secondplaya].availabilities = R_GetSkinAvailabilities();
-
 	// If you're not in a netgame, merely update the skin, color, and name.
 	if (botingame)
 	{
diff --git a/src/d_player.h b/src/d_player.h
index 69080bd9dc230450241fb0ca668a53c32d54889c..ff8c312039900e0b329226e8470d524020389be8 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -234,7 +234,9 @@ typedef enum
 	CR_ZOOMTUBE,
 	CR_ROPEHANG,
 	CR_MACESPIN,
-	CR_MINECART
+	CR_MINECART,
+	CR_ROLLOUT,
+	CR_PTERABYTE
 } carrytype_t; // pw_carry
 
 // Player powers. (don't edit this comment)
diff --git a/src/dehacked.c b/src/dehacked.c
index 8110378e2c2e2f5fe184b308f8ac2920a6fe4b8b..0faee77cc9abe06989f38fbfbe70de2329c1c428 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -2447,6 +2447,14 @@ static actionpointer_t actionpointers[] =
 	{{A_SaloonDoorSpawn},        "A_SALOONDOORSPAWN"},
 	{{A_MinecartSparkThink},     "A_MINECARTSPARKTHINK"},
 	{{A_ModuloToState},          "A_MODULOTOSTATE"},
+	{{A_LavafallRocks},          "A_LAVAFALLROCKS"},
+	{{A_LavafallLava},           "A_LAVAFALLLAVA"},
+	{{A_FallingLavaCheck},       "A_FALLINGLAVACHECK"},
+	{{A_FireShrink},             "A_FIRESHRINK"},
+	{{A_SpawnPterabytes},        "A_SPAWNPTERABYTES"},
+	{{A_PterabyteHover},         "A_PTERABYTEHOVER"},
+	{{A_RolloutSpawn},           "A_ROLLOUTSPAWN"},
+	{{A_RolloutRock},            "A_ROLLOUTROCK"},
 	{{NULL},                     "NONE"},
 
 	// This NULL entry must be the last in the list
@@ -4618,6 +4626,22 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_CANARIVOREGAS_7",
 	"S_CANARIVOREGAS_8",
 
+	// Pyre Fly
+	"S_PYREFLY_FLY",
+	"S_PYREFLY_BURN",
+	"S_PYREFIRE1",
+	"S_PYREFIRE2",
+
+	// Pterabyte
+	"S_PTERABYTESPAWNER",
+	"S_PTERABYTEWAYPOINT",
+	"S_PTERABYTE_FLY1",
+	"S_PTERABYTE_FLY2",
+	"S_PTERABYTE_FLY3",
+	"S_PTERABYTE_FLY4",
+	"S_PTERABYTE_SWOOPDOWN",
+	"S_PTERABYTE_SWOOPUP",
+
 	// Boss Explosion
 	"S_BOSSEXPLODE",
 
@@ -5861,7 +5885,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 
 	// Saloon door
 	"S_SALOONDOOR",
-	"S_SALOONDOORTHINKER",
+	"S_SALOONDOORCENTER",
 
 	// Train cameo
 	"S_TRAINCAMEOSPAWNER_1",
@@ -5894,6 +5918,28 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_FLAMEJETFLAMEB2",
 	"S_FLAMEJETFLAMEB3",
 
+	// Lavafall
+	"S_LAVAFALL_DORMANT",
+	"S_LAVAFALL_TELL",
+	"S_LAVAFALL_SHOOT",
+	"S_LAVAFALL_LAVA1",
+	"S_LAVAFALL_LAVA2",
+	"S_LAVAFALL_LAVA3",
+	"S_LAVAFALLROCK",
+
+	// Rollout Rock
+	"S_ROLLOUTSPAWN",
+	"S_ROLLOUTROCK",
+
+	// RVZ scenery
+	"S_BIGFERNLEAF",
+	"S_BIGFERN1",
+	"S_BIGFERN2",
+	"S_JUNGLEPALM",
+	"S_TORCHFLOWER",
+	"S_WALLVINE_LONG",
+	"S_WALLVINE_SHORT",
+
 	// Trapgoyles
 	"S_TRAPGOYLE",
 	"S_TRAPGOYLE_CHECK",
@@ -5945,6 +5991,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_LAMPPOST1",  // normal
 	"S_LAMPPOST2",  // with snow
 	"S_HANGSTAR",
+	"S_MISTLETOE",
 	// Xmas GFZ bushes
 	"S_XMASBLUEBERRYBUSH",
 	"S_XMASBERRYBUSH",
@@ -5952,6 +5999,16 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	// FHZ
 	"S_FHZICE1",
 	"S_FHZICE2",
+	"S_ROSY_IDLE1",
+	"S_ROSY_IDLE2",
+	"S_ROSY_IDLE3",
+	"S_ROSY_IDLE4",
+	"S_ROSY_JUMP",
+	"S_ROSY_WALK",
+	"S_ROSY_HUG",
+	"S_ROSY_PAIN",
+	"S_ROSY_STND",
+	"S_ROSY_UNHAPPY",
 
 	// Halloween Scenery
 	// Pumpkins
@@ -6623,6 +6680,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_SPLISH8",
 	"S_SPLISH9",
 
+	// Lava splish
+	"S_LAVASPLISH",
+
 	// added water splash
 	"S_SPLASH1",
 	"S_SPLASH2",
@@ -7273,6 +7333,11 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	"MT_UNIBALL", // Unidus Ball
 	"MT_CANARIVORE", // Canarivore
 	"MT_CANARIVORE_GAS", // Canarivore gas
+	"MT_PYREFLY", // Pyre Fly
+	"MT_PYREFLY_FIRE", // Pyre Fly fire
+	"MT_PTERABYTESPAWNER", // Pterabyte spawner
+	"MT_PTERABYTEWAYPOINT", // Pterabyte waypoint
+	"MT_PTERABYTE", // Pterabyte
 
 	// Generic Boss Items
 	"MT_BOSSEXPLODE",
@@ -7601,7 +7666,7 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	"MT_MINECARTSIDEMARK",
 	"MT_MINECARTSPARK",
 	"MT_SALOONDOOR",
-	"MT_SALOONDOORTHINKER",
+	"MT_SALOONDOORCENTER",
 	"MT_TRAINCAMEOSPAWNER",
 	"MT_TRAINSEG",
 	"MT_TRAINDUSTSPAWNER",
@@ -7618,6 +7683,20 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 
 	"MT_FLAMEJETFLAMEB", // Blade's flame
 
+	"MT_LAVAFALL",
+	"MT_LAVAFALL_LAVA",
+	"MT_LAVAFALLROCK",
+
+	"MT_ROLLOUTSPAWN",
+	"MT_ROLLOUTROCK",
+
+	"MT_BIGFERNLEAF",
+	"MT_BIGFERN",
+	"MT_JUNGLEPALM",
+	"MT_TORCHFLOWER",
+	"MT_WALLVINE_LONG",
+	"MT_WALLVINE_SHORT",
+
 	// Dark City Scenery
 
 	// Egg Rock Scenery
@@ -7649,6 +7728,7 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	"MT_LAMPPOST1",  // normal
 	"MT_LAMPPOST2",  // with snow
 	"MT_HANGSTAR",
+	"MT_MISTLETOE",
 	// Xmas GFZ bushes
 	"MT_XMASBLUEBERRYBUSH",
 	"MT_XMASBERRYBUSH",
@@ -7656,6 +7736,8 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	// FHZ
 	"MT_FHZICE1",
 	"MT_FHZICE2",
+	"MT_ROSY",
+	"MT_CDLHRT",
 
 	// Halloween Scenery
 	// Pumpkins
@@ -7784,6 +7866,7 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	"MT_RAIN", // Rain
 	"MT_SNOWFLAKE", // Snowflake
 	"MT_SPLISH", // Water splish!
+	"MT_LAVASPLISH", // Lava splish!
 	"MT_SMOKE",
 	"MT_SMALLBUBBLE", // small bubble
 	"MT_MEDIUMBUBBLE", // medium bubble
@@ -8609,6 +8692,8 @@ struct {
 	{"CR_ROPEHANG",CR_ROPEHANG},
 	{"CR_MACESPIN",CR_MACESPIN},
 	{"CR_MINECART",CR_MINECART},
+	{"CR_ROLLOUT", CR_ROLLOUT},
+	{"CR_PTERABYTE",CR_PTERABYTE},
 
 	// Ring weapons (ringweapons_t)
 	// Useful for A_GiveWeapon
diff --git a/src/f_finale.c b/src/f_finale.c
index ee22ecb2f6f8b3afe399bc0887c6649821ab4b6b..e84d8227974e91d1257ea3469e0a9955a0b8c905 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -637,6 +637,7 @@ static void F_IntroDrawScene(void)
 		}
 		else
 		{
+			menuanimtimer = animtimer; // Reusing this variable for the intro to fix the scrolling sky, better than changing the function around.
 			F_SkyScroll(80*4, 0, "TITLESKY");
 			if (timetonext == 6)
 			{
diff --git a/src/g_input.c b/src/g_input.c
index 45c517e1a634740caf8a25accf5facc93df35227..afefbcc3b7629ea03ad57e58522d9a39f41c219b 100644
--- a/src/g_input.c
+++ b/src/g_input.c
@@ -709,8 +709,8 @@ void G_DefineDefaultControls(void)
 
 	for (i = 1; i < num_gamecontrolschemes; i++) // skip gcs_custom (0)
 	{
-		gamecontroldefault[i][gc_weaponnext ][0] = 'e';
-		gamecontroldefault[i][gc_weaponprev ][0] = 'q';
+		gamecontroldefault[i][gc_weaponnext ][0] = KEY_MOUSEWHEELUP+0;
+		gamecontroldefault[i][gc_weaponprev ][0] = KEY_MOUSEWHEELDOWN+0;
 		gamecontroldefault[i][gc_wepslot1   ][0] = '1';
 		gamecontroldefault[i][gc_wepslot2   ][0] = '2';
 		gamecontroldefault[i][gc_wepslot3   ][0] = '3';
diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h
index e2fa90eb035de94d0b5ad7d81de624ed0fbe4341..e0507bc7083f9f54cebe7b3ab6952fa5a932ee03 100644
--- a/src/hardware/hw_drv.h
+++ b/src/hardware/hw_drv.h
@@ -47,6 +47,7 @@ EXPORT void HWRAPI(SetPalette) (RGBA_t *ppal, RGBA_t *pgamma);
 EXPORT void HWRAPI(FinishUpdate) (INT32 waitvbl);
 EXPORT void HWRAPI(Draw2DLine) (F2DCoord *v1, F2DCoord *v2, RGBA_t Color);
 EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo *pSurf, FOutVector *pOutVerts, FUINT iNumPts, FBITFIELD PolyFlags);
+EXPORT void HWRAPI(RenderSkyDome) (INT32 tex, INT32 texture_width, INT32 texture_height, FTransform transform);
 EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags);
 EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor);
 EXPORT void HWRAPI(SetTexture) (FTextureInfo *TexInfo);
@@ -89,6 +90,7 @@ struct hwdriver_s
 	FinishUpdate        pfnFinishUpdate;
 	Draw2DLine          pfnDraw2DLine;
 	DrawPolygon         pfnDrawPolygon;
+	RenderSkyDome       pfnRenderSkyDome;
 	SetBlend            pfnSetBlend;
 	ClearBuffer         pfnClearBuffer;
 	SetTexture          pfnSetTexture;
diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c
index b613fdae1d641de30d762d0e0e7f1d8dc38d7ce9..f4637ff7f4aee2d3350dc3e74f921ed870916de0 100644
--- a/src/hardware/hw_light.c
+++ b/src/hardware/hw_light.c
@@ -180,6 +180,8 @@ light_t *t_lspr[NUMSPRITES] =
 	&lspr[NOLIGHT],     // SPR_UNID
 	&lspr[NOLIGHT],     // SPR_CANA
 	&lspr[NOLIGHT],     // SPR_CANG
+	&lspr[NOLIGHT],     // SPR_PYRE
+	&lspr[NOLIGHT],     // SPR_PTER
 
 	// Generic Boos Items
 	&lspr[JETLIGHT_L],     // SPR_JETF // Boss jet fumes
@@ -260,6 +262,7 @@ light_t *t_lspr[NUMSPRITES] =
 	&lspr[NOLIGHT],     // SPR_WSPB
 	&lspr[NOLIGHT],     // SPR_STPT
 	&lspr[NOLIGHT],     // SPR_BMNE
+	&lspr[NOLIGHT],     // SPR_PUMI
 
 	// Monitor Boxes
 	&lspr[NOLIGHT],     // SPR_MSTV
@@ -377,6 +380,10 @@ light_t *t_lspr[NUMSPRITES] =
 	// Red Volcano Scenery
 	&lspr[REDBALL_L],   // SPR_FLME
 	&lspr[REDBALL_L],   // SPR_DFLM
+	&lspr[NOLIGHT],     // SPR_LFAL
+	&lspr[NOLIGHT],     // SPR_JPLA
+	&lspr[NOLIGHT],     // SPR_TFLO
+	&lspr[NOLIGHT],     // SPR_WVIN
 
 	// Dark City Scenery
 
@@ -388,7 +395,9 @@ light_t *t_lspr[NUMSPRITES] =
 	&lspr[NOLIGHT],     // SPR_XMS3
 	&lspr[NOLIGHT],     // SPR_XMS4
 	&lspr[NOLIGHT],     // SPR_XMS5
+	&lspr[NOLIGHT],     // SPR_XMS6
 	&lspr[NOLIGHT],     // SPR_FHZI
+	&lspr[NOLIGHT],     // SPR_ROSY
 
 	// Halloween Scenery
 	&lspr[RINGLIGHT_L], // SPR_PUMK
@@ -474,6 +483,7 @@ light_t *t_lspr[NUMSPRITES] =
 	&lspr[NOLIGHT],     // SPR_RAIN
 	&lspr[NOLIGHT],     // SPR_SNO1
 	&lspr[NOLIGHT],     // SPR_SPLH
+	&lspr[NOLIGHT],     // SPR_LSPL
 	&lspr[NOLIGHT],     // SPR_SPLA
 	&lspr[NOLIGHT],     // SPR_SMOK
 	&lspr[NOLIGHT],     // SPR_BUBL
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 4a075d376bf232dfa8c4e452a7cfbb3f7d206ec2..f2658707dba7c5f84ee7c35f3aaaf0cd7415ea33 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -5454,7 +5454,7 @@ static void HWR_AddSprites(sector_t *sec)
 #ifdef HWPRECIP
 	precipmobj_t *precipthing;
 #endif
-	fixed_t approx_dist, limit_dist;
+	fixed_t approx_dist, limit_dist, hoop_limit_dist;
 
 	// BSP is traversed by subsector.
 	// A sector might have been split into several
@@ -5471,7 +5471,9 @@ static void HWR_AddSprites(sector_t *sec)
 
 	// Handle all things in sector.
 	// If a limit exists, handle things a tiny bit different.
-	if ((limit_dist = (fixed_t)((maptol & TOL_NIGHTS) ? cv_drawdist_nights.value : cv_drawdist.value) << FRACBITS))
+	limit_dist = (fixed_t)(cv_drawdist.value) << FRACBITS;
+	hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS;
+	if (limit_dist || hoop_limit_dist)
 	{
 		for (thing = sec->thinglist; thing; thing = thing->snext)
 		{
@@ -5480,8 +5482,16 @@ static void HWR_AddSprites(sector_t *sec)
 
 			approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y);
 
-			if (approx_dist > limit_dist)
-				continue;
+			if (thing->sprite == SPR_HOOP)
+			{
+				if (hoop_limit_dist && approx_dist > hoop_limit_dist)
+					continue;
+			}
+			else
+			{
+				if (limit_dist && approx_dist > limit_dist)
+					continue;
+			}
 
 			HWR_ProjectSprite(thing);
 		}
@@ -5711,6 +5721,13 @@ static void HWR_ProjectSprite(mobj_t *thing)
 			return;
 	}
 
+	if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer)
+	{
+		// bodge support - not nearly as comprehensive as r_things.c, but better than nothing
+		if (thing->tracer->sprite == SPR_NULL || thing->tracer->flags2 & MF2_DONTDRAW)
+			return;
+	}
+
 	// store information in a vissprite
 	vis = HWR_NewVisSprite();
 	vis->x1 = x1;
@@ -5724,7 +5741,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
 	vis->z2 = z2;
 
 	//Hurdler: 25/04/2000: now support colormap in hardware mode
-	if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
+	if ((vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
 	{
 		if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized)
 			vis->colormap = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
@@ -5869,86 +5886,122 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
 // ==========================================================================
 //
 // ==========================================================================
-static void HWR_DrawSkyBackground(void)
+static void HWR_DrawSkyBackground(player_t *player)
 {
-	FOutVector v[4];
-	angle_t angle;
-	float dimensionmultiply;
-	float aspectratio;
-	float angleturn;
+	if (cv_grskydome.value)
+	{
+		FTransform transform;
+		const float fpov = FIXED_TO_FLOAT(cv_grfov.value+player->fovadd);
+		postimg_t *type;
 
-	HWR_GetTexture(texturetranslation[skytexture]);
-	aspectratio = (float)vid.width/(float)vid.height;
+		if (splitscreen && player == &players[secondarydisplayplayer])
+			type = &postimgtype2;
+		else
+			type = &postimgtype;
 
-	//Hurdler: the sky is the only texture who need 4.0f instead of 1.0
-	//         because it's called just after clearing the screen
-	//         and thus, the near clipping plane is set to 3.99
-	// Sryder: Just use the near clipping plane value then
+		memset(&transform, 0x00, sizeof(FTransform));
 
-	//  3--2
-	//  | /|
-	//  |/ |
-	//  0--1
-	v[0].x = v[3].x = -ZCLIP_PLANE-1;
-	v[1].x = v[2].x =  ZCLIP_PLANE+1;
-	v[0].y = v[1].y = -ZCLIP_PLANE-1;
-	v[2].y = v[3].y =  ZCLIP_PLANE+1;
+		//04/01/2000: Hurdler: added for T&L
+		//                     It should replace all other gr_viewxxx when finished
+		transform.anglex = (float)(aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
+		transform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES);
 
-	v[0].z = v[1].z = v[2].z = v[3].z = ZCLIP_PLANE+1;
+		if (*type == postimg_flip)
+			transform.flip = true;
+		else
+			transform.flip = false;
 
-	// X
+		transform.scalex = 1;
+		transform.scaley = (float)vid.width/vid.height;
+		transform.scalez = 1;
+		transform.fovxangle = fpov; // Tails
+		transform.fovyangle = fpov; // Tails
+		transform.splitscreen = splitscreen;
 
-	// NOTE: This doesn't work right with texture widths greater than 1024
-	// software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly
-	// The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture
+		HWR_GetTexture(texturetranslation[skytexture]);
+		HWD.pfnRenderSkyDome(skytexture, textures[skytexture]->width, textures[skytexture]->height, transform);
+	}
+	else
+	{
+		FOutVector v[4];
+		angle_t angle;
+		float dimensionmultiply;
+		float aspectratio;
+		float angleturn;
 
-	angle = (dup_viewangle + gr_xtoviewangle[0]);
+		HWR_GetTexture(texturetranslation[skytexture]);
+		aspectratio = (float)vid.width/(float)vid.height;
 
-	dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f);
+		//Hurdler: the sky is the only texture who need 4.0f instead of 1.0
+		//         because it's called just after clearing the screen
+		//         and thus, the near clipping plane is set to 3.99
+		// Sryder: Just use the near clipping plane value then
 
-	v[0].sow = v[3].sow = (-1.0f * angle) / ((ANGLE_90-1)*dimensionmultiply); // left
-	v[2].sow = v[1].sow = v[0].sow + (1.0f/dimensionmultiply); // right (or left + 1.0f)
-	// use +angle and -1.0f above instead if you wanted old backwards behavior
+		//  3--2
+		//  | /|
+		//  |/ |
+		//  0--1
+		v[0].x = v[3].x = -ZCLIP_PLANE-1;
+		v[1].x = v[2].x =  ZCLIP_PLANE+1;
+		v[0].y = v[1].y = -ZCLIP_PLANE-1;
+		v[2].y = v[3].y =  ZCLIP_PLANE+1;
 
-	// Y
-	angle = aimingangle;
-	dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->height/(128.0f*aspectratio));
+		v[0].z = v[1].z = v[2].z = v[3].z = ZCLIP_PLANE+1;
 
-	if (splitscreen)
-	{
-		dimensionmultiply *= 2;
-		angle *= 2;
-	}
+		// X
 
-	// Middle of the sky should always be at angle 0
-	// need to keep correct aspect ratio with X
-	if (atransform.flip)
-	{
-		// During vertical flip the sky should be flipped and it's y movement should also be flipped obviously
-		v[3].tow = v[2].tow = -(0.5f-(0.5f/dimensionmultiply)); // top
-		v[0].tow = v[1].tow = v[3].tow - (1.0f/dimensionmultiply); // bottom (or top - 1.0f)
-	}
-	else
-	{
-		v[0].tow = v[1].tow = -(0.5f-(0.5f/dimensionmultiply)); // bottom
-		v[3].tow = v[2].tow = v[0].tow - (1.0f/dimensionmultiply); // top (or bottom - 1.0f)
-	}
+		// NOTE: This doesn't work right with texture widths greater than 1024
+		// software doesn't draw any further than 1024 for skies anyway, but this doesn't overlap properly
+		// The only time this will probably be an issue is when a sky wider than 1024 is used as a sky AND a regular wall texture
 
-	angleturn = (((float)ANGLE_45-1.0f)*aspectratio)*dimensionmultiply;
+		angle = (dup_viewangle + gr_xtoviewangle[0]);
 
-	if (angle > ANGLE_180) // Do this because we don't want the sky to suddenly teleport when crossing over 0 to 360 and vice versa
-	{
-		angle = InvAngle(angle);
-		v[3].tow = v[2].tow += ((float) angle / angleturn);
-		v[0].tow = v[1].tow += ((float) angle / angleturn);
-	}
-	else
-	{
-		v[3].tow = v[2].tow -= ((float) angle / angleturn);
-		v[0].tow = v[1].tow -= ((float) angle / angleturn);
-	}
+		dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f);
+
+		v[0].sow = v[3].sow = (-1.0f * angle) / ((ANGLE_90-1)*dimensionmultiply); // left
+		v[2].sow = v[1].sow = v[0].sow + (1.0f/dimensionmultiply); // right (or left + 1.0f)
+		// use +angle and -1.0f above instead if you wanted old backwards behavior
 
-	HWD.pfnDrawPolygon(NULL, v, 4, 0);
+		// Y
+		angle = aimingangle;
+		dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->height/(128.0f*aspectratio));
+
+		if (splitscreen)
+		{
+			dimensionmultiply *= 2;
+			angle *= 2;
+		}
+
+		// Middle of the sky should always be at angle 0
+		// need to keep correct aspect ratio with X
+		if (atransform.flip)
+		{
+			// During vertical flip the sky should be flipped and it's y movement should also be flipped obviously
+			v[3].tow = v[2].tow = -(0.5f-(0.5f/dimensionmultiply)); // top
+			v[0].tow = v[1].tow = v[3].tow - (1.0f/dimensionmultiply); // bottom (or top - 1.0f)
+		}
+		else
+		{
+			v[0].tow = v[1].tow = -(0.5f-(0.5f/dimensionmultiply)); // bottom
+			v[3].tow = v[2].tow = v[0].tow - (1.0f/dimensionmultiply); // top (or bottom - 1.0f)
+		}
+
+		angleturn = (((float)ANGLE_45-1.0f)*aspectratio)*dimensionmultiply;
+
+		if (angle > ANGLE_180) // Do this because we don't want the sky to suddenly teleport when crossing over 0 to 360 and vice versa
+		{
+			angle = InvAngle(angle);
+			v[3].tow = v[2].tow += ((float) angle / angleturn);
+			v[0].tow = v[1].tow += ((float) angle / angleturn);
+		}
+		else
+		{
+			v[3].tow = v[2].tow -= ((float) angle / angleturn);
+			v[0].tow = v[1].tow -= ((float) angle / angleturn);
+		}
+
+		HWD.pfnDrawPolygon(NULL, v, 4, 0);
+	}
 }
 
 
@@ -6100,7 +6153,7 @@ if (0)
 }
 
 	if (drawsky)
-		HWR_DrawSkyBackground();
+		HWR_DrawSkyBackground(player);
 
 	//Hurdler: it doesn't work in splitscreen mode
 	drawsky = splitscreen;
@@ -6317,7 +6370,7 @@ if (0)
 }
 
 	if (!skybox && drawsky) // Don't draw the regular sky if there's a skybox
-		HWR_DrawSkyBackground();
+		HWR_DrawSkyBackground(player);
 
 	//Hurdler: it doesn't work in splitscreen mode
 	drawsky = splitscreen;
diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h
index f8524990f9d6f3096150ae76e505400c5708cb8e..31e97cc130fb9ce740194a704a8525905bdc0369 100644
--- a/src/hardware/hw_main.h
+++ b/src/hardware/hw_main.h
@@ -98,6 +98,7 @@ extern consvar_t cv_voodoocompatibility;
 extern consvar_t cv_grfovchange;
 extern consvar_t cv_grsolvetjoin;
 extern consvar_t cv_grspritebillboarding;
+extern consvar_t cv_grskydome;
 
 extern float gr_viewwidth, gr_viewheight, gr_baseviewwindowy;
 
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index cd1b957f0b36465edd69f0f9ec156ceac938ce40..b847fdbc359c3f5d44d589705c1ce96ecfcdda3e 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -1277,6 +1277,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 
 	// MD2 colormap fix
 	// colormap test
+	if (spr->mobj->subsector)
 	{
 		sector_t *sector = spr->mobj->subsector->sector;
 		UINT8 lightlevel = 255;
@@ -1308,6 +1309,8 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 		else
 			Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false);
 	}
+	else
+		Surf.FlatColor.rgba = 0xFFFFFFFF;
 
 	// Look at HWR_ProjectSprite for more
 	{
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index dfee19857cca3881adbd9dc123fd56b48aef7416..ac989613a3be866ede5596ec0f7df44ab494fa54 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -1427,6 +1427,219 @@ EXPORT void HWRAPI(DrawPolygon) (FSurfaceInfo  *pSurf,
 		Clamp2D(GL_TEXTURE_WRAP_T);
 }
 
+typedef struct vbo_vertex_s
+{
+	float x, y, z;
+	float u, v;
+	unsigned char r, g, b, a;
+} vbo_vertex_t;
+
+typedef struct
+{
+	int mode;
+	int vertexcount;
+	int vertexindex;
+	int use_texture;
+} GLSkyLoopDef;
+
+typedef struct
+{
+	int id;
+	int rows, columns;
+	int loopcount;
+	GLSkyLoopDef *loops;
+	vbo_vertex_t *data;
+} GLSkyVBO;
+
+// The texture offset to be applied to the texture coordinates in SkyVertex().
+static int rows, columns;
+static boolean yflip;
+static int texw, texh;
+static boolean foglayer;
+static float delta = 0.0f;
+
+static int gl_sky_detail = 16;
+
+static INT32 lasttex = -1;
+
+#define MAP_COEFF 128.0f
+
+static void SkyVertex(vbo_vertex_t *vbo, int r, int c)
+{
+	const float radians = (M_PIl / 180.0f);
+	const float scale = 10000.0f;
+	const float maxSideAngle = 60.0f;
+
+	float topAngle = (c / (float)columns * 360.0f);
+	float sideAngle = (maxSideAngle * (rows - r) / rows);
+	float height = sin(sideAngle * radians);
+	float realRadius = scale * cos(sideAngle * radians);
+	float x = realRadius * cos(topAngle * radians);
+	float y = (!yflip) ? scale * height : -scale * height;
+	float z = realRadius * sin(topAngle * radians);
+	float timesRepeat = (4 * (256.0f / texw));
+	if (fpclassify(timesRepeat) == FP_ZERO)
+		timesRepeat = 1.0f;
+
+	if (!foglayer)
+	{
+		vbo->r = 255;
+		vbo->g = 255;
+		vbo->b = 255;
+		vbo->a = (r == 0 ? 0 : 255);
+
+		// And the texture coordinates.
+		vbo->u = (-timesRepeat * c / (float)columns);
+		if (!yflip)	// Flipped Y is for the lower hemisphere.
+			vbo->v = (r / (float)rows) + 0.5f;
+		else
+			vbo->v = 1.0f + ((rows - r) / (float)rows) + 0.5f;
+	}
+
+	if (r != 4)
+	{
+		y += 300.0f;
+	}
+
+	// And finally the vertex.
+	vbo->x = x;
+	vbo->y = y + delta;
+	vbo->z = z;
+}
+
+static GLSkyVBO sky_vbo;
+
+static void gld_BuildSky(int row_count, int col_count)
+{
+	int c, r;
+	vbo_vertex_t *vertex_p;
+	int vertex_count = 2 * row_count * (col_count * 2 + 2) + col_count * 2;
+
+	GLSkyVBO *vbo = &sky_vbo;
+
+	if ((vbo->columns != col_count) || (vbo->rows != row_count))
+	{
+		free(vbo->loops);
+		free(vbo->data);
+		memset(vbo, 0, sizeof(&vbo));
+	}
+
+	if (!vbo->data)
+	{
+		memset(vbo, 0, sizeof(&vbo));
+		vbo->loops = malloc((row_count * 2 + 2) * sizeof(vbo->loops[0]));
+		// create vertex array
+		vbo->data = malloc(vertex_count * sizeof(vbo->data[0]));
+	}
+
+	vbo->columns = col_count;
+	vbo->rows = row_count;
+
+	vertex_p = &vbo->data[0];
+	vbo->loopcount = 0;
+
+	for (yflip = 0; yflip < 2; yflip++)
+	{
+		vbo->loops[vbo->loopcount].mode = GL_TRIANGLE_FAN;
+		vbo->loops[vbo->loopcount].vertexindex = vertex_p - &vbo->data[0];
+		vbo->loops[vbo->loopcount].vertexcount = col_count;
+		vbo->loops[vbo->loopcount].use_texture = false;
+		vbo->loopcount++;
+
+		delta = 0.0f;
+		foglayer = true;
+		for (c = 0; c < col_count; c++)
+		{
+			SkyVertex(vertex_p, 1, c);
+			vertex_p->r = 255;
+			vertex_p->g = 255;
+			vertex_p->b = 255;
+			vertex_p->a = 255;
+			vertex_p++;
+		}
+		foglayer = false;
+
+		delta = (yflip ? 5.0f : -5.0f) / MAP_COEFF;
+
+		for (r = 0; r < row_count; r++)
+		{
+			vbo->loops[vbo->loopcount].mode = GL_TRIANGLE_STRIP;
+			vbo->loops[vbo->loopcount].vertexindex = vertex_p - &vbo->data[0];
+			vbo->loops[vbo->loopcount].vertexcount = 2 * col_count + 2;
+			vbo->loops[vbo->loopcount].use_texture = true;
+			vbo->loopcount++;
+
+			for (c = 0; c <= col_count; c++)
+			{
+				SkyVertex(vertex_p++, r + (yflip ? 1 : 0), (c ? c : 0));
+				SkyVertex(vertex_p++, r + (yflip ? 0 : 1), (c ? c : 0));
+			}
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------
+//
+//
+//
+//-----------------------------------------------------------------------------
+
+static void RenderDome(INT32 skytexture)
+{
+	int i, j;
+	GLSkyVBO *vbo = &sky_vbo;
+
+	pglRotatef(270.0f, 0.0f, 1.0f, 0.0f);
+
+	rows = 4;
+	columns = 4 * gl_sky_detail;
+
+	if (lasttex != skytexture)
+	{
+		lasttex = skytexture;
+		gld_BuildSky(rows, columns);
+	}
+
+	pglScalef(1.0f, (float)texh / 230.0f, 1.0f);
+
+	for (j = 0; j < 2; j++)
+	{
+		for (i = 0; i < vbo->loopcount; i++)
+		{
+			GLSkyLoopDef *loop = &vbo->loops[i];
+
+			if (j == 0 ? loop->use_texture : !loop->use_texture)
+				continue;
+			else
+			{
+				int k;
+				pglBegin(loop->mode);
+				for (k = loop->vertexindex; k < (loop->vertexindex + loop->vertexcount); k++)
+				{
+					vbo_vertex_t *v = &vbo->data[k];
+					if (loop->use_texture)
+						pglTexCoord2f(v->u, v->v);
+					pglColor4f(v->r, v->g, v->b, v->a);
+					pglVertex3f(v->x, v->y, v->z);
+				}
+				pglEnd();
+			}
+		}
+	}
+
+	pglScalef(1.0f, 1.0f, 1.0f);
+	pglColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+}
+
+EXPORT void HWRAPI(RenderSkyDome) (INT32 tex, INT32 texture_width, INT32 texture_height, FTransform transform)
+{
+	SetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated);
+	SetTransform(&transform);
+	texw = texture_width;
+	texh = texture_height;
+	RenderDome(tex);
+	SetBlend(0);
+}
 
 // ==========================================================================
 //
diff --git a/src/info.c b/src/info.c
index 5fb4d3070247e4cce5ead0eb8c90ad4661c0cc4e..dd5338ef0f0fd312124608d2ac18956e728467b5 100644
--- a/src/info.c
+++ b/src/info.c
@@ -68,6 +68,8 @@ char sprnames[NUMSPRITES + 1][5] =
 	"UNID", // Unidus
 	"CANA", // Canarivore
 	"CANG", // Canarivore gas
+	"PYRE", // Pyre Fly
+	"PTER", // Pterabyte
 
 	// Generic Boss Items
 	"JETF", // Boss jet fumes
@@ -149,6 +151,7 @@ char sprnames[NUMSPRITES + 1][5] =
 	"WSPB", // Wall spike base
 	"STPT", // Starpost
 	"BMNE", // Big floating mine
+	"PUMI", // Rollout Rock
 
 	// Monitor Boxes
 	"MSTV", // MiSc TV sprites
@@ -263,7 +266,6 @@ char sprnames[NUMSPRITES + 1][5] =
 	"ADST", // Arid dust
 	"MCRT", // Minecart
 	"MCSP", // Minecart spark
-	"NON2", // Saloon door thinker
 	"SALD", // Saloon door
 	"TRAE", // Train cameo locomotive
 	"TRAI", // Train cameo wagon
@@ -272,6 +274,10 @@ char sprnames[NUMSPRITES + 1][5] =
 	// Red Volcano Scenery
 	"FLME", // Flame jet
 	"DFLM", // Blade's flame
+	"LFAL", // Lavafall
+	"JPLA", // Jungle palm
+	"TFLO", // Torch flower
+	"WVIN", // Wall vines
 
 	// Dark City Scenery
 
@@ -283,7 +289,9 @@ char sprnames[NUMSPRITES + 1][5] =
 	"XMS3", // Snowman
 	"XMS4", // Lamppost
 	"XMS5", // Hanging Star
+	"XMS6", // Mistletoe
 	"FHZI", // FHZ ice
+	"ROSY",
 
 	// Halloween Scenery
 	"PUMK", // Pumpkins
@@ -369,6 +377,7 @@ char sprnames[NUMSPRITES + 1][5] =
 	"RAIN", // Rain
 	"SNO1", // Snowflake
 	"SPLH", // Water Splish
+	"LSPL", // Lava Splish
 	"SPLA", // Water Splash
 	"SMOK",
 	"BUBL", // Bubble
@@ -1184,6 +1193,22 @@ state_t states[NUMSTATES] =
 	{SPR_CANG, 0|FF_TRANS80, 10,        {NULL},            0, 0,       S_CANARIVOREGAS_8}, // S_CANARIVOREGAS_7
 	{SPR_CANG, 0|FF_TRANS90, 10,        {NULL},            0, 0,       S_NULL},            // S_CANARIVOREGAS_8
 
+	// Pyre Fly
+	{SPR_PYRE, FF_ANIMATE, -1, {NULL}, 3, 2, S_NULL}, // S_PYREFLY_FLY
+	{SPR_PYRE, 4|FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 3, 2, S_NULL}, // S_PYREFLY_BURN
+	{SPR_FLAM, FF_FULLBRIGHT, 10, {NULL}, 0, 0, S_PYREFIRE2}, // S_PYREFIRE1
+	{SPR_FLAM, 1|FF_FULLBRIGHT, 10, {A_FireShrink}, 0, 16, S_NULL}, // S_PYREFIRE2
+
+	// Pterabyte
+	{SPR_NULL, 0, -1, {A_SpawnPterabytes}, 0, 0, S_PTERABYTESPAWNER},    // S_PTERABYTESPAWNER
+	{SPR_NULL, 0,  1, {A_PterabyteHover},  0, 0, S_PTERABYTEWAYPOINT},   // S_PTERABYTEWAYPOINT
+	{SPR_PTER, 0,  6, {NULL},              0, 0, S_PTERABYTE_FLY2},      // S_PTERABYTE_FLY1
+	{SPR_PTER, 1,  2, {NULL},              0, 0, S_PTERABYTE_FLY3},      // S_PTERABYTE_FLY2
+	{SPR_PTER, 2,  6, {NULL},              0, 0, S_PTERABYTE_FLY4},      // S_PTERABYTE_FLY3
+	{SPR_PTER, 3,  2, {NULL},              0, 0, S_PTERABYTE_FLY1},      // S_PTERABYTE_FLY4
+	{SPR_PTER, 4,  1, {NULL},              0, 0, S_PTERABYTE_SWOOPDOWN}, // S_PTERABYTE_SWOOPDOWN
+	{SPR_PTER, 0,  1, {NULL},              0, 0, S_PTERABYTE_SWOOPUP},   // S_PTERABYTE_SWOOPUP
+
 	// Boss Explosion
 	{SPR_BOM2, FF_FULLBRIGHT|FF_ANIMATE, (5*7), {NULL}, 6, 5, S_NULL}, // S_BOSSEXPLODE
 
@@ -2462,8 +2487,8 @@ state_t states[NUMSTATES] =
 	{SPR_MCSP, FF_FULLBRIGHT,                1, {A_MinecartSparkThink}, 0, 0, S_MINECARTSPARK},   // S_MINECARTSPARK
 
 	// Saloon door
-	{SPR_SALD, 0|FF_PAPERSPRITE, -1, {NULL},              0, 0, S_NULL}, // S_SALOONDOOR
-	{SPR_NON2, 0,                -1, {A_SaloonDoorSpawn}, 0, 0, S_NULL}, // S_SALONDOORTHINKER
+	{SPR_SALD, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SALOONDOOR
+	{SPR_NULL, 0, -1, {A_SaloonDoorSpawn}, MT_SALOONDOOR, 48, S_NULL}, // S_SALOONDOORCENTER
 
 	// Train cameo
 	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_TRAINCAMEOSPAWNER_2}, // S_TRAINCAMEOSPAWNER_1
@@ -2498,6 +2523,28 @@ state_t states[NUMSTATES] =
 	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40, 1, {A_MoveRelative}, 0, 7, S_FLAMEJETFLAMEB3}, // S_FLAMEJETFLAMEB2
 	{SPR_DFLM, FF_FULLBRIGHT|FF_TRANS40|FF_ANIMATE, (12*7), {NULL}, 7, 12, S_NULL},  // S_FLAMEJETFLAMEB3
 
+	// Lavafall
+	{SPR_LFAL, 5, 1, {NULL}, 0, 0, S_LAVAFALL_DORMANT}, // S_LAVAFALL_DORMANT
+	{SPR_LFAL, 6|FF_ANIMATE, 4, {A_LavafallRocks}, 1, 2, S_LAVAFALL_TELL}, // S_LAVAFALL_TELL
+	{SPR_LFAL, 9|FF_FULLBRIGHT|FF_ANIMATE, 2, {A_LavafallLava}, 1, 1, S_LAVAFALL_SHOOT}, // S_LAVAFALL_SHOOT
+	{SPR_LFAL, FF_FULLBRIGHT, 1, {A_FallingLavaCheck}, 0, 0, S_LAVAFALL_LAVA2}, // S_LAVAFALL_LAVA1
+	{SPR_LFAL, FF_FULLBRIGHT, 1, {A_FallingLavaCheck}, 0, 0, S_LAVAFALL_LAVA1}, // S_LAVAFALL_LAVA2
+	{SPR_LFAL, 2|FF_FULLBRIGHT|FF_ANIMATE, 9, {NULL}, 2, 3, S_NULL}, // S_LAVAFALL_LAVA3
+	{SPR_LFAL, 11|FF_ANIMATE|FF_RANDOMANIM, 12, {NULL}, 3, 3, S_LAVAFALLROCK}, // S_LAVAFALLROCK
+
+	// Rollout Rock
+	{SPR_NULL, 0, 1, {A_RolloutSpawn}, 256*FRACUNIT, MT_ROLLOUTROCK, S_ROLLOUTSPAWN}, // S_ROLLOUTSPAWN
+	{SPR_PUMI, 0, 1, {A_RolloutRock},    63*FRACUNIT/64,  7*FRACUNIT/10,  S_ROLLOUTROCK}, // S_ROLLOUTROCK
+
+	// RVZ scenery
+	{SPR_JPLA, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BIGFERNLEAF
+	{SPR_JPLA, 1, 1, {NULL}, 0, 0, S_BIGFERN2}, // S_BIGFERN1
+	{SPR_JPLA, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BIGFERN2
+	{SPR_JPLA, 2, -1, {NULL}, 0, 0, S_NULL}, // S_JUNGLEPALM
+	{SPR_TFLO, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_TORCHFLOWER}, // S_TORCHFLOWER
+	{SPR_WVIN, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_WALLVINE_LONG
+	{SPR_WVIN, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_WALLVINE_SHORT
+
 	// Trapgoyles
 	{SPR_GARG, 0, 67, {NULL},       0, 0, S_TRAPGOYLE_CHECK},  // S_TRAPGOYLE
 	{SPR_GARG, 0,  3, {NULL},       0, 0, S_TRAPGOYLE_FIRE1},  // S_TRAPGOYLE_CHECK
@@ -2552,6 +2599,7 @@ state_t states[NUMSTATES] =
 	{SPR_XMS4, 0, -1, {NULL}, 0, 0, S_NULL}, // S_LAMPPOST1
 	{SPR_XMS4, 1, -1, {NULL}, 0, 0, S_NULL}, // S_LAMPPOST2
 	{SPR_XMS5, 0, -1, {NULL}, 0, 0, S_NULL}, // S_HANGSTAR
+	{SPR_XMS6, 0, -1, {NULL}, 0, 0, S_NULL}, // S_MISTLETOE
 	// Xmas GFZ bushes
 	{SPR_BUS3, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBLUEBERRYBUSH
 	{SPR_BUS1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_XMASBERRYBUSH
@@ -2559,6 +2607,16 @@ state_t states[NUMSTATES] =
 	// FHZ
 	{SPR_FHZI, 0, -1, {NULL}, 0, 0, S_NULL}, // S_FHZICE1
 	{SPR_FHZI, 1, -1, {NULL}, 0, 0, S_NULL}, // S_FHZICE2
+	{SPR_ROSY, 16, 8, {NULL}, 0, 0, S_ROSY_IDLE2}, // S_ROSY_IDLE1
+	{SPR_ROSY, 17, 4, {NULL}, 0, 0, S_ROSY_IDLE3}, // S_ROSY_IDLE2
+	{SPR_ROSY, 18, 8, {NULL}, 0, 0, S_ROSY_IDLE4}, // S_ROSY_IDLE3
+	{SPR_ROSY, 17, 4, {NULL}, 0, 0, S_ROSY_IDLE1}, // S_ROSY_IDLE4
+	{SPR_ROSY, 14, -1, {NULL}, 1, 0, S_NULL}, // S_ROSY_JUMP
+	{SPR_ROSY,  5, -1, {NULL}, 7, 0, S_NULL}, // S_ROSY_WALK
+	{SPR_ROSY, 19, -1, {NULL}, 0, 0, S_NULL}, // S_ROSY_HUG
+	{SPR_ROSY, 13, -1, {NULL}, 0, 0, S_NULL}, // S_ROSY_PAIN
+	{SPR_ROSY,  1|FF_ANIMATE, -1, {NULL}, 3, 16, S_NULL}, // S_ROSY_STND
+	{SPR_ROSY, 20|FF_ANIMATE, TICRATE, {NULL}, 3, 4, S_ROSY_WALK}, // S_ROSY_UNHAPPY
 
 	// Halloween Scenery
 	// Pumpkins
@@ -3234,6 +3292,9 @@ state_t states[NUMSTATES] =
 	{SPR_SPLH, FF_TRANS50|7, 2, {NULL}, 0, 0, S_SPLISH9}, // S_SPLISH8
 	{SPR_SPLH, FF_TRANS50|8, 2, {NULL}, 0, 0, S_NULL},    // S_SPLISH9
 
+	// Lava splish
+	{SPR_LSPL, FF_ANIMATE, 16, {NULL}, 7, 2, S_NULL}, // S_LAVASPLISH
+
 	// Water Splash
 	{SPR_SPLA, FF_TRANS50  , 3, {NULL}, 0, 0, S_SPLASH2},    // S_SPLASH1
 	{SPR_SPLA, FF_TRANS70|1, 3, {NULL}, 0, 0, S_SPLASH3},    // S_SPLASH2
@@ -3545,7 +3606,7 @@ state_t states[NUMSTATES] =
 
 	// Puma (Mario fireball)
 	{SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_START2},   // S_PUMA_START1
-	{SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_PlaySound}, sfx_s3k70, 1, S_PUMA_UP1},   // S_PUMA_START2
+	{SPR_PUMA, FF_FULLBRIGHT|2, 1, {A_PlaySound}, sfx_s3k70, 1 + (1<<16), S_PUMA_UP1},   // S_PUMA_START2
 	{SPR_PUMA, FF_FULLBRIGHT  , 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP2},   // S_PUMA_UP1
 	{SPR_PUMA, FF_FULLBRIGHT|1, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP3},   // S_PUMA_UP2
 	{SPR_PUMA, FF_FULLBRIGHT|2, 2, {A_FishJump}, 0, MT_PUMATRAIL, S_PUMA_UP1},   // S_PUMA_UP3
@@ -4780,7 +4841,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		100,            // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_SCENERY|MF_PAIN|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+		MF_SCENERY|MF_PAIN|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
 		S_SNAPPER_LEGRAISE // raisestate
 	},
 
@@ -4807,7 +4868,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		100,            // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_PAIN|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
+		MF_PAIN|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags
 		S_NULL          // raisestate
 	},
 
@@ -5027,6 +5088,141 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
+	{           // MT_PYREFLY
+		136,            // doomednum
+		S_PYREFLY_FLY,  // spawnstate
+		1,              // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		0,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_PYREFLY_BURN, // meleestate
+		S_NULL,         // missilestate
+		S_XPLD_FLICKY,  // deathstate
+		S_NULL,         // xdeathstate
+		sfx_pop,        // deathsound
+		1,              // speed
+		24*FRACUNIT,    // radius
+		34*FRACUNIT,    // height
+		0,              // display offset
+		DMG_FIRE,       // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOGRAVITY|MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_SLIDEME, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_PYREFLY_FIRE
+		-1,             // doomednum
+		S_PYREFIRE1,    // spawnstate
+		1,              // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		0,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		24*FRACUNIT,    // radius
+		34*FRACUNIT,    // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOGRAVITY|MF_NOBLOCKMAP|MF_FIRE|MF_PAIN, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_PTERABYTESPAWNER
+		135,            // doomednum
+		S_PTERABYTESPAWNER, // spawnstate
+		1,              // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		0,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		16*FRACUNIT,    // radius
+		16*FRACUNIT,    // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOGRAVITY|MF_NOCLIPTHING|MF_NOBLOCKMAP|MF_RUNSPAWNFUNC, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_PTERABYTEWAYPOINT
+		-1,             // doomednum
+		S_PTERABYTEWAYPOINT, // spawnstate
+		1,              // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		0,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		4*FRACUNIT,     // speed
+		24*FRACUNIT,    // radius
+		48*FRACUNIT,    // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOGRAVITY|MF_NOCLIPTHING|MF_NOBLOCKMAP|MF_RUNSPAWNFUNC, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_PTERABYTE
+		-1,             // doomednum
+		S_PTERABYTE_FLY1, // spawnstate
+		1,              // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		0,              // reactiontime
+		sfx_pscree,     // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_XPLD_FLICKY,  // deathstate
+		S_NULL,         // xdeathstate
+		sfx_pop,        // deathsound
+		4*FRACUNIT,     // speed
+		24*FRACUNIT,    // radius
+		48*FRACUNIT,    // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_SPECIAL|MF_SHOOTABLE|MF_ENEMY|MF_NOGRAVITY|MF_SLIDEME, // flags
+		S_NULL          // raisestate
+	},
+
 	{           // MT_BOSSEXPLODE
 		-1,             // doomednum
 		S_BOSSEXPLODE,  // spawnstate
@@ -12199,7 +12395,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		100,            // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_SOLID|MF_SHOOTABLE|MF_ENEMY|MF_PUSHABLE, // flags
+		MF_SOLID|MF_SHOOTABLE|MF_PUSHABLE, // flags
 		S_NULL          // raisestate
 	},
 
@@ -12527,9 +12723,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
-	{          // MT_SALOONDOORTHINKER
+	{          // MT_SALOONDOORCENTER
 		1221,           // doomednum
-		S_SALOONDOORTHINKER,   // spawnstate
+		S_SALOONDOORCENTER, // spawnstate
 		1,              // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
@@ -12550,7 +12746,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		100,            // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_NOGRAVITY|MF_RUNSPAWNFUNC, // flags
+		MF_SOLID|MF_NOGRAVITY|MF_RUNSPAWNFUNC|MF_PAPERCOLLISION|MF_NOCLIPHEIGHT, // flags
 		S_NULL          // raisestate
 	},
 
@@ -12851,6 +13047,303 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
+	{           // MT_LAVAFALL
+		1304,           // doomednum
+		S_LAVAFALL_DORMANT, // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_lvfal1,     // seesound
+		8,              // reactiontime
+		sfx_s3kd5l,     // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		30*FRACUNIT,    // radius
+		32*FRACUNIT,    // height
+		1,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOGRAVITY|MF_SPAWNCEILING, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_LAVAFALL_LAVA
+		-1,             // doomednum
+		S_LAVAFALL_LAVA1, // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_LAVAFALL_LAVA3, // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		30*FRACUNIT,    // radius
+		48*FRACUNIT,    // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_SPECIAL|MF_PAIN|MF_NOGRAVITY, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_LAVAFALLROCK
+		-1,             // doomednum
+		S_LAVAFALLROCK, // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		8*FRACUNIT,     // radius
+		8*FRACUNIT,     // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOBLOCKMAP,  // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_ROLLOUTSPAWN
+		1305,           // doomednum
+		S_ROLLOUTSPAWN, // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		0,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		8*FRACUNIT,     // radius
+		8*FRACUNIT,     // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_SPAWNCEILING,  // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_ROLLOUTROCK
+		-1,             // doomednum
+		S_ROLLOUTROCK,  // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime (sets number of frames the rock cycles through)
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		12*TICRATE,     // painchance (sets how long an unridden rock should last before disappearing - set to 0 to disable)
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		32*FRACUNIT,    // speed
+		30*FRACUNIT,    // radius
+		60*FRACUNIT,    // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_PUSHABLE|MF_SOLID|MF_SLIDEME,  // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_BIGFERNLEAF
+		-1,             // doomednum
+		S_BIGFERNLEAF,  // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		32*FRACUNIT,    // radius
+		48*FRACUNIT,    // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_SCENERY|MF_NOBLOCKMAP, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_BIGFERN
+		1306,           // doomednum
+		S_BIGFERN1,     // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		32*FRACUNIT,    // radius
+		48*FRACUNIT,    // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_SCENERY|MF_NOBLOCKMAP|MF_RUNSPAWNFUNC, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_JUNGLEPALM
+		1307,           // doomednum
+		S_JUNGLEPALM,   // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		32*FRACUNIT,    // radius
+		48*FRACUNIT,    // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_SCENERY|MF_NOBLOCKMAP, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_TORCHFLOWER
+		1308,           // doomednum
+		S_TORCHFLOWER,  // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		14*FRACUNIT,    // radius
+		110*FRACUNIT,   // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_SCENERY|MF_NOBLOCKMAP, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_WALLVINE_LONG
+		1309,           // doomednum
+		S_WALLVINE_LONG, // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		1*FRACUNIT,    // radius
+		288*FRACUNIT,   // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_WALLVINE_SHORT
+		1310,           // doomednum
+		S_WALLVINE_SHORT, // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		1*FRACUNIT,    // radius
+		288*FRACUNIT,   // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_SCENERY|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP, // flags
+		S_NULL          // raisestate
+	},
+
 	{           // MT_TRAPGOYLE
 		1500,           // doomednum
 		S_TRAPGOYLE,    // spawnstate
@@ -13445,6 +13938,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
+	{           // MT_MISTLETOE
+		2105,           // doomednum
+		S_MISTLETOE,    // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		52*FRACUNIT,    // radius
+		106*FRACUNIT,   // height
+		0,              // display offset
+		100,            // mass
+		1,              // damage
+		sfx_None,       // activesound
+		MF_NOBLOCKMAP|MF_NOCLIP|MF_SPAWNCEILING|MF_NOGRAVITY|MF_SCENERY, // flags
+		S_NULL          // raisestate
+	},
+
 	{           // MT_XMASBLUEBERRYBUSH
 		1859,           // doomednum
 		S_XMASBLUEBERRYBUSH, // spawnstate
@@ -13580,6 +14100,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
+	{           // MT_ROSY
+		2104,           // doomednum
+		S_ROSY_IDLE1,   // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		16*FRACUNIT,    // radius
+		48*FRACUNIT,    // height
+		0,              // display offset
+		100,            // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_SCENERY|MF_ENEMY|MF_SLIDEME, // flags -- "enemy" may seem weird but it doesn't have any unintended consequences in context because no MF_SHOOTABLE|MF_SPECIAL
+		S_NULL          // raisestate
+	},
+
+	{           // MT_CDLHRT
+		-1,             // doomednum
+		S_LHRT,         // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		4*FRACUNIT,     // speed
+		4*FRACUNIT,     // radius
+		4*FRACUNIT,     // height
+		1,              // display offset
+		4,              // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_SCENERY, // flags
+		S_NULL          // raisestate
+	},
+
 	{           // MT_JACKO1
 		2006,           // doomednum
 		S_JACKO1,       // spawnstate
@@ -16635,6 +17209,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
+	{           // MT_LAVASPLISH
+		-1,             // doomednum
+		S_LAVASPLISH,   // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		6*FRACUNIT,     // radius
+		1*FRACUNIT,     // height
+		0,              // display offset
+		100,            // mass
+		1,              // damage
+		sfx_None,       // activesound
+		MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags
+		S_NULL          // raisestate
+	},
+
 	{           // MT_SMOKE
 		-1,             // doomednum
 		S_SMOKE1,       // spawnstate
diff --git a/src/info.h b/src/info.h
index 79a191cccd67bb25f19ee4025b1d9ed9a364313a..0502fd095d4a8af49ef3c83d265f3694f93128bc 100644
--- a/src/info.h
+++ b/src/info.h
@@ -268,6 +268,14 @@ void A_SnapperThinker();
 void A_SaloonDoorSpawn();
 void A_MinecartSparkThink();
 void A_ModuloToState();
+void A_LavafallRocks();
+void A_LavafallLava();
+void A_FallingLavaCheck();
+void A_FireShrink();
+void A_SpawnPterabytes();
+void A_PterabyteHover();
+void A_RolloutSpawn();
+void A_RolloutRock();
 
 // ratio of states to sprites to mobj types is roughly 6 : 1 : 1
 #define NUMMOBJFREESLOTS 512
@@ -316,6 +324,8 @@ typedef enum sprite
 	SPR_UNID, // Unidus
 	SPR_CANA, // Canarivore
 	SPR_CANG, // Canarivore gas
+	SPR_PYRE, // Pyre Fly
+	SPR_PTER, // Pterabyte
 
 	// Generic Boss Items
 	SPR_JETF, // Boss jet fumes
@@ -397,6 +407,7 @@ typedef enum sprite
 	SPR_WSPB, // Wall spike base
 	SPR_STPT, // Starpost
 	SPR_BMNE, // Big floating mine
+	SPR_PUMI, // Rollout Rock
 
 	// Monitor Boxes
 	SPR_MSTV, // MiSc TV sprites
@@ -511,7 +522,6 @@ typedef enum sprite
 	SPR_ADST, // Arid dust
 	SPR_MCRT, // Minecart
 	SPR_MCSP, // Minecart spark
-	SPR_NON2, // Saloon door thinker
 	SPR_SALD, // Saloon door
 	SPR_TRAE, // Train cameo locomotive
 	SPR_TRAI, // Train cameo wagon
@@ -520,6 +530,10 @@ typedef enum sprite
 	// Red Volcano Scenery
 	SPR_FLME, // Flame jet
 	SPR_DFLM, // Blade's flame
+	SPR_LFAL, // Lavafall
+	SPR_JPLA, // Jungle palm
+	SPR_TFLO, // Torch flower
+	SPR_WVIN, // Wall vines
 
 	// Dark City Scenery
 
@@ -531,7 +545,9 @@ typedef enum sprite
 	SPR_XMS3, // Snowman
 	SPR_XMS4, // Lamppost
 	SPR_XMS5, // Hanging Star
+	SPR_XMS6, // Mistletoe
 	SPR_FHZI, // FHZ Ice
+	SPR_ROSY,
 
 	// Halloween Scenery
 	SPR_PUMK, // Pumpkins
@@ -617,6 +633,7 @@ typedef enum sprite
 	SPR_RAIN, // Rain
 	SPR_SNO1, // Snowflake
 	SPR_SPLH, // Water Splish
+	SPR_LSPL, // Lava Splish
 	SPR_SPLA, // Water Splash
 	SPR_SMOK,
 	SPR_BUBL, // Bubble
@@ -1333,6 +1350,22 @@ typedef enum state
 	S_CANARIVOREGAS_7,
 	S_CANARIVOREGAS_8,
 
+	// Pyre Fly
+	S_PYREFLY_FLY,
+	S_PYREFLY_BURN,
+	S_PYREFIRE1,
+	S_PYREFIRE2,
+
+	// Pterabyte
+	S_PTERABYTESPAWNER,
+	S_PTERABYTEWAYPOINT,
+	S_PTERABYTE_FLY1,
+	S_PTERABYTE_FLY2,
+	S_PTERABYTE_FLY3,
+	S_PTERABYTE_FLY4,
+	S_PTERABYTE_SWOOPDOWN,
+	S_PTERABYTE_SWOOPUP,
+
 	// Boss Explosion
 	S_BOSSEXPLODE,
 
@@ -2576,7 +2609,7 @@ typedef enum state
 
 	// Saloon door
 	S_SALOONDOOR,
-	S_SALOONDOORTHINKER,
+	S_SALOONDOORCENTER,
 
 	// Train cameo
 	S_TRAINCAMEOSPAWNER_1,
@@ -2609,6 +2642,28 @@ typedef enum state
 	S_FLAMEJETFLAMEB2,
 	S_FLAMEJETFLAMEB3,
 
+	// Lavafall
+	S_LAVAFALL_DORMANT,
+	S_LAVAFALL_TELL,
+	S_LAVAFALL_SHOOT,
+	S_LAVAFALL_LAVA1,
+	S_LAVAFALL_LAVA2,
+	S_LAVAFALL_LAVA3,
+	S_LAVAFALLROCK,
+
+	// Rollout Rock
+	S_ROLLOUTSPAWN,
+	S_ROLLOUTROCK,
+
+	// RVZ scenery
+	S_BIGFERNLEAF,
+	S_BIGFERN1,
+	S_BIGFERN2,
+	S_JUNGLEPALM,
+	S_TORCHFLOWER,
+	S_WALLVINE_LONG,
+	S_WALLVINE_SHORT,
+
 	// Trapgoyles
 	S_TRAPGOYLE,
 	S_TRAPGOYLE_CHECK,
@@ -2660,6 +2715,7 @@ typedef enum state
 	S_LAMPPOST1,  // normal
 	S_LAMPPOST2,  // with snow
 	S_HANGSTAR,
+	S_MISTLETOE,
 	// Xmas GFZ bushes
 	S_XMASBLUEBERRYBUSH,
 	S_XMASBERRYBUSH,
@@ -2667,6 +2723,16 @@ typedef enum state
 	// FHZ
 	S_FHZICE1,
 	S_FHZICE2,
+	S_ROSY_IDLE1,
+	S_ROSY_IDLE2,
+	S_ROSY_IDLE3,
+	S_ROSY_IDLE4,
+	S_ROSY_JUMP,
+	S_ROSY_WALK,
+	S_ROSY_HUG,
+	S_ROSY_PAIN,
+	S_ROSY_STND,
+	S_ROSY_UNHAPPY,
 
 	// Halloween Scenery
 	// Pumpkins
@@ -3338,6 +3404,9 @@ typedef enum state
 	S_SPLISH8,
 	S_SPLISH9,
 
+	// Lava Splish
+	S_LAVASPLISH,
+
 	// added water splash
 	S_SPLASH1,
 	S_SPLASH2,
@@ -4010,6 +4079,11 @@ typedef enum mobj_type
 	MT_UNIBALL, // Unidus Ball
 	MT_CANARIVORE, // Canarivore
 	MT_CANARIVORE_GAS, // Canarivore gas
+	MT_PYREFLY, // Pyre Fly
+	MT_PYREFLY_FIRE, // Pyre Fly fire
+	MT_PTERABYTESPAWNER, // Pterabyte spawner
+	MT_PTERABYTEWAYPOINT, // Pterabyte waypoint
+	MT_PTERABYTE, // Pterabyte
 
 	// Generic Boss Items
 	MT_BOSSEXPLODE,
@@ -4338,7 +4412,7 @@ typedef enum mobj_type
 	MT_MINECARTSIDEMARK,
 	MT_MINECARTSPARK,
 	MT_SALOONDOOR,
-	MT_SALOONDOORTHINKER,
+	MT_SALOONDOORCENTER,
 	MT_TRAINCAMEOSPAWNER,
 	MT_TRAINSEG,
 	MT_TRAINDUSTSPAWNER,
@@ -4355,6 +4429,20 @@ typedef enum mobj_type
 
 	MT_FLAMEJETFLAMEB, // Blade's flame
 
+	MT_LAVAFALL,
+	MT_LAVAFALL_LAVA,
+	MT_LAVAFALLROCK,
+
+	MT_ROLLOUTSPAWN,
+	MT_ROLLOUTROCK,
+
+	MT_BIGFERNLEAF,
+	MT_BIGFERN,
+	MT_JUNGLEPALM,
+	MT_TORCHFLOWER,
+	MT_WALLVINE_LONG,
+	MT_WALLVINE_SHORT,
+
 	// Dark City Scenery
 
 	// Egg Rock Scenery
@@ -4386,6 +4474,7 @@ typedef enum mobj_type
 	MT_LAMPPOST1,  // normal
 	MT_LAMPPOST2,  // with snow
 	MT_HANGSTAR,
+	MT_MISTLETOE,
 	// Xmas GFZ bushes
 	MT_XMASBLUEBERRYBUSH,
 	MT_XMASBERRYBUSH,
@@ -4393,6 +4482,8 @@ typedef enum mobj_type
 	// FHZ
 	MT_FHZICE1,
 	MT_FHZICE2,
+	MT_ROSY,
+	MT_CDLHRT,
 
 	// Halloween Scenery
 	// Pumpkins
@@ -4521,6 +4612,7 @@ typedef enum mobj_type
 	MT_RAIN, // Rain
 	MT_SNOWFLAKE, // Snowflake
 	MT_SPLISH, // Water splish!
+	MT_LAVASPLISH, // Lava splish!
 	MT_SMOKE,
 	MT_SMALLBUBBLE, // small bubble
 	MT_MEDIUMBUBBLE, // medium bubble
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index a69e8a188d0030a2893ce4e4eac8237130edafc9..8f173e32ede8f26cda15a3fb1a91a048690601ac 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -816,15 +816,12 @@ static int lib_pCheckDeathPitCollide(lua_State *L)
 
 static int lib_pCheckSolidLava(lua_State *L)
 {
-	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
 	ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
 	//HUDSAFE
 	INLEVEL
-	if (!mo)
-		return LUA_ErrInvalid(L, "mobj_t");
 	if (!rover)
 		return LUA_ErrInvalid(L, "ffloor_t");
-	lua_pushboolean(L, P_CheckSolidLava(mo, rover));
+	lua_pushboolean(L, P_CheckSolidLava(rover));
 	return 1;
 }
 
diff --git a/src/m_menu.c b/src/m_menu.c
index 1ab361b80a5aa2ba1039f796af93bf2364d78855..fb276f77d1ae78886455ef89085f7dfd6a6c68da 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -247,6 +247,7 @@ menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef;
 // Single Player
 static void M_StartTutorial(INT32 choice);
 static void M_LoadGame(INT32 choice);
+static void M_HandleTimeAttackLevelSelect(INT32 choice);
 static void M_TimeAttackLevelSelect(INT32 choice);
 static void M_TimeAttack(INT32 choice);
 static void M_NightsAttackLevelSelect(INT32 choice);
@@ -743,7 +744,7 @@ static menuitem_t SP_TimeAttackLevelSelectMenu[] =
 // Single Player Time Attack
 static menuitem_t SP_TimeAttackMenu[] =
 {
-	{IT_STRING|IT_CALL,        NULL, "Level Select...", &M_TimeAttackLevelSelect,   52},
+	{IT_STRING|IT_KEYHANDLER,  NULL, "Level Select...", M_HandleTimeAttackLevelSelect,   52},
 	{IT_STRING|IT_CVAR,        NULL, "Character",       &cv_chooseskin,             62},
 
 	{IT_DISABLED,              NULL, "Guest Option...", &SP_GuestReplayDef, 100},
@@ -1224,7 +1225,7 @@ static menuitem_t OP_VideoOptionsMenu[] =
 	{IT_HEADER, NULL, "Level", NULL, 155},
 	{IT_STRING | IT_CVAR, NULL, "Draw Distance",             &cv_drawdist,        161},
 	{IT_STRING | IT_CVAR, NULL, "Weather Draw Dist.",        &cv_drawdist_precip, 166},
-	{IT_STRING | IT_CVAR, NULL, "NiGHTS mode Draw Dist.",    &cv_drawdist_nights, 171},
+	{IT_STRING | IT_CVAR, NULL, "NiGHTS Hoop Draw Dist.",    &cv_drawdist_nights, 171},
 
 	{IT_HEADER, NULL, "Diagnostic", NULL, 180},
 	{IT_STRING | IT_CVAR, NULL, "Show FPS",                  &cv_ticrate,         186},
@@ -8330,7 +8331,18 @@ void M_DrawTimeAttackMenu(void)
 		else
 			PictureOfLevel = W_CachePatchName("BLANKLVL", PU_CACHE);
 
-		V_DrawSmallScaledPatch(208, 32+lsheadingheight, 0, PictureOfLevel);
+		y = 32+lsheadingheight;
+		V_DrawSmallScaledPatch(208, y, 0, PictureOfLevel);
+
+		if (itemOn == talevel)
+		{
+			/* Draw arrows !! */
+			y = y + 25 - 4;
+			V_DrawCharacter(208 - 10 - (skullAnimCounter/5), y,
+					'\x1C' | V_YELLOWMAP, false);
+			V_DrawCharacter(208 + 80 + 2 + (skullAnimCounter/5), y,
+					'\x1D' | V_YELLOWMAP, false);
+		}
 
 		V_DrawString(104 - 72, 32+lsheadingheight/2, 0, "* LEVEL RECORDS *");
 
@@ -8400,6 +8412,39 @@ void M_DrawTimeAttackMenu(void)
 	}
 }
 
+static void M_HandleTimeAttackLevelSelect(INT32 choice)
+{
+	switch (choice)
+	{
+		case KEY_DOWNARROW:
+			M_NextOpt();
+			break;
+		case KEY_UPARROW:
+			M_PrevOpt();
+			break;
+
+		case KEY_LEFTARROW:
+			CV_AddValue(&cv_nextmap, -1);
+			break;
+		case KEY_RIGHTARROW:
+			CV_AddValue(&cv_nextmap, 1);
+			break;
+
+		case KEY_ENTER:
+			M_TimeAttackLevelSelect(0);
+			break;
+
+		case KEY_ESCAPE:
+			noFurtherInput = true;
+			M_GoBack(0);
+			return;
+
+		default:
+			return;
+	}
+	S_StartSound(NULL, sfx_menu1);
+}
+
 static void M_TimeAttackLevelSelect(INT32 choice)
 {
 	(void)choice;
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 000b5cbfb009b5a9e4beaecc308bb882d1a56f83..314e976069880219708d92f93bcbfb2df1227198 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -298,6 +298,14 @@ void A_SnapperThinker(mobj_t *actor);
 void A_SaloonDoorSpawn(mobj_t *actor);
 void A_MinecartSparkThink(mobj_t *actor);
 void A_ModuloToState(mobj_t *actor);
+void A_LavafallRocks(mobj_t *actor);
+void A_LavafallLava(mobj_t *actor);
+void A_FallingLavaCheck(mobj_t *actor);
+void A_FireShrink(mobj_t *actor);
+void A_SpawnPterabytes(mobj_t *actor);
+void A_PterabyteHover(mobj_t *actor);
+void A_RolloutSpawn(mobj_t *actor);
+void A_RolloutRock(mobj_t *actor);
 
 //for p_enemy.c
 
@@ -5343,20 +5351,22 @@ static mobj_t *minus;
 
 static boolean PIT_MinusCarry(mobj_t *thing)
 {
+	if (minus->tracer)
+		return true;
+
 	if (minus->type == thing->type)
 		return true;
 
-	if (!(thing->flags & MF_SHOOTABLE) || !(thing->flags & MF_ENEMY))
+	if (!(thing->flags & (MF_PUSHABLE|MF_ENEMY)))
 		return true;
 
-	if (P_AproxDistance(minus->x - thing->x, minus->y - thing->y) >= minus->radius * 3)
+	if (P_AproxDistance(minus->x - thing->x, minus->y - thing->y) >= minus->radius*3)
 		return true;
 
 	if (abs(thing->z - minus->z) > minus->height)
 		return true;
 
 	P_SetTarget(&minus->tracer, thing);
-	minus->tracer->flags &= ~MF_PUSHABLE;
 
 	return true;
 }
@@ -5420,6 +5430,9 @@ void A_MinusDigging(mobj_t *actor)
 	A_Chase(actor);
 
 	// Carry over shit, maybe
+	if (P_MobjWasRemoved(actor->tracer) || !actor->tracer->health)
+		P_SetTarget(&actor->tracer, NULL);
+
 	if (!actor->tracer)
 	{
 		fixed_t radius = 3*actor->radius;
@@ -5469,7 +5482,6 @@ void A_MinusPopup(mobj_t *actor)
 	else
 		actor->momz = 10*FRACUNIT;
 
-	actor->flags |= MF_SPECIAL|MF_SHOOTABLE;
 	S_StartSound(actor, sfx_s3k82);
 	for (i = 1; i <= num; i++)
 	{
@@ -5482,6 +5494,7 @@ void A_MinusPopup(mobj_t *actor)
 	if (actor->tracer)
 		P_DamageMobj(actor->tracer, actor, actor, 1, 0);
 
+	actor->flags = (actor->flags & ~MF_NOCLIPTHING)|MF_SPECIAL|MF_SHOOTABLE;
 }
 
 // Function: A_MinusCheck
@@ -8408,8 +8421,8 @@ void A_ChangeAngleAbsolute(mobj_t *actor)
 //
 // var1 = sound # to play
 // var2:
-//		0 = Play sound without an origin
-//		1 = Play sound using calling object as origin
+//		lower 16 bits = If 1, play sound using calling object as origin. If 0, play sound without an origin
+//		upper 16 bits = If 1, do not play sound during preticker.
 //
 void A_PlaySound(mobj_t *actor)
 {
@@ -8420,7 +8433,10 @@ void A_PlaySound(mobj_t *actor)
 		return;
 #endif
 
-	S_StartSound(locvar2 ? actor : NULL, locvar1);
+	if (leveltime < 2 && (locvar2 >> 16))
+		return;
+
+	S_StartSound((locvar2 & 65535) ? actor : NULL, locvar1);
 }
 
 // Function: A_FindTarget
@@ -12197,7 +12213,7 @@ void A_MineExplode(mobj_t *actor)
 #undef dist
 
 		if (actor->watertop != INT32_MAX)
-			P_SpawnMobj(actor->x, actor->y, actor->watertop, MT_SPLISH);
+			P_SpawnMobj(actor->x, actor->y, actor->watertop, (actor->eflags & MFE_TOUCHLAVA) ? MT_LAVASPLISH : MT_SPLISH);
 	}
 }
 
@@ -12237,7 +12253,6 @@ void A_ConnectToGround(mobj_t *actor)
 	mobj_t *work;
 	fixed_t workz;
 	fixed_t workh;
-	SINT8 dir;
 	angle_t ang;
 	INT32 locvar1 = var1;
 	INT32 locvar2 = var2;
@@ -12251,23 +12266,17 @@ void A_ConnectToGround(mobj_t *actor)
 		P_AdjustMobjFloorZ_FFloors(actor, actor->subsector->sector, 2);
 
 	if (actor->flags2 & MF2_OBJECTFLIP)
-	{
-		workz = actor->ceilingz - (actor->z + actor->height);
-		dir = -1;
-	}
+		workz = (actor->z + actor->height) - actor->ceilingz;
 	else
-	{
 		workz = actor->floorz - actor->z;
-		dir = 1;
-	}
 
 	if (locvar2)
 	{
 		workh = FixedMul(mobjinfo[locvar2].height, actor->scale);
 		if (actor->flags2 & MF2_OBJECTFLIP)
-			workz -= workh;
+			workz += workh;
 		work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar2);
-		workz += dir*workh;
+		workz += workh;
 	}
 
 	if (!locvar1)
@@ -12276,21 +12285,18 @@ void A_ConnectToGround(mobj_t *actor)
 	if (!(workh = FixedMul(mobjinfo[locvar1].height, actor->scale)))
 		return;
 
-	if (actor->flags2 & MF2_OBJECTFLIP)
-		workz -= workh;
-
 	ang = actor->angle + ANGLE_45;
-	while (dir*workz < 0)
+	while (workz < 0)
 	{
 		work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar1);
 		if (work)
 			work->angle = ang;
 		ang += ANGLE_90;
-		workz += dir*workh;
+		workz += workh;
 	}
 
 	if (workz != 0)
-		actor->z += workz;
+		actor->z += P_MobjFlip(actor)*workz;
 }
 
 // Function: A_SpawnParticleRelative
@@ -13455,6 +13461,13 @@ void A_TNTExplode(mobj_t *actor)
 	if (LUA_CallAction("A_TNTExplode", actor))
 		return;
 #endif
+
+	if (actor->tracer)
+	{
+		P_SetTarget(&actor->tracer->tracer, NULL);
+		P_SetTarget(&actor->tracer, NULL);
+	}
+
 	P_UnsetThingPosition(actor);
 	if (sector_list)
 	{
@@ -13668,8 +13681,6 @@ void A_KillSegments(mobj_t *actor)
 static void P_SnapperLegPlace(mobj_t *mo)
 {
 	mobj_t *seg = mo->tracer;
-	fixed_t x0 = mo->x;
-	fixed_t y0 = mo->y;
 	angle_t a = mo->angle;
 	angle_t fa = (a >> ANGLETOFINESHIFT) & FINEMASK;
 	fixed_t c = FINECOSINE(fa);
@@ -13684,7 +13695,8 @@ static void P_SnapperLegPlace(mobj_t *mo)
 	fixed_t rad = mo->radius;
 	INT32 necklen = (32*(mo->info->reactiontime - mo->reactiontime))/mo->info->reactiontime; // Not in FU
 
-	P_TeleportMove(seg, mo->x + FixedMul(c, rad) + necklen*c, mo->y + FixedMul(s, rad) + necklen*s, mo->z + mo->height/3);
+	seg->z = mo->z + ((mo->eflags & MFE_VERTICALFLIP) ? (((mo->height<<1)/3) - seg->height) : mo->height/3);
+	P_TryMove(seg, mo->x + FixedMul(c, rad) + necklen*c, mo->y + FixedMul(s, rad) + necklen*s, true);
 	seg->angle = a;
 
 	// Move as many legs as available.
@@ -13704,13 +13716,14 @@ static void P_SnapperLegPlace(mobj_t *mo)
 		{
 			x = c*o2 + s*o1;
 			y = s*o2 - c*o1;
-			P_TryMove(seg, x0 + x, y0 + y, true);
+			seg->z = mo->z + (((mo->eflags & MFE_VERTICALFLIP) ? (mo->height - seg->height) : 0));
+			P_TryMove(seg, mo->x + x, mo->y + y, true);
 			P_SetMobjState(seg, seg->info->raisestate);
 		}
 		else
 			P_SetMobjState(seg, seg->info->spawnstate);
 
-		seg->angle = R_PointToAngle2(x0, y0, seg->x, seg->y);
+		seg->angle = R_PointToAngle2(mo->x, mo->y, seg->x, seg->y);
 
 		seg = seg->tracer;
 	} while (seg);
@@ -13738,14 +13751,14 @@ void A_SnapperSpawn(mobj_t *actor)
 #endif
 
 	// It spawns 1 head.
-	seg = P_SpawnMobj(actor->x, actor->y, actor->z, headtype);
+	seg = P_SpawnMobjFromMobj(actor, 0, 0, 0, headtype);
 	P_SetTarget(&ptr->tracer, seg);
 	ptr = seg;
 
 	// It spawns 4 legs which will be handled in the thinker function.
 	for (i = 1; i <= 4; i++)
 	{
-		seg = P_SpawnMobj(actor->x, actor->y, actor->z, legtype);
+		seg = P_SpawnMobjFromMobj(actor, 0, 0, 0, legtype);
 		P_SetTarget(&ptr->tracer, seg);
 		ptr = seg;
 
@@ -13893,51 +13906,43 @@ void A_SnapperThinker(mobj_t *actor)
 //
 // Description: Spawns a saloon door.
 //
-// var1 = unused
-// var2 = unused
+// var1 = mobjtype for sides
+// var2 = distance sides should be placed apart
 //
 void A_SaloonDoorSpawn(mobj_t *actor)
 {
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
 	angle_t ang = actor->angle;
 	angle_t fa = (ang >> ANGLETOFINESHIFT) & FINEMASK;
-	fixed_t c = FINECOSINE(fa);
-	fixed_t s = FINESINE(fa);
-	INT32 d = 48;
-	fixed_t x = actor->x;
-	fixed_t y = actor->y;
-	fixed_t z = actor->z;
+	fixed_t c = FINECOSINE(fa)*locvar2;
+	fixed_t s = FINESINE(fa)*locvar2;
 	mobj_t *door;
+	mobjflag2_t ambush = (actor->flags & MF2_AMBUSH);
 
 #ifdef HAVE_BLUA
 	if (LUA_CallAction("A_SaloonDoorSpawn", actor))
 		return;
 #endif
 
-	//Front
-	door = P_SpawnMobj(x + c*d, y + s*d, z, MT_SALOONDOOR);
-	door->angle = ang + ANGLE_180;
-
-	// Origin angle
-	door->extravalue1 = AngleFixed(door->angle);
-
-	// Angular speed
-	door->extravalue2 = 0;
+	if (!locvar1)
+		return;
 
-	// Origin door
-	P_SetTarget(&door->tracer, actor);
+	// One door...
+	if (!(door = P_SpawnMobjFromMobj(actor, c, s, 0, locvar1))) return;
+	door->angle = ang + ANGLE_180;
+	door->extravalue1 = AngleFixed(door->angle); // Origin angle
+	door->extravalue2 = 0; // Angular speed
+	P_SetTarget(&door->tracer, actor); // Origin door
+	door->flags2 |= ambush; // Can be opened by normal players?
 
-	//Back
-	door = P_SpawnMobj(x - c*d, y - s*d, z, MT_SALOONDOOR);
+	// ...two door!
+	if (!(door = P_SpawnMobjFromMobj(actor, -c, -s, 0, locvar1))) return;
 	door->angle = ang;
-
-	// Origin angle
-	door->extravalue1 = AngleFixed(door->angle);
-
-	// Angular speed
-	door->extravalue2 = 0;
-
-	// Origin door
-	P_SetTarget(&door->tracer, actor);
+	door->extravalue1 = AngleFixed(door->angle); // Origin angle
+	door->extravalue2 = 0; // Angular speed
+	P_SetTarget(&door->tracer, actor); // Origin door
+	door->flags2 |= ambush; // Can be opened by normal players?
 }
 
 // Function: A_MinecartSparkThink
@@ -13998,3 +14003,290 @@ void A_ModuloToState(mobj_t *actor)
 		P_SetMobjState(actor, (locvar2));
 	modulothing++;
 }
+
+// Function: A_LavafallRocks
+//
+// Description: Spawn random rock particles.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_LavafallRocks(mobj_t *actor)
+{
+	UINT8 i;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_LavafallRocks", actor))
+		return;
+#endif
+
+	// Don't spawn rocks unless a player is relatively close by.
+	for (i = 0; i < MAXPLAYERS; ++i)
+		if (playeringame[i] && players[i].mo
+			&& P_AproxDistance(actor->x - players[i].mo->x, actor->y - players[i].mo->y) < (1600 << FRACBITS))
+			break; // Stop looking.
+
+	if (i < MAXPLAYERS)
+	{
+		angle_t fa = (FixedAngle(P_RandomKey(360) << FRACBITS) >> ANGLETOFINESHIFT) & FINEMASK;
+		fixed_t offset = P_RandomRange(4, 12) << FRACBITS;
+		fixed_t xoffs = FixedMul(FINECOSINE(fa), actor->radius + offset);
+		fixed_t yoffs = FixedMul(FINESINE(fa), actor->radius + offset);
+		P_SpawnMobjFromMobj(actor, xoffs, yoffs, 0, MT_LAVAFALLROCK);
+	}
+}
+
+// Function: A_LavafallLava
+//
+// Description: Spawn lava from lavafall.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_LavafallLava(mobj_t *actor)
+{
+	mobj_t *lavafall;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_LavafallLava", actor))
+		return;
+#endif
+
+	if ((40 - actor->fuse) % (2*(actor->scale >> FRACBITS)))
+		return;
+
+	lavafall = P_SpawnMobjFromMobj(actor, 0, 0, -8*FRACUNIT, MT_LAVAFALL_LAVA);
+	lavafall->momz = -P_MobjFlip(actor)*25*FRACUNIT;
+}
+
+// Function: A_FallingLavaCheck
+//
+// Description: If actor hits the ground or a water surface, enter the death animation.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_FallingLavaCheck(mobj_t *actor)
+{
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FallingLavaCheck", actor))
+		return;
+#endif
+
+	if (actor->eflags & MFE_TOUCHWATER || P_IsObjectOnGround(actor))
+	{
+		actor->flags = MF_NOGRAVITY|MF_NOCLIPTHING;
+		actor->momz = 0;
+		if (actor->eflags & MFE_TOUCHWATER)
+			actor->z = (actor->eflags & MFE_VERTICALFLIP) ? actor->waterbottom : actor->watertop;
+		P_SetMobjState(actor, actor->info->deathstate);
+	}
+}
+
+// Function: A_FireShrink
+//
+// Description: Shrink the actor down to the specified scale at the specified speed.
+//
+// var1 = Scale to shrink to
+// var2 = Shrinking speed
+//
+void A_FireShrink(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FireShrink", actor))
+		return;
+#endif
+
+	actor->destscale = locvar1;
+	actor->scalespeed = FRACUNIT/locvar2;
+}
+
+// Function: A_SpawnPterabytes
+//
+// Description: Spawn Pterabytes around the actor in a circle.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_SpawnPterabytes(mobj_t *actor)
+{
+	mobj_t *waypoint, *ptera;
+	fixed_t c, s;
+	fixed_t rad = 280*FRACUNIT;
+	angle_t ang = 0;
+	angle_t interval, fa;
+	UINT8 amount = 1;
+	UINT8 i;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_SpawnPterabytes", actor))
+		return;
+#endif
+
+	if (actor->spawnpoint)
+		amount = actor->spawnpoint->extrainfo + 1;
+
+	interval = FixedAngle(FRACUNIT*360/amount);
+
+	for (i = 0; i < amount; i++)
+	{
+		fa = (ang >> ANGLETOFINESHIFT) & FINEMASK;
+		c = FINECOSINE(fa);
+		s = FINESINE(fa);
+		waypoint = P_SpawnMobjFromMobj(actor, FixedMul(c, rad), FixedMul(s, rad), 0, MT_PTERABYTEWAYPOINT);
+		waypoint->angle = ang + ANGLE_90;
+		P_SetTarget(&waypoint->tracer, actor);
+		ptera = P_SpawnMobjFromMobj(waypoint, 0, 0, 0, MT_PTERABYTE);
+		ptera->angle = waypoint->angle;
+		P_SetTarget(&ptera->tracer, waypoint);
+		ptera->extravalue1 = 0;
+		ang += interval;
+	}
+}
+
+// Function: A_PterabyteHover
+//
+// Description: Hover in a circular fashion, bobbing up and down slightly.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_PterabyteHover(mobj_t *actor)
+{
+	angle_t ang, fa;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_PterabyteHover", actor))
+		return;
+#endif
+
+	P_InstaThrust(actor, actor->angle, actor->info->speed);
+	actor->angle += ANG1;
+	actor->extravalue1 = (actor->extravalue1 + 3) % 360;
+	ang = actor->extravalue1*ANG1;
+	fa = (ang >> ANGLETOFINESHIFT) & FINEMASK;
+	actor->z += FINESINE(fa);
+}
+// Function: A_RolloutSpawn
+//
+// Description: Spawns a new Rollout Rock when the currently spawned rock is destroyed or moves far enough away.
+//
+// var1 = Distance currently spawned rock should travel before spawning a new one
+// var2 = Object type to spawn
+//
+void A_RolloutSpawn(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_RolloutSpawn", actor))
+		return;
+#endif
+
+	if (!(actor->target)
+		|| P_MobjWasRemoved(actor->target)
+		|| P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y) > locvar1)
+	{
+		actor->target = P_SpawnMobj(actor->x, actor->y, actor->z, locvar2);
+		actor->target->flags2 |= (actor->flags2 & (MF2_AMBUSH | MF2_OBJECTFLIP)) | MF2_SLIDEPUSH;
+		actor->target->eflags |= (actor->eflags & MFE_VERTICALFLIP);
+
+		if (actor->target->flags2 & MF2_AMBUSH)
+		{
+			actor->target->color = SKINCOLOR_SUPERRUST3;
+			actor->target->colorized = true;
+		}
+	}
+}
+
+// Function: A_RolloutRock
+//
+// Description: Thinker for Rollout Rock.
+//
+// var1 = Drag
+// var2 = Vertical bobbing speed factor
+//
+void A_RolloutRock(mobj_t *actor)
+{
+	INT32 locvar1 = var1;
+	INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_RolloutRock", actor))
+		return;
+#endif
+
+	UINT8 maxframes = actor->info->reactiontime; // number of frames the mobj cycles through
+	fixed_t pi = (22*FRACUNIT/7);
+	fixed_t circumference = FixedMul(2 * pi, actor->radius); // used to calculate when to change frame
+	fixed_t speed = P_AproxDistance(actor->momx, actor->momy), topspeed = FixedMul(actor->info->speed, actor->scale);
+	boolean inwater = actor->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER);
+
+	actor->friction = FRACUNIT; // turns out riding on solids sucks, so let's just make it easier on ourselves
+
+	if (actor->threshold)
+		actor->threshold--;
+
+	if (inwater && !(actor->flags2 & MF2_AMBUSH)) // buoyancy in water (or lava)
+	{
+		UINT8 flip = P_MobjFlip(actor);
+		fixed_t prevmomz = actor->momz;
+		actor->momz = FixedMul(actor->momz, locvar2);
+		actor->momz += flip * FixedMul(locvar2, actor->scale);
+		if (flip*prevmomz < 0 && flip*actor->momz >= 0 && !actor->threshold)
+		{
+			if (actor->eflags & MFE_UNDERWATER)
+				S_StartSound(actor, sfx_splash);
+			else if (!actor->threshold)
+				S_StartSound(actor, sfx_splish);
+			actor->threshold = max((topspeed - speed) >> FRACBITS, 8);
+		}
+	}
+
+	if (speed > topspeed) // cap speed
+	{
+		actor->momx = FixedMul(FixedDiv(actor->momx, speed), topspeed);
+		actor->momy = FixedMul(FixedDiv(actor->momy, speed), topspeed);
+	}
+
+	if (P_IsObjectOnGround(actor) || inwater) // apply drag to speed (compensates for lack of friction but also works in liquids)
+	{
+		actor->momx = FixedMul(actor->momx, locvar1);
+		actor->momy = FixedMul(actor->momy, locvar1);
+	}
+
+	speed = P_AproxDistance(actor->momx, actor->momy); // recalculate speed for visual rolling
+
+	if (speed < actor->scale >> 1) // stop moving if speed is insignificant
+	{
+		actor->momx = 0;
+		actor->momy = 0;
+	}
+	else if (speed > actor->scale)
+	{
+		actor->movecount = 1; // rock has moved; fuse should be set so we don't have a trillion rocks lying around
+		actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); // set rock's angle to movement direction
+		actor->movefactor += speed;
+		if (actor->movefactor > circumference / maxframes) // if distance moved is enough to change frame, change it!
+		{
+			actor->reactiontime++;
+			actor->reactiontime %= maxframes;
+			actor->movefactor = 0;
+		}
+	}
+
+	actor->frame = actor->reactiontime % maxframes; // set frame
+
+	if (!(actor->flags & MF_PUSHABLE)) // if being ridden, don't disappear
+		actor->fuse = 0;
+	else if (!actor->fuse && actor->movecount == 1) // otherwise if rock has moved, set its fuse
+		actor->fuse = actor->info->painchance;
+
+	if (actor->fuse && actor->fuse < 2*TICRATE)
+		actor->flags2 ^= MF2_DONTDRAW;
+
+}
diff --git a/src/p_floor.c b/src/p_floor.c
index 7887dc530a6291adb50adb1304baee52197fe440..19b7611b8b9ac59c1c4c5cc5916a038a22debf77 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -1778,6 +1778,7 @@ static mobj_t *SearchMarioNode(msecnode_t *node)
 		case MT_RAIN:
 		case MT_SNOWFLAKE:
 		case MT_SPLISH:
+		case MT_LAVASPLISH:
 		case MT_SMOKE:
 		case MT_SMALLBUBBLE:
 		case MT_MEDIUMBUBBLE:
diff --git a/src/p_inter.c b/src/p_inter.c
index 403f36b53943b411f2bc78782a4378920211db5f..cce9df91bc06615ce26c0528e8bce91e82b3fcac 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -428,7 +428,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 					  || special->state == &states[S_FANG_BOUNCE4]
 					  || special->state == &states[S_FANG_PINCHBOUNCE3]
 					  || special->state == &states[S_FANG_PINCHBOUNCE4])
-					&& P_MobjFlip(special)*((special->z + special->height/2) - (toucher->z - toucher->height/2)) > -(special->height/4))
+					&& P_MobjFlip(special)*((special->z + special->height/2) - (toucher->z - toucher->height/2)) > (special->height/4))
 					{
 						P_DamageMobj(toucher, special, special, 1, 0);
 						P_SetTarget(&special->tracer, toucher);
@@ -450,12 +450,18 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 					}
 				}
 				break;
+			case MT_PYREFLY:
+				if (special->extravalue2 == 2 && P_DamageMobj(player->mo, special, special, 1, DMG_FIRE))
+					return;
 			default:
 				break;
 		}
 
 		if (P_PlayerCanDamage(player, special)) // Do you possess the ability to subdue the object?
 		{
+			if (special->type == MT_PTERABYTE && special->target == player->mo && special->extravalue1 == 1)
+				return; // Can't hurt a Pterabyte if it's trying to pick you up
+
 			if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1))
 			{
 				if (elementalpierce == 2)
@@ -477,7 +483,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				P_TwinSpinRejuvenate(player, player->thokitem);
 		}
 		else
+		{
+			if (special->type == MT_PTERABYTE && special->target == player->mo)
+				return; // Don't hurt the player you're trying to grab
+
 			P_DamageMobj(toucher, special, special, 1, 0);
+		}
 
 		return;
 	}
@@ -1074,7 +1085,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			if (player->exiting)
 				return;
 
-			if (player->bumpertime < TICRATE/4)
+			if (player->bumpertime <= (TICRATE/2)-5)
 			{
 				S_StartSound(toucher, special->info->seesound);
 				if (player->powers[pw_carry] == CR_NIGHTSMODE)
@@ -1765,7 +1776,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			return;
 
 		case MT_MINECARTSPAWNER:
-			if (!special->fuse || player->powers[pw_carry] != CR_MINECART)
+			if (!player->bot && (special->fuse < TICRATE || player->powers[pw_carry] != CR_MINECART))
 			{
 				mobj_t *mcart = P_SpawnMobj(special->x, special->y, special->z, MT_MINECART);
 				P_SetTarget(&mcart->target, toucher);
@@ -1775,7 +1786,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				P_ResetPlayer(player);
 				player->pflags |= PF_JUMPDOWN;
 				player->powers[pw_carry] = CR_MINECART;
-				toucher->player->pflags &= ~PF_APPLYAUTOBRAKE;
+				player->pflags &= ~PF_APPLYAUTOBRAKE;
 				P_SetTarget(&toucher->tracer, mcart);
 				toucher->momx = toucher->momy = toucher->momz = 0;
 
diff --git a/src/p_local.h b/src/p_local.h
index 4a58650272b7c8ba20c69ef3db283872c958fa57..02f497850d23b02d0331501ab80908e358d64916 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -303,7 +303,7 @@ fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, f
 
 boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover);
 boolean P_CheckDeathPitCollide(mobj_t *mo);
-boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover);
+boolean P_CheckSolidLava(ffloor_t *rover);
 void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype);
 
 mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zofs, mobjtype_t type);
diff --git a/src/p_map.c b/src/p_map.c
index 8035d64a576386c2b22475f4be1958eecf62906a..810d85e347d8588b8f3688f1b413d769beae7c69 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -208,7 +208,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 			{
 				angle_t nightsangle = 0;
 
-				if (object->player->bumpertime >= TICRATE/4)
+				if (object->player->bumpertime > (TICRATE/2)-5)
 					return false;
 
 				if ((object->player->pflags & PF_TRANSFERTOCLOSEST) && object->player->axis1 && object->player->axis2)
@@ -490,6 +490,42 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
 	}
 }
 
+static void P_DoPterabyteCarry(player_t *player, mobj_t *ptera)
+{
+	if (player->powers[pw_carry] && players->powers[pw_carry] != CR_ROLLOUT)
+		return;
+	if (ptera->extravalue1 != 1)
+		return; // Not swooping
+	if (ptera->target != player->mo)
+		return; // Not swooping for you!
+
+	if (player->spectator)
+		return;
+
+	if ((player->mo->eflags & MFE_VERTICALFLIP) != (ptera->eflags & MFE_VERTICALFLIP))
+		return; // Both should be in same gravity
+
+	if (ptera->eflags & MFE_VERTICALFLIP)
+	{
+		if (ptera->ceilingz - (ptera->z + ptera->height) < player->mo->height - FixedMul(2*FRACUNIT, player->mo->scale))
+			return;
+	}
+	else if (ptera->z - ptera->floorz < player->mo->height - FixedMul(2*FRACUNIT, player->mo->scale))
+		return; // No room to pick up this guy!
+
+	P_ResetPlayer(player);
+	P_SetTarget(&player->mo->tracer, ptera);
+	player->pflags &= ~PF_APPLYAUTOBRAKE;
+	player->powers[pw_carry] = CR_PTERABYTE;
+	S_StartSound(player->mo, sfx_s3k4a);
+	P_UnsetThingPosition(player->mo);
+	player->mo->x = ptera->x;
+	player->mo->y = ptera->y;
+	P_SetThingPosition(player->mo);
+	ptera->movefactor = 3*TICRATE;
+	ptera->watertop = ptera->waterbottom = ptera->cusval = 0;
+}
+
 static void P_DoTailsCarry(player_t *sonic, player_t *tails)
 {
 	INT32 p;
@@ -604,6 +640,34 @@ static void P_SlapStick(mobj_t *fang, mobj_t *pole)
 	P_SetTarget(&pole->tracer, NULL);
 }
 
+static void P_PlayerBarrelCollide(mobj_t *toucher, mobj_t *barrel)
+{
+	if (toucher->momz < 0)
+	{
+		if (toucher->z + toucher->momz > barrel->z + barrel->height)
+			return;
+	}
+	else
+	{
+		if (toucher->z > barrel->z + barrel->height)
+			return;
+	}
+
+	if (toucher->momz > 0)
+	{
+		if (toucher->z + toucher->height + toucher->momz < barrel->z)
+			return;
+	}
+	else
+	{
+		if (toucher->z + toucher->height < barrel->z)
+			return;
+	}
+
+	if (P_PlayerCanDamage(toucher->player, barrel))
+		P_DamageMobj(barrel, toucher, toucher, 1, 0);
+}
+
 //
 // PIT_CheckThing
 //
@@ -854,6 +918,15 @@ static boolean PIT_CheckThing(mobj_t *thing)
 	}
 #endif
 
+	if (tmthing->type == MT_LAVAFALL_LAVA && (thing->type == MT_RING || thing->type == MT_REDTEAMRING || thing->type == MT_BLUETEAMRING || thing->type == MT_FLINGRING))
+	{
+		//height check
+		if (tmthing->z > thing->z + thing->height || thing->z > tmthing->z + tmthing->height || !(thing->health))
+			return true;
+
+		P_KillMobj(thing, tmthing, tmthing, DMG_FIRE);
+	}
+
 	if (tmthing->type == MT_MINECART)
 	{
 		//height check
@@ -872,12 +945,11 @@ static boolean PIT_CheckThing(mobj_t *thing)
 
 	if (thing->type == MT_SALOONDOOR && tmthing->player)
 	{
-		if (tmthing->player->powers[pw_carry] == CR_MINECART && tmthing->tracer && !P_MobjWasRemoved(tmthing->tracer) && tmthing->tracer->health)
+		mobj_t *ref = (tmthing->player->powers[pw_carry] == CR_MINECART && tmthing->tracer && !P_MobjWasRemoved(tmthing->tracer)) ? tmthing->tracer : tmthing;
+		if ((thing->flags & MF2_AMBUSH) || ref != tmthing)
 		{
-			fixed_t dx = tmthing->tracer->momx;
-			fixed_t dy = tmthing->tracer->momy;
-			fixed_t dm = min(FixedHypot(dx, dy), 16*FRACUNIT);
-			angle_t ang = R_PointToAngle2(0, 0, dx, dy) - thing->angle;
+			fixed_t dm = min(FixedHypot(ref->momx, ref->momy), 16*FRACUNIT);
+			angle_t ang = R_PointToAngle2(0, 0, ref->momx, ref->momy) - thing->angle;
 			fixed_t s = FINESINE((ang >> ANGLETOFINESHIFT) & FINEMASK);
 			S_StartSound(tmthing, thing->info->activesound);
 			thing->extravalue2 += 2*FixedMul(s, dm)/3;
@@ -885,41 +957,73 @@ static boolean PIT_CheckThing(mobj_t *thing)
 		}
 	}
 
-	if (thing->type == MT_TNTBARREL && tmthing->player)
+	if (thing->type == MT_SALOONDOORCENTER && tmthing->player)
+	{
+		if ((thing->flags & MF2_AMBUSH) || (tmthing->player->powers[pw_carry] == CR_MINECART && tmthing->tracer && !P_MobjWasRemoved(tmthing->tracer)))
+			return true;
+	}
+
+	if (thing->type == MT_ROLLOUTROCK && tmthing->player && tmthing->health)
 	{
-		if (tmthing->momz < 0)
+		if (tmthing->player->powers[pw_carry] == CR_ROLLOUT)
 		{
-			if (tmthing->z + tmthing->momz > thing->z + thing->height)
-				return true;
+			return true;
 		}
-		else
+		if ((thing->flags & MF_PUSHABLE) // not carrying a player
+			&& (tmthing->player->powers[pw_carry] == CR_NONE) // player is not already riding something
+			&& ((tmthing->eflags & MFE_VERTICALFLIP) == (thing->eflags & MFE_VERTICALFLIP))
+			&& (P_AproxDistance(thing->x - tmthing->x, thing->y - tmthing->y) < (thing->radius))
+			&& (P_MobjFlip(tmthing)*tmthing->momz <= 0)
+			&& ((!(tmthing->eflags & MFE_VERTICALFLIP) && abs(thing->z + thing->height - tmthing->z) < (thing->height>>2))
+				|| (tmthing->eflags & MFE_VERTICALFLIP && abs(tmthing->z + tmthing->height - thing->z) < (thing->height>>2))))
 		{
-			if (tmthing->z > thing->z + thing->height)
-				return true;
+			thing->flags &= ~MF_PUSHABLE; // prevent riding player from applying pushable movement logic
+			thing->flags2 &= ~MF2_DONTDRAW; // don't leave the rock invisible if it was flashing prior to boarding
+			P_SetTarget(&thing->tracer, tmthing);
+			P_ResetPlayer(tmthing->player);
+			P_SetPlayerMobjState(tmthing, S_PLAY_WALK);
+			tmthing->player->powers[pw_carry] = CR_ROLLOUT;
+			P_SetTarget(&tmthing->tracer, thing);
+			P_SetObjectMomZ(thing, tmthing->momz, true);
+			return true;
 		}
+	}
+	else if (tmthing->type == MT_ROLLOUTROCK)
+	{
+		if (tmthing->z > thing->z + thing->height || thing->z > tmthing->z + tmthing->height || !thing->health)
+			return true;
+		
+		if (thing == tmthing->tracer) // don't collide with rider
+			return true;
 
-		if (tmthing->momz > 0)
+		if (thing->flags & MF_SPRING) // bounce on springs
 		{
-			if (tmthing->z + tmthing->height + tmthing->momz < thing->z)
-				return true;
+			P_DoSpring(thing, tmthing);
+			return true;
 		}
-		else
+		else if ((thing->flags & (MF_MONITOR|MF_SHOOTABLE)) == (MF_MONITOR|MF_SHOOTABLE) && !(tmthing->flags & MF_PUSHABLE)) // pop monitors while carrying a player
 		{
-			if (tmthing->z + tmthing->height < thing->z)
-				return true;
+			P_KillMobj(thing, tmthing, tmthing->tracer, 0);
+			return true;
+		}
+		
+		if (thing->type == tmthing->type // bounce against other rollout rocks
+			&& (tmthing->momx || tmthing->momy || thing->momx || thing->momy))
+		{
+			fixed_t tempmomx = thing->momx, tempmomy = thing->momy;
+			thing->momx = tmthing->momx;
+			thing->momy = tmthing->momy;
+			tmthing->momx = tempmomx;
+			tmthing->momy = tempmomy;
 		}
-
-		if ((tmthing->player->pflags & (PF_SPINNING | PF_GLIDING))
-			|| ((tmthing->player->pflags & PF_JUMPED)
-				&& (!(tmthing->player->pflags & PF_NOJUMPDAMAGE)
-					|| (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
-			|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)
-			|| ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING)
-				&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height / 2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0))
-			|| (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (tmthing->player->pflags & PF_SHIELDABILITY)))
-			P_DamageMobj(thing, tmthing, tmthing, 1, 0);
 	}
 
+	if (thing->type == MT_PTERABYTE && tmthing->player)
+		P_DoPterabyteCarry(tmthing->player, thing);
+
+	if (thing->type == MT_TNTBARREL && tmthing->player)
+		P_PlayerBarrelCollide(tmthing, thing);
+
 	if (thing->type == MT_VULTURE && tmthing->type == MT_VULTURE)
 	{
 		fixed_t dx = thing->x - tmthing->x;
@@ -1560,8 +1664,8 @@ static boolean PIT_CheckThing(mobj_t *thing)
 		}
 	}
 
-	if ((!tmthing->player) && (thing->player))
-		; // no solid thing should ever be able to step up onto a player
+	if ((tmthing->flags & MF_SPRING || tmthing->type == MT_STEAM) && (thing->player))
+		; // springs and gas jets should never be able to step up onto a player
 	// z checking at last
 	// Treat noclip things as non-solid!
 	else if ((thing->flags & (MF_SOLID|MF_NOCLIP)) == MF_SOLID
@@ -1964,7 +2068,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
 				continue;
 			}
 
-			if (thing->player && (P_CheckSolidLava(thing, rover) || P_CanRunOnWater(thing->player, rover)))
+			if (thing->player && (P_CheckSolidLava(rover) || P_CanRunOnWater(thing->player, rover)))
 				;
 			else if (thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE))
 				;
@@ -2629,8 +2733,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
 						thing->eflags |= MFE_JUSTSTEPPEDDOWN;
 					}
 #ifdef ESLOPE
-					// HACK TO FIX DSZ2: apply only if slopes are involved
-					else if (tmceilingslope && tmceilingz < thingtop && thingtop - tmceilingz <= maxstep)
+					else if (tmceilingz < thingtop && thingtop - tmceilingz <= maxstep)
 					{
 						thing->z = (thing->ceilingz = thingtop = tmceilingz) - thing->height;
 						thing->ceilingrover = tmceilingrover;
@@ -2645,8 +2748,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
 					thing->eflags |= MFE_JUSTSTEPPEDDOWN;
 				}
 #ifdef ESLOPE
-				// HACK TO FIX DSZ2: apply only if slopes are involved
-				else if (tmfloorslope && tmfloorz > thing->z && tmfloorz - thing->z <= maxstep)
+				else if (tmfloorz > thing->z && tmfloorz - thing->z <= maxstep)
 				{
 					thing->z = thing->floorz = tmfloorz;
 					thing->floorrover = tmfloorrover;
@@ -3479,6 +3581,64 @@ stairstep:
 		goto retry;
 }
 
+static void P_CheckLavaWall(mobj_t *mo, sector_t *sec)
+{
+	ffloor_t *rover;
+	fixed_t topheight, bottomheight;
+
+	for (rover = sec->ffloors; rover; rover = rover->next)
+	{
+		if (!(rover->flags & FF_EXISTS))
+			continue;
+
+		if (!(rover->flags & FF_SWIMMABLE))
+			continue;
+
+		if (GETSECSPECIAL(rover->master->frontsector->special, 1) != 3)
+			continue;
+
+		if (rover->master->flags & ML_BLOCKMONSTERS)
+			continue;
+
+		topheight =
+#ifdef ESLOPE
+			*rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) :
+#endif
+			*rover->topheight;
+
+		if (mo->eflags & MFE_VERTICALFLIP)
+		{
+			if (topheight < mo->z - mo->height)
+				continue;
+		}
+		else
+		{
+			if (topheight < mo->z)
+				continue;
+		}
+
+		bottomheight =
+#ifdef ESLOPE
+			*rover->b_slope ? P_GetZAt(*rover->b_slope, mo->x, mo->y) :
+#endif
+			*rover->bottomheight;
+
+		if (mo->eflags & MFE_VERTICALFLIP)
+		{
+			if (bottomheight > mo->z)
+				continue;
+		}
+		else
+		{
+			if (bottomheight > mo->z + mo->height)
+				continue;
+		}
+
+		P_DamageMobj(mo, NULL, NULL, 1, DMG_FIRE);
+		return;
+	}
+}
+
 //
 // P_SlideMove
 // The momx / momy move is bad, so try to slide
@@ -3639,6 +3799,12 @@ retry:
 	P_PathTraverse(leadx, traily, leadx + mo->momx, traily + mo->momy,
 		PT_ADDLINES, PTR_SlideTraverse);
 
+	if (bestslideline && mo->player && bestslideline->sidenum[1] != 0xffff)
+	{
+		sector_t *sec = P_PointOnLineSide(mo->x, mo->y, bestslideline) ? bestslideline->frontsector : bestslideline->backsector;
+		P_CheckLavaWall(mo, sec);
+	}
+
 	// Some walls are bouncy even if you're not
 	if (bestslideline && bestslideline->flags & ML_BOUNCY)
 	{
diff --git a/src/p_maputl.c b/src/p_maputl.c
index 45fc82fbfe2b0b97e9ee27b7491d8de0edebd6fc..22998c60e7ac96da14104b4e439a57b1f5a66930 100644
--- a/src/p_maputl.c
+++ b/src/p_maputl.c
@@ -662,7 +662,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 				if (!(rover->flags & FF_EXISTS))
 					continue;
 
-				if (mobj->player && (P_CheckSolidLava(mobj, rover) || P_CanRunOnWater(mobj->player, rover)))
+				if (mobj->player && (P_CheckSolidLava(rover) || P_CanRunOnWater(mobj->player, rover)))
 					;
 				else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
 					|| (rover->flags & FF_BLOCKOTHERS && !mobj->player)))
@@ -708,7 +708,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 				if (!(rover->flags & FF_EXISTS))
 					continue;
 
-				if (mobj->player && (P_CheckSolidLava(mobj, rover) || P_CanRunOnWater(mobj->player, rover)))
+				if (mobj->player && (P_CheckSolidLava(rover) || P_CanRunOnWater(mobj->player, rover)))
 					;
 				else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
 					|| (rover->flags & FF_BLOCKOTHERS && !mobj->player)))
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 5c4609f046907792f771e6fc119fc4772e712b71..7fa51111d357dcf26b0fe4d4b20a1e7e6f0cece7 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -1578,7 +1578,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
 
 	// Goop has slower, reversed gravity
 	if (goopgravity)
-		gravityadd = -gravityadd/5;
+		gravityadd = -((gravityadd/5) + (gravityadd/8));
 
 	gravityadd = FixedMul(gravityadd, mo->scale);
 
@@ -2222,7 +2222,7 @@ void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motype)
 		topheight = P_GetFOFTopZ(mo, sector, rover, mo->x, mo->y, NULL);
 		bottomheight = P_GetFOFBottomZ(mo, sector, rover, mo->x, mo->y, NULL);
 
-		if (mo->player && (P_CheckSolidLava(mo, rover) || P_CanRunOnWater(mo->player, rover))) // only the player should stand on lava or run on water
+		if (mo->player && (P_CheckSolidLava(rover) || P_CanRunOnWater(mo->player, rover))) // only the player should stand on lava or run on water
 			;
 		else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only
 			continue;
@@ -2369,9 +2369,9 @@ boolean P_CheckDeathPitCollide(mobj_t *mo)
 		return false;
 
 	if (((mo->z <= mo->subsector->sector->floorheight
-		&& !(mo->eflags & MFE_VERTICALFLIP) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_FLOOR))
+		&& ((mo->subsector->sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_FLOOR))
 	|| (mo->z + mo->height >= mo->subsector->sector->ceilingheight
-		&& (mo->eflags & MFE_VERTICALFLIP) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_CEILING)))
+		&& ((mo->subsector->sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_CEILING)))
 	&& (GETSECSPECIAL(mo->subsector->sector->special, 1) == 6
 	|| GETSECSPECIAL(mo->subsector->sector->special, 1) == 7))
 		return true;
@@ -2379,43 +2379,11 @@ boolean P_CheckDeathPitCollide(mobj_t *mo)
 	return false;
 }
 
-boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover)
+boolean P_CheckSolidLava(ffloor_t *rover)
 {
-	fixed_t topheight;
-
-	I_Assert(mo != NULL);
-	I_Assert(!P_MobjWasRemoved(mo));
-
-	// not a lava block with solid planes
-	if (!(rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3
-		&& !(rover->master->flags & ML_BLOCKMONSTERS)))
-		return false;
-
-	// is solid from the sides
-	if (rover->master->flags & ML_EFFECT3)
-		return true;
-
-	if (mo->eflags & MFE_VERTICALFLIP)
-	{
-		topheight =
-	#ifdef ESLOPE
-			*rover->b_slope ? P_GetZAt(*rover->b_slope, mo->x, mo->y) :
-	#endif
-			*rover->bottomheight;
-
-		if (mo->z+mo->height-mo->momz < topheight + FixedMul(16*FRACUNIT, mo->scale))
-				return true;
-		return false;
-	}
-
-	topheight =
-	#ifdef ESLOPE
-		*rover->t_slope ? P_GetZAt(*rover->t_slope, mo->x, mo->y) :
-	#endif
-		*rover->topheight;
-
-	if (mo->z-mo->momz > topheight - FixedMul(16*FRACUNIT, mo->scale))
-		return true;
+	if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3
+		&& !(rover->master->flags & ML_BLOCKMONSTERS))
+			return true;
 
 	return false;
 }
@@ -3350,7 +3318,7 @@ void P_MobjCheckWater(mobj_t *mobj)
 	mobj->watertop = mobj->waterbottom = mobj->z - 1000*FRACUNIT;
 
 	// Reset water state.
-	mobj->eflags &= ~(MFE_UNDERWATER|MFE_TOUCHWATER|MFE_GOOWATER);
+	mobj->eflags &= ~(MFE_UNDERWATER|MFE_TOUCHWATER|MFE_GOOWATER|MFE_TOUCHLAVA);
 
 	for (rover = sector->ffloors; rover; rover = rover->next)
 	{
@@ -3391,16 +3359,18 @@ void P_MobjCheckWater(mobj_t *mobj)
 		// Just touching the water?
 		if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - height < bottomheight)
 		 || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + height > topheight))
-		{
 			mobj->eflags |= MFE_TOUCHWATER;
-			if (rover->flags & FF_GOOWATER && !(mobj->flags & MF_NOGRAVITY))
-				mobj->eflags |= MFE_GOOWATER;
-		}
+
 		// Actually in the water?
 		if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - (height>>1) > bottomheight)
 		 || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + (height>>1) < topheight))
-		{
 			mobj->eflags |= MFE_UNDERWATER;
+
+		if (mobj->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER))
+		{
+			if (GETSECSPECIAL(rover->master->frontsector->special, 1) == 3)
+				mobj->eflags |= MFE_TOUCHLAVA;
+
 			if (rover->flags & FF_GOOWATER && !(mobj->flags & MF_NOGRAVITY))
 				mobj->eflags |= MFE_GOOWATER;
 		}
@@ -3464,9 +3434,18 @@ void P_MobjCheckWater(mobj_t *mobj)
 			|| ((mobj->eflags & MFE_VERTICALFLIP) && mobj->ceilingz-mobj->waterbottom <= height>>1))
 			return;
 
-		if (!wasgroundpounding && (mobj->eflags & MFE_GOOWATER || wasingoo)) { // Decide what happens to your momentum when you enter/leave goopy water.
-			if (P_MobjFlip(mobj)*mobj->momz < 0) // You are entering the goo?
-				mobj->momz = FixedMul(mobj->momz, FixedDiv(2*FRACUNIT, 5*FRACUNIT)); // kill momentum significantly, to make the goo feel thick.
+		if (mobj->eflags & MFE_GOOWATER || wasingoo) { // Decide what happens to your momentum when you enter/leave goopy water.
+			if (P_MobjFlip(mobj)*mobj->momz > 0)
+			{
+				mobj->momz -= (mobj->momz/8); // cut momentum a little bit to prevent multiple bobs
+				//CONS_Printf("leaving\n");
+			}
+			else
+			{
+				if (!wasgroundpounding)
+					mobj->momz >>= 1; // kill momentum significantly, to make the goo feel thick.
+				//CONS_Printf("entering\n");
+			}
 		}
 		else if (wasinwater && P_MobjFlip(mobj)*mobj->momz > 0)
 			mobj->momz = FixedMul(mobj->momz, FixedDiv(780*FRACUNIT, 457*FRACUNIT)); // Give the mobj a little out-of-water boost.
@@ -3478,14 +3457,15 @@ void P_MobjCheckWater(mobj_t *mobj)
 			{
 				// Spawn a splash
 				mobj_t *splish;
+				mobjtype_t splishtype = (mobj->eflags & MFE_TOUCHLAVA) ? MT_LAVASPLISH : MT_SPLISH;
 				if (mobj->eflags & MFE_VERTICALFLIP)
 				{
-					splish = P_SpawnMobj(mobj->x, mobj->y, mobj->waterbottom-FixedMul(mobjinfo[MT_SPLISH].height, mobj->scale), MT_SPLISH);
+					splish = P_SpawnMobj(mobj->x, mobj->y, mobj->waterbottom-FixedMul(mobjinfo[splishtype].height, mobj->scale), splishtype);
 					splish->flags2 |= MF2_OBJECTFLIP;
 					splish->eflags |= MFE_VERTICALFLIP;
 				}
 				else
-					splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, MT_SPLISH);
+					splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, splishtype);
 				splish->destscale = mobj->scale;
 				P_SetScale(splish, mobj->scale);
 			}
@@ -3513,14 +3493,15 @@ void P_MobjCheckWater(mobj_t *mobj)
 			{
 				// Spawn a splash
 				mobj_t *splish;
+				mobjtype_t splishtype = (mobj->eflags & MFE_TOUCHLAVA) ? MT_LAVASPLISH : MT_SPLISH;
 				if (mobj->eflags & MFE_VERTICALFLIP)
 				{
-					splish = P_SpawnMobj(mobj->x, mobj->y, mobj->waterbottom-FixedMul(mobjinfo[MT_SPLISH].height, mobj->scale), MT_SPLISH);
+					splish = P_SpawnMobj(mobj->x, mobj->y, mobj->waterbottom-FixedMul(mobjinfo[splishtype].height, mobj->scale), splishtype);
 					splish->flags2 |= MF2_OBJECTFLIP;
 					splish->eflags |= MFE_VERTICALFLIP;
 				}
 				else
-					splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, MT_SPLISH);
+					splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, splishtype);
 				splish->destscale = mobj->scale;
 				P_SetScale(splish, mobj->scale);
 			}
@@ -3536,6 +3517,8 @@ void P_MobjCheckWater(mobj_t *mobj)
 
 			if (mobj->eflags & MFE_GOOWATER || wasingoo)
 				S_StartSound(mobj, sfx_ghit);
+			else if (mobj->eflags & MFE_TOUCHLAVA)
+				S_StartSound(mobj, sfx_splash);
 			else
 				S_StartSound(mobj, sfx_splish); // And make a sound!
 
@@ -4146,6 +4129,45 @@ void P_RainThinker(precipmobj_t *mobj)
 	P_SetPrecipMobjState(mobj, S_SPLASH1);
 }
 
+static void P_KillRingsInLava(mobj_t *mo)
+{
+	msecnode_t *node;
+	I_Assert(mo != NULL);
+	I_Assert(!P_MobjWasRemoved(mo));
+
+	// go through all sectors being touched by the ring
+	for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
+	{
+		if (!node->m_sector)
+			break;
+
+		if (node->m_sector->ffloors)
+		{
+			ffloor_t *rover;
+			fixed_t topheight, bottomheight;
+
+			for (rover = node->m_sector->ffloors; rover; rover = rover->next) // go through all fofs in the sector
+			{
+				if (!(rover->flags & FF_EXISTS)) continue; // fof must be real
+
+				if (!(rover->flags & FF_SWIMMABLE // fof must be water
+					&& GETSECSPECIAL(rover->master->frontsector->special, 1) == 3)) // fof must be lava water
+					continue;
+
+				// find heights of FOF
+				topheight = P_GetFOFTopZ(mo, node->m_sector, rover, mo->x, mo->y, NULL);
+				bottomheight = P_GetFOFBottomZ(mo, node->m_sector, rover, mo->x, mo->y, NULL);
+
+				if (mo->z <= topheight && mo->z + mo->height >= bottomheight) // if ring touches it, KILL IT
+				{
+					P_KillMobj(mo, NULL, NULL, DMG_FIRE);
+					return;
+				}
+			}
+		}
+	}
+}
+
 static void P_RingThinker(mobj_t *mobj)
 {
 	if (mobj->momx || mobj->momy)
@@ -7054,6 +7076,16 @@ void P_HandleMinecartSegments(mobj_t *mobj)
 	P_UpdateMinecartSegments(mobj);
 }
 
+static void P_PyreFlyBurn(mobj_t *mobj, fixed_t hoffs, INT16 vrange, mobjtype_t mobjtype, fixed_t momz)
+{
+	angle_t fa = (FixedAngle(P_RandomKey(360)*FRACUNIT) >> ANGLETOFINESHIFT) & FINEMASK;
+	fixed_t xoffs = FixedMul(FINECOSINE(fa), mobj->radius + hoffs);
+	fixed_t yoffs = FixedMul(FINESINE(fa), mobj->radius + hoffs);
+	fixed_t zoffs = P_RandomRange(-vrange, vrange)*FRACUNIT;
+	mobj_t *particle = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, zoffs, mobjtype);
+	particle->momz = momz;
+}
+
 //
 // P_MobjThinker
 //
@@ -7619,6 +7651,7 @@ void P_MobjThinker(mobj_t *mobj)
 			case MT_ROCKCRUMBLE16:
 			case MT_WOODDEBRIS:
 			case MT_BRICKDEBRIS:
+			case MT_BROKENROBOT:
 				if (mobj->z <= P_FloorzAtPos(mobj->x, mobj->y, mobj->z, mobj->height)
 					&& mobj->state != &states[mobj->info->deathstate])
 				{
@@ -7683,6 +7716,237 @@ void P_MobjThinker(mobj_t *mobj)
 				if (mobj->movedir)
 					mobj->angle += mobj->movedir;
 				break;
+			case MT_ROSY:
+				{
+					UINT8 i;
+					fixed_t pdist = 1700*mobj->scale, work, actualwork;
+					player_t *player = NULL;
+					statenum_t stat = (mobj->state-states);
+					for (i = 0; i < MAXPLAYERS; i++)
+					{
+						if (!playeringame[i])
+							continue;
+						if (!players[i].mo)
+							continue;
+						if (players[i].bot)
+							continue;
+						if (!players[i].mo->health)
+							continue;
+						actualwork = work = FixedHypot(mobj->x-players[i].mo->x, mobj->y-players[i].mo->y);
+						if (player)
+						{
+							if (players[i].skin == 0 || players[i].skin == 3)
+								work = (2*work)/3;
+							if (work >= pdist)
+								continue;
+						}
+						pdist = actualwork;
+						player = &players[i];
+					}
+
+					if (stat == S_ROSY_JUMP || stat == S_ROSY_PAIN)
+					{
+						if (P_IsObjectOnGround(mobj))
+						{
+							mobj->momx = mobj->momy = 0;
+							if (player && mobj->cvmem < (-2*TICRATE))
+								stat = S_ROSY_UNHAPPY;
+							else
+								stat = S_ROSY_WALK;
+							P_SetMobjState(mobj, stat);
+						}
+						else if (P_MobjFlip(mobj)*mobj->momz < 0)
+							mobj->frame = mobj->state->frame+mobj->state->var1;
+					}
+
+					if (!player)
+					{
+						if ((stat < S_ROSY_IDLE1 || stat > S_ROSY_IDLE4) && stat != S_ROSY_JUMP)
+						{
+							mobj->momx = mobj->momy = 0;
+							P_SetMobjState(mobj, S_ROSY_IDLE1);
+						}
+					}
+					else
+					{
+						boolean dojump = false, targonground, love, makeheart = false;
+						if (mobj->target != player->mo)
+							P_SetTarget(&mobj->target, player->mo);
+						targonground = (P_IsObjectOnGround(mobj->target) && (player->panim == PA_IDLE || player->panim == PA_WALK || player->panim == PA_RUN));
+						love = (player->skin == 0 || player->skin == 3);
+
+						switch (stat)
+						{
+							case S_ROSY_IDLE1:
+							case S_ROSY_IDLE2:
+							case S_ROSY_IDLE3:
+							case S_ROSY_IDLE4:
+								dojump = true;
+								break;
+							case S_ROSY_JUMP:
+							case S_ROSY_PAIN:
+								// handled above
+								break;
+							case S_ROSY_WALK:
+								{
+									fixed_t x = mobj->x, y = mobj->y, z = mobj->z;
+									angle_t angletoplayer = R_PointToAngle2(x, y, mobj->target->x, mobj->target->y);
+									boolean allowed = P_TryMove(mobj, mobj->target->x, mobj->target->y, false);
+
+									P_UnsetThingPosition(mobj);
+									mobj->x = x;
+									mobj->y = y;
+									mobj->z = z;
+									P_SetThingPosition(mobj);
+
+									if (allowed)
+									{
+										fixed_t mom, max;
+										P_Thrust(mobj, angletoplayer, (3*FRACUNIT)>>1);
+										mom = FixedHypot(mobj->momx, mobj->momy);
+										max = pdist;
+										if ((--mobj->extravalue1) <= 0)
+										{
+											if (++mobj->frame > mobj->state->frame+mobj->state->var1)
+												mobj->frame = mobj->state->frame;
+											if (mom > 12*mobj->scale)
+												mobj->extravalue1 = 2;
+											else if (mom > 6*mobj->scale)
+												mobj->extravalue1 = 3;
+											else
+												mobj->extravalue1 = 4;
+										}
+										if (max < (mobj->radius + mobj->target->radius))
+										{
+											mobj->momx = mobj->target->player->cmomx;
+											mobj->momy = mobj->target->player->cmomy;
+											if ((mobj->cvmem > TICRATE && !player->exiting) || !targonground)
+												P_SetMobjState(mobj, (stat = S_ROSY_STND));
+											else
+											{
+												mobj->target->momx = mobj->momx;
+												mobj->target->momy = mobj->momy;
+												P_SetMobjState(mobj, (stat = S_ROSY_HUG));
+												S_StartSound(mobj, sfx_cdpcm6);
+												mobj->angle = angletoplayer;
+											}
+										}
+										else
+										{
+											max /= 3;
+											if (max > 30*mobj->scale)
+												max = 30*mobj->scale;
+											if (mom > max && max > mobj->scale)
+											{
+												max = FixedDiv(max, mom);
+												mobj->momx = FixedMul(mobj->momx, max);
+												mobj->momy = FixedMul(mobj->momy, max);
+											}
+											if (abs(mobj->momx) > mobj->scale || abs(mobj->momy) > mobj->scale)
+												mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy);
+										}
+									}
+									else
+										dojump = true;
+								}
+								break;
+							case S_ROSY_HUG:
+								if (targonground)
+								{
+									player->pflags |= PF_STASIS;
+									if (mobj->cvmem < 5*TICRATE)
+										mobj->cvmem++;
+									if (love && !(leveltime & 7))
+										makeheart = true;
+								}
+								else
+								{
+									if (mobj->cvmem < (love ? 5*TICRATE : 0))
+									{
+										P_SetMobjState(mobj, (stat = S_ROSY_PAIN));
+										S_StartSound(mobj, sfx_cdpcm7);
+									}
+									else
+										P_SetMobjState(mobj, (stat = S_ROSY_JUMP));
+									var1 = var2 = 0;
+									A_DoNPCPain(mobj);
+									mobj->cvmem -= TICRATE;
+								}
+								break;
+							case S_ROSY_STND:
+								if ((pdist > (mobj->radius + mobj->target->radius + 3*(mobj->scale + mobj->target->scale))))
+									P_SetMobjState(mobj, (stat = S_ROSY_WALK));
+								else if (!targonground)
+									;
+								else
+								{
+									if (love && !(leveltime & 15))
+										makeheart = true;
+									if (player->exiting || --mobj->cvmem < TICRATE)
+									{
+										P_SetMobjState(mobj, (stat = S_ROSY_HUG));
+										S_StartSound(mobj, sfx_cdpcm6);
+										mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y);
+										mobj->target->momx = mobj->momx;
+										mobj->target->momy = mobj->momy;
+									}
+								}
+								break;
+							case S_ROSY_UNHAPPY:
+							default:
+								break;
+						}
+
+						if (stat == S_ROSY_HUG)
+						{
+							if (player->panim != PA_IDLE)
+								P_SetPlayerMobjState(mobj->target, S_PLAY_STND);
+							player->pflags |= PF_STASIS;
+						}
+
+						if (dojump)
+						{
+							P_SetMobjState(mobj, S_ROSY_JUMP);
+							mobj->z += P_MobjFlip(mobj);
+							mobj->momx = mobj->momy = 0;
+							P_SetObjectMomZ(mobj, 6<<FRACBITS, false);
+							S_StartSound(mobj, sfx_cdfm02);
+						}
+
+						if (makeheart)
+						{
+							mobj_t *cdlhrt = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_CDLHRT);
+							cdlhrt->destscale = (5*mobj->scale)>>4;
+							P_SetScale(cdlhrt, cdlhrt->destscale);
+							cdlhrt->fuse = (5*TICRATE)>>1;
+							cdlhrt->momz = mobj->scale;
+							P_SetTarget(&cdlhrt->target, mobj);
+							cdlhrt->extravalue1 = mobj->x;
+							cdlhrt->extravalue2 = mobj->y;
+						}
+					}
+				}
+				break;
+			case MT_CDLHRT:
+				{
+					if (mobj->cvmem < 24)
+						mobj->cvmem++;
+					mobj->movedir += ANG10;
+					P_UnsetThingPosition(mobj);
+					mobj->x = mobj->extravalue1 + P_ReturnThrustX(mobj, mobj->movedir, mobj->cvmem*mobj->scale);
+					mobj->y = mobj->extravalue2 + P_ReturnThrustY(mobj, mobj->movedir, mobj->cvmem*mobj->scale);
+					P_SetThingPosition(mobj);
+					if ((--mobj->fuse) < 6)
+					{
+						if (!mobj->fuse)
+						{
+							P_RemoveMobj(mobj);
+							return;
+						}
+						mobj->frame = (mobj->frame & ~FF_TRANSMASK)|((10-(mobj->fuse*2))<<(FF_TRANSSHIFT));
+					}
+				}
+				break;
 			case MT_VWREF:
 			case MT_VWREB:
 				{
@@ -8896,13 +9160,17 @@ void P_MobjThinker(mobj_t *mobj)
 				}
 				break;
 			case MT_RING:
+			case MT_REDTEAMRING:
+			case MT_BLUETEAMRING:
+				P_KillRingsInLava(mobj);
+				if (P_MobjWasRemoved(mobj))
+					return;
+				/* FALLTHRU */
 			case MT_COIN:
 			case MT_BLUESPHERE:
 			case MT_BOMBSPHERE:
 			case MT_NIGHTSCHIP:
 			case MT_NIGHTSSTAR:
-			case MT_REDTEAMRING:
-			case MT_BLUETEAMRING:
 				// No need to check water. Who cares?
 				P_RingThinker(mobj);
 				if (mobj->flags2 & MF2_NIGHTSPULL)
@@ -8912,6 +9180,10 @@ void P_MobjThinker(mobj_t *mobj)
 				return;
 			// Flung items
 			case MT_FLINGRING:
+				P_KillRingsInLava(mobj);
+				if (P_MobjWasRemoved(mobj))
+					return;
+				/* FALLTHRU */
 			case MT_FLINGCOIN:
 			case MT_FLINGBLUESPHERE:
 			case MT_FLINGNIGHTSCHIP:
@@ -9113,6 +9385,159 @@ void P_MobjThinker(mobj_t *mobj)
 				}
 				mobj->flags2 ^= MF2_DONTDRAW;
 				break;
+			case MT_LAVAFALLROCK:
+				if (P_IsObjectOnGround(mobj))
+					P_RemoveMobj(mobj);
+				break;
+			case MT_PYREFLY:
+				{
+					fixed_t hdist;
+
+					mobj->extravalue1 = (mobj->extravalue1 + 3) % 360;
+					mobj->z += FINESINE(((mobj->extravalue1*ANG1) >> ANGLETOFINESHIFT) & FINEMASK);
+
+					if (!(mobj->flags2 & MF2_BOSSNOTRAP))
+						P_LookForPlayers(mobj, true, false, 1500*FRACUNIT);
+
+					if (!mobj->target)
+						break;
+
+					if (mobj->extravalue2 == 1)
+						P_PyreFlyBurn(mobj, 0, 20, MT_SMOKE, 4*FRACUNIT);
+					else if (mobj->extravalue2 == 2)
+					{
+						INT32 fireradius = min(100 - mobj->fuse, 52);
+						P_PyreFlyBurn(mobj, P_RandomRange(0, fireradius)*FRACUNIT, 20, MT_FLAMEPARTICLE, 4*FRACUNIT);
+						P_PyreFlyBurn(mobj, fireradius*FRACUNIT, 40, MT_PYREFLY_FIRE, 0);
+					}
+
+					hdist = R_PointToDist2(mobj->x, mobj->y, mobj->target->x, mobj->target->y);
+
+					if (!(mobj->flags2 & MF2_BOSSNOTRAP) && hdist <= 450*FRACUNIT)
+						mobj->flags2 |= MF2_BOSSNOTRAP;
+
+					if (!(mobj->flags2 & MF2_BOSSNOTRAP))
+						break;
+
+					if (hdist < 1000*FRACUNIT)
+					{
+						//Aim for player z position. If too close to floor/ceiling, aim just above/below them.
+						fixed_t destz = min(max(mobj->target->z, mobj->target->floorz + 70*FRACUNIT), mobj->target->ceilingz - 80*FRACUNIT - mobj->height);
+						fixed_t dist = P_AproxDistance(hdist, destz - mobj->z);
+						P_InstaThrust(mobj, R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y), 2*FRACUNIT);
+						mobj->momz = FixedMul(FixedDiv(destz - mobj->z, dist), 2*FRACUNIT);
+					}
+					else
+					{
+						mobj->momx = 0;
+						mobj->momy = 0;
+						mobj->momz = 0;
+						if (hdist >= 1500*FRACUNIT)
+						{
+							mobj->flags2 &= ~MF2_BOSSNOTRAP;
+							P_SetTarget(&mobj->target, NULL);
+						}
+					}
+					break;
+				}
+			case MT_PTERABYTE:
+				{
+					if (mobj->extravalue1 & 4) // Cooldown after grabbing
+					{
+						if (mobj->movefactor)
+							mobj->movefactor--;
+						else
+						{
+							P_SetTarget(&mobj->target, NULL);
+							mobj->extravalue1 &= 3;
+						}
+					}
+
+					if ((mobj->extravalue1 & 3) == 0) // Hovering
+					{
+						fixed_t vdist, hdist, time;
+						fixed_t hspeed = 3*mobj->info->speed;
+						angle_t fa;
+
+						var1 = 1;
+						var2 = 0;
+						A_CapeChase(mobj);
+
+						if (mobj->target)
+							break; // Still carrying a player or in cooldown
+
+						P_LookForPlayers(mobj, true, false, 256*FRACUNIT);
+
+						if (!mobj->target)
+							break;
+
+						if (mobj->target->player->powers[pw_flashing])
+						{
+							P_SetTarget(&mobj->target, NULL);
+							break;
+						}
+
+						vdist = mobj->z - mobj->target->z - mobj->target->height;
+						if (P_MobjFlip(mobj)*vdist <= 0)
+						{
+							P_SetTarget(&mobj->target, NULL);
+							break;
+						}
+
+						hdist = R_PointToDist2(mobj->x, mobj->y, mobj->target->x, mobj->target->y);
+						if (hdist > 450*FRACUNIT)
+						{
+							P_SetTarget(&mobj->target, NULL);
+							break;
+						}
+
+						P_SetMobjState(mobj, S_PTERABYTE_SWOOPDOWN);
+						mobj->extravalue1++;
+						S_StartSound(mobj, mobj->info->attacksound);
+						time = FixedDiv(hdist, hspeed);
+						mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y);
+						fa = (mobj->angle >> ANGLETOFINESHIFT) & FINEMASK;
+						mobj->momx = FixedMul(FINECOSINE(fa), hspeed);
+						mobj->momy = FixedMul(FINESINE(fa), hspeed);
+						mobj->momz = -2*FixedDiv(vdist, time);
+						mobj->extravalue2 = -FixedDiv(mobj->momz, time); //Z accel
+						mobj->movecount = time >> FRACBITS;
+						mobj->reactiontime = mobj->movecount;
+					}
+					else if ((mobj->extravalue1 & 3) == 1) // Swooping
+					{
+						mobj->reactiontime--;
+						mobj->momz += mobj->extravalue2;
+						if (mobj->reactiontime)
+							break;
+
+						if (mobj->state - states == S_PTERABYTE_SWOOPDOWN)
+						{
+							P_SetMobjState(mobj, S_PTERABYTE_SWOOPUP);
+							mobj->reactiontime = mobj->movecount;
+						}
+						else if (mobj->state - states == S_PTERABYTE_SWOOPUP)
+						{
+							P_SetMobjState(mobj, S_PTERABYTE_FLY1);
+							mobj->extravalue1++;
+							if (mobj->target && mobj->target->tracer != mobj)
+								P_SetTarget(&mobj->target, NULL); // Failed to grab the target
+							mobj->momx = mobj->momy = mobj->momz = 0;
+						}
+					}
+					else // Returning
+					{
+						var1 = 2*mobj->info->speed;
+						var2 = 1;
+						A_HomingChase(mobj);
+						if (P_AproxDistance(mobj->x - mobj->tracer->x, mobj->y - mobj->tracer->y) <= mobj->info->speed)
+						{
+							mobj->extravalue1 -= 2;
+							mobj->momx = mobj->momy = mobj->momz = 0;
+						}
+					}
+					break;
+				}
 			case MT_SPINFIRE:
 				if (mobj->flags & MF_NOGRAVITY)
 				{
@@ -9343,6 +9768,52 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
 				case MT_NIGHTSCORE:
 					P_RemoveMobj(mobj);
 					return;
+				case MT_LAVAFALL:
+					if (mobj->state - states == S_LAVAFALL_DORMANT)
+					{
+						mobj->fuse = 30;
+						P_SetMobjState(mobj, S_LAVAFALL_TELL);
+						S_StartSound(mobj, mobj->info->seesound);
+					}
+					else if (mobj->state - states == S_LAVAFALL_TELL)
+					{
+						mobj->fuse = 40;
+						P_SetMobjState(mobj, S_LAVAFALL_SHOOT);
+						S_StopSound(mobj);
+						S_StartSound(mobj, mobj->info->attacksound);
+					}
+					else
+					{
+						mobj->fuse = 30;
+						P_SetMobjState(mobj, S_LAVAFALL_DORMANT);
+						S_StopSound(mobj);
+					}
+					return;
+				case MT_PYREFLY:
+					if (mobj->health <= 0)
+						break;
+
+					mobj->extravalue2 = (mobj->extravalue2 + 1) % 3;
+					if (mobj->extravalue2 == 0)
+					{
+						P_SetMobjState(mobj, mobj->info->spawnstate);
+						mobj->fuse = 100;
+						S_StopSound(mobj);
+						S_StartSound(mobj, sfx_s3k8c);
+					}
+					else if (mobj->extravalue2 == 1)
+					{
+						mobj->fuse = 50;
+						S_StartSound(mobj, sfx_s3ka3);
+					}
+					else
+					{
+						P_SetMobjState(mobj, mobj->info->meleestate);
+						mobj->fuse = 100;
+						S_StopSound(mobj);
+						S_StartSound(mobj, sfx_s3kc2l);
+					}
+					return;
 				case MT_PLAYER:
 					break; // don't remove
 				default:
@@ -9900,6 +10371,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 		case MT_FANG:
 			sc = 4;
 			break;
+		case MT_ROSY:
+			sc = 5;
+			break;
 		case MT_CORK:
 			mobj->flags2 |= MF2_SUPERFIRE;
 			break;
@@ -9915,11 +10389,23 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 			}
 		case MT_TNTBARREL:
 			mobj->momx = 1; //stack hack
+			mobj->flags2 |= MF2_INVERTAIMABLE;
 			break;
 		case MT_MINECARTEND:
 			P_SetTarget(&mobj->tracer, P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_MINECARTENDSOLID));
 			mobj->tracer->angle = mobj->angle + ANGLE_90;
 			break;
+		case MT_TORCHFLOWER:
+			{
+				mobj_t *fire = P_SpawnMobjFromMobj(mobj, 0, 0, 46*FRACUNIT, MT_FLAME);
+				P_SetTarget(&mobj->target, fire);
+				break;
+			}
+		case MT_PYREFLY:
+			mobj->extravalue1 = (FixedHypot(mobj->x, mobj->y)/FRACUNIT) % 360;
+			mobj->extravalue2 = 0;
+			mobj->fuse = 100;
+			break;
 		default:
 			break;
 	}
@@ -10237,7 +10723,7 @@ void P_SpawnPrecipitation(void)
 		if (curWeather == PRECIP_SNOW)
 		{
 			// Not in a sector with visible sky -- exception for NiGHTS.
-			if (!(maptol & TOL_NIGHTS) && precipsector->sector->ceilingpic != skyflatnum)
+			if ((!(maptol & TOL_NIGHTS) && (precipsector->sector->ceilingpic != skyflatnum)) == !(precipsector->sector->flags & SF_INVERTPRECIP))
 				continue;
 
 			rainmo = P_SpawnSnowMobj(x, y, height, MT_SNOWFLAKE);
@@ -10250,7 +10736,7 @@ void P_SpawnPrecipitation(void)
 		else // everything else.
 		{
 			// Not in a sector with visible sky.
-			if (precipsector->sector->ceilingpic != skyflatnum)
+			if ((precipsector->sector->ceilingpic != skyflatnum) == !(precipsector->sector->flags & SF_INVERTPRECIP))
 				continue;
 
 			rainmo = P_SpawnRainMobj(x, y, height, MT_RAIN);
@@ -11070,6 +11556,14 @@ You should think about modifying the deathmatch starts to take full advantage of
 		// They're likely facets of the level's design and therefore required to progress.
 	}
 
+	if (i == MT_ROSY)
+	{
+		if (mariomode)
+			i = MT_TOAD; // don't remove on penalty of death
+		else if (!(netgame || multiplayer) && players[consoleplayer].skin == 5)
+			return; // no doubles
+	}
+
 	if (i == MT_TOKEN && ((gametype != GT_COOP && gametype != GT_COMPETITION) || ultimatemode || tokenbits == 30 || tokenlist & (1 << tokenbits++)))
 		return; // you already got this token, or there are too many, or the gametype's not right
 
@@ -11283,9 +11777,10 @@ You should think about modifying the deathmatch starts to take full advantage of
 		else
 			mobj->health = FixedMul(ss->sector->ceilingheight-ss->sector->floorheight, 3*(FRACUNIT/4))>>FRACBITS;
 		break;
-	case MT_FANG:
 	case MT_METALSONIC_RACE:
 	case MT_METALSONIC_BATTLE:
+	case MT_FANG:
+	case MT_ROSY:
 		if (mthing->options & MTF_EXTRA)
 		{
 			mobj->color = SKINCOLOR_SILVER;
@@ -11957,6 +12452,38 @@ ML_EFFECT5 : Don't stop thinking when too far away
 		if (mthing->angle > 0)
 			mobj->tics += mthing->angle;
 		break;
+	case MT_LAVAFALL:
+		mobj->fuse = 30 + mthing->angle;
+		if (mthing->options & MTF_AMBUSH)
+		{
+			P_SetScale(mobj, 2*mobj->scale);
+			mobj->destscale = mobj->scale;
+		}
+		break;
+	case MT_PYREFLY:
+		//start on fire if Ambush flag is set, otherwise behave normally
+		if (mthing->options & MTF_AMBUSH)
+		{
+			P_SetMobjState(mobj, mobj->info->meleestate);
+			mobj->extravalue2 = 2;
+			S_StartSound(mobj, sfx_s3kc2l);
+		}
+		break;
+	case MT_BIGFERN:
+	{
+		angle_t angle = FixedAngle(mthing->angle << FRACBITS);
+		UINT8 j;
+		for (j = 0; j < 8; j++)
+		{
+			angle_t fa = (angle >> ANGLETOFINESHIFT) & FINEMASK;
+			fixed_t xoffs = FINECOSINE(fa);
+			fixed_t yoffs = FINESINE(fa);
+			mobj_t *leaf = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, 0, MT_BIGFERNLEAF);
+			leaf->angle = angle;
+			angle += ANGLE_45;
+		}
+		break;
+	}
 	default:
 		break;
 	}
diff --git a/src/p_mobj.h b/src/p_mobj.h
index a9d5244b044ad58840238d753e2e70184e2fc585..94fcc29879727f110205e10656bcb97f45a81472 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -233,15 +233,17 @@ typedef enum
 	MFE_VERTICALFLIP      = 1<<5,
 	// Goo water
 	MFE_GOOWATER          = 1<<6,
+	// The mobj is touching a lava block
+	MFE_TOUCHLAVA         = 1<<7,
 	// Mobj was already pushed this tic
-	MFE_PUSHED            = 1<<7,
+	MFE_PUSHED            = 1<<8,
 	// Mobj was already sprung this tic
-	MFE_SPRUNG            = 1<<8,
+	MFE_SPRUNG            = 1<<9,
 	// Platform movement
-	MFE_APPLYPMOMZ        = 1<<9,
+	MFE_APPLYPMOMZ        = 1<<10,
 	// Compute and trigger on mobj angle relative to tracer
 	// See Linedef Exec 457 (Track mobj angle to point)
-	MFE_TRACERANGLE       = 1<<10,
+	MFE_TRACERANGLE       = 1<<11,
 	// free: to and including 1<<15
 } mobjeflag_t;
 
diff --git a/src/p_spec.c b/src/p_spec.c
index 256ca3453f0017311392d0b7d7d3043f7fe576a6..ebee50a45d141d9e72f600146b5defe9b9c32bb2 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -4174,26 +4174,11 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
 		// Check the 3D floor's type...
 		if (rover->flags & FF_BLOCKPLAYER)
 		{
+			boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == topheight));
+			boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == bottomheight));
 			// Thing must be on top of the floor to be affected...
-			if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
-				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
-			{
-				if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
-					continue;
-			}
-			else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
-				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
-			{
-				if (!(player->mo->eflags & MFE_VERTICALFLIP)
-					|| player->mo->z + player->mo->height != bottomheight)
-					continue;
-			}
-			else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
-			{
-				if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
-					|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
-					continue;
-			}
+			if (!(floorallowed || ceilingallowed))
+				continue;
 		}
 		else
 		{
@@ -4234,26 +4219,11 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
 			// Check the 3D floor's type...
 			if (rover->flags & FF_BLOCKPLAYER)
 			{
+				boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == topheight));
+				boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == bottomheight));
 				// Thing must be on top of the floor to be affected...
-				if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
-					&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
-				{
-					if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
-						continue;
-				}
-				else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
-					&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
-				{
-					if (!(player->mo->eflags & MFE_VERTICALFLIP)
-						|| player->mo->z + player->mo->height != bottomheight)
-						continue;
-				}
-				else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
-				{
-					if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
-						|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
-						continue;
-				}
+				if (!(floorallowed || ceilingallowed))
+					continue;
 			}
 			else
 			{
@@ -4304,26 +4274,11 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar
 		// Check the 3D floor's type...
 		if (rover->flags & FF_BLOCKPLAYER)
 		{
+			boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->z == top));
+			boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->z + mo->height == bottom));
 			// Thing must be on top of the floor to be affected...
-			if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
-				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
-			{
-				if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != top)
-					return false;
-			}
-			else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
-				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
-			{
-				if (!(mo->eflags & MFE_VERTICALFLIP)
-					|| mo->z + mo->height != bottom)
-					return false;
-			}
-			else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
-			{
-				if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == bottom)
-					|| (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == top)))
-					return false;
-			}
+			if (!(floorallowed || ceilingallowed))
+				continue;
 		}
 		else
 		{
@@ -4345,10 +4300,10 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar
 //
 static boolean P_MobjReadyToTrigger(mobj_t *mo, sector_t *sec)
 {
-	if (mo->eflags & MFE_VERTICALFLIP)
-		return (mo->z+mo->height == P_GetSpecialTopZ(mo, sec, sec) && sec->flags & SF_FLIPSPECIAL_CEILING);
-	else
-		return (mo->z == P_GetSpecialBottomZ(mo, sec, sec) && sec->flags & SF_FLIPSPECIAL_FLOOR);
+	boolean floorallowed = ((sec->flags & SF_FLIPSPECIAL_FLOOR) && ((sec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->z == P_GetSpecialBottomZ(mo, sec, sec)));
+	boolean ceilingallowed = ((sec->flags & SF_FLIPSPECIAL_CEILING) && ((sec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->z + mo->height == P_GetSpecialTopZ(mo, sec, sec)));
+	// Thing must be on top of the floor to be affected...
+	return (floorallowed || ceilingallowed);
 }
 
 /** Applies a sector special to a player.
@@ -5312,26 +5267,11 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
 		if (((rover->flags & FF_BLOCKPLAYER) && mo->player)
 			|| ((rover->flags & FF_BLOCKOTHERS) && !mo->player))
 		{
+			boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->z == topheight));
+			boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->z + mo->height == bottomheight));
 			// Thing must be on top of the floor to be affected...
-			if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
-				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
-			{
-				if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != topheight)
-					continue;
-			}
-			else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
-				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
-			{
-				if (!(mo->eflags & MFE_VERTICALFLIP)
-					|| mo->z + mo->height != bottomheight)
-					continue;
-			}
-			else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
-			{
-				if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == bottomheight)
-					|| (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == topheight)))
-					continue;
-			}
+			if (!(floorallowed || ceilingallowed))
+				continue;
 		}
 		else
 		{
@@ -5374,26 +5314,11 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
 		// Check the 3D floor's type...
 		if (rover->flags & FF_BLOCKPLAYER)
 		{
+			boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == topheight));
+			boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == bottomheight));
 			// Thing must be on top of the floor to be affected...
-			if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
-				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
-			{
-				if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
-					continue;
-			}
-			else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
-				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
-			{
-				if (!(player->mo->eflags & MFE_VERTICALFLIP)
-					|| player->mo->z + player->mo->height != bottomheight)
-					continue;
-			}
-			else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
-			{
-				if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
-					|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
-					continue;
-			}
+			if (!(floorallowed || ceilingallowed))
+				continue;
 		}
 		else
 		{
@@ -5450,38 +5375,16 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
 			}
 
 			if (!(po->flags & POF_TESTHEIGHT)) // Don't do height checking
-			{
-			}
+				;
 			else if (po->flags & POF_SOLID)
 			{
+				boolean floorallowed = ((polysec->flags & SF_FLIPSPECIAL_FLOOR) && ((polysec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == polysec->ceilingheight));
+				boolean ceilingallowed = ((polysec->flags & SF_FLIPSPECIAL_CEILING) && ((polysec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == polysec->floorheight));
 				// Thing must be on top of the floor to be affected...
-				if ((polysec->flags & SF_FLIPSPECIAL_FLOOR)
-					&& !(polysec->flags & SF_FLIPSPECIAL_CEILING))
-				{
-					if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != polysec->ceilingheight)
-					{
-						po = (polyobj_t *)(po->link.next);
-						continue;
-					}
-				}
-				else if ((polysec->flags & SF_FLIPSPECIAL_CEILING)
-					&& !(polysec->flags & SF_FLIPSPECIAL_FLOOR))
+				if (!(floorallowed || ceilingallowed))
 				{
-					if (!(player->mo->eflags & MFE_VERTICALFLIP)
-						|| player->mo->z + player->mo->height != polysec->floorheight)
-					{
-						po = (polyobj_t *)(po->link.next);
-						continue;
-					}
-				}
-				else if (polysec->flags & SF_FLIPSPECIAL_BOTH)
-				{
-					if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == polysec->floorheight)
-						|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == polysec->ceilingheight)))
-					{
-						po = (polyobj_t *)(po->link.next);
-						continue;
-					}
+					po = (polyobj_t *)(po->link.next);
+					continue;
 				}
 			}
 			else
@@ -5580,17 +5483,13 @@ static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector)
 	f_affectpoint = P_GetSpecialBottomZ(player->mo, sector, sector);
 	c_affectpoint = P_GetSpecialTopZ(player->mo, sector, sector);
 
-	// Only go further if on the ground
-	if ((sector->flags & SF_FLIPSPECIAL_FLOOR) && !(sector->flags & SF_FLIPSPECIAL_CEILING) && player->mo->z != f_affectpoint)
-		return;
-
-	if ((sector->flags & SF_FLIPSPECIAL_CEILING) && !(sector->flags & SF_FLIPSPECIAL_FLOOR) && player->mo->z + player->mo->height != c_affectpoint)
-		return;
-
-	if ((sector->flags & SF_FLIPSPECIAL_BOTH)
-		&& player->mo->z != f_affectpoint
-		&& player->mo->z + player->mo->height != c_affectpoint)
-		return;
+	{
+		boolean floorallowed = ((sector->flags & SF_FLIPSPECIAL_FLOOR) && ((sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == f_affectpoint));
+		boolean ceilingallowed = ((sector->flags & SF_FLIPSPECIAL_CEILING) && ((sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == c_affectpoint));
+		// Thing must be on top of the floor to be affected...
+		if (!(floorallowed || ceilingallowed))
+			return;
+	}
 
 	P_ProcessSpecialSector(player, sector, NULL);
 }
@@ -6683,6 +6582,11 @@ void P_SpawnSpecials(INT32 fromnetsave)
 
 					if (lines[i].flags & ML_EFFECT3)
 						sectors[s].flags |= SF_TRIGGERSPECIAL_TOUCH;
+					if (lines[i].flags & ML_EFFECT2)
+						sectors[s].flags |= SF_TRIGGERSPECIAL_HEADBUMP;
+
+					if (lines[i].flags & ML_EFFECT1)
+						sectors[s].flags |= SF_INVERTPRECIP;
 
 					if (lines[i].frontsector && GETSECSPECIAL(lines[i].frontsector->special, 4) == 12)
 						sectors[s].camsec = sides[*lines[i].sidenum].sector-sectors;
@@ -7171,15 +7075,15 @@ void P_SpawnSpecials(INT32 fromnetsave)
 				break;
 
 			case 252: // Shatter block (breaks when touched)
-				ffloorflags = FF_EXISTS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER;
+				ffloorflags = FF_EXISTS|FF_BLOCKOTHERS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER;
 				if (lines[i].flags & ML_NOCLIMB)
-					ffloorflags |= FF_SOLID|FF_SHATTERBOTTOM;
+					ffloorflags |= FF_BLOCKPLAYER|FF_SHATTERBOTTOM;
 
 				P_AddFakeFloorsByLine(i, ffloorflags, secthinkers);
 				break;
 
 			case 253: // Translucent shatter block (see 76)
-				P_AddFakeFloorsByLine(i, FF_EXISTS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER|FF_TRANSLUCENT, secthinkers);
+				P_AddFakeFloorsByLine(i, FF_EXISTS|FF_BLOCKOTHERS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER|FF_TRANSLUCENT, secthinkers);
 				break;
 
 			case 254: // Bustable block
diff --git a/src/p_tick.c b/src/p_tick.c
index 7606510fef2d8a302809f0d541616babb003e95a..6b5c7980c86d7307a460e66111b70d0bad37a23e 100644
--- a/src/p_tick.c
+++ b/src/p_tick.c
@@ -482,7 +482,7 @@ static inline void P_DoSpecialStageStuff(void)
 				countspheres += players[i].spheres;
 
 				// If in water, deplete timer 6x as fast.
-				if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER))
+				if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(players[i].powers[pw_shield] & SH_PROTECTWATER))
 					players[i].nightstime -= 5;
 				if (--players[i].nightstime > 6)
 				{
diff --git a/src/p_user.c b/src/p_user.c
index e4792c1071e8ca08fa650de7ced26b569f8aebb2..33f84e2db2187df6d5b35b018811f0a5aa929c37 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -898,7 +898,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 	if (player->mo->target)
 	{
 		player->angle_pos = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y);
-		player->drawangle = player->mo->angle = player->angle_pos
+		player->drawangle = player->angle_pos
 			+ ((player->mo->target->flags2 & MF2_AMBUSH) ? // if axis is invert, take the opposite right angle
 				-ANGLE_90 : ANGLE_90); // flyangle is always 0 here, below is kept for posterity
 				/*(player->flyangle > 90 && player->flyangle < 270 ? ANGLE_90 : -ANGLE_90)
@@ -1031,6 +1031,17 @@ void P_ResetPlayer(player_t *player)
 {
 	player->pflags &= ~(PF_SPINNING|PF_STARTDASH|PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_THOKKED|PF_CANCARRY|PF_SHIELDABILITY|PF_BOUNCING);
 
+	if (player->powers[pw_carry] == CR_ROLLOUT)
+	{
+		if (player->mo->tracer && !P_MobjWasRemoved(player->mo->tracer))
+		{
+			player->mo->tracer->flags |= MF_PUSHABLE;
+			P_SetTarget(&player->mo->tracer->tracer, NULL);
+		}
+		P_SetTarget(&player->mo->tracer, NULL);
+		player->powers[pw_carry] = CR_NONE;
+	}
+
 	if (!(player->powers[pw_carry] == CR_NIGHTSMODE || player->powers[pw_carry] == CR_NIGHTSFALL || player->powers[pw_carry] == CR_BRAKGOOP || player->powers[pw_carry] == CR_MINECART))
 		player->powers[pw_carry] = CR_NONE;
 
@@ -2249,7 +2260,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
 				else if (!player->skidtime)
 					player->pflags &= ~PF_GLIDING;
 			}
-			else if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)
+			else if (player->charability2 == CA2_MELEE && ((player->panim == PA_ABILITY2) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
 			{
 				if (player->mo->state-states != S_PLAY_MELEE_LANDING)
 				{
@@ -3689,7 +3700,7 @@ static void P_DoTeeter(player_t *player)
 				bottomheight = *rover->bottomheight;
 #endif
 
-				if (P_CheckSolidLava(player->mo, rover))
+				if (P_CheckSolidLava(rover))
 					;
 				else if (!(rover->flags & FF_BLOCKPLAYER || rover->flags & FF_QUICKSAND))
 					continue; // intangible 3d floor
@@ -4311,6 +4322,16 @@ void P_DoJump(player_t *player, boolean soundandstate)
 		if (player->mo->ceilingz-player->mo->floorz <= player->mo->height-1)
 			return;
 
+		if (player->powers[pw_carry] == CR_PTERABYTE)
+		{
+			S_StartSound(player->mo, sfx_s3kd7s);
+			player->mo->tracer->cusval += 10;
+			player->mo->tracer->watertop = P_RandomRange(-player->mo->tracer->cusval, player->mo->tracer->cusval) << (FRACBITS - 1);
+			player->mo->tracer->waterbottom = P_RandomRange(-player->mo->tracer->cusval, player->mo->tracer->cusval) << (FRACBITS - 1);
+			player->mo->tracer->cvmem = P_RandomRange(-player->mo->tracer->cusval, player->mo->tracer->cusval) << (FRACBITS - 1);
+			return;
+		}
+
 		// Jump this high.
 		if (player->powers[pw_carry] == CR_PLAYER)
 		{
@@ -4324,6 +4345,8 @@ void P_DoJump(player_t *player, boolean soundandstate)
 		{
 			player->mo->momz = 9*FRACUNIT;
 			player->powers[pw_carry] = CR_NONE;
+			player->mo->tracer->flags |= MF_PUSHABLE;
+			P_SetTarget(&player->mo->tracer->target, NULL);
 			P_SetTarget(&player->mo->tracer, NULL);
 		}
 		else if (player->powers[pw_carry] == CR_ROPEHANG)
@@ -4332,6 +4355,14 @@ void P_DoJump(player_t *player, boolean soundandstate)
 			player->powers[pw_carry] = CR_NONE;
 			P_SetTarget(&player->mo->tracer, NULL);
 		}
+		else if (player->powers[pw_carry] == CR_ROLLOUT)
+		{
+			player->mo->momz = 9*FRACUNIT + player->mo->tracer->momz;
+			player->powers[pw_carry] = CR_NONE;
+			player->mo->tracer->flags |= MF_PUSHABLE;
+			P_SetTarget(&player->mo->tracer->tracer, NULL);
+			P_SetTarget(&player->mo->tracer, NULL);
+		}
 		else if (player->mo->eflags & MFE_GOOWATER)
 		{
 			player->mo->momz = 7*FRACUNIT;
@@ -4643,8 +4674,9 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
 						if (player->speed < FixedMul(player->maxdash, player->mo->scale))
 #endif
 						{
-							player->drawangle = player->mo->angle;
-							P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->maxdash, player->mo->scale));
+							if (player->panim == PA_IDLE)
+								player->drawangle = player->mo->angle;
+							P_InstaThrust(player->mo, player->drawangle, FixedMul(player->maxdash, player->mo->scale));
 						}
 						player->mo->momx += player->cmomx;
 						player->mo->momy += player->cmomy;
@@ -5842,35 +5874,28 @@ static void P_3dMovement(player_t *player)
 		else
 			topspeed = normalspd;
 	}
-	else if (player->powers[pw_super] || player->powers[pw_sneakers])
+	else
 	{
-		thrustfactor = player->thrustfactor*2;
-		acceleration = player->accelstart/2 + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration/2;
-
-		if (player->powers[pw_tailsfly])
-			topspeed = normalspd;
-		else if (player->mo->eflags & (MFE_UNDERWATER|MFE_GOOWATER))
+		if (player->powers[pw_super] || player->powers[pw_sneakers])
 		{
-			topspeed = normalspd;
-			acceleration = 2*acceleration/3;
+			topspeed = 5 * normalspd / 3; // 1.67x
+			thrustfactor = player->thrustfactor*2;
+			acceleration = player->accelstart/2 + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration/2;
 		}
 		else
-			topspeed = normalspd * 2;
-	}
-	else
-	{
-		thrustfactor = player->thrustfactor;
-		acceleration = player->accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration;
+		{
+			topspeed = normalspd;
+			thrustfactor = player->thrustfactor;
+			acceleration = player->accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration;
+		}
 
 		if (player->powers[pw_tailsfly])
-			topspeed = normalspd/2;
+			topspeed >>= 1;
 		else if (player->mo->eflags & (MFE_UNDERWATER|MFE_GOOWATER))
 		{
-			topspeed = normalspd/2;
+			topspeed >>= 1;
 			acceleration = 2*acceleration/3;
 		}
-		else
-			topspeed = normalspd;
 	}
 
 	if (spin) // Prevent gaining speed whilst rolling!
@@ -7350,10 +7375,13 @@ static void P_NiGHTSMovement(player_t *player)
 		&& player->mo->z + player->mo->height - P_GetPlayerHeight(player) <= player->mo->waterbottom && player->mo->z + player->mo->height >= player->mo->waterbottom))
 	&& player->speed > 9000 && leveltime % (TICRATE/7) == 0 && !player->spectator)
 	{
+		mobjtype_t splishtype = (player->mo->eflags & MFE_TOUCHLAVA) ? MT_LAVASPLISH : MT_SPLISH;
 		mobj_t *water = P_SpawnMobj(player->mo->x, player->mo->y,
-			((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_SPLISH].height, player->mo->scale) : player->mo->watertop), MT_SPLISH);
+			((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[splishtype].height, player->mo->scale) : player->mo->watertop), splishtype);
 		if (player->mo->eflags & MFE_GOOWATER)
 			S_StartSound(water, sfx_ghit);
+		else if (player->mo->eflags & MFE_TOUCHLAVA)
+			S_StartSound(water, sfx_splash);
 		else
 			S_StartSound(water, sfx_wslap);
 		if (player->mo->eflags & MFE_VERTICALFLIP)
@@ -8115,10 +8143,13 @@ static void P_MovePlayer(player_t *player)
 	&& (player->speed > runspd || (player->pflags & PF_STARTDASH))
 	&& leveltime % (TICRATE/7) == 0 && player->mo->momz == 0 && !(player->pflags & PF_SLIDING) && !player->spectator)
 	{
+		mobjtype_t splishtype = (player->mo->eflags & MFE_TOUCHLAVA) ? MT_LAVASPLISH : MT_SPLISH;
 		mobj_t *water = P_SpawnMobj(player->mo->x - P_ReturnThrustX(NULL, player->mo->angle, player->mo->radius), player->mo->y - P_ReturnThrustY(NULL, player->mo->angle, player->mo->radius),
-			((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[MT_SPLISH].height, player->mo->scale) : player->mo->watertop), MT_SPLISH);
+			((player->mo->eflags & MFE_VERTICALFLIP) ? player->mo->waterbottom - FixedMul(mobjinfo[splishtype].height, player->mo->scale) : player->mo->watertop), splishtype);
 		if (player->mo->eflags & MFE_GOOWATER)
 			S_StartSound(water, sfx_ghit);
+		else if (player->mo->eflags & MFE_TOUCHLAVA)
+			S_StartSound(water, sfx_splash);
 		else
 			S_StartSound(water, sfx_wslap);
 		if (player->mo->eflags & MFE_VERTICALFLIP)
@@ -8855,7 +8886,7 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius)
 			continue;
 
 		if (mo->type == MT_MINUS && !(mo->flags & (MF_SPECIAL|MF_SHOOTABLE)))
-			mo->flags |= MF_SPECIAL|MF_SHOOTABLE;
+			mo->flags = (mo->flags & ~MF_NOCLIPTHING)|MF_SPECIAL|MF_SHOOTABLE;
 
 		if (mo->type == MT_EGGGUARD && mo->tracer) //nuke Egg Guard's shield!
 			P_KillMobj(mo->tracer, inflictor, source, DMG_NUKE);
@@ -10254,7 +10285,7 @@ static sector_t *P_GetMinecartSector(fixed_t x, fixed_t y, fixed_t z, fixed_t *n
 		ffloor_t *rover;
 		for (rover = sec->ffloors; rover; rover = rover->next)
 		{
-			if (!(rover->flags & FF_EXISTS))
+			if (!(rover->flags & (FF_EXISTS|FF_BLOCKOTHERS)))
 				continue;
 
 			*nz = *rover->t_slope ? P_GetZAt(*rover->t_slope, x, y) : *rover->topheight;
@@ -11240,6 +11271,8 @@ void P_PlayerThink(player_t *player)
 
 	// deez New User eXperiences.
 	{
+		angle_t diff = 0;
+		UINT8 factor;
 		// Directionchar!
 		// Camera angle stuff.
 		if (player->exiting // no control, no modification
@@ -11266,8 +11299,16 @@ void P_PlayerThink(player_t *player)
 					/* FALLTHRU */
 				case CR_MINECART:
 				case CR_GENERIC:
+				case CR_PTERABYTE:
 					player->drawangle = player->mo->tracer->angle;
 					break;
+				case CR_ROLLOUT:
+					if (cmd->forwardmove || cmd->sidemove) // only when you're pressing movement keys
+					{ // inverse direction!
+						diff = ((player->mo->angle + R_PointToAngle2(0, 0, -cmd->forwardmove<<FRACBITS, cmd->sidemove<<FRACBITS)) - player->drawangle);
+						factor = 4;
+					}
+					break;
 				/* -- in case we wanted to have the camera freely movable during zoom tubes
 				case CR_ZOOMTUBE:*/
 				case CR_ROPEHANG:
@@ -11288,9 +11329,6 @@ void P_PlayerThink(player_t *player)
 			;
 		else
 		{
-			angle_t diff;
-			UINT8 factor;
-
 			if (player->pflags & PF_SLIDING)
 			{
 #if 0 // fun hydrocity style horizontal spin
@@ -11326,15 +11364,15 @@ void P_PlayerThink(player_t *player)
 				diff = (player->mo->angle - player->drawangle);
 				factor = 8;
 			}
+		}
 
-			if (diff)
-			{
-				if (diff > ANGLE_180)
-					diff = InvAngle(InvAngle(diff)/factor);
-				else
-					diff /= factor;
-				player->drawangle += diff;
-			}
+		if (diff)
+		{
+			if (diff > ANGLE_180)
+				diff = InvAngle(InvAngle(diff)/factor);
+			else
+				diff /= factor;
+			player->drawangle += diff;
 		}
 
 		// Autobrake! check ST_drawInput if you modify this
@@ -11653,6 +11691,36 @@ void P_PlayerThink(player_t *player)
 	}*/
 }
 
+// Checks if the mobj is above lava. Used by Pterabyte.
+static boolean P_MobjAboveLava(mobj_t *mobj)
+{
+	sector_t *sector = mobj->subsector->sector;
+
+	if (sector->ffloors)
+	{
+		ffloor_t *rover;
+
+		for (rover = sector->ffloors; rover; rover = rover->next)
+		{
+			if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || GETSECSPECIAL(rover->master->frontsector->special, 1) != 3)
+				continue;
+
+			if (mobj->eflags & MFE_VERTICALFLIP)
+			{
+				if (*rover->bottomheight <= mobj->ceilingz && *rover->bottomheight >= mobj->z)
+					return true;
+			}
+			else
+			{
+				if (*rover->topheight >= mobj->floorz && *rover->topheight <= mobj->z)
+					return true;
+			}
+		}
+	}
+
+	return false;
+}
+
 //
 // P_PlayerAfterThink
 //
@@ -11968,6 +12036,114 @@ void P_PlayerAfterThink(player_t *player)
 				}
 				break;
 			}
+			case CR_ROLLOUT:
+			{
+				mobj_t *mo = player->mo, *rock = player->mo->tracer;
+				UINT8 walktics = mo->state->tics - P_GetPlayerControlDirection(player);
+
+				if (!rock || P_MobjWasRemoved(rock))
+				{
+					P_SetTarget(&player->mo->tracer, NULL);
+					player->powers[pw_carry] = CR_NONE;
+					break;
+				}
+
+				if (player->cmd.forwardmove || player->cmd.sidemove)
+				{
+					rock->movedir = (player->cmd.angleturn << FRACBITS) + R_PointToAngle2(0, 0, player->cmd.forwardmove << FRACBITS, -player->cmd.sidemove << FRACBITS);
+					P_Thrust(rock, rock->movedir, rock->scale >> 1);
+				}
+
+				mo->momx = rock->momx;
+				mo->momy = rock->momy;
+				mo->momz = 0;
+				
+				if (player->panim == PA_IDLE && (mo->momx || mo->momy))
+				{
+					P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
+				}
+
+				if (player->panim == PA_WALK && mo->tics > walktics)
+				{
+					mo->tics = walktics;
+				}
+
+				P_TeleportMove(player->mo, rock->x, rock->y, rock->z + rock->height);
+				break;
+			}
+			case CR_PTERABYTE: // being carried by a Pterabyte
+			{
+				mobj_t *ptera = player->mo->tracer;
+				mobj_t *spawnpoint = ptera->tracer->tracer;
+				player->mo->height = FixedDiv(P_GetPlayerHeight(player), FixedDiv(14 * FRACUNIT, 10 * FRACUNIT));
+
+				if (ptera->health <= 0)
+					goto dropoff;
+
+				if (P_MobjAboveLava(ptera) && ptera->movefactor <= 3*TICRATE - 10)
+					goto dropoff;
+
+				if (player->mo->eflags & MFE_VERTICALFLIP)
+				{
+					if ((ptera->z + ptera->height + player->mo->height + FixedMul(FRACUNIT, player->mo->scale)) <= ptera->ceilingz
+						&& (ptera->eflags & MFE_VERTICALFLIP)) // Reverse gravity check for the carrier - Flame
+						player->mo->z = ptera->z + ptera->height + FixedMul(FRACUNIT, player->mo->scale);
+
+					if (ptera->ceilingz - ptera->z > spawnpoint->ceilingz - spawnpoint->z + 512*FRACUNIT && ptera->movefactor <= 3 * TICRATE - 10)
+						goto dropoff;
+				}
+				else
+				{
+					if ((ptera->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale)) >= ptera->floorz
+						&& !(ptera->eflags & MFE_VERTICALFLIP)) // Correct gravity check for the carrier - Flame
+						player->mo->z = ptera->z - player->mo->height - FixedMul(FRACUNIT, player->mo->scale);
+
+					if (ptera->z - ptera->floorz > spawnpoint->z - spawnpoint->floorz + 512 * FRACUNIT && ptera->movefactor <= 3 * TICRATE - 10)
+						goto dropoff;
+				}
+
+				ptera->movefactor--;
+				if (!ptera->movefactor)
+					goto dropoff;
+
+				if (ptera->cusval >= 50)
+				{
+					player->powers[pw_carry] = CR_NONE;
+					P_SetTarget(&player->mo->tracer, NULL);
+					P_KillMobj(ptera, player->mo, player->mo, 0);
+					player->mo->momz = 9*FRACUNIT;
+					player->pflags |= PF_APPLYAUTOBRAKE|PF_JUMPED|PF_THOKKED;
+					P_SetMobjState(player->mo, S_PLAY_ROLL);
+					break;
+				}
+
+				if (ptera->cusval)
+					ptera->cusval--;
+
+				P_TryMove(player->mo, ptera->x + ptera->watertop, ptera->y + ptera->waterbottom, true);
+				player->mo->z += ptera->cvmem;
+				player->mo->momx = ptera->momx;
+				player->mo->momy = ptera->momy;
+				player->mo->momz = ptera->momz;
+
+				if (P_AproxDistance(player->mo->x - ptera->x - ptera->watertop, player->mo->y - ptera->y - ptera->waterbottom) > player->mo->radius)
+					goto dropoff;
+
+				ptera->watertop >>= 1;
+				ptera->waterbottom >>= 1;
+				ptera->cvmem >>= 1;
+
+				if (player->mo->state-states != S_PLAY_FALL)
+					P_SetPlayerMobjState(player->mo, S_PLAY_FALL);
+				break;
+
+			dropoff:
+				player->powers[pw_carry] = CR_NONE;
+				P_SetTarget(&player->mo->tracer, NULL);
+				ptera->movefactor = TICRATE;
+				ptera->extravalue1 |= 4;
+				break;
+			}
 			default:
 				break;
 		}
diff --git a/src/r_defs.h b/src/r_defs.h
index def7b46f3b8aa5ecdd81c9d1d359848b87268822..6aeb0671c49ece68838c5fc0c69ddbaf55572682 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -263,10 +263,15 @@ typedef struct pslope_s
 
 typedef enum
 {
-	SF_FLIPSPECIAL_FLOOR    =  1,
-	SF_FLIPSPECIAL_CEILING  =  2,
-	SF_FLIPSPECIAL_BOTH     =  3,
-	SF_TRIGGERSPECIAL_TOUCH =  4,
+	// flipspecial - planes with effect
+	SF_FLIPSPECIAL_FLOOR       =  1,
+	SF_FLIPSPECIAL_CEILING     =  1<<1,
+	SF_FLIPSPECIAL_BOTH        =  (SF_FLIPSPECIAL_FLOOR|SF_FLIPSPECIAL_CEILING),
+	// triggerspecial - conditions under which plane touch causes effect
+	SF_TRIGGERSPECIAL_TOUCH    =  1<<2,
+	SF_TRIGGERSPECIAL_HEADBUMP =  1<<3,
+	// invertprecip - inverts presence of precipitation
+	SF_INVERTPRECIP            =  1<<4,
 } sectorflags_t;
 
 //
diff --git a/src/r_main.c b/src/r_main.c
index 9cce412888ccba4c04b8c30925eb6fcd66501bed..9d9d1c39a8c6826b2597070f5fb3d986183b438c 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -1219,6 +1219,7 @@ void R_RegisterEngineStuff(void)
 #endif
 	CV_RegisterVar(&cv_grmd2);
 	CV_RegisterVar(&cv_grspritebillboarding);
+	CV_RegisterVar(&cv_grskydome);
 #endif
 
 #ifdef HWRENDER
diff --git a/src/r_things.c b/src/r_things.c
index 43e006a30ac6bcaaee6529cbf03690b7404da799..5c99edcec3d74e135a605fd591ff55b3f0166fcb 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -1230,7 +1230,7 @@ static void R_ProjectSprite(mobj_t *thing)
 		else
 			range = 1;
 
-		scalestep = (yscale2 - yscale)/range;
+		scalestep = (yscale2 - yscale)/range ?: 1;
 
 		// The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2?
 		// sortscale = max(yscale, yscale2);
@@ -1637,7 +1637,7 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
 	mobj_t *thing;
 	precipmobj_t *precipthing; // Tails 08-25-2002
 	INT32 lightnum;
-	fixed_t approx_dist, limit_dist;
+	fixed_t approx_dist, limit_dist, hoop_limit_dist;
 
 	if (rendermode != render_soft)
 		return;
@@ -1668,7 +1668,9 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
 
 	// Handle all things in sector.
 	// If a limit exists, handle things a tiny bit different.
-	if ((limit_dist = (fixed_t)((maptol & TOL_NIGHTS) ? cv_drawdist_nights.value : cv_drawdist.value) << FRACBITS))
+	limit_dist = (fixed_t)(cv_drawdist.value) << FRACBITS;
+	hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS;
+	if (limit_dist || hoop_limit_dist)
 	{
 		for (thing = sec->thinglist; thing; thing = thing->snext)
 		{
@@ -1677,8 +1679,16 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
 
 			approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y);
 
-			if (approx_dist > limit_dist)
-				continue;
+			if (thing->sprite == SPR_HOOP)
+			{
+				if (hoop_limit_dist && approx_dist > hoop_limit_dist)
+					continue;
+			}
+			else
+			{
+				if (limit_dist && approx_dist > limit_dist)
+					continue;
+			}
 
 			R_ProjectSprite(thing);
 		}
@@ -2786,9 +2796,9 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
 	}
 
 	if (P_IsLocalPlayer(player))
-		CONS_Alert(CONS_WARNING, M_GetText("Requested skin not found\n"));
+		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 not found\n", playernum, player_names[playernum]);
+		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
 }
 
diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c
index 05ac6450e2267c0c08182775cece05eeaefabeab..103398405f1e98518b65157859f39a981836fca1 100644
--- a/src/sdl/hwsym_sdl.c
+++ b/src/sdl/hwsym_sdl.c
@@ -79,6 +79,7 @@ void *hwSym(const char *funcName,void *handle)
 	GETFUNC(Init);
 	GETFUNC(Draw2DLine);
 	GETFUNC(DrawPolygon);
+	GETFUNC(RenderSkyDome);
 	GETFUNC(SetBlend);
 	GETFUNC(ClearBuffer);
 	GETFUNC(SetTexture);
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 46c05aea9190000fdc6e0b478894a956d8ce5fa3..f5c7e3714d17fc72ae36622c0c81c21f33d898f8 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -1629,6 +1629,7 @@ void I_StartupGraphics(void)
 		HWD.pfnFinishUpdate     = NULL;
 		HWD.pfnDraw2DLine       = hwSym("Draw2DLine",NULL);
 		HWD.pfnDrawPolygon      = hwSym("DrawPolygon",NULL);
+		HWD.pfnRenderSkyDome    = hwSym("RenderSkyDome",NULL);
 		HWD.pfnSetBlend         = hwSym("SetBlend",NULL);
 		HWD.pfnClearBuffer      = hwSym("ClearBuffer",NULL);
 		HWD.pfnSetTexture       = hwSym("SetTexture",NULL);
diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c
index d94010d9add02dcc47693b9149f5b7fc177b148d..c4b2f98f4d73dbbe85df4f0ef7933568cc7fcbd2 100644
--- a/src/sdl/mixer_sound.c
+++ b/src/sdl/mixer_sound.c
@@ -878,7 +878,11 @@ boolean I_SetSongSpeed(float speed)
 #ifdef HAVE_OPENMPT
 	if (openmpt_mhandle)
 	{
-		char modspd[16];
+		char modspd[13];
+
+		if (speed > 4.0f)
+			speed = 4.0f; // Limit this to 4x to prevent crashing, stupid fix but... ~SteelT 27/9/19
+
 		sprintf(modspd, "%g", speed);
 		openmpt_module_ctl_set(openmpt_mhandle, "play.tempo_factor", modspd);
 		return true;
diff --git a/src/sounds.c b/src/sounds.c
index 6940cd9ee69cfc86479bdaea6a1019be2c761d74..e5dfeec8ad09c3db66d13e5ee882a57ef253b966 100644
--- a/src/sounds.c
+++ b/src/sounds.c
@@ -218,6 +218,8 @@ sfxinfo_t S_sfx[NUMSFX] =
   {"chuchu", false,  32,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Train horn"},
   {"bsnipe", false, 200,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Home-run smash"},
   {"sprong", false, 112,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Power spring"},
+  {"lvfal1",  true,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Rumble"},
+  {"pscree", false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "SCREE!"},
 
   // Menu, interface
   {"chchng", false, 120,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Score"},
@@ -504,7 +506,7 @@ sfxinfo_t S_sfx[NUMSFX] =
   {"s3k6d",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, ""},
   {"s3k6e",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Mechanical damage"},
   {"s3k6f",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Ominous rumbling"},
-  {"s3k70",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Burst"},
+  {"s3k70",   true,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Burst"},
   {"s3k71",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Basic Shield"},
   {"s3k72",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Movement"},
   {"s3k73",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Warp"},
@@ -555,7 +557,7 @@ sfxinfo_t S_sfx[NUMSFX] =
   {"s3ka0",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Launch"},
   {"s3ka1",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, ""},
   {"s3ka2",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Launch"},
-  {"s3ka3",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Lift"},
+  {"s3ka3",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Rising charge"},
   {"s3ka4",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Powering up"},
   {"s3ka5",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, ""},
   {"s3ka6",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Attraction fizzle"},
diff --git a/src/sounds.h b/src/sounds.h
index e5568b59a49148382c22bcc9b60ae7c57404ea22..9f6e0bab640128b2e8c4a36182479bc2b28f7cbe 100644
--- a/src/sounds.h
+++ b/src/sounds.h
@@ -267,6 +267,8 @@ typedef enum
 	sfx_chuchu,
 	sfx_bsnipe,
 	sfx_sprong,
+	sfx_lvfal1,
+	sfx_pscree,
 
 	// Menu, interface
 	sfx_chchng,
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 20a132b3a19aecb158ba428e7a66460480e1de71..11d05f547e0fe2a7480efba60ccb4d01ebe1982d 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -1474,12 +1474,9 @@ static void ST_drawNightsRecords(void)
 
 			if (P_HasGrades(gamemap, stplyr->lastmare + 1))
 			{
-				if (aflag)
-					V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, 160, aflag,
-										   ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]);
-				else
-					V_DrawScaledPatch(BASEVIDWIDTH/2 + 60, 160, 0,
-									  ngradeletters[P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare)]);
+				UINT8 grade = P_GetGrade(stplyr->lastmarescore, gamemap, stplyr->lastmare);
+				if (modeattacking || grade >= GRADE_A)
+					V_DrawTranslucentPatch(BASEVIDWIDTH/2 + 60, 160, aflag, ngradeletters[grade]);
 			}
 			break;
 		}
@@ -1857,7 +1854,8 @@ static void ST_drawNiGHTSHUD(void)
 			numbersize = 48/2;
 
 		if ((oldspecialstage && leveltime & 2)
-			&& (stplyr->mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER)))
+			&& (stplyr->mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER))
+			&& !(stplyr->powers[pw_shield] & SH_PROTECTWATER))
 			col = SKINCOLOR_ORANGE;
 
 		ST_DrawNightsOverlayNum((160 + numbersize)<<FRACBITS, 14<<FRACBITS, FRACUNIT, V_PERPLAYER|V_SNAPTOTOP, realnightstime, nightsnum, col);
diff --git a/src/v_video.c b/src/v_video.c
index 93fefdd97f8241752d3d2035248d133e9183da54..7473001147bda0d95db5bcda274f42186655a21d 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -112,6 +112,7 @@ static CV_PossibleValue_t CV_MD2[] = {{0, "Off"}, {1, "On"}, {2, "Old"}, {0, NUL
 // console variables in development
 consvar_t cv_grmd2 = {"gr_md2", "Off", CV_SAVE, CV_MD2, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_grspritebillboarding = {"gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_grskydome = {"gr_skydome", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 #endif
 
 // local copy of the palette for V_GetColor()
diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c
index 71eda04371d4223dedcd5e193d8c27ed8cf0f70d..4ea792a250d353596a20dfb67b006b9ada06ad7f 100644
--- a/src/win32/win_dll.c
+++ b/src/win32/win_dll.c
@@ -102,6 +102,7 @@ static loadfunc_t hwdFuncTable[] = {
 	{"FinishUpdate@4",      &hwdriver.pfnFinishUpdate},
 	{"Draw2DLine@12",       &hwdriver.pfnDraw2DLine},
 	{"DrawPolygon@16",      &hwdriver.pfnDrawPolygon},
+	{"RenderSkyDome@16",    &hwdriver.pfnRenderSkyDome},
 	{"SetBlend@4",          &hwdriver.pfnSetBlend},
 	{"ClearBuffer@12",      &hwdriver.pfnClearBuffer},
 	{"SetTexture@4",        &hwdriver.pfnSetTexture},
@@ -133,6 +134,7 @@ static loadfunc_t hwdFuncTable[] = {
 	{"FinishUpdate",        &hwdriver.pfnFinishUpdate},
 	{"Draw2DLine",          &hwdriver.pfnDraw2DLine},
 	{"DrawPolygon",         &hwdriver.pfnDrawPolygon},
+	{"RenderSkyDome",       &hwdriver.pfnRenderSkyDome},
 	{"SetBlend",            &hwdriver.pfnSetBlend},
 	{"ClearBuffer",         &hwdriver.pfnClearBuffer},
 	{"SetTexture",          &hwdriver.pfnSetTexture},