diff --git a/src/d_player.h b/src/d_player.h
index 90098917f6a9b1cd341e0c74d9c457c967ac59d2..f2fdda0500ad09e1efa88736985f087c6428e5a8 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -513,6 +513,10 @@ typedef struct player_s
 #endif
 } player_t;
 
+// Values for dashmode
+#define DASHMODE_THRESHOLD (3*TICRATE)
+#define DASHMODE_MAX (DASHMODE_THRESHOLD + 3)
+
 // Value for infinite lives
 #define INFLIVES 0x7F
 
diff --git a/src/dehacked.c b/src/dehacked.c
index e84a818efafbedf35f89423647bd37a19be86459..34ee1f17016e274a385e37c5cead8060bb2a13eb 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -4358,6 +4358,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_TAILSOVERLAY_GASP",
 	"S_TAILSOVERLAY_EDGE",
 
+	// [:
+	"S_JETFUMEFLASH",
+
 	// Blue Crawla
 	"S_POSS_STND",
 	"S_POSS_RUN1",
@@ -7394,6 +7397,7 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 	"MT_THOK", // Thok! mobj
 	"MT_PLAYER",
 	"MT_TAILSOVERLAY", // c:
+	"MT_METALJETFUME", // [:
 
 	// Enemies
 	"MT_BLUECRAWLA", // Crawla (Blue)
@@ -9192,6 +9196,7 @@ struct {
 	{"TC_ALLWHITE",TC_ALLWHITE},
 	{"TC_RAINBOW",TC_RAINBOW},
 	{"TC_BLINK",TC_BLINK},
+	{"TC_DASHMODE",TC_DASHMODE},
 #endif
 
 	{NULL,0}
diff --git a/src/info.c b/src/info.c
index 9af477e4210d8e107fcdb3d3e1194d832b81e47d..cfaad552dcf4213dcab1201fe3d7c7c0880a1a99 100644
--- a/src/info.c
+++ b/src/info.c
@@ -867,6 +867,9 @@ state_t states[NUMSTATES] =
 	{SPR_PLAY, SPR2_TALA|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_GASP}, // S_TAILSOVERLAY_GASP
 	{SPR_PLAY, SPR2_TALB                , 35, {NULL}, 0, 0, S_TAILSOVERLAY_EDGE}, // S_TAILSOVERLAY_EDGE
 
+	// [:
+	{SPR_JETF, 3|FF_ANIMATE|FF_FULLBRIGHT, 2, {NULL}, 1, 1, S_JETFUME1}, // S_JETFUMEFLASH
+
 	// Blue Crawla
 	{SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND},   // S_POSS_STND
 	{SPR_POSS, 0, 3, {A_Chase}, 0, 0, S_POSS_RUN2},   // S_POSS_RUN1
@@ -4134,6 +4137,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
+	{           // MT_METALJETFUME
+		-1,             // doomednum
+		S_INVISIBLE,    // spawnstate
+		1000,           // spawnhealth
+		S_JETFUMEFLASH, // 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
+		8*FRACUNIT,     // radius
+		16*FRACUNIT,    // height
+		2,              // display offset
+		16,             // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
+		S_JETFUME1      // raisestate
+	},
+
 	{           // MT_BLUECRAWLA
 		100,            // doomednum
 		S_POSS_STND,    // spawnstate
diff --git a/src/info.h b/src/info.h
index 0d258f0c6b6c29a5be02f906141db2fe1e628b91..e7f41f585cbd959b88a3ab332edd44bc0979b58d 100644
--- a/src/info.h
+++ b/src/info.h
@@ -1031,6 +1031,9 @@ typedef enum state
 	S_TAILSOVERLAY_GASP,
 	S_TAILSOVERLAY_EDGE,
 
+	// [:
+	S_JETFUMEFLASH,
+
 	// Blue Crawla
 	S_POSS_STND,
 	S_POSS_RUN1,
@@ -4090,6 +4093,7 @@ typedef enum mobj_type
 	MT_THOK, // Thok! mobj
 	MT_PLAYER,
 	MT_TAILSOVERLAY, // c:
+	MT_METALJETFUME,
 
 	// Enemies
 	MT_BLUECRAWLA, // Crawla (Blue)
diff --git a/src/p_inter.c b/src/p_inter.c
index 1098273c8dd4001ac390835eb91480cfa2ac154a..9017f795d38d6066c9512c37298e581560a02aaa 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -485,6 +485,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 					toucher->momx = 7*toucher->momx>>3;
 					toucher->momy = 7*toucher->momy>>3;
 				}
+				else if (player->dashmode >= DASHMODE_THRESHOLD && (player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE)
+					&& player->panim == PA_DASH)
+					P_DoPlayerPain(player, special, special);
 			}
 			P_DamageMobj(special, toucher, toucher, 1, 0);
 			if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)
diff --git a/src/p_user.c b/src/p_user.c
index 7dbef843011520e9b91c747c6adee0f884e927f3..42d1340de4f3d9a518a492a1ad6e27dfa96e6f52 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -1096,6 +1096,9 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing)
 	// Spinning.
 	if (player->pflags & PF_SPINNING)
 		return true;
+	
+	if (player->dashmode >= DASHMODE_THRESHOLD && (player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE))
+		return true;
 
 	// From the front.
 	if (((player->pflags & PF_GLIDING) || (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
@@ -1990,7 +1993,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
 		mobj_t *ghost2 = P_SpawnGhostMobj(mobj->player->followmobj);
 		P_SetTarget(&ghost2->tracer, ghost);
 		P_SetTarget(&ghost->tracer, ghost2);
-		ghost2->flags2 |= MF2_LINKDRAW;
+		ghost2->flags2 |= (mobj->player->followmobj->flags2 & MF2_LINKDRAW);
 	}
 
 	return ghost;
@@ -2325,7 +2328,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
 			{
 				if (player->cmomx || player->cmomy)
 				{
-					if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH)
+					if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD && player->panim != PA_DASH)
 						P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
 					else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)
 					&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
@@ -2338,7 +2341,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
 				}
 				else
 				{
-					if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH)
+					if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD && player->panim != PA_DASH)
 						P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
 					else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)
 					&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
@@ -2499,7 +2502,7 @@ static void P_CheckBustableBlocks(player_t *player)
 					// or you are recording for Metal Sonic
 					if (!((player->pflags & PF_SPINNING) && !(player->pflags & PF_JUMPED))
 						&& !(player->powers[pw_super])
-						&& !((player->charflags & SF_DASHMODE) && (player->dashmode >= 3*TICRATE))
+						&& !(((player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE)) && (player->dashmode >= DASHMODE_THRESHOLD))
 						&& !(player->pflags & PF_DRILLING)
 						&& !metalrecording)
 						continue;
@@ -5324,7 +5327,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 				case CA_SLOWFALL: // Slow descent hover
 					if (!(player->pflags & PF_THOKKED) || player->charflags & SF_MULTIABILITY)
 					{
-						if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE)
+						if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD)
 							P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
 						else if (player->speed >= FixedMul(player->runspeed, player->mo->scale))
 							P_SetPlayerMobjState(player->mo, S_PLAY_FLOAT_RUN);
@@ -7978,7 +7981,7 @@ static void P_MovePlayer(player_t *player)
 	if ((cmd->forwardmove != 0 || cmd->sidemove != 0) || (player->powers[pw_super] && !onground))
 	{
 		// If the player is in dashmode, here's their peelout.
-		if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim == PA_RUN && !player->skidtime && (onground || ((player->charability == CA_FLOAT || player->charability == CA_SLOWFALL) && player->secondjump == 1) || player->powers[pw_super]))
+		if (player->charflags & SF_DASHMODE && player->dashmode >= DASHMODE_THRESHOLD && player->panim == PA_RUN && !player->skidtime && (onground || ((player->charability == CA_FLOAT || player->charability == CA_SLOWFALL) && player->secondjump == 1) || player->powers[pw_super]))
 			P_SetPlayerMobjState (player->mo, S_PLAY_DASH);
 		// If the player is moving fast enough,
 		// break into a run!
@@ -8002,7 +8005,7 @@ static void P_MovePlayer(player_t *player)
 
 	// If your peelout animation is playing, and you're
 	// going too slow, switch back to the run.
-	if (player->charflags & SF_DASHMODE && player->panim == PA_DASH && player->dashmode < 3*TICRATE)
+	if (player->charflags & SF_DASHMODE && player->panim == PA_DASH && player->dashmode < DASHMODE_THRESHOLD)
 		P_SetPlayerMobjState(player->mo, S_PLAY_RUN);
 
 	// If your running animation is playing, and you're
@@ -10947,6 +10950,122 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails)
 	P_SetThingPosition(tails);
 }
 
+// Metal Sonic's jet fume
+static void P_DoMetalJetFume(player_t *player, mobj_t *fume)
+{
+	static const UINT8 FUME_SKINCOLORS[] =
+	{
+		SKINCOLOR_ICY,
+		SKINCOLOR_SKY,
+		SKINCOLOR_CYAN,
+		SKINCOLOR_WAVE,
+		SKINCOLOR_TEAL,
+		SKINCOLOR_AQUA,
+		SKINCOLOR_SEAFOAM,
+		SKINCOLOR_MINT,
+		SKINCOLOR_PERIDOT,
+		SKINCOLOR_LIME,
+		SKINCOLOR_YELLOW,
+		SKINCOLOR_SANDY,
+		SKINCOLOR_GOLD,
+		SKINCOLOR_APRICOT,
+		SKINCOLOR_SUNSET
+	};
+	mobj_t *mo = player->mo;
+	angle_t angle = player->drawangle;
+	fixed_t dist;
+	panim_t panim = player->panim;
+	tic_t dashmode = player->dashmode;
+	boolean underwater = mo->eflags & MFE_UNDERWATER;
+	
+	if (panim != PA_WALK && panim != PA_RUN && panim != PA_DASH) // turn invisible when not in a coherent movement state
+	{
+		if (fume->state-states != fume->info->spawnstate)
+			P_SetMobjState(fume, fume->info->spawnstate);
+		return;
+	}
+	
+	if (underwater) // No fume underwater; spawn bubbles instead!
+	{
+		fume->movedir	+= FixedAngle(FixedDiv(2 * player->speed, 3 * mo->scale));
+		fume->movefactor += player->speed;
+		
+		if (fume->movefactor > FixedDiv(2 * player->normalspeed, 3 * mo->scale))
+		{
+			INT16 i;
+			fixed_t radiusV = 4*FRACUNIT;
+			fixed_t radiusX = P_ReturnThrustX(mo, angle, -mo->radius >> (panim == PA_WALK ? 1 : 0));
+			fixed_t radiusY = P_ReturnThrustY(mo, angle, -mo->radius >> (panim == PA_WALK ? 1 : 0));
+			fixed_t factorX = P_ReturnThrustX(mo, angle + ANGLE_90, mo->scale);
+			fixed_t factorY = P_ReturnThrustY(mo, angle + ANGLE_90, mo->scale);
+			fixed_t offsetH, offsetV, x, y, z;
+			
+			for (i = -1; i < 2; i += 2)
+			{
+				offsetH = i*P_ReturnThrustX(fume, fume->movedir, radiusV);
+				offsetV = i*P_ReturnThrustY(fume, fume->movedir, radiusV);
+				x = mo->x + radiusX + FixedMul(offsetH, factorX);
+				y = mo->y + radiusY + FixedMul(offsetH, factorY);
+				z = mo->z + (mo->height >> 1) + offsetV;
+				P_SpawnMobj(x, y, z, MT_SMALLBUBBLE)->scale = mo->scale >> 1;
+			}
+			
+			fume->movefactor = 0;
+		}
+		
+		if (panim == PA_WALK)
+		{
+			if (fume->state-states != fume->info->spawnstate)
+				P_SetMobjState(fume, fume->info->spawnstate);
+			return;
+		}
+	}
+	
+	if (fume->state-states == fume->info->spawnstate) // If currently inivisble, activate!
+	{
+		P_SetMobjState(fume, fume->info->seestate);
+		P_SetScale(fume, mo->scale);
+	}
+	
+	if (dashmode > DASHMODE_THRESHOLD && fume->state-states != fume->info->seestate) // If in dashmode, grow really big and flash
+	{
+		fume->destscale = mo->scale;
+		fume->flags2 ^= MF2_DONTDRAW;
+		fume->flags2 |= mo->flags2 & MF2_DONTDRAW;
+	}
+	else // Otherwise, pick a size and color depending on speed and proximity to dashmode
+	{
+		if (dashmode == DASHMODE_THRESHOLD && dashmode > fume->movecount) // If just about to enter dashmode, play the startup animation again
+		{
+			P_SetMobjState(fume, fume->info->seestate);
+			P_SetScale(fume, mo->scale << 1);
+		}
+		fume->flags2 = (fume->flags2 & ~MF2_DONTDRAW) | (mo->flags2 & MF2_DONTDRAW);
+		fume->destscale = (mo->scale + FixedDiv(player->speed, player->normalspeed)) / (underwater ? 6 : 3);
+		fume->color = FUME_SKINCOLORS[(dashmode * sizeof(FUME_SKINCOLORS)) / (DASHMODE_MAX + 1)];
+		
+		if (underwater)
+		{
+			fume->frame = (fume->frame & FF_FRAMEMASK) | FF_ANIMATE | (P_RandomRange(0, 9) * FF_TRANS10);
+		}
+	}
+	
+	fume->movecount = dashmode; // keeps track of previous dashmode value so we know whether Metal is entering or leaving it
+	fume->eflags = (fume->eflags & ~MFE_VERTICALFLIP) | (mo->eflags & MFE_VERTICALFLIP); // Make sure to flip in reverse gravity!
+	
+	// Finally, set its position
+	dist = -mo->radius - FixedMul(fume->info->radius, fume->destscale - mo->scale/3);
+	
+	P_UnsetThingPosition(fume);
+	fume->x = mo->x + P_ReturnThrustX(fume, angle, dist);
+	fume->y = mo->y + P_ReturnThrustY(fume, angle, dist);
+	if (fume->eflags & MFE_VERTICALFLIP)
+		fume->z = mo->z + ((mo->height + fume->height) >> 1);
+	else
+		fume->z = mo->z + ((mo->height - fume->height) >> 1);
+	P_SetThingPosition(fume);
+}
+
 //
 // P_PlayerThink
 //
@@ -11699,9 +11818,9 @@ void P_PlayerThink(player_t *player)
 
 		if ((totallyradical && !floating) || (player->pflags & PF_STARTDASH))
 		{
-			if (dashmode < 3*TICRATE + 3)
+			if (dashmode < DASHMODE_MAX)
 				dashmode++; // Counter. Adds 1 to dash mode per tic in top speed.
-			if (dashmode == 3*TICRATE) // This isn't in the ">=" equation because it'd cause the sound to play infinitely.
+			if (dashmode == DASHMODE_THRESHOLD) // This isn't in the ">=" equation because it'd cause the sound to play infinitely.
 				S_StartSound(player->mo, sfx_s3ka2); // If the player enters dashmode, play this sound on the the tic it starts.
 		}
 		else if ((!totallyradical || !floating) && !(player->pflags & PF_SPINNING))
@@ -11712,7 +11831,7 @@ void P_PlayerThink(player_t *player)
 				dashmode = 0;
 		}
 
-		if (dashmode < 3*TICRATE) // Exits Dash Mode if you drop below speed/dash counter tics. Not in the above block so it doesn't keep disabling in midair.
+		if (dashmode < DASHMODE_THRESHOLD) // Exits Dash Mode if you drop below speed/dash counter tics. Not in the above block so it doesn't keep disabling in midair.
 		{
 			player->normalspeed = skins[player->skin].normalspeed; // Reset to default if not capable of entering dash mode.
 			player->jumpfactor = skins[player->skin].jumpfactor;
@@ -11734,7 +11853,7 @@ void P_PlayerThink(player_t *player)
 	}
 	else if (dashmode)
 	{
-		if (dashmode >= 3*TICRATE) // catch getting the flag!
+		if (dashmode >= DASHMODE_THRESHOLD) // catch getting the flag!
 		{
 			player->normalspeed = skins[player->skin].normalspeed;
 			player->jumpfactor = skins[player->skin].jumpfactor;
@@ -12280,7 +12399,15 @@ void P_PlayerAfterThink(player_t *player)
 		{
 			P_SetTarget(&player->followmobj, P_SpawnMobjFromMobj(player->mo, 0, 0, 0, player->followitem));
 			P_SetTarget(&player->followmobj->tracer, player->mo);
-			player->followmobj->flags2 |= MF2_LINKDRAW;
+			switch (player->followmobj->type)
+			{
+				case MT_METALJETFUME:
+					player->followmobj->colorized = true;
+					break;
+				default:
+					player->followmobj->flags2 |= MF2_LINKDRAW;
+					break;
+			}
 		}
 
 		if (player->followmobj)
@@ -12296,6 +12423,9 @@ void P_PlayerAfterThink(player_t *player)
 					case MT_TAILSOVERLAY: // c:
 						P_DoTailsOverlay(player, player->followmobj);
 						break;
+					case MT_METALJETFUME:
+						P_DoMetalJetFume(player, player->followmobj);
+						break;
 					default:
 						var1 = 1;
 						var2 = 0;
diff --git a/src/r_draw.c b/src/r_draw.c
index 1754403c44141a2ca599bddcc28d0ca6ed90ca80..bb70a319f0a5137d3f95740e10b77efda06eeed7 100644
--- a/src/r_draw.c
+++ b/src/r_draw.c
@@ -130,10 +130,11 @@ UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask;
 #define ALLWHITE_TT_CACHE_INDEX (MAXSKINS + 3)
 #define RAINBOW_TT_CACHE_INDEX (MAXSKINS + 4)
 #define BLINK_TT_CACHE_INDEX (MAXSKINS + 5)
+#define DASHMODE_TT_CACHE_INDEX (MAXSKINS + 6)
 #define DEFAULT_STARTTRANSCOLOR 96
 #define NUM_PALETTE_ENTRIES 256
 
-static UINT8** translationtablecache[MAXSKINS + 6] = {NULL};
+static UINT8** translationtablecache[MAXSKINS + 7] = {NULL};
 
 const UINT8 Color_Index[MAXTRANSLATIONS-1][16] = {
 	// {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // SKINCOLOR_NONE
@@ -569,6 +570,40 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
 				dest_colormap[Color_Index[SKINCOLOR_BLUE-1][12-i]] = Color_Index[SKINCOLOR_BLUE-1][i];
 			dest_colormap[159] = dest_colormap[253] = dest_colormap[254] = 0;
 		}
+		else if (skinnum == TC_DASHMODE) // This is a long one, because MotorRoach basically hand-picked the indices
+		{
+			// greens -> ketchups
+			dest_colormap[96] = dest_colormap[97] = 48;
+			dest_colormap[98] = 49;
+			dest_colormap[99] = 51;
+			dest_colormap[100] = 52;
+			dest_colormap[101] = dest_colormap[102] = 54;
+			dest_colormap[103] = 34;
+			dest_colormap[104] = 37;
+			dest_colormap[105] = 39;
+			dest_colormap[106] = 41;
+			for (i = 0; i < 5; i++)
+				dest_colormap[107 + i] = 43 + i;
+
+			// reds -> steel blues
+			dest_colormap[32] = 146;
+			dest_colormap[33] = 147;
+			dest_colormap[34] = dest_colormap[35] = 170;
+			dest_colormap[36] = 171;
+			dest_colormap[37] = dest_colormap[38] = 172;
+			dest_colormap[39] = dest_colormap[40] = dest_colormap[41] = 173;
+			dest_colormap[42] = dest_colormap[43] = dest_colormap[44] = 174;
+			dest_colormap[45] = dest_colormap[46] = dest_colormap[47] = 175;
+			dest_colormap[71] = 139;
+
+			// steel blues -> oranges
+			dest_colormap[170] = 52;
+			dest_colormap[171] = 54;
+			dest_colormap[172] = 56;
+			dest_colormap[173] = 42;
+			dest_colormap[174] = 45;
+			dest_colormap[175] = 47;
+		}
 		return;
 	}
 	else if (color == SKINCOLOR_NONE)
@@ -628,6 +663,7 @@ UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags)
 		case TC_ALLWHITE:   skintableindex = ALLWHITE_TT_CACHE_INDEX; break;
 		case TC_RAINBOW:    skintableindex = RAINBOW_TT_CACHE_INDEX; break;
 		case TC_BLINK:      skintableindex = BLINK_TT_CACHE_INDEX; break;
+		case TC_DASHMODE:   skintableindex = DASHMODE_TT_CACHE_INDEX; break;
 		     default:       skintableindex = skinnum; break;
 	}
 
diff --git a/src/r_draw.h b/src/r_draw.h
index 3c142972257c446a29e32fd1c36a810e47c63bc0..a0ab748480930d6f06191b6de78adfefdb539ce5 100644
--- a/src/r_draw.h
+++ b/src/r_draw.h
@@ -109,6 +109,7 @@ extern lumpnum_t viewborderlump[8];
 #define TC_ALLWHITE   -4 // For Cy-Brak-demon
 #define TC_RAINBOW    -5 // For single colour
 #define TC_BLINK      -6 // For item blinking, according to kart
+#define TC_DASHMODE   -7 // For Metal Sonic's dashmode
 
 // Initialize color translation tables, for player rendering etc.
 void R_InitTranslationTables(void);
diff --git a/src/r_things.c b/src/r_things.c
index 5c99edcec3d74e135a605fd591ff55b3f0166fcb..00eaae1c206423618885834fa7e268a01da0d42e 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -753,6 +753,13 @@ static void R_DrawVisSprite(vissprite_t *vis)
 		dc_transmap = vis->transmap;
 		if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized)
 			dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE);
+		else if (!(vis->cut & SC_PRECIP)
+			&& vis->mobj->player && vis->mobj->player->dashmode >= DASHMODE_THRESHOLD
+			&& (vis->mobj->player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE)
+			&& ((leveltime/2) & 1))
+		{
+			dc_translation = R_GetTranslationColormap(TC_DASHMODE, 0, GTC_CACHE);
+		}
 		else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_>
 		{
 			size_t skinnum = (skin_t*)vis->mobj->skin-skins;
@@ -774,6 +781,13 @@ static void R_DrawVisSprite(vissprite_t *vis)
 		// New colormap stuff for skins Tails 06-07-2002
 		if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized)
 			dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE);
+		else if (!(vis->cut & SC_PRECIP)
+			&& vis->mobj->player && vis->mobj->player->dashmode >= DASHMODE_THRESHOLD
+			&& (vis->mobj->player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE)
+			&& ((leveltime/2) & 1))
+		{
+			dc_translation = R_GetTranslationColormap(TC_DASHMODE, 0, GTC_CACHE);
+		}
 		else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player!
 		{
 			size_t skinnum = (skin_t*)vis->mobj->skin-skins;