From ec1712064c9c45eafb2b6f3a1818b83b05bf1971 Mon Sep 17 00:00:00 2001
From: toaster <rollerorbital@gmail.com>
Date: Thu, 26 Sep 2019 17:06:29 +0100
Subject: [PATCH] * Add vwre vwre intro for Fang Clone Fighter battle. (Still
 skipped with presence of MTF_AMBUSH) *
 https://cdn.discordapp.com/attachments/428262628893261828/626792815451701259/srb20006.gif
 * Add fadeout instead of slapstick for Fang Clone Fighter death. * Allow
 placed Fang and Metal Sonic objects to be marked as Clone Fighters always
 through presence of MTF_EXTRA.

---
 src/dehacked.c          |  17 +++++++
 src/hardware/hw_light.c |  16 +++---
 src/info.c              | 106 ++++++++++++++++++++++++++++++++++++++--
 src/info.h              |  19 +++++++
 src/p_enemy.c           |  51 +++++++++++++++++--
 src/p_mobj.c            |  54 +++++++++++++++++++-
 src/sounds.c            |   1 +
 src/sounds.h            |   1 +
 8 files changed, 248 insertions(+), 17 deletions(-)

diff --git a/src/dehacked.c b/src/dehacked.c
index dcce68404..a6019e948 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -4786,6 +4786,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 
 	// Boss 5
 	"S_FANG_SETUP",
+	"S_FANG_INTRO0",
 	"S_FANG_INTRO1",
 	"S_FANG_INTRO2",
 	"S_FANG_INTRO3",
@@ -4798,6 +4799,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_FANG_INTRO10",
 	"S_FANG_INTRO11",
 	"S_FANG_INTRO12",
+	"S_FANG_CLONE1",
+	"S_FANG_CLONE2",
+	"S_FANG_CLONE3",
+	"S_FANG_CLONE4",
 	"S_FANG_IDLE0",
 	"S_FANG_IDLE1",
 	"S_FANG_IDLE2",
@@ -4881,6 +4886,15 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_ALART1",
 	"S_ALART2",
 
+	"S_VWREF",
+	"S_VWREB",
+
+	"S_PROJECTORLIGHT1",
+	"S_PROJECTORLIGHT2",
+	"S_PROJECTORLIGHT3",
+	"S_PROJECTORLIGHT4",
+	"S_PROJECTORLIGHT5",
+
 	"S_FBOMB1",
 	"S_FBOMB2",
 	"S_FBOMB_EXPL1",
@@ -7291,6 +7305,9 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	// Boss 5
 	"MT_FANG",
 	"MT_BROKENROBOT",
+	"MT_VWREF",
+	"MT_VWREB",
+	"MT_PROJECTORLIGHT",
 	"MT_FBOMB",
 	"MT_TNTDUST", // also used by barrel
 	"MT_FSGNA",
diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c
index 36ebbf133..8f1dbf2d2 100644
--- a/src/hardware/hw_light.c
+++ b/src/hardware/hw_light.c
@@ -204,13 +204,15 @@ light_t *t_lspr[NUMSPRITES] =
 	&lspr[NOLIGHT],     // SPR_EGR1
 
 	// Boss 5 (Arid Canyon)
-	&lspr[NOLIGHT],     //SPR_FANG // replaces EGGQ
-	&lspr[NOLIGHT],     //SPR_BRKN
-	&lspr[NOLIGHT],     //SPR_WHAT
-	&lspr[NOLIGHT],     //SPR_FBOM
-	&lspr[NOLIGHT],     //SPR_FSGN
-	&lspr[REDBALL_L],   //SPR_BARX // bomb explosion (also used by barrel)
-	&lspr[NOLIGHT],     //SPR_BARD // bomb dust (also used by barrel)
+	&lspr[NOLIGHT],      // SPR_FANG // replaces EGGQ
+	&lspr[NOLIGHT],      // SPR_BRKN
+	&lspr[NOLIGHT],      // SPR_WHAT
+	&lspr[INVINCIBLE_L], // SPR_VWRE
+	&lspr[INVINCIBLE_L], // SPR_PROJ
+	&lspr[NOLIGHT],      // SPR_FBOM
+	&lspr[NOLIGHT],      // SPR_FSGN
+	&lspr[REDBALL_L],    // SPR_BARX // bomb explosion (also used by barrel)
+	&lspr[NOLIGHT],      // SPR_BARD // bomb dust (also used by barrel)
 
 	// Boss 6 (Red Volcano)
 	&lspr[NOLIGHT],     // SPR_EEGR
diff --git a/src/info.c b/src/info.c
index 27c2a9c02..a7a165683 100644
--- a/src/info.c
+++ b/src/info.c
@@ -95,6 +95,8 @@ char sprnames[NUMSPRITES + 1][5] =
 	"FANG", // replaces EGGQ
 	"BRKN", // broken robot chunk
 	"WHAT", // alart
+	"VWRE",
+	"PROJ", // projector light
 	"FBOM",
 	"FSGN",
 	"BARX", // bomb explosion (also used by barrel)
@@ -1350,9 +1352,10 @@ state_t states[NUMSTATES] =
 	{SPR_EFIR, FF_FULLBRIGHT|2,          -1, {NULL}, 0, 0, S_NULL}, // S_EGGROBOJET
 
 	// Boss 5
-	{SPR_NULL, 0, 2, {A_CheckFlags2}, MF2_AMBUSH, S_FANG_IDLE0, S_FANG_INTRO1}, // S_FANG_SETUP
+	{SPR_NULL, 0, 2, {A_CheckFlags2}, MF2_AMBUSH, S_FANG_IDLE0, S_FANG_INTRO0}, // S_FANG_SETUP
 
-	{SPR_NULL, 0, 2, {A_Boss5MakeJunk}, 0, 0, S_FANG_INTRO2}, // S_FANG_INTRO1
+	{SPR_NULL, 0, 2, {NULL}, 0, 0, S_FANG_INTRO1}, // S_FANG_INTRO0
+	{SPR_NULL, 0, 2, {A_Boss5MakeJunk}, -S_FANG_CLONE1, 0, S_FANG_INTRO2}, // S_FANG_INTRO1
 	{SPR_NULL, 0, 0, {A_Repeat}, 25, S_FANG_INTRO1, S_FANG_INTRO3}, // S_FANG_INTRO2
 	{SPR_NULL, 0, 0, {A_Boss5MakeJunk}, 0, 1, S_FANG_INTRO4}, // S_FANG_INTRO3
 	{SPR_FANG, 30, 1, {A_ZThrust}, 9, (1<<16)|1, S_FANG_INTRO5}, // S_FANG_INTRO4
@@ -1365,6 +1368,11 @@ state_t states[NUMSTATES] =
 	{SPR_FANG, 26, 2, {A_Boss5MakeJunk}, S_BROKENROBOTD, 2, S_FANG_INTRO12}, // S_FANG_INTRO11
 	{SPR_FANG, 31|FF_ANIMATE, 50, {NULL}, 3, 4, S_FANG_IDLE1}, // S_FANG_INTRO12
 
+	{SPR_FANG, 11, 2, {A_Boss5MakeJunk}, 0, -1, S_FANG_CLONE2}, // S_FANG_CLONE1
+	{SPR_FANG, 11, 0, {A_Repeat}, 49, S_FANG_CLONE1, S_FANG_CLONE3}, // S_FANG_INTRO2
+	{SPR_FANG, 12, 0, {A_SetObjectFlags}, MF_NOGRAVITY, 1, S_FANG_CLONE4}, // S_FANG_CLONE3
+	{SPR_FANG, 12, 1, {A_Boss5CheckOnGround}, S_FANG_IDLE0, 0, S_FANG_CLONE4}, // S_FANG_CLONE4
+
 	{SPR_FANG, 0,  0, {A_SetObjectFlags}, MF_NOCLIPTHING, 1, S_FANG_IDLE1}, // S_FANG_IDLE0
 	{SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE2}, // S_FANG_IDLE1
 	{SPR_FANG, 3, 16, {A_Look}, 1, 0, S_FANG_IDLE3}, // S_FANG_IDLE2
@@ -1440,8 +1448,8 @@ state_t states[NUMSTATES] =
 	{SPR_FANG, 21, 0, {A_DoNPCPain},                    0, 0, S_FANG_DIE2}, // S_FANG_DIE1
 	{SPR_FANG, 21, 1, {A_Boss5CheckOnGround}, S_FANG_DIE3, 0, S_FANG_DIE2}, // S_FANG_DIE2
 
-	{SPR_FANG, 22,   0, {A_Scream}, 0, 0, S_FANG_DIE4}, // S_FANG_DIE3
-	{SPR_FANG, 22, 104, {NULL},     0, 0, S_FANG_DIE5}, // S_FANG_DIE4
+	{SPR_FANG, 22,  0, {A_Scream}, 0, 0, S_FANG_DIE4}, // S_FANG_DIE3
+	{SPR_FANG, 22, -1, {A_SetFuse}, 70, 0, S_FANG_DIE5}, // S_FANG_DIE4
 
 	{SPR_FANG, 11, 0, {A_PlaySound}, sfx_jump, 0, S_FANG_DIE6}, // S_FANG_DIE5
 	{SPR_FANG, 11, 1, {A_ZThrust}, 6, (1<<16)|1, S_FANG_DIE7}, // S_FANG_DIE6
@@ -1466,6 +1474,15 @@ state_t states[NUMSTATES] =
 	{SPR_WHAT,   FF_ANIMATE|FF_FULLBRIGHT,  4, {NULL}, 1, 2, S_ALART2}, // S_ALART1
 	{SPR_WHAT, 2|FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_NULL},   // S_ALART2
 
+	{SPR_VWRE,   FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_VWREF
+	{SPR_VWRE, 1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_VWREB
+
+	{SPR_PROJ,   FF_TRANS20|FF_FULLBRIGHT,  4, {NULL}, 0, 0, S_PROJECTORLIGHT2}, // S_PROJECTORLIGHT1
+	{SPR_PROJ, 1|FF_TRANS40|FF_FULLBRIGHT,  1, {NULL}, 0, 0, S_PROJECTORLIGHT3}, // S_PROJECTORLIGHT2
+	{SPR_PROJ, 2|FF_TRANS20|FF_FULLBRIGHT,  1, {NULL}, 0, 0, S_PROJECTORLIGHT4}, // S_PROJECTORLIGHT3
+	{SPR_PROJ, 3|FF_TRANS40|FF_FULLBRIGHT,  2, {A_Repeat}, 39, S_PROJECTORLIGHT2, S_PROJECTORLIGHT5}, // S_PROJECTORLIGHT4
+	{SPR_PROJ, 4|FF_TRANS60|FF_FULLBRIGHT,  2, {NULL}, 0, 0, S_NULL}, // S_PROJECTORLIGHT5
+
 	{SPR_FBOM, 0, 1, {A_GhostMe}, 0, 0, S_FBOMB2}, // S_FBOMB1
 	{SPR_FBOM, 1, 1, {A_GhostMe}, 0, 0, S_FBOMB1}, // S_FBOMB2
 	{SPR_BARX, 0|FF_FULLBRIGHT, 3, {A_SetObjectFlags}, MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP, 0, S_FBOMB_EXPL2}, // S_FBOMB_EXPL1
@@ -5706,6 +5723,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
+	{           // MT_VWREF
+		-1,             // doomednum
+		S_VWREF,         // spawnstate
+		1,              // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		0,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		3,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		42*FRACUNIT,    // radius
+		12*FRACUNIT,    // height
+		1,              // display offset
+		1000,           // mass
+		8,              // damage
+		sfx_None,       // activesound
+		MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_VWREB
+		-1,             // doomednum
+		S_VWREB,         // spawnstate
+		1,              // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		0,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		3,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		42*FRACUNIT,    // radius
+		12*FRACUNIT,    // height
+		-1,             // display offset
+		1000,           // mass
+		8,              // damage
+		sfx_None,       // activesound
+		MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
+		S_NULL          // raisestate
+	},
+
+	{           // MT_PROJECTORLIGHT
+		-1,             // doomednum
+		S_PROJECTORLIGHT1, // spawnstate
+		1,              // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		0,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		3,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		42*FRACUNIT,    // radius
+		52*FRACUNIT,    // height
+		-1,             // display offset
+		1000,           // mass
+		8,              // damage
+		sfx_None,       // activesound
+		MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
+		S_NULL          // raisestate
+	},
+
 	{           // MT_FBOMB
 		-1,                // doomednum
 		S_FBOMB1,          // spawnstate
diff --git a/src/info.h b/src/info.h
index 771eb18d3..6d04f388c 100644
--- a/src/info.h
+++ b/src/info.h
@@ -342,6 +342,8 @@ typedef enum sprite
 	SPR_FANG, // replaces EGGQ
 	SPR_BRKN,
 	SPR_WHAT,
+	SPR_VWRE,
+	SPR_PROJ, // projector light
 	SPR_FBOM,
 	SPR_FSGN,
 	SPR_BARX, // bomb explosion (also used by barrel)
@@ -1499,6 +1501,7 @@ typedef enum state
 
 	// Boss 5
 	S_FANG_SETUP,
+	S_FANG_INTRO0,
 	S_FANG_INTRO1,
 	S_FANG_INTRO2,
 	S_FANG_INTRO3,
@@ -1511,6 +1514,10 @@ typedef enum state
 	S_FANG_INTRO10,
 	S_FANG_INTRO11,
 	S_FANG_INTRO12,
+	S_FANG_CLONE1,
+	S_FANG_CLONE2,
+	S_FANG_CLONE3,
+	S_FANG_CLONE4,
 	S_FANG_IDLE0,
 	S_FANG_IDLE1,
 	S_FANG_IDLE2,
@@ -1594,6 +1601,15 @@ typedef enum state
 	S_ALART1,
 	S_ALART2,
 
+	S_VWREF,
+	S_VWREB,
+
+	S_PROJECTORLIGHT1,
+	S_PROJECTORLIGHT2,
+	S_PROJECTORLIGHT3,
+	S_PROJECTORLIGHT4,
+	S_PROJECTORLIGHT5,
+
 	S_FBOMB1,
 	S_FBOMB2,
 	S_FBOMB_EXPL1,
@@ -4026,6 +4042,9 @@ typedef enum mobj_type
 	// Boss 5
 	MT_FANG,
 	MT_BROKENROBOT,
+	MT_VWREF,
+	MT_VWREB,
+	MT_PROJECTORLIGHT,
 	MT_FBOMB,
 	MT_TNTDUST, // also used by barrel
 	MT_FSGNA,
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 6eec0e9b6..c35d903af 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -4026,13 +4026,17 @@ bossjustdie:
 		}
 		case MT_FANG:
 		{
+			if (mo->flags2 & MF2_SLIDEPUSH)
+			{
+				P_RemoveMobj(mo);
+				return;
+			}
 			if (mo->tracer)
 			{
 				var1 = var2 = 0;
 				A_Boss5Jump(mo);
 				mo->momx = ((16 - 1)*mo->momx)/16;
 				mo->momy = ((16 - 1)*mo->momy)/16;
-				if (!(mo->spawnpoint && mo->spawnpoint->options & MTF_EXTRA))
 				{
 					const fixed_t time = FixedHypot(mo->tracer->x - mo->x, mo->tracer->y - mo->y)/FixedHypot(mo->momx, mo->momy);
 					const fixed_t speed = 64*FRACUNIT;
@@ -12980,8 +12984,8 @@ void A_Boss5MakeItRain(mobj_t *actor)
 //
 // Description: Make a mess.
 //
-// var1 = state # to set on MT_BROKENROBOT (if 0 do nothing)
-// var2 = mode (0 = make 1, & 1 make 8, & 2 alart mode)
+// var1 = state # to set on MT_BROKENROBOT (if 0 do nothing, if -1 go to if colorized)
+// var2 = mode (-1 = spin, 0 = make 1, & 1 make 8, & 2 alart mode)
 //
 void A_Boss5MakeJunk(mobj_t *actor)
 {
@@ -12995,8 +12999,45 @@ void A_Boss5MakeJunk(mobj_t *actor)
 		return;
 #endif
 
-	if (leveltime < 2)
+	if (locvar1 < 0 && (actor->flags2 & MF2_SLIDEPUSH)) // this entire action is a hack, don't judge me
+	{
+		INT32 curextravalue2 = actor->extravalue2;
+		P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_PROJECTORLIGHT);
+		actor->z += P_MobjFlip(actor)*actor->height;
+		actor->flags |= MF_NOGRAVITY;
+		S_StartSound(actor, sfx_vwre);
+		actor->extravalue2 = 49;
+		P_SetMobjState(actor, -locvar1);
+		actor->extravalue2 = curextravalue2;
+		actor->angle -= FixedAngle((49*45)<<FRACBITS);
 		return;
+	}
+
+	if (locvar2 == -1)
+	{
+		INT32 trans = (10*actor->extravalue2)/50;
+		if (trans > 9)
+			trans = 9;
+		if (trans < 0)
+			trans = 0;
+		if (!(actor->extravalue2 & 1))
+		{
+			if (actor->extravalue2 > 10)
+			{
+				mobj_t *front = P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_VWREF);
+				broked = P_SpawnMobjFromMobj(front, 0, 0, 0, MT_VWREB);
+				front->z = broked->z = front->z - broked->height;
+				P_SetObjectMomZ(front, (4<<FRACBITS), false);
+				broked->momz = front->momz;
+				broked->fuse = front->fuse = (actor->height+(2*front->height))/front->momz;
+			}
+			if (!(actor->colorized = !actor->colorized))
+				actor->frame |= FF_FULLBRIGHT;
+		}
+		actor->angle += ANGLE_45;
+		actor->frame = (actor->frame & ~FF_TRANSMASK)|(trans<<FF_TRANSSHIFT);
+		return;
+	}
 
 	ang = FixedAngle((P_RandomKey(36)*10)<<FRACBITS);
 	while (i--)
@@ -13009,7 +13050,7 @@ void A_Boss5MakeJunk(mobj_t *actor)
 		broked->angle = ang;
 		P_InstaThrust(broked, ang, ((locvar2 & 2) ? 8 : 5)*actor->scale);
 		P_SetObjectMomZ(broked, (((locvar2) ? 4 : 0) + P_RandomRange(2, 5))<<FRACBITS, false);
-		if (locvar1 != 0)
+		if (locvar1 > 0)
 			P_SetMobjState(broked, locvar1);
 		if (!P_MobjWasRemoved(broked))
 			P_TeleportMove(broked, broked->x + broked->momx, broked->y + broked->momy, broked->z);
diff --git a/src/p_mobj.c b/src/p_mobj.c
index a459300a1..d9ddda26c 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -5063,6 +5063,24 @@ static void P_Boss5Thinker(mobj_t *mobj)
 {
 	if (!mobj->health)
 	{
+		if (mobj->fuse)
+		{
+			if (mobj->flags2 & MF2_SLIDEPUSH)
+			{
+				INT32 trans = 10-((10*mobj->fuse)/70);
+				if (trans > 9)
+					trans = 9;
+				if (trans < 0)
+					trans = 0;
+				mobj->frame = (mobj->frame & ~FF_TRANSMASK)|(trans<<FF_TRANSSHIFT);
+				if (!(mobj->fuse & 1))
+				{
+					mobj->colorized = !mobj->colorized;
+					mobj->frame ^= FF_FULLBRIGHT;
+				}
+			}
+			return;
+		}
 		if (mobj->state == &states[mobj->info->xdeathstate])
 			mobj->momz -= (2*FRACUNIT)/3;
 		else if (mobj->tracer && P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y) < 2*mobj->radius)
@@ -7649,6 +7667,17 @@ void P_MobjThinker(mobj_t *mobj)
 				if (mobj->movedir)
 					mobj->angle += mobj->movedir;
 				break;
+			case MT_VWREF:
+			case MT_VWREB:
+				{
+					INT32 strength;
+					++mobj->movedir;
+					mobj->frame &= ~FF_TRANSMASK;
+					strength = min(mobj->fuse, mobj->movedir)*3;
+					if (strength < 10)
+						mobj->frame |= ((10-strength)<<(FF_TRANSSHIFT));
+				}
+				/* FALLTHRU */
 			default:
 				if (mobj->fuse)
 				{ // Scenery object fuse! Very basic!
@@ -9269,6 +9298,18 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
 					}
 					P_RemoveMobj(mobj);
 					return;
+				case MT_FANG:
+					if (mobj->flags2 & MF2_SLIDEPUSH)
+					{
+						var1 = 0;
+						var2 = 0;
+						A_BossDeath(mobj);
+						return;
+					}
+					P_SetMobjState(mobj, mobj->state->nextstate);
+					if (P_MobjWasRemoved(mobj))
+						return;
+					break;
 				case MT_METALSONIC_BATTLE:
 					break; // don't remove
 				case MT_SPIKE:
@@ -9867,7 +9908,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 			break;
 	}
 
-	if (sc != -1)
+	if (sc != -1 && !(mobj->flags2 & MF2_SLIDEPUSH))
 	{
 		UINT8 i;
 		for (i = 0; i < MAXPLAYERS; i++)
@@ -9879,6 +9920,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 			{
 				mobj->color = SKINCOLOR_SILVER;
 				mobj->colorized = true;
+				mobj->flags2 |= MF2_SLIDEPUSH;
 				break;
 			}
 		}
@@ -11225,6 +11267,16 @@ You should think about modifying the deathmatch starts to take full advantage of
 		else
 			mobj->health = FixedMul(ss->sector->ceilingheight-ss->sector->floorheight, 3*(FRACUNIT/4))>>FRACBITS;
 		break;
+	case MT_FANG:
+	case MT_METALSONIC_RACE:
+	case MT_METALSONIC_BATTLE:
+		if (mthing->options & MTF_EXTRA)
+		{
+			mobj->color = SKINCOLOR_SILVER;
+			mobj->colorized = true;
+			mobj->flags2 |= MF2_SLIDEPUSH;
+		}
+		break;
 	case MT_BALLOON:
 		if (mthing->angle > 0)
 			mobj->color = ((mthing->angle-1) % (MAXSKINCOLORS-1))+1;
diff --git a/src/sounds.c b/src/sounds.c
index 1bfcf4cc8..cf37efd0a 100644
--- a/src/sounds.c
+++ b/src/sounds.c
@@ -213,6 +213,7 @@ sfxinfo_t S_sfx[NUMSFX] =
   {"corkp",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Cork fired"},
   {"corkh",  false,  32,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Cork hit"},
   {"alart",  false, 200,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Caught red handed!"},
+  {"vwre",   false, 200,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Clone fighter!"},
   {"bowl",   false,  32,  0, -1, NULL, 0,        -1,  -1, LUMPERROR, "Bowling"},
   {"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"},
diff --git a/src/sounds.h b/src/sounds.h
index d25a22619..e5568b59a 100644
--- a/src/sounds.h
+++ b/src/sounds.h
@@ -262,6 +262,7 @@ typedef enum
 	sfx_corkp,
 	sfx_corkh,
 	sfx_alart,
+	sfx_vwre,
 	sfx_bowl,
 	sfx_chuchu,
 	sfx_bsnipe,