diff --git a/src/dehacked.c b/src/dehacked.c
index 2fdd4ff46..a39cf9136 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -3940,6 +3940,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	// CA2_MELEE
 	"S_PLAY_MELEE",
 	"S_PLAY_MELEE_FINISH",
+	"S_PLAY_MELEE_LANDING",
 
 	// SF_SUPER
 	"S_PLAY_SUPERTRANS1",
diff --git a/src/doomdef.h b/src/doomdef.h
index ed197e20c..73ecf7dc9 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -543,4 +543,7 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
 /// Experimental attempts at preventing MF_PAPERCOLLISION objects from getting stuck in walls.
 //#define PAPER_COLLISIONCORRECTION
 
+/// Hudname padding.
+#define SKINNAMEPADDING
+
 #endif // __DOOMDEF__
diff --git a/src/info.c b/src/info.c
index 932ef4a58..e62b66ccd 100644
--- a/src/info.c
+++ b/src/info.c
@@ -421,6 +421,7 @@ char spr2names[NUMPLAYERSPRITES][5] =
 	"TWIN",
 
 	"MLEE",
+	"MLEL",
 
 	"TRNS",
 
@@ -530,7 +531,8 @@ state_t states[NUMSTATES] =
 
 	// CA2_MELEE
 	{SPR_PLAY, SPR2_MLEE|FF_SPR2ENDSTATE, 1, {NULL}, S_PLAY_MELEE_FINISH, 0, S_PLAY_MELEE}, // S_PLAY_MELEE
-	{SPR_PLAY, SPR2_MLEE,                20, {NULL},                   0, 0, S_PLAY_FALL}, // S_PLAY_MELEE_FINISH
+	{SPR_PLAY, SPR2_MLEE,                20, {NULL},                   0, 0, S_PLAY_FALL},  // S_PLAY_MELEE_FINISH
+	{SPR_PLAY, SPR2_MLEL,                35, {NULL},                   0, 0, S_PLAY_WALK},  // S_PLAY_MELEE_LANDING
 
 	// SF_SUPER
 	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER,                4, {NULL}, 0, 0, S_PLAY_SUPER_TRANS2}, // S_PLAY_SUPER_TRANS
diff --git a/src/info.h b/src/info.h
index d5508d501..a981a39fa 100644
--- a/src/info.h
+++ b/src/info.h
@@ -634,6 +634,7 @@ enum playersprite
 	SPR2_TWIN, // twinspin
 
 	SPR2_MLEE, // melee
+	SPR2_MLEL, // melee land
 
 	SPR2_TRNS, // transformation
 
@@ -741,6 +742,7 @@ typedef enum state
 	// CA2_MELEE
 	S_PLAY_MELEE,
 	S_PLAY_MELEE_FINISH,
+	S_PLAY_MELEE_LANDING,
 
 	// SF_SUPER
 	S_PLAY_SUPER_TRANS,
diff --git a/src/p_inter.c b/src/p_inter.c
index bf002e62e..36e800bf0 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -379,7 +379,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			{
 				if (elementalpierce == 2)
 					P_DoBubbleBounce(player);
-				else
+				else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
 					toucher->momz = -toucher->momz;
 			}
 			if (player->pflags & PF_BOUNCING)
@@ -437,7 +437,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			{
 				if (elementalpierce == 2)
 					P_DoBubbleBounce(player);
-				else
+				else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
 					toucher->momz = -toucher->momz;
 			}
 			if (player->pflags & PF_BOUNCING)
diff --git a/src/p_map.c b/src/p_map.c
index 10202b8c4..b91358140 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -1085,7 +1085,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
 				{
 					if (elementalpierce == 2)
 						P_DoBubbleBounce(player);
-					else
+					else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
 						*momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically.
 				}
 				if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough.
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 3e099eab6..e867175ae 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -468,6 +468,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
 	case S_PLAY_SPINDASH: // ...but the act of SPINDASHING is charability2 specific.
 	case S_PLAY_MELEE:
 	case S_PLAY_MELEE_FINISH:
+	case S_PLAY_MELEE_LANDING:
 		player->panim = PA_ABILITY2;
 		break;
 	case S_PLAY_RIDE:
@@ -3194,8 +3195,8 @@ static void P_PlayerZMovement(mobj_t *mo)
 					// aren't pressing any controls.
 					if (!(mo->player->cmd.forwardmove || mo->player->cmd.sidemove) && !mo->player->cmomx && !mo->player->cmomy && !(mo->player->pflags & PF_SPINNING))
 					{
-						mo->momx = mo->momx/2;
-						mo->momy = mo->momy/2;
+						mo->momx >>= 1;
+						mo->momy >>= 1;
 					}
 				}
 
@@ -3206,10 +3207,11 @@ static void P_PlayerZMovement(mobj_t *mo)
 						mo->player->skidtime = TICRATE;
 						mo->tics = -1;
 					}
-					else if (mo->player->charability2 == CA2_MELEE && mo->player->panim == PA_ABILITY2)
+					else if (mo->player->charability2 == CA2_MELEE && ((mo->player->charability == CA_TWINSPIN && mo->player->panim == PA_ABILITY) || (mo->player->panim == PA_ABILITY2)))
 					{
-						P_InstaThrust(mo, mo->angle, 0);
-						P_SetPlayerMobjState(mo, S_PLAY_STND);
+						P_SetPlayerMobjState(mo, S_PLAY_MELEE_LANDING);
+						mo->tics = mo->player->powers[pw_nocontrol] = (mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(mo->movefactor)))>>FRACBITS;
+						S_StartSound(mo, sfx_s3k8b);
 					}
 					else if (mo->player->pflags & PF_JUMPED || (mo->player->pflags & (PF_SPINNING|PF_USEDOWN)) != (PF_SPINNING|PF_USEDOWN)
 					|| mo->player->powers[pw_tailsfly] || mo->state-states == S_PLAY_FLY_TIRED)
diff --git a/src/p_user.c b/src/p_user.c
index c1e483a87..c8d0c59e3 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -3815,19 +3815,33 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
 				}
 				break;
 			case CA2_MELEE: // Melee attack
-				if (!(player->panim == PA_ABILITY2) && (cmd->buttons & BT_USE) && player->speed < FixedMul(10<<FRACBITS, player->mo->scale)
+				if (!(player->panim == PA_ABILITY2) && (cmd->buttons & BT_USE)
 				&& !player->mo->momz && onground && !(player->pflags & PF_USEDOWN)
 				&& canstand)
 				{
 					P_ResetPlayer(player);
-					player->mo->z += P_MobjFlip(player->mo);
-					player->mo->momx = player->cmomx = 0;
-					player->mo->momy = player->cmomy = 0;
-					P_SetObjectMomZ(player->mo, player->mindash, false);
-					P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->maxdash, player->mo->scale));
-					P_SetPlayerMobjState(player->mo, S_PLAY_MELEE);
+					if ((player->charability == CA_TWINSPIN) && (player->speed > FixedMul(player->runspeed, player->mo->scale)))
+					{
+						P_DoJump(player, false);
+						player->jumping = 0;
+						player->mo->momz = FixedMul(player->mo->momz, 3*FRACUNIT/2);
+						player->pflags |= PF_THOKKED;
+						P_SetPlayerMobjState(player->mo, S_PLAY_TWINSPIN);
+						S_StartSound(player->mo, sfx_s3k8b);
+					}
+					else
+					{
+						player->powers[pw_nocontrol] = TICRATE;
+						player->mo->z += P_MobjFlip(player->mo);
+						P_SetObjectMomZ(player->mo, player->mindash, false);
+						if (FixedMul(player->speed, FINECOSINE(((player->mo->angle - R_PointToAngle2(0, 0, player->rmomx, player->rmomy)) >> ANGLETOFINESHIFT) & FINEMASK)) < FixedMul(player->maxdash, player->mo->scale))
+							P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->maxdash, player->mo->scale));
+						player->mo->momx += player->cmomx;
+						player->mo->momy += player->cmomy;
+						P_SetPlayerMobjState(player->mo, S_PLAY_MELEE);
+						S_StartSound(player->mo, sfx_s3k42);
+					}
 					player->pflags |= PF_USEDOWN;
-					S_StartSound(player->mo, sfx_s3k8b);
 				}
 				break;
 		}
@@ -6503,11 +6517,10 @@ static void P_SkidStuff(player_t *player)
 			// If your push angle is more than this close to a full 180 degrees, trigger a skid.
 			if (dang > ANGLE_157h)
 			{
-				player->skidtime = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS;
-				S_StartSound(player->mo, sfx_skid);
 				if (player->panim != PA_WALK)
 					P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
-				player->mo->tics = player->skidtime;
+				player->mo->tics = player->skidtime = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS;
+				S_StartSound(player->mo, sfx_skid);
 			}
 		}
 	}