From 1eb84f57c5f9035349b7df8f31dc5cb03795df7d Mon Sep 17 00:00:00 2001
From: toasterbabe <rollerorbital@gmail.com>
Date: Thu, 26 Apr 2018 20:18:51 +0100
Subject: [PATCH] * Billiards mines! With support for both above and below
 water, replacing both the below-and-above-water old mines at once. *
 Explosion executors. * Minor refactor of P_KillMobj.

---
 src/dehacked.c          |  30 +++---
 src/hardware/hw_light.c |   1 +
 src/info.c              | 101 ++++++++++----------
 src/info.h              |  31 +++---
 src/p_enemy.c           |  89 ++++++++++++++++-
 src/p_inter.c           | 207 +++++++++++++++-------------------------
 src/p_map.c             |  25 +++++
 src/p_mobj.c            |  40 ++------
 src/sounds.c            |   2 +-
 9 files changed, 279 insertions(+), 247 deletions(-)

diff --git a/src/dehacked.c b/src/dehacked.c
index 83e3177ff1..e5bafabad6 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -1811,6 +1811,8 @@ static actionpointer_t actionpointers[] =
 	{{A_FadeOverlay},          "A_FADEOVERLAY"},
 	{{A_Boss5Jump},            "A_BOSS5JUMP"},
 	{{A_LightBeamReset},       "A_LIGHTBEAMRESET"},
+	{{A_MineExplode},          "A_MINEEXPLODE"},
+	{{A_MineRange},            "A_MINERANGE"},
 
 	{{NULL},                   "NONE"},
 
@@ -4504,14 +4506,18 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_STARPOST_ENDSPIN",
 
 	// Big floating mine
-	"S_BIGMINE1",
-	"S_BIGMINE2",
-	"S_BIGMINE3",
-	"S_BIGMINE4",
-	"S_BIGMINE5",
-	"S_BIGMINE6",
-	"S_BIGMINE7",
-	"S_BIGMINE8",
+	"S_BIGMINE_IDLE",
+	"S_BIGMINE_ALERT1",
+	"S_BIGMINE_ALERT2",
+	"S_BIGMINE_ALERT3",
+	"S_BIGMINE_SET1",
+	"S_BIGMINE_SET2",
+	"S_BIGMINE_SET3",
+	"S_BIGMINE_BLAST1",
+	"S_BIGMINE_BLAST2",
+	"S_BIGMINE_BLAST3",
+	"S_BIGMINE_BLAST4",
+	"S_BIGMINE_BLAST5",
 
 	// Cannon Launcher
 	"S_CANNONLAUNCHER1",
@@ -4780,12 +4786,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_LIGHTBEAM10",
 	"S_LIGHTBEAM11",
 	"S_LIGHTBEAM12",
-	"S_LIGHTBEAM13",
-	"S_LIGHTBEAM14",
-	"S_LIGHTBEAM15",
-	"S_LIGHTBEAM16",
-	"S_LIGHTBEAM17",
-	"S_LIGHTBEAM18",
 
 	// CEZ Chain
 	"S_CEZCHAIN",
@@ -6111,7 +6111,7 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	"MT_WALLSPIKEBASE",
 	"MT_STARPOST",
 	"MT_BIGMINE",
-	"MT_BIGAIRMINE",
+	"MT_BLASTEXECUTOR",
 	"MT_CANNONLAUNCHER",
 
 	// Monitor miscellany
diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c
index 267666749b..0496e64237 100644
--- a/src/hardware/hw_light.c
+++ b/src/hardware/hw_light.c
@@ -246,6 +246,7 @@ light_t *t_lspr[NUMSPRITES] =
 	&lspr[NOLIGHT],     // SPR_WSPB
 	&lspr[NOLIGHT],     // SPR_STPT
 	&lspr[NOLIGHT],     // SPR_BMNE
+	&lspr[REDBALL_L],   // SPR_BMNB
 
 	// Monitor Boxes
 	&lspr[NOLIGHT],     // SPR_MSTV
diff --git a/src/info.c b/src/info.c
index 9fe41090a0..1805c555be 100644
--- a/src/info.c
+++ b/src/info.c
@@ -134,6 +134,7 @@ char sprnames[NUMSPRITES + 1][5] =
 	"WSPB", // Wall spike base
 	"STPT", // Starpost
 	"BMNE", // Big floating mine
+	"BMNB",
 
 	// Monitor Boxes
 	"MSTV", // MiSc TV sprites
@@ -1717,14 +1718,18 @@ state_t states[NUMSTATES] =
 	{SPR_STPT, FF_ANIMATE|15,  2, {NULL},  1, 1, S_STARPOST_FLASH}, // S_STARPOST_ENDSPIN
 
 	// Big floating mine
-	{SPR_BMNE, 0, 5, {NULL}, 0, 0, S_BIGMINE2},    // S_BIGMINE1
-	{SPR_BMNE, 1, 5, {NULL}, 0, 0, S_BIGMINE3},    // S_BIGMINE2
-	{SPR_BMNE, 2, 5, {NULL}, 0, 0, S_BIGMINE4},    // S_BIGMINE3
-	{SPR_BMNE, 3, 5, {NULL}, 0, 0, S_BIGMINE5},    // S_BIGMINE4
-	{SPR_BMNE, 4, 5, {NULL}, 0, 0, S_BIGMINE6},    // S_BIGMINE5
-	{SPR_BMNE, 5, 5, {NULL}, 0, 0, S_BIGMINE7},    // S_BIGMINE6
-	{SPR_BMNE, 6, 5, {NULL}, 0, 0, S_BIGMINE8},    // S_BIGMINE7
-	{SPR_BMNE, 7, 5, {NULL}, 0, 0, S_BIGMINE1},    // S_BIGMINE8
+	{SPR_BMNE, 0,  2, {A_Look},      ((224<<FRACBITS)|1), 0, S_BIGMINE_IDLE},   // S_BIGMINE_IDLE
+	{SPR_BMNE, 1,  2, {A_MineRange}, 112,                 0, S_BIGMINE_ALERT2}, // S_BIGMINE_ALERT1
+	{SPR_BMNE, 2,  2, {A_MineRange}, 112,                 0, S_BIGMINE_ALERT3}, // S_BIGMINE_ALERT2
+	{SPR_BMNE, 0,  1, {A_Look},      ((224<<FRACBITS)|1), 1, S_BIGMINE_IDLE},   // S_BIGMINE_ALERT3
+	{SPR_BMNE, 3, 25, {A_Pain},           0,            0, S_BIGMINE_SET2},   // S_BIGMINE_SET1
+	{SPR_BMNE, 3, 10, {A_SetObjectFlags}, MF_SHOOTABLE, 1, S_BIGMINE_SET3},   // S_BIGMINE_SET1
+	{SPR_BMNE, 3,  1, {A_MineExplode},    0,            0, S_BIGMINE_BLAST1}, // S_BIGMINE_SET3
+	{SPR_BMNB,   FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BIGMINE_BLAST2}, // S_BIGMINE_BLAST1
+	{SPR_BMNB, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BIGMINE_BLAST3}, // S_BIGMINE_BLAST2
+	{SPR_BMNB, 2|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BIGMINE_BLAST4}, // S_BIGMINE_BLAST3
+	{SPR_BMNB, 3|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BIGMINE_BLAST5}, // S_BIGMINE_BLAST4
+	{SPR_NULL, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BIGMINE_BLAST5
 
 	// Cannon launcher
 	{SPR_NULL, 0, 1,    {A_FindTarget},     MT_PLAYER,         0, S_CANNONLAUNCHER2}, // S_CANNONLAUNCHER1
@@ -1980,24 +1985,18 @@ state_t states[NUMSTATES] =
 	{SPR_DSTG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_DSZ2STALAGMITE
 
 	// DSZ Light beam
-	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightBeamReset}, 0, 0, S_LIGHTBEAM2}, // S_LIGHTBEAM1
-	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM3}, // S_LIGHTBEAM2
-	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM4}, // S_LIGHTBEAM3
-	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM5}, // S_LIGHTBEAM4
-	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM6}, // S_LIGHTBEAM5
-	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM7}, // S_LIGHTBEAM6
-	{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM8}, // S_LIGHTBEAM7
-	{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM9}, // S_LIGHTBEAM8
-	{SPR_LIBE, 0|FF_TRANS30|FF_FULLBRIGHT|FF_PAPERSPRITE, 9, {NULL}, 0, 0, S_LIGHTBEAM10}, // S_LIGHTBEAM9
-	{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM11}, // S_LIGHTBEAM10
-	{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM12}, // S_LIGHTBEAM11
-	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM13}, // S_LIGHTBEAM12
-	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM14}, // S_LIGHTBEAM13
-	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM15}, // S_LIGHTBEAM14
-	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM16}, // S_LIGHTBEAM15
-	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM17}, // S_LIGHTBEAM16
-	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM18}, // S_LIGHTBEAM17
-	{SPR_NULL, 0, 2, {A_SetRandomTics}, 4, 35, S_LIGHTBEAM1}, // S_LIGHTBEAM18
+	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {A_LightBeamReset}, 0, 0, S_LIGHTBEAM2}, // S_LIGHTBEAM1
+	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM3},  // S_LIGHTBEAM2
+	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM4},  // S_LIGHTBEAM3
+	{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM5},  // S_LIGHTBEAM4
+	{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM6},  // S_LIGHTBEAM5
+	{SPR_LIBE, 0|FF_TRANS30|FF_FULLBRIGHT|FF_PAPERSPRITE, 9, {NULL}, 0, 0, S_LIGHTBEAM7},  // S_LIGHTBEAM6
+	{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM8},  // S_LIGHTBEAM7
+	{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM9},  // S_LIGHTBEAM8
+	{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM10}, // S_LIGHTBEAM9
+	{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM11}, // S_LIGHTBEAM10
+	{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM12}, // S_LIGHTBEAM11
+	{SPR_NULL, 0, 2, {A_SetRandomTics}, 4, 35, S_LIGHTBEAM1}, // S_LIGHTBEAM12
 
 	// CEZ Chain
 	{SPR_CHAN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZCHAIN
@@ -6348,55 +6347,55 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 
 	{           // MT_BIGMINE
 		524,            // doomednum
-		S_BIGMINE1,     // spawnstate
+		S_BIGMINE_IDLE, // spawnstate
 		1,              // spawnhealth
-		S_NULL,         // seestate
-		sfx_None,       // seesound
+		S_BIGMINE_ALERT1, // seestate
+		sfx_s3k5c,      // seesound
 		8,              // reactiontime
 		sfx_None,       // attacksound
 		S_NULL,         // painstate
-		TICRATE,        // painchance
-		sfx_None,       // painsound
-		S_NULL,         // meleestate
+		0,              // painchance
+		sfx_s3k86,      // painsound
+		S_BIGMINE_SET1, // meleestate
 		S_NULL,         // missilestate
-		S_NULL,         // deathstate
+		S_BIGMINE_SET2, // deathstate
 		S_NULL,         // xdeathstate
 		sfx_None,       // deathsound
 		2*FRACUNIT,     // speed
-		16*FRACUNIT,    // radius
-		32*FRACUNIT,    // height
+		28*FRACUNIT,    // radius
+		56*FRACUNIT,    // height
 		0,              // display offset
 		MT_UWEXPLODE,   // mass
-		64*FRACUNIT,    // damage
-		sfx_gbeep,      // activesound
-		MF_SPECIAL|MF_NOGRAVITY,     // flags
+		0,              // damage
+		sfx_s3k9e,      // activesound
+		MF_SPECIAL|MF_NOGRAVITY|MF_SHOOTABLE|MF_ENEMY, // flags
 		S_NULL          // raisestate
 	},
 
-	{           // MT_BIGAIRMINE
-		527,            // doomednum
-		S_BIGMINE1,     // spawnstate
+	{           // MT_BLASTEXECUTOR
+		1505,           // doomednum
+		S_INVISIBLE,    // spawnstate
 		1,              // spawnhealth
 		S_NULL,         // seestate
 		sfx_None,       // seesound
 		8,              // reactiontime
 		sfx_None,       // attacksound
 		S_NULL,         // painstate
-		TICRATE,        // painchance
+		0,              // painchance
 		sfx_None,       // painsound
 		S_NULL,         // meleestate
 		S_NULL,         // missilestate
 		S_NULL,         // deathstate
 		S_NULL,         // xdeathstate
-		sfx_bexpld,     // deathsound
-		2*FRACUNIT,     // speed
-		16*FRACUNIT,    // radius
-		32*FRACUNIT,    // height
+		sfx_None,       // deathsound
+		8,              // speed
+		32*FRACUNIT,    // radius
+		16*FRACUNIT,    // height
 		0,              // display offset
-		MT_BOSSEXPLODE, // mass
-		64*FRACUNIT,    // damage
-		sfx_gbeep,      // activesound
-		MF_SPECIAL|MF_NOGRAVITY,     // flags
+		4,              // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_SHOOTABLE|MF_NOGRAVITY|MF_NOCLIPTHING, // flags
 		S_NULL          // raisestate
 	},
 
@@ -15512,7 +15511,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		100,            // mass
 		0,              // damage
 		sfx_None,       // activesound
-		MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags
+		MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
 		S_NULL          // raisestate
 	},
 
diff --git a/src/info.h b/src/info.h
index 60fc12e0fa..dad067a234 100644
--- a/src/info.h
+++ b/src/info.h
@@ -219,6 +219,8 @@ void A_FlameParticle();
 void A_FadeOverlay();
 void A_Boss5Jump();
 void A_LightBeamReset();
+void A_MineExplode();
+void A_MineRange();
 
 // ratio of states to sprites to mobj types is roughly 6 : 1 : 1
 #define NUMMOBJFREESLOTS 256
@@ -334,6 +336,7 @@ typedef enum sprite
 	SPR_WSPB, // Wall spike base
 	SPR_STPT, // Starpost
 	SPR_BMNE, // Big floating mine
+	SPR_BMNB,
 
 	// Monitor Boxes
 	SPR_MSTV, // MiSc TV sprites
@@ -1822,14 +1825,18 @@ typedef enum state
 	S_STARPOST_ENDSPIN,
 
 	// Big floating mine
-	S_BIGMINE1,
-	S_BIGMINE2,
-	S_BIGMINE3,
-	S_BIGMINE4,
-	S_BIGMINE5,
-	S_BIGMINE6,
-	S_BIGMINE7,
-	S_BIGMINE8,
+	S_BIGMINE_IDLE,
+	S_BIGMINE_ALERT1,
+	S_BIGMINE_ALERT2,
+	S_BIGMINE_ALERT3,
+	S_BIGMINE_SET1,
+	S_BIGMINE_SET2,
+	S_BIGMINE_SET3,
+	S_BIGMINE_BLAST1,
+	S_BIGMINE_BLAST2,
+	S_BIGMINE_BLAST3,
+	S_BIGMINE_BLAST4,
+	S_BIGMINE_BLAST5,
 
 	// Cannon Launcher
 	S_CANNONLAUNCHER1,
@@ -2100,12 +2107,6 @@ typedef enum state
 	S_LIGHTBEAM10,
 	S_LIGHTBEAM11,
 	S_LIGHTBEAM12,
-	S_LIGHTBEAM13,
-	S_LIGHTBEAM14,
-	S_LIGHTBEAM15,
-	S_LIGHTBEAM16,
-	S_LIGHTBEAM17,
-	S_LIGHTBEAM18,
 
 	// CEZ Chain
 	S_CEZCHAIN,
@@ -3451,7 +3452,7 @@ typedef enum mobj_type
 	MT_WALLSPIKEBASE,
 	MT_STARPOST,
 	MT_BIGMINE,
-	MT_BIGAIRMINE,
+	MT_BLASTEXECUTOR,
 	MT_CANNONLAUNCHER,
 
 	// Monitor miscellany
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 44b9560606..cc1d14a9b4 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -247,6 +247,8 @@ void A_FlameParticle(mobj_t *actor);
 void A_FadeOverlay(mobj_t *actor);
 void A_Boss5Jump(mobj_t *actor);
 void A_LightBeamReset(mobj_t *actor);
+void A_MineExplode(mobj_t *actor);
+void A_MineRange(mobj_t *actor);
 
 //
 // ENEMY THINKING
@@ -10615,8 +10617,9 @@ void A_Boss5Jump(mobj_t *actor)
 		actor->z++;
 
 	// Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle.
-	actor->momx = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINECOSINE(actor->angle >> ANGLETOFINESHIFT));
-	actor->momy = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINESINE(actor->angle >> ANGLETOFINESHIFT));
+	fixedHypotenuse = FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)); // variable reuse
+	actor->momx = FixedMul(fixedHypotenuse, FINECOSINE(actor->angle >> ANGLETOFINESHIFT));
+	actor->momy = FixedMul(fixedHypotenuse, FINESINE(actor->angle >> ANGLETOFINESHIFT));
 	// Then the vertical axis. No angle-correction needed here.
 	actor->momz = FixedMul(v, FINESINE(theta >> ANGLETOFINESHIFT));
 	// I hope that's all that's needed, ugh
@@ -10630,6 +10633,9 @@ void A_Boss5Jump(mobj_t *actor)
 //
 void A_LightBeamReset(mobj_t *actor)
 {
+	// INT32 locvar1 = var1;
+	// INT32 locvar2 = var2;
+
 #ifdef HAVE_BLUA
 	if (LUA_CallAction("A_LightBeamReset", actor))
 		return;
@@ -10651,3 +10657,82 @@ void A_LightBeamReset(mobj_t *actor)
 	actor->z = actor->spawnpoint->z*FRACUNIT + P_SignedRandom()*FRACUNIT/2;
 	P_SetThingPosition(actor);
 }
+
+// Function: A_MineExplode
+// Description: Handles the explosion of a DSZ mine.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_MineExplode(mobj_t *actor)
+{
+	// INT32 locvar1 = var1;
+	// INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MineExplode", actor))
+		return;
+#endif
+
+	A_Scream(actor);
+	actor->flags = MF_NOGRAVITY|MF_NOCLIP;
+
+	quake.epicenter = NULL;
+	quake.radius = 512*FRACUNIT;
+	quake.intensity = 8*FRACUNIT;
+	quake.time = TICRATE/3;
+
+	P_RadiusAttack(actor, actor->tracer, 192*FRACUNIT);
+	P_MobjCheckWater(actor);
+
+	{
+#define dist 64
+		UINT8 i;
+		mobjtype_t type = ((actor->eflags & MFE_UNDERWATER) ? MT_UWEXPLODE : MT_BOSSEXPLODE);
+		S_StartSound(actor, ((actor->eflags & MFE_UNDERWATER) ? sfx_s3k57 : sfx_s3k4e));
+		P_SpawnMobj(actor->x, actor->y, actor->z, type);
+		for (i = 0; i < 16; i++)
+		{
+			mobj_t *b = P_SpawnMobj(actor->x+P_RandomRange(-dist, dist)*FRACUNIT,
+				actor->y+P_RandomRange(-dist, dist)*FRACUNIT,
+				actor->z+P_RandomRange(((actor->eflags & MFE_UNDERWATER) ? -dist : 0), dist)*FRACUNIT,
+				type);
+			fixed_t dx = b->x - actor->x, dy = b->y - actor->y, dz = b->z - actor->z;
+			fixed_t dm = P_AproxDistance(dz, P_AproxDistance(dy, dx));
+			b->momx = FixedDiv(dx, dm)*3;
+			b->momy = FixedDiv(dy, dm)*3;
+			b->momz = FixedDiv(dz, dm)*3;
+			if ((actor->watertop == INT32_MAX) || (b->z + b->height > actor->watertop))
+				b->flags &= ~MF_NOGRAVITY;
+		}
+#undef dist
+
+		if (actor->watertop != INT32_MAX)
+			P_SpawnMobj(actor->x, actor->y, actor->watertop, MT_SPLISH);
+	}
+}
+
+// Function: A_MineRange
+// Description: If the target gets too close, change the state to meleestate.
+//
+// var1 = Distance to alert at
+// var2 = unused
+//
+void A_MineRange(mobj_t *actor)
+{
+	fixed_t dm;
+	INT32 locvar1 = var1;
+	// INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_MineRange", actor))
+		return;
+#endif
+
+	if (!actor->target)
+		return;
+
+	dm = P_AproxDistance(actor->z - actor->target->z, P_AproxDistance(actor->y - actor->target->y, actor->x - actor->target->x));
+	if ((dm>>FRACBITS) < locvar1)
+		P_SetMobjState(actor, actor->info->meleestate);
+}
diff --git a/src/p_inter.c b/src/p_inter.c
index 7892e0bcfa..5de8b7fd37 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -412,7 +412,22 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 		////////////////////////////////////////////////////////
 		/////ENEMIES!!//////////////////////////////////////////
 		////////////////////////////////////////////////////////
-		if (special->type == MT_GSNAPPER && !(((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING))
+		if (special->type == MT_BIGMINE)
+		{
+			special->momx = toucher->momx/3;
+			special->momy = toucher->momy/3;
+			special->momz = toucher->momz/3;
+			toucher->momx /= -8;
+			toucher->momy /= -8;
+			toucher->momz /= -8;
+			special->flags &= ~MF_SPECIAL;
+			if (special->info->activesound)
+				S_StartSound(special, special->info->activesound);
+			P_SetTarget(&special->tracer, toucher);
+			player->homing = 0;
+			return;
+		}
+		else if (special->type == MT_GSNAPPER && !(((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING))
 		|| player->powers[pw_invulnerability] || player->powers[pw_super] || elementalpierce)
 		&& toucher->z < special->z + special->height && toucher->z + toucher->height > special->z
 		&& !(player->powers[pw_shield] & SH_PROTECTSPIKE))
@@ -1529,14 +1544,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			// Can't jump first frame
 			player->pflags |= PF_JUMPSTASIS;
 
-			return;
-		case MT_BIGMINE:
-		case MT_BIGAIRMINE:
-			// Spawn explosion!
-			P_SpawnMobj(special->x, special->y, special->z, special->info->mass);
-			P_RadiusAttack(special, special, special->info->damage);
-			S_StartSound(special, special->info->deathsound);
-			P_SetMobjState(special, special->info->deathstate);
 			return;
 		case MT_SPECIALSPIKEBALL:
 			if (!useNightsSS && G_IsSpecialStage(gamemap)) // Only for old special stages
@@ -2349,78 +2356,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 	if (source && target && target->player && source->player)
 		P_PlayVictorySound(source); // Killer laughs at you. LAUGHS! BWAHAHAHA!
 
-#ifdef OLDANIMALSPAWNING
-	// Drop stuff.
-	// This determines the kind of object spawned
-	// during the death frame of a thing.
-	if (!mariomode // Don't show birds, etc. in Mario Mode Tails 12-23-2001
-	&& target->flags & MF_ENEMY)
-	{
-		mobjtype_t item;
-		INT32 prandom;
-
-		switch (target->type)
-		{
-			case MT_REDCRAWLA:
-			case MT_GOLDBUZZ:
-			case MT_SKIM:
-			case MT_UNIDUS:
-				item = MT_FLICKY_02/*MT_BUNNY*/;
-				break;
-
-			case MT_BLUECRAWLA:
-			case MT_JETTBOMBER:
-			case MT_GFZFISH:
-				item = MT_FLICKY_01/*MT_BIRD*/;
-				break;
-
-			case MT_JETTGUNNER:
-			case MT_CRAWLACOMMANDER:
-			case MT_REDBUZZ:
-			case MT_DETON:
-				item = MT_FLICKY_12/*MT_MOUSE*/;
-				break;
-
-			case MT_GSNAPPER:
-			case MT_EGGGUARD:
-			case MT_SPRINGSHELL:
-				item = MT_FLICKY_11/*MT_COW*/;
-				break;
-
-			case MT_MINUS:
-			case MT_VULTURE:
-			case MT_POINTY:
-			case MT_YELLOWSHELL:
-				item = MT_FLICKY_03/*MT_CHICKEN*/;
-				break;
-
-			case MT_AQUABUZZ:
-				item = MT_FLICKY_01/*MT_REDBIRD*/;
-				break;
-
-			default:
-				if (target->info->doomednum)
-					prandom = target->info->doomednum%5; // "Random" animal for new enemies.
-				else
-					prandom = P_RandomKey(5); // No placable object, just use a random number.
-
-				switch(prandom)
-				{
-					default: item = MT_FLICKY_02/*MT_BUNNY*/; break;
-					case 1: item = MT_FLICKY_01/*MT_BIRD*/; break;
-					case 2: item = MT_FLICKY_12/*MT_MOUSE*/; break;
-					case 3: item = MT_FLICKY_11/*MT_COW*/; break;
-					case 4: item = MT_FLICKY_03/*MT_CHICKEN*/; break;
-				}
-				break;
-		}
-
-		mo = P_SpawnMobj(target->x, target->y, target->z + (target->height / 2) - FixedMul(mobjinfo[item].height / 2, target->scale), item);
-		mo->destscale = target->scale;
-		P_SetScale(mo, mo->destscale);
-	}
-	else
-#endif
 	// Other death animation effects
 	switch(target->type)
 	{
@@ -2434,6 +2369,64 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 			target->fuse = target->info->damage;
 			break;
 
+		case MT_AQUABUZZ:
+			if (inflictor && inflictor->player // did a player kill you? Spawn relative to the player so they're bound to get it
+			&& P_AproxDistance(inflictor->x - target->x, inflictor->y - target->y) <= inflictor->radius + target->radius + FixedMul(8*FRACUNIT, inflictor->scale) // close enough?
+			&& inflictor->z <= target->z + target->height + FixedMul(8*FRACUNIT, inflictor->scale)
+			&& inflictor->z + inflictor->height >= target->z - FixedMul(8*FRACUNIT, inflictor->scale))
+				mo = P_SpawnMobj(inflictor->x + inflictor->momx, inflictor->y + inflictor->momy, inflictor->z + (inflictor->height / 2) + inflictor->momz, MT_EXTRALARGEBUBBLE);
+			else
+				mo = P_SpawnMobj(target->x, target->y, target->z, MT_EXTRALARGEBUBBLE);
+			mo->destscale = target->scale;
+			P_SetScale(mo, mo->destscale);
+			break;
+
+		case MT_YELLOWSHELL:
+			P_SpawnMobjFromMobj(target, 0, 0, 0, MT_YELLOWSPRING);
+			break;
+
+		case MT_EGGMOBILE3:
+			{
+				thinker_t *th;
+				UINT32 i = 0; // to check how many clones we've removed
+
+				// scan the thinkers to make sure all the old pinch dummies are gone on death
+				// this can happen if the boss was hurt earlier than expected
+				for (th = thinkercap.next; th != &thinkercap; th = th->next)
+				{
+					if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+						continue;
+
+					mo = (mobj_t *)th;
+					if (mo->type == (mobjtype_t)target->info->mass && mo->tracer == target)
+					{
+						P_RemoveMobj(mo);
+						i++;
+					}
+					if (i == 2) // we've already removed 2 of these, let's stop now
+						break;
+				}
+			}
+			break;
+
+		case MT_BIGMINE:
+			if (inflictor)
+			{
+				fixed_t dx = target->x - inflictor->x, dy = target->y - inflictor->y, dz = target->z - inflictor->z;
+				fixed_t dm = FixedHypot(dz, FixedHypot(dy, dx));
+				target->momx = FixedDiv(FixedDiv(dx, dm), dm)*512;
+				target->momy = FixedDiv(FixedDiv(dy, dm), dm)*512;
+				target->momz = FixedDiv(FixedDiv(dz, dm), dm)*512;
+			}
+			if (source)
+				P_SetTarget(&target->tracer, source);
+			break;
+
+		case MT_BLASTEXECUTOR:
+			if (target->spawnpoint)
+				P_LinedefExecute(target->spawnpoint->angle, (source ? source : inflictor), target->subsector->sector);
+			break;
+
 		case MT_EGGTRAP:
 			// Time for birdies! Yaaaaaaaay!
 			target->fuse = TICRATE*2;
@@ -2467,57 +2460,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 			break;
 	}
 
-	// Enemy drops that ALWAYS occur regardless of mode
-	if (target->type == MT_AQUABUZZ) // Additionally spawns breathable bubble for players to get
-	{
-		if (inflictor && inflictor->player // did a player kill you? Spawn relative to the player so he's bound to get it
-		&& P_AproxDistance(inflictor->x - target->x, inflictor->y - target->y) <= inflictor->radius + target->radius + FixedMul(8*FRACUNIT, inflictor->scale) // close enough?
-		&& inflictor->z <= target->z + target->height + FixedMul(8*FRACUNIT, inflictor->scale)
-		&& inflictor->z + inflictor->height >= target->z - FixedMul(8*FRACUNIT, inflictor->scale))
-			mo = P_SpawnMobj(inflictor->x + inflictor->momx, inflictor->y + inflictor->momy, inflictor->z + (inflictor->height / 2) + inflictor->momz, MT_EXTRALARGEBUBBLE);
-		else
-			mo = P_SpawnMobj(target->x, target->y, target->z, MT_EXTRALARGEBUBBLE);
-		mo->destscale = target->scale;
-		P_SetScale(mo, mo->destscale);
-	}
-	else if (target->type == MT_YELLOWSHELL) // Spawns a spring that falls to the ground
-	{
-		mobjtype_t spawnspring = MT_YELLOWSPRING;
-		fixed_t spawnheight = target->z;
-		if (!(target->eflags & MFE_VERTICALFLIP))
-			spawnheight += target->height;
-
-		mo = P_SpawnMobj(target->x, target->y, spawnheight, spawnspring);
-		mo->destscale = target->scale;
-		P_SetScale(mo, mo->destscale);
-
-		if (target->flags2 & MF2_OBJECTFLIP)
-			mo->flags2 |= MF2_OBJECTFLIP;
-	}
-
-	if (target->type == MT_EGGMOBILE3)
-	{
-		thinker_t *th;
-		UINT32 i = 0; // to check how many clones we've removed
-
-		// scan the thinkers to make sure all the old pinch dummies are gone on death
-		// this can happen if the boss was hurt earlier than expected
-		for (th = thinkercap.next; th != &thinkercap; th = th->next)
-		{
-			if (th->function.acp1 != (actionf_p1)P_MobjThinker)
-				continue;
-
-			mo = (mobj_t *)th;
-			if (mo->type == (mobjtype_t)target->info->mass && mo->tracer == target)
-			{
-				P_RemoveMobj(mo);
-				i++;
-			}
-			if (i == 2) // we've already removed 2 of these, let's stop now
-				break;
-		}
-	}
-
+	// Final state setting - do something instead of P_SetMobjState;
 	if (target->type == MT_SPIKE && target->info->deathstate != S_NULL)
 	{
 		const angle_t ang = ((inflictor) ? inflictor->angle : 0) + ANGLE_90;
diff --git a/src/p_map.c b/src/p_map.c
index 6d17605965..3715e765bd 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -622,6 +622,31 @@ static boolean PIT_CheckThing(mobj_t *thing)
 	}
 #endif
 
+	// Billiards mines!
+	if (thing->type == MT_BIGMINE && tmthing->type == MT_BIGMINE)
+	{
+		if (!tmthing->momx && !tmthing->momy)
+			return true;
+		if ((statenum_t)(thing->state-states) != thing->info->spawnstate)
+			return true;
+		if (thing->z > tmthing->z + tmthing->height)
+			return true; // overhead
+		if (thing->z + thing->height < tmthing->z)
+			return true; // underneath
+
+		thing->momx = tmthing->momx/3;
+		thing->momy = tmthing->momy/3;
+		thing->momz = tmthing->momz/3;
+		tmthing->momx /= -8;
+		tmthing->momy /= -8;
+		tmthing->momz /= -8;
+		if (thing->info->activesound)
+			S_StartSound(thing, thing->info->activesound);
+		P_SetMobjState(thing, thing->info->meleestate);
+		P_SetTarget(&thing->tracer, tmthing->tracer);
+		return true;
+	}
+
 	// When solid spikes move, assume they just popped up and teleport things on top of them to hurt.
 	if (tmthing->type == MT_SPIKE && tmthing->flags & MF_SOLID)
 	{
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 185a483408..45e1434d25 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -7379,9 +7379,7 @@ void P_MobjThinker(mobj_t *mobj)
 			}
 			break;
 		case MT_AQUABUZZ:
-			P_MobjCheckWater(mobj); // solely for MFE_UNDERWATER for A_FlickySpawn
-			/* FALLTHRU */
-		case MT_BIGAIRMINE:
+			mobj->eflags |= MFE_UNDERWATER; //P_MobjCheckWater(mobj); // solely for MFE_UNDERWATER for A_FlickySpawn
 			{
 				if (mobj->tracer && mobj->tracer->player && mobj->tracer->health > 0
 					&& P_AproxDistance(P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y), mobj->tracer->z - mobj->z) <= mobj->radius * 16)
@@ -7406,34 +7404,11 @@ void P_MobjThinker(mobj_t *mobj)
 			}
 			break;
 		case MT_BIGMINE:
-			{
-				if (mobj->tracer && mobj->tracer->player && mobj->tracer->health > 0
-					&& P_AproxDistance(P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y), mobj->tracer->z - mobj->z) <= mobj->radius * 16)
-				{
-					P_MobjCheckWater(mobj);
-
-					// Home in on the target.
-					P_HomingAttack(mobj, mobj->tracer);
-
-					// Don't let it go out of water
-					if (mobj->z + mobj->height > mobj->watertop)
-						mobj->z = mobj->watertop - mobj->height;
-
-					if (mobj->z < mobj->floorz)
-						mobj->z = mobj->floorz;
-
-					if (leveltime % mobj->info->painchance == 0)
-						S_StartSound(mobj, mobj->info->activesound);
-				}
-				else
-				{
-					// Try to find a player
-					P_LookForPlayers(mobj, true, true, mobj->radius * 16);
-					mobj->momx >>= 1;
-					mobj->momy >>= 1;
-					mobj->momz >>= 1;
-				}
-			}
+			mobj->extravalue1 += 3;
+			mobj->extravalue1 %= 360;
+			P_UnsetThingPosition(mobj);
+			mobj->z += FINESINE(mobj->extravalue1*(FINEMASK+1)/360);
+			P_SetThingPosition(mobj);
 			break;
 		case MT_EGGCAPSULE:
 			if (!mobj->reactiontime)
@@ -8496,6 +8471,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 			}
 			break;
 		}
+		case MT_BIGMINE:
+			mobj->extravalue1 = FixedHypot(mobj->x, mobj->y)>>FRACBITS;
+			break;
 		case MT_EGGMOBILE2:
 			// Special condition for the 2nd boss.
 			mobj->watertop = mobj->info->speed;
diff --git a/src/sounds.c b/src/sounds.c
index 293ce381d4..3a7219c6d5 100644
--- a/src/sounds.c
+++ b/src/sounds.c
@@ -310,7 +310,7 @@ sfxinfo_t S_sfx[NUMSFX] =
   {"s3k54",  false,  64, 64, -1, NULL, 0,        -1,  -1, LUMPERROR, "Firing"}, // MetalSonic shot fire
   {"s3k55",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Mechanical movement"},
   {"s3k56",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Heavy landing"},
-  {"s3k57",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Splash"},
+  {"s3k57",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Burst"},
   {"s3k58",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Mechanical movement"},
   {"s3k59",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Crumbling"},
   {"s3k5a",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Aiming"},
-- 
GitLab