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 bd3bad36247cd0d28d9f85f736b1a417794dc83c..8d240326d8f937349e8f4035d2a1346baf4954d5 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",
 
@@ -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",
@@ -6634,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",
@@ -7284,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",
@@ -7629,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
@@ -7798,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
@@ -8623,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/hardware/hw_light.c b/src/hardware/hw_light.c
index c76b1d2969beb3828050481b1a9707ef122d9a63..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
 
@@ -476,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/info.c b/src/info.c
index 17bd19e8a5c89fcfb4e9d12a411d25d851aa8429..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
@@ -271,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
 
@@ -370,6 +377,7 @@ char sprnames[NUMSPRITES + 1][5] =
 	"RAIN", // Rain
 	"SNO1", // Snowflake
 	"SPLH", // Water Splish
+	"LSPL", // Lava Splish
 	"SPLA", // Water Splash
 	"SMOK",
 	"BUBL", // Bubble
@@ -1185,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
 
@@ -2499,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
@@ -3246,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
@@ -3557,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
@@ -5039,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
@@ -12863,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
@@ -16728,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 024328be1fdacbb6115ad2e223761af99f0b1787..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
@@ -519,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
 
@@ -618,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
@@ -1334,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,
 
@@ -2610,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,
@@ -3350,6 +3404,9 @@ typedef enum state
 	S_SPLISH8,
 	S_SPLISH9,
 
+	// Lava Splish
+	S_LAVASPLISH,
+
 	// added water splash
 	S_SPLASH1,
 	S_SPLASH2,
@@ -4022,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,
@@ -4367,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
@@ -4536,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/p_enemy.c b/src/p_enemy.c
index 26b28b0c97e78f66aa60df4a6c982b2b7f44c38c..10251910e79210df9d16e3b045d99de05470c264 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
 
@@ -8413,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)
 {
@@ -8425,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
@@ -12202,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);
 	}
 }
 
@@ -14002,3 +14013,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 53b8c5906da8649fd9186f615369d535f648484a..d11fddcdadb3f4b6a924da25bed1e7bd4f36d3e4 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -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;
 	}
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 43e9d031931aeb97cb02847a5fe8e94a91a91575..ac5459fede9be39b1b2102cfa90276c76886c5b2 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -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;
@@ -882,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
@@ -918,6 +963,64 @@ static boolean PIT_CheckThing(mobj_t *thing)
 			return true;
 	}
 
+	if (thing->type == MT_ROLLOUTROCK && tmthing->player && tmthing->health)
+	{
+		if (tmthing->player->powers[pw_carry] == CR_ROLLOUT)
+		{
+			return true;
+		}
+		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))))
+		{
+			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 (thing->flags & MF_SPRING) // bounce on springs
+		{
+			P_DoSpring(thing, tmthing);
+			return true;
+		}
+		else if ((thing->flags & (MF_MONITOR|MF_SHOOTABLE)) == (MF_MONITOR|MF_SHOOTABLE) && !(tmthing->flags & MF_PUSHABLE)) // pop monitors while carrying a player
+		{
+			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 (thing->type == MT_PTERABYTE && tmthing->player)
+		P_DoPterabyteCarry(tmthing->player, thing);
+
 	if (thing->type == MT_TNTBARREL && tmthing->player)
 		P_PlayerBarrelCollide(tmthing, thing);
 
@@ -1965,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))
 				;
@@ -3480,6 +3583,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
@@ -3640,6 +3801,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 4e6684887286c3c33f22020315d0dbeab56f0886..7fa51111d357dcf26b0fe4d4b20a1e7e6f0cece7 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -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;
@@ -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;
 		}
@@ -3487,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);
 			}
@@ -3522,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);
 			}
@@ -3545,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!
 
@@ -4155,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)
@@ -7063,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
 //
@@ -9137,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)
@@ -9153,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:
@@ -9354,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)
 				{
@@ -9584,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:
@@ -10165,6 +10395,17 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 			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;
 	}
@@ -12211,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_user.c b/src/p_user.c
index a72a00a113c865cce69da2bac87af1d917ddb1b5..ff30778ee6eaa5145f03794343682b2bec451f77 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -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;
 
@@ -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;
@@ -7350,10 +7381,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 +8149,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)
@@ -11240,6 +11277,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 +11305,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 +11335,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 +11370,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 +11697,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 +12042,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/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,