diff --git a/src/d_player.h b/src/d_player.h
index b01edc8f583ccf7b15df41168ec53a43e3c5c186..465bbe3f735d30c490403461ff73eda9257fe7c2 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -43,7 +43,7 @@ typedef enum
 	SF_NOJUMPDAMAGE     = 1<<8, // Don't damage enemies, etc whilst jumping?
 	SF_STOMPDAMAGE      = 1<<9, // Always damage enemies, etc by landing on them, no matter your vunerability?
 	SF_MARIODAMAGE      = SF_NOJUMPDAMAGE|SF_STOMPDAMAGE, // The Mario method of being able to damage enemies, etc.
-	SF_NOMIDDLESTART    = 1<<10, // Some animations can randomly start you halfway through. Disable this?
+	SF_MACHINE          = 1<<10, // Beep boop. Are you a robot?
 } skinflags_t;
 
 //Primary and secondary skin abilities
diff --git a/src/dehacked.c b/src/dehacked.c
index fa9674a1e49e4bf90be6ee25fa20c84586726d14..d174aede1e3ab12c55b8ee8da0fdec6cb8f43371 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -5552,6 +5552,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 
 	"S_POP1", // Extra Large bubble goes POP!
 
+	"S_WATERZAP",
+
 	"S_FOG1",
 	"S_FOG2",
 	"S_FOG3",
@@ -5593,6 +5595,13 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_FOUR1",
 	"S_FIVE1",
 
+	"S_ZERO2",
+	"S_ONE2",
+	"S_TWO2",
+	"S_THREE2",
+	"S_FOUR2",
+	"S_FIVE2",
+
 	// Tag Sign
 	"S_TTAG1",
 
@@ -6501,6 +6510,7 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	"MT_SMALLBUBBLE", // small bubble
 	"MT_MEDIUMBUBBLE", // medium bubble
 	"MT_EXTRALARGEBUBBLE", // extra large bubble
+	"MT_WATERZAP",
 	"MT_TFOG",
 	"MT_SEED",
 	"MT_PARTICLE",
@@ -7146,7 +7156,7 @@ struct {
 	{"SF_NOJUMPDAMAGE",SF_NOJUMPDAMAGE},
 	{"SF_STOMPDAMAGE",SF_STOMPDAMAGE},
 	{"SF_MARIODAMAGE",SF_MARIODAMAGE},
-	{"SF_NOMIDDLESTART",SF_NOMIDDLESTART},
+	{"SF_MACHINE",SF_MACHINE},
 
 	// Character abilities!
 	// Primary
diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c
index a93e96dc3d3e27ea2497b0230c90812ad363744f..96f79f807196ac25e6ee1deaaba56295aecc17ca 100644
--- a/src/hardware/hw_light.c
+++ b/src/hardware/hw_light.c
@@ -387,6 +387,7 @@ light_t *t_lspr[NUMSPRITES] =
 	&lspr[NOLIGHT],     // SPR_BUBN
 	&lspr[NOLIGHT],     // SPR_BUBM
 	&lspr[NOLIGHT],     // SPR_POPP
+	&lspr[SUPERSPARK_L], // SPR_WZAP
 	&lspr[SUPERSPARK_L], // SPR_TFOG
 	&lspr[NIGHTSLIGHT_L],     // SPR_SEED // Sonic CD flower seed
 	&lspr[NOLIGHT],     // SPR_PRTL
diff --git a/src/info.c b/src/info.c
index a3130789513403a64fa6725d86e3bfac01cd0c79..2fa4d790ec904c549431418fabb1613bc7f04d23 100644
--- a/src/info.c
+++ b/src/info.c
@@ -45,15 +45,15 @@ char sprnames[NUMSPRITES + 1][5] =
 	"ELEM","FORC","PITY","IVSP","SSPK","GOAL","BIRD","BUNY","MOUS","CHIC",
 	"COWZ","RBRD","SPRY","SPRR","SPRB","YSPR","RSPR","SSWY","SSWR","SSWB",
 	"RAIN","SNO1","SPLH","SPLA","SMOK","BUBP","BUBO","BUBN","BUBM","POPP",
-	"TFOG","SEED","PRTL","SCOR","DRWN","TTAG","GFLG","RRNG","RNGB","RNGR",
-	"RNGI","RNGA","RNGE","RNGS","RNGG","PIKB","PIKR","PIKA","PIKE","PIKS",
-	"PIKG","TAUT","TGRE","TSCR","COIN","CPRK","GOOM","BGOM","FFWR","FBLL",
-	"SHLL","PUMA","HAMM","KOOP","BFLM","MAXE","MUS1","MUS2","TOAD","NDRN",
-	"SUPE","SUPZ","NDRL","NSPK","NBMP","HOOP","NSCR","NPRU","CAPS","SUPT",
-	"SPRK","BOM1","BOM2","BOM3","BOM4","ROIA","ROIB","ROIC","ROID","ROIE",
-	"ROIF","ROIG","ROIH","ROII","ROIJ","ROIK","ROIL","ROIM","ROIN","ROIO",
-	"ROIP","BBAL","GWLG","GWLR","SRBA","SRBB","SRBC","SRBD","SRBE","SRBF",
-	"SRBG","SRBH","SRBI","SRBJ","SRBK","SRBL","SRBM","SRBN","SRBO",
+	"WZAP","TFOG","SEED","PRTL","SCOR","DRWN","TTAG","GFLG","RRNG","RNGB",
+	"RNGR","RNGI","RNGA","RNGE","RNGS","RNGG","PIKB","PIKR","PIKA","PIKE",
+	"PIKS","PIKG","TAUT","TGRE","TSCR","COIN","CPRK","GOOM","BGOM","FFWR",
+	"FBLL","SHLL","PUMA","HAMM","KOOP","BFLM","MAXE","MUS1","MUS2","TOAD",
+	"NDRN","SUPE","SUPZ","NDRL","NSPK","NBMP","HOOP","NSCR","NPRU","CAPS",
+	"SUPT","SPRK","BOM1","BOM2","BOM3","BOM4","ROIA","ROIB","ROIC","ROID",
+	"ROIE","ROIF","ROIG","ROIH","ROII","ROIJ","ROIK","ROIL","ROIM","ROIN",
+	"ROIO","ROIP","BBAL","GWLG","GWLR","SRBA","SRBB","SRBC","SRBD","SRBE",
+	"SRBF","SRBG","SRBH","SRBI","SRBJ","SRBK","SRBL","SRBM","SRBN","SRBO",
 };
 
 char spr2names[NUMPLAYERSPRITES][5] =
@@ -1936,6 +1936,8 @@ state_t states[NUMSTATES] =
 	// Extra Large Bubble goes POP!
 	{SPR_POPP, 0, 16, {NULL}, 0, 0, S_NULL}, // S_POP1
 
+	{SPR_WZAP, FF_TRANS10|FF_ANIMATE|FF_MIDDLESTARTCHANCE, 4, {NULL}, 3, 2, S_NULL},  // S_WATERZAP
+
 	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50,    2, {NULL}, 0, 0, S_FOG2},  // S_FOG1
 	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|1,  2, {NULL}, 0, 0, S_FOG3},  // S_FOG2
 	{SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50|2,  2, {NULL}, 0, 0, S_FOG4},  // S_FOG3
@@ -1978,6 +1980,13 @@ state_t states[NUMSTATES] =
 	{SPR_DRWN, 4, 40, {NULL}, 0, 0, S_NULL}, // S_FOUR1
 	{SPR_DRWN, 5, 40, {NULL}, 0, 0, S_NULL}, // S_FIVE1
 
+	{SPR_DRWN,  6, 40, {NULL}, 0, 0, S_NULL}, // S_ZERO2
+	{SPR_DRWN,  7, 40, {NULL}, 0, 0, S_NULL}, // S_ONE2
+	{SPR_DRWN,  8, 40, {NULL}, 0, 0, S_NULL}, // S_TWO2
+	{SPR_DRWN,  9, 40, {NULL}, 0, 0, S_NULL}, // S_THREE2
+	{SPR_DRWN, 10, 40, {NULL}, 0, 0, S_NULL}, // S_FOUR2
+	{SPR_DRWN, 11, 40, {NULL}, 0, 0, S_NULL}, // S_FIVE2
+
 	{SPR_TTAG, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_TTAG1
 
 	// CTF Sign
@@ -10514,6 +10523,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
+	{           // MT_WATERZAP
+		-1,             // doomednum
+		S_WATERZAP,     // 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
+		8,              // speed
+		4*FRACUNIT,     // radius
+		4*FRACUNIT,     // height
+		0,              // display offset
+		16,             // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags
+		S_NULL          // raisestate
+	},
+
 	{           // MT_TFOG
 		-1,             // doomednum
 		S_FOG1,         // spawnstate
diff --git a/src/info.h b/src/info.h
index f5e2ce43339e0c5ae761b01213f231c38d0ae5a1..ccb223c6ce34deb44c8e523fac7e02a95171cb20 100644
--- a/src/info.h
+++ b/src/info.h
@@ -463,6 +463,7 @@ typedef enum sprite
 	SPR_BUBN, // Large bubble
 	SPR_BUBM, // Extra Large (would you like fries with that?) bubble
 	SPR_POPP, // Extra Large bubble goes POP!
+	SPR_WZAP,
 	SPR_TFOG, // Teleport Fog
 	SPR_SEED, // Sonic CD flower seed
 	SPR_PRTL, // Particle (for fans, etc.)
@@ -2434,6 +2435,8 @@ typedef enum state
 
 	S_POP1, // Extra Large bubble goes POP!
 
+	S_WATERZAP,
+
 	S_FOG1,
 	S_FOG2,
 	S_FOG3,
@@ -2475,6 +2478,13 @@ typedef enum state
 	S_FOUR1,
 	S_FIVE1,
 
+	S_ZERO2,
+	S_ONE2,
+	S_TWO2,
+	S_THREE2,
+	S_FOUR2,
+	S_FIVE2,
+
 	// Tag Sign
 	S_TTAG1,
 
@@ -3401,6 +3411,7 @@ typedef enum mobj_type
 	MT_SMALLBUBBLE, // small bubble
 	MT_MEDIUMBUBBLE, // medium bubble
 	MT_EXTRALARGEBUBBLE, // extra large bubble
+	MT_WATERZAP,
 	MT_TFOG,
 	MT_SEED,
 	MT_PARTICLE,
diff --git a/src/p_inter.c b/src/p_inter.c
index 76391705f902692efee0883c3139e7461d2b40cc..26cae304e960f629cb71aa82fd281d86773c91ac 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -2261,7 +2261,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
 			target->momx = target->momy = target->momz = 0;
 			if (damagetype == DMG_DROWNED) // drowned
 			{
-				S_StartSound(target, sfx_drown);
+				if (target->player->charflags & SF_MACHINE)
+					S_StartSound(target, sfx_fizzle);
+				else
+					S_StartSound(target, sfx_drown);
 				// Don't jump up when drowning
 			}
 			else
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 7740e5f28a4486066c5b61f0bf2601d953efc928..ad19d442340d4f965aa0a5d424a0ab54fdc5d0a3 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -489,7 +489,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
 			}
 			else if (mobj->sprite2 != spr2)
 			{
-				if ((st->frame & FF_MIDDLESTARTCHANCE) && !(player->charflags & SF_NOMIDDLESTART) && numframes && P_RandomChance(FRACUNIT/2))
+				if ((st->frame & FF_MIDDLESTARTCHANCE) && numframes && P_RandomChance(FRACUNIT/2))
 					frame = numframes/2;
 				else
 					frame = 0;
@@ -609,7 +609,7 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
 			}
 			else if (mobj->sprite2 != spr2)
 			{
-				if ((st->frame & FF_MIDDLESTARTCHANCE) && !(skin->flags & SF_NOMIDDLESTART) && numframes && P_RandomChance(FRACUNIT/2))
+				if ((st->frame & FF_MIDDLESTARTCHANCE) && numframes && P_RandomChance(FRACUNIT/2))
 					frame = numframes/2;
 				else
 					frame = 0;
diff --git a/src/p_user.c b/src/p_user.c
index 5a3d952a30f15337ae4f06c1be8c1543e95c9ec6..89d07e3d2ebd60faefc92b80912b97bb6bddae03 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -2018,9 +2018,15 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player)
 
 		mobj_t *numbermobj = P_SpawnMobj(player->mo->x, player->mo->y, height, MT_DROWNNUMBERS);
 
-		timeleft /= (2*TICRATE); // To be strictly accurate it'd need to be ((timeleft/TICRATE) - 1)/2, but integer division rounds down for us
+		timeleft /= (2*TICRATE); // To be strictly accurate it'd need to be (((timeleft - 1)/TICRATE) - 1)/2, but integer division rounds down for us
 
-		S_StartSound(player->mo, sfx_dwnind);
+		if (player->charflags & SF_MACHINE)
+		{
+			S_StartSound(player->mo, sfx_buzz1);
+			timeleft += 6;
+		}
+		else
+			S_StartSound(player->mo, sfx_dwnind);
 
 		if (timeleft) // Don't waste time setting the state if the time is 0.
 			P_SetMobjState(numbermobj, numbermobj->info->spawnstate+timeleft);
@@ -2059,11 +2065,9 @@ static void P_CheckUnderwaterAndSpaceTimer(player_t *player)
 	// Underwater audio cues
 	if (P_IsLocalPlayer(player) && !player->bot)
 	{
-		if (player->powers[pw_underwater] == 25*TICRATE + 1)
-			S_StartSound(NULL, sfx_wtrdng);
-		else if (player->powers[pw_underwater] == 20*TICRATE + 1)
-			S_StartSound(NULL, sfx_wtrdng);
-		else if (player->powers[pw_underwater] == 15*TICRATE + 1)
+		if ((player->powers[pw_underwater] == 25*TICRATE + 1)
+		|| (player->powers[pw_underwater] == 20*TICRATE + 1)
+		|| (player->powers[pw_underwater] == 15*TICRATE + 1))
 			S_StartSound(NULL, sfx_wtrdng);
 
 		if (player->powers[pw_underwater] == 11*TICRATE + 1
@@ -2141,21 +2145,39 @@ static void P_CheckInvincibilityTimer(player_t *player)
 //
 static void P_DoBubbleBreath(player_t *player)
 {
-	fixed_t zh;
+	fixed_t x = player->mo->x;
+	fixed_t y = player->mo->y;
+	fixed_t z = player->mo->z;
 	mobj_t *bubble = NULL;
 
-	if (player->mo->eflags & MFE_VERTICALFLIP)
-		zh = player->mo->z + player->mo->height - FixedDiv(player->mo->height,5*(FRACUNIT/4));
-	else
-		zh = player->mo->z + FixedDiv(player->mo->height,5*(FRACUNIT/4));
-
 	if (!(player->mo->eflags & MFE_UNDERWATER) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL && !(player->pflags & PF_NIGHTSMODE)) || player->spectator)
 		return;
 
-	if (P_RandomChance(FRACUNIT/16))
-		bubble = P_SpawnMobj(player->mo->x, player->mo->y, zh, MT_SMALLBUBBLE);
-	else if (P_RandomChance(3*FRACUNIT/256))
-		bubble = P_SpawnMobj(player->mo->x, player->mo->y, zh, MT_MEDIUMBUBBLE);
+	if (player->charflags & SF_MACHINE)
+	{
+		if (P_RandomChance((128-(player->powers[pw_underwater]/4))*FRACUNIT/256))
+		{
+			fixed_t rad = player->mo->radius>>FRACBITS;
+			x += (P_RandomRange(rad, -rad)<<FRACBITS);
+			y += (P_RandomRange(rad, -rad)<<FRACBITS);
+			z += (P_RandomKey(player->mo->height>>FRACBITS)<<FRACBITS);
+			bubble = P_SpawnMobj(x, y, z, MT_WATERZAP);
+			S_StartSound(bubble, sfx_beelec);
+		}
+	}
+	else
+	{
+		if (player->mo->eflags & MFE_VERTICALFLIP)
+			z += player->mo->height - FixedDiv(player->mo->height,5*(FRACUNIT/4));
+		else
+			z += FixedDiv(player->mo->height,5*(FRACUNIT/4));
+
+		if (P_RandomChance(FRACUNIT/16))
+			bubble = P_SpawnMobj(x, y, z, MT_SMALLBUBBLE);
+		else if (P_RandomChance(3*FRACUNIT/256))
+			bubble = P_SpawnMobj(x, y, z, MT_MEDIUMBUBBLE);
+	}
+
 	if (bubble)
 	{
 		bubble->threshold = 42;