From d631d0ef04abee423411eef9ef3c198836f8a455 Mon Sep 17 00:00:00 2001
From: ZTsukei <ztsukei@gmail.com>
Date: Sun, 14 Aug 2016 23:51:08 -0400
Subject: [PATCH] S_PLAY states, HUD stuff

---
 src/b_bot.c           |    4 +-
 src/command.c         |    5 +
 src/command.h         |    4 +
 src/d_main.c          |    3 +
 src/d_netcmd.c        |   27 +
 src/d_netcmd.h        |    8 +
 src/d_player.h        |   75 ++-
 src/dehacked.c        |   31 ++
 src/g_game.c          |    2 +-
 src/hardware/hw_md2.c |    2 +-
 src/hu_stuff.c        |   14 +
 src/hu_stuff.h        |    9 +-
 src/info.c            |   43 +-
 src/info.h            |   32 ++
 src/k_kart.c          | 1230 ++++++++++++++++++++++++++++++++++++++++-
 src/k_kart.h          |   81 +--
 src/m_cheat.c         |    2 +-
 src/p_inter.c         |   74 ++-
 src/p_map.c           |   12 +-
 src/p_mobj.c          |   59 +-
 src/p_spec.c          |   35 +-
 src/p_telept.c        |    4 +-
 src/p_user.c          |  249 +++++++--
 src/st_stuff.c        |   14 +-
 src/v_video.c         |   95 ++++
 src/v_video.h         |    1 +
 26 files changed, 1901 insertions(+), 214 deletions(-)

diff --git a/src/b_bot.c b/src/b_bot.c
index 56be0613b..3aa456abe 100644
--- a/src/b_bot.c
+++ b/src/b_bot.c
@@ -273,11 +273,11 @@ void B_RespawnBot(INT32 playernum)
 	P_TeleportMove(tails, x, y, z);
 	if (player->charability == CA_FLY)
 	{
-		P_SetPlayerMobjState(tails, S_PLAY_ABL1);
+		P_SetPlayerMobjState(tails, S_KART_STND); // SRB2kart - was S_PLAY_ABL1
 		tails->player->powers[pw_tailsfly] = (UINT16)-1;
 	}
 	else
-		P_SetPlayerMobjState(tails, S_PLAY_FALL1);
+		P_SetPlayerMobjState(tails, S_KART_STND); // SRB2kart - was S_PLAY_FALL1
 	P_SetScale(tails, sonic->scale);
 	tails->destscale = sonic->destscale;
 }
diff --git a/src/command.c b/src/command.c
index 84d777acf..a96ce0436 100644
--- a/src/command.c
+++ b/src/command.c
@@ -62,6 +62,11 @@ CV_PossibleValue_t CV_YesNo[] = {{0, "No"}, {1, "Yes"}, {0, NULL}};
 CV_PossibleValue_t CV_Unsigned[] = {{0, "MIN"}, {999999999, "MAX"}, {0, NULL}};
 CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}};
 
+//SRB2kart
+CV_PossibleValue_t karthud_cons_t[] = {
+	{0, "Off"}, {1, "Default"}, {2, "SNES"}, {3, "MK64"}, 
+	{0, NULL}};
+
 #define COM_BUF_SIZE 8192 // command buffer size
 
 static INT32 com_wait; // one command per frame (for cmd sequences)
diff --git a/src/command.h b/src/command.h
index 989ead8cf..74160d3c8 100644
--- a/src/command.h
+++ b/src/command.h
@@ -125,6 +125,10 @@ extern CV_PossibleValue_t CV_OnOff[];
 extern CV_PossibleValue_t CV_YesNo[];
 extern CV_PossibleValue_t CV_Unsigned[];
 extern CV_PossibleValue_t CV_Natural[];
+
+// SRB2kart
+extern CV_PossibleValue_t karthud_cons_t[];
+
 // register a variable for use at the console
 void CV_RegisterVar(consvar_t *variable);
 
diff --git a/src/d_main.c b/src/d_main.c
index 14a8a06e1..b44bccef8 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -822,6 +822,9 @@ static void IdentifyVersion(void)
 	D_AddFile(va(pandf,srb2waddir,"patch.dta"));
 #endif
 
+	// SRB2kart - Add graphics (temp)
+	D_AddFile(va(pandf,srb2waddir,"AllKartGraphics.wad"));
+
 #if !defined (HAVE_SDL) || defined (HAVE_MIXER)
 	{
 #if defined (DC) && 0
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index fa95274d7..50d06424d 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -291,6 +291,31 @@ consvar_t cv_bombshield =    {"tv_bombshield",    "5", CV_NETVAR|CV_CHEAT, chanc
 consvar_t cv_1up =           {"tv_1up",           "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_eggmanbox =     {"tv_eggman",        "5", CV_NETVAR|CV_CHEAT, chances_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 
+// SRB2kart
+consvar_t cv_magnet = 			{"magnets", 			"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_boo = 				{"boos", 				"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_mushroom = 		{"mushrooms", 			"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_triplemushroom = 	{"triplemushrooms", 	"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_megashroom = 		{"megashrooms", 		"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_goldshroom = 		{"goldshrooms", 		"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_star = 			{"stars", 				"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_triplebanana = 	{"triplebananas", 		"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_fakeitem = 		{"fakeitems", 			"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_banana = 			{"bananas", 			"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_greenshell = 		{"greenshells", 		"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_redshell = 		{"redshells", 			"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_laserwisp = 		{"laserwisps", 			"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_triplegreenshell = {"triplegreenshells", 	"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_bobomb = 			{"bobombs", 			"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_blueshell = 		{"blueshells", 			"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_jaws = 			{"jaws", 				"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_fireflower = 		{"fireflowers", 		"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_tripleredshell = 	{"tripleredshells", 	"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_lightning = 		{"lightning", 			"On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+
+consvar_t cv_karthud = {"karthud", "Default", CV_SAVE|CV_CALL, karthud_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+//
+
 consvar_t cv_ringslinger = {"ringslinger", "No", CV_NETVAR|CV_NOSHOWHELP|CV_CALL|CV_CHEAT, CV_YesNo,
 	Ringslinger_OnChange, 0, NULL, NULL, 0, 0, NULL};
 consvar_t cv_gravity = {"gravity", "0.5", CV_RESTRICT|CV_FLOAT|CV_CALL, NULL, Gravity_OnChange, 0, NULL, NULL, 0, 0, NULL};
@@ -496,6 +521,8 @@ void D_RegisterServerCommands(void)
 	CV_RegisterVar(&cv_bombshield);
 	CV_RegisterVar(&cv_1up);
 	CV_RegisterVar(&cv_eggmanbox);
+	
+	K_RegisterKartStuff(); // SRB2kart
 
 	CV_RegisterVar(&cv_ringslinger);
 
diff --git a/src/d_netcmd.h b/src/d_netcmd.h
index c090699f1..55865d9ee 100644
--- a/src/d_netcmd.h
+++ b/src/d_netcmd.h
@@ -98,6 +98,14 @@ extern consvar_t cv_jumpshield, cv_watershield, cv_ringshield, cv_forceshield, c
 extern consvar_t cv_1up, cv_eggmanbox;
 extern consvar_t cv_recycler;
 
+// SRB2kart items
+extern consvar_t cv_magnet, cv_boo, cv_mushroom, cv_triplemushroom, cv_megashroom;
+extern consvar_t cv_goldshroom, cv_star, cv_triplebanana, cv_fakeitem, cv_banana;
+extern consvar_t cv_greenshell, cv_redshell, cv_laserwisp, cv_triplegreenshell, cv_bobomb;
+extern consvar_t cv_blueshell, cv_jaws, cv_fireflower, cv_tripleredshell, cv_lightning;
+extern consvar_t cv_karthud;
+
+
 extern consvar_t cv_itemfinder;
 
 extern consvar_t cv_inttime, cv_advancemap, cv_playersforexit;
diff --git a/src/d_player.h b/src/d_player.h
index 6a32c3169..3387ee6a6 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -29,9 +29,6 @@
 // as commands per game tick.
 #include "d_ticcmd.h"
 
-// SRB2kart stuff
-#include "k_kart.h"
-
 // Extra abilities/settings for skins (combinable stuff)
 typedef enum
 {
@@ -233,6 +230,78 @@ typedef enum
 	NUMPOWERS
 } powertype_t;
 
+//{ SRB2kart - kartstuff
+typedef enum
+{
+	// Basic gameplay things
+	k_position,			// Used for Kart positions, mostly for deterministic stuff
+	k_playerahead,		// Is someone ahead of me or not?
+	k_oldposition,		// Used for taunting when you pass someone
+	k_prevcheck,		// Previous checkpoint distance; for p_user.c (was "pw_pcd")
+	k_nextcheck,		// Next checkpoint distance; for p_user.c (was "pw_ncd")
+	k_waypoint,			// Waypoints.
+	k_starpostwp,		// Temporarily stores player waypoint for... some reason. Used when respawning and finishing.
+	
+	k_throwdir, 		// Held dir of controls; 1 = forward, 0 = none, -1 = backward (was "player->heldDir")
+	k_turndir,			// Turn direction for drifting; -1 = Left, 1 = Right, 0 = none
+	k_sounds,			// Used this to avoid sounds being played every tic
+	
+	k_boosting,			// Determines if you're currently shroom-boosting to change how drifting works
+	k_spinout,			// Separate confirmation to prevent endless wipeout loops
+	k_spinouttype,		// Determines whether to thrust forward or not while spinning out; 0 = move forwards, 1 = stay still
+	
+	k_drift,			// Drifting Left or Right, plus a bigger counter = sharper turn
+	k_driftcharge,		// Charge your drift so you can release a burst of speed
+	k_jmp,				// In Mario Kart, letting go of the jump button stops the drift
+	k_lakitu,			// > 0 = Lakitu fishing, < 0 = Lakitu lap counter (was "player->airtime") // NOTE: Check for ->lakitu, replace with this
+	
+	k_itemroulette,		// Used for the roulette when deciding what item to give you (was "pw_kartitem")
+	k_itemslot,			// If you have X item, and kartitem chose X too, save it
+	k_itemclose,		// Used to animate the item window closing (was "pw_psychic")
+
+	// Some items use timers for their duration or effects
+	k_magnettimer,		// Duration of Magnet's item-break and item box pull
+	k_bootaketimer,		// You are stealing an item, this is your timer
+	k_boostolentimer,	// You are being stolen from, this is your timer
+	k_mushroomtimer,	// Duration of the Mushroom Boost itself
+	k_growshrinktimer,	// > 0 = Big, < 0 = small
+	k_squishedtimer,	// Squished frame timer
+	k_goldshroomtimer,	// Gold Mushroom duration timer
+	k_startimer,		// Invincibility timer
+	k_spinouttimer,		// Wipe-out from a banana peel or oil slick (was "pw_bananacam")
+	k_laserwisptimer,	// The duration and relative angle of the laser
+	k_fireflowertimer,	// Duration of Fire Flower
+
+	// Each item needs its own power slot, for the HUD and held use
+	k_magnet,			// 0x1 = Magnet in inventory
+	k_boo,				// 0x1 = Boo in inventory
+	k_mushroom,			// 0x1 = 1 Mushroom in inventory, 0x2 = 2 Mushrooms in inventory
+						// 0x4 = 3 Mushrooms in inventory
+	k_megashroom,		// 0x1 = Mega Mushroom in inventory
+	k_goldshroom,		// 0x1 = Gold Mushroom in inventory
+	k_star,				// 0x1 = Star in inventory
+	k_triplebanana,		// 0x1 = 1 Banana following, 0x2 = 2 Bananas following
+						// 0x4 = 3 Bananas following, 0x8 = Triple Banana in inventory
+	k_fakeitem,			// 0x1 = Fake Item being held, 0x2 = Fake Item in inventory
+	k_banana,			// 0x1 = Banana being held, 0x2 = Banana in inventory
+	k_greenshell,		// 0x1 = Green Shell being held, 0x2 = Green Shell in inventory
+	k_redshell,			// 0x1 = Red Shell being held, 0x2 = Red Shell in inventory
+	k_laserwisp,		// 0x1 = Laser Wisp in inventory
+	k_triplegreenshell,	// 0x1 = 1 Green Shell orbiting, 0x2 = 2 Green Shells orbiting
+						// 0x4 = 3 Green Shells orbiting, 0x8 = Triple Green Shell in inventory
+	k_bobomb,			// 0x1 = Bob-omb being held, 0x2 = Bob-omb in inventory
+	k_blueshell,		// 0x1 = Blue Shell in inventory
+	k_jaws,				// 0x1 = 1 Jaws orbiting, 0x2 = 2 Jaws orbiting, 
+						// 0x4 = 2x Jaws in inventory
+	k_fireflower,		// 0x1 = Fire Flower in inventory
+	k_tripleredshell,	// 0x1 = 1 Red Shell orbiting, 0x2 = 2 Red Shells orbiting
+						// 0x4 = 3 Red Shells orbiting, 0x8 = Triple Red Shell in inventory
+	k_lightning,		// 0x1 = Lightning in inventory
+
+	NUMKARTSTUFF
+} kartstufftype_t;
+//}
+
 #define WEP_AUTO    1
 #define WEP_BOUNCE  2
 #define WEP_SCATTER 3
diff --git a/src/dehacked.c b/src/dehacked.c
index b93220072..613dc85ed 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -3789,6 +3789,36 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	// Thok
 	"S_THOK",
 
+	// SRB2kart Frames
+	"S_KART_STND",
+	"S_KART_STND_L",
+	"S_KART_STND_R",
+	"S_KART_WALK1",
+	"S_KART_WALK2",
+	"S_KART_WALK_L1",
+	"S_KART_WALK_L2",
+	"S_KART_WALK_R1",
+	"S_KART_WALK_R2",
+	"S_KART_RUN1",
+	"S_KART_RUN2",
+	"S_KART_RUN_L1",
+	"S_KART_RUN_L2",
+	"S_KART_RUN_R1",
+	"S_KART_RUN_R2",
+	"S_KART_DRIFT_L1",
+	"S_KART_DRIFT_L2",
+	"S_KART_DRIFT_R1",
+	"S_KART_DRIFT_R2",
+	"S_KART_SPIN1",
+	"S_KART_SPIN2",
+	"S_KART_SPIN3",
+	"S_KART_SPIN4",
+	"S_KART_SPIN5",
+	"S_KART_SPIN6",
+	"S_KART_SPIN7",
+	"S_KART_SPIN8",
+	"S_KART_SQUISH",
+	/*
 	"S_PLAY_STND",
 	"S_PLAY_TAP1",
 	"S_PLAY_TAP2",
@@ -3844,6 +3874,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_PLAY_SUPERTRANS7",
 	"S_PLAY_SUPERTRANS8",
 	"S_PLAY_SUPERTRANS9", // This has special significance in the code. If you add more frames, search for it and make the appropriate changes.
+	*/
 
 	// technically the player goes here but it's an infinite tic state
 	"S_OBJPLACE_DUMMY",
diff --git a/src/g_game.c b/src/g_game.c
index 4b8fa81e8..d61d070f1 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -5357,7 +5357,7 @@ void G_AddGhost(char *defdemoname)
 		gh->mo = P_SpawnMobj(x, y, z, MT_GHOST);
 		gh->mo->angle = FixedAngle(mthing->angle*FRACUNIT);
 	}
-	gh->mo->state = states+S_PLAY_STND;
+	gh->mo->state = states+S_KART_STND; // SRB2kart - was S_PLAY_STND
 	gh->mo->sprite = gh->mo->state->sprite;
 	gh->mo->frame = (gh->mo->state->frame & FF_FRAMEMASK) | tr_trans20<<FF_TRANSSHIFT;
 	gh->mo->tics = -1;
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index e2cd70d6b..c4ebb9a8b 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -1347,7 +1347,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 			else
 			{
 				if (spr->mobj->state->nextstate != S_NULL && states[spr->mobj->state->nextstate].sprite != SPR_NULL
-					&& !(spr->mobj->player && (spr->mobj->state->nextstate == S_PLAY_TAP1 || spr->mobj->state->nextstate == S_PLAY_TAP2) && spr->mobj->state == &states[S_PLAY_STND]))
+					&& !(spr->mobj->player && spr->mobj->state == &states[S_KART_STND])) // SRB2kart
 				{
 					const UINT32 nextframe = (states[spr->mobj->state->nextstate].frame & FF_FRAMEMASK) % md2->model->header.numFrames;
 					next = &md2->model->frames[nextframe];
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index ec747305e..048caf42c 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -62,6 +62,7 @@
 //              heads up font
 //-------------------------------------------
 patch_t *hu_font[HU_FONTSIZE];
+patch_t *kart_font[KART_FONTSIZE];	// SRB2kart
 patch_t *tny_font[HU_FONTSIZE];
 patch_t *tallnum[10]; // 0-9
 patch_t *nightsnum[10]; // 0-9
@@ -213,6 +214,19 @@ void HU_LoadGraphics(void)
 	lt_font[17] = (patch_t *)W_CachePatchName("LTFNT056", PU_HUDGFX);
 	lt_font[18] = (patch_t *)W_CachePatchName("LTFNT057", PU_HUDGFX);
 
+	// SRB2kart
+	j = KART_FONTSTART;
+	for (i = 0; i < KART_FONTSIZE; i++, j++)
+	{
+		// cache the heads-up font for entire game execution
+		sprintf(buffer, "MKFNT%.3d", j);
+		if (W_CheckNumForName(buffer) == LUMPERROR)
+			kart_font[i] = NULL;
+		else
+			kart_font[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX);
+	}
+	//
+
 	j = LT_FONTSTART;
 	for (i = 0; i < LT_FONTSIZE; i++)
 	{
diff --git a/src/hu_stuff.h b/src/hu_stuff.h
index f0dd40096..be251ce03 100644
--- a/src/hu_stuff.h
+++ b/src/hu_stuff.h
@@ -26,6 +26,13 @@
 
 #define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1)
 
+// SRB2kart
+#define KART_FONTSTART '\"' // the first font character
+#define KART_FONTEND 'Z'
+
+#define KART_FONTSIZE (KART_FONTEND - KART_FONTSTART + 1)
+//
+
 // Level title font
 #define LT_FONTSTART '!' // the first font characters
 #define LT_FONTEND 'Z' // the last font characters
@@ -58,7 +65,7 @@ typedef struct
 //------------------------------------
 #define HU_MAXMSGLEN 224
 
-extern patch_t *hu_font[HU_FONTSIZE], *tny_font[HU_FONTSIZE];
+extern patch_t *hu_font[HU_FONTSIZE], *kart_font[KART_FONTSIZE], *tny_font[HU_FONTSIZE];	// SRB2kart
 extern patch_t *tallnum[10];
 extern patch_t *nightsnum[10];
 extern patch_t *lt_font[LT_FONTSIZE];
diff --git a/src/info.c b/src/info.c
index c621378e3..0ca0007c7 100644
--- a/src/info.c
+++ b/src/info.c
@@ -81,7 +81,37 @@ state_t states[NUMSTATES] =
 	// Thok
 	{SPR_THOK, FF_TRANS50, 8, {NULL}, 0, 0, S_NULL}, // S_THOK
 
-	// Player
+	// Player // SRB2kart
+	{SPR_PLAY,     0,  -1, {NULL},   0, 0, S_KART_STND},     // S_KART_STND		A
+	{SPR_PLAY,     1,  -1, {NULL},   0, 0, S_KART_STND_L},   // S_KART_STND_L	B
+	{SPR_PLAY,     2,  -1, {NULL},   0, 0, S_KART_STND_R},   // S_KART_STND_R	C
+	{SPR_PLAY,     3,   4, {NULL},   0, 0, S_KART_WALK2},    // S_KART_WALK1	D
+	{SPR_PLAY,     4,   4, {NULL},   0, 0, S_KART_WALK1},    // S_KART_WALK2	E
+	{SPR_PLAY,     5,   4, {NULL},   0, 0, S_KART_WALK_L2},  // S_KART_WALK_L1	F
+	{SPR_PLAY,     6,   4, {NULL},   0, 0, S_KART_WALK_L1},  // S_KART_WALK_L2	G
+	{SPR_PLAY,     7,   4, {NULL},   0, 0, S_KART_WALK_R2},  // S_KART_WALK_R1	H
+	{SPR_PLAY,     8,   4, {NULL},   0, 0, S_KART_WALK_R1},  // S_KART_WALK_R2	I
+	{SPR_PLAY,     0,   2, {NULL},   0, 0, S_KART_RUN2},     // S_KART_RUN1		A
+	{SPR_PLAY,     3,   2, {NULL},   0, 0, S_KART_RUN1},     // S_KART_RUN2		D
+	{SPR_PLAY,     1,   2, {NULL},   0, 0, S_KART_RUN_L2},   // S_KART_RUN_L1	B
+	{SPR_PLAY,     4,   2, {NULL},   0, 0, S_KART_RUN_L1},   // S_KART_RUN_L2	F
+	{SPR_PLAY,     2,   2, {NULL},   0, 0, S_KART_RUN_R2},   // S_KART_RUN_R1	C
+	{SPR_PLAY,     5,   2, {NULL},   0, 0, S_KART_RUN_R1},   // S_KART_RUN_R2	H
+	{SPR_PLAY,     9,   2, {NULL},   0, 0, S_KART_DRIFT_L2}, // S_KART_DRIFT_L1	J
+	{SPR_PLAY,    10,   2, {NULL},   0, 0, S_KART_DRIFT_L1}, // S_KART_DRIFT_L2 K
+	{SPR_PLAY,    11,   2, {NULL},   0, 0, S_KART_DRIFT_R2}, // S_KART_DRIFT_R1 L
+	{SPR_PLAY,    12,   2, {NULL},   0, 0, S_KART_DRIFT_R1}, // S_KART_DRIFT_R2 M
+	{SPR_PLAY,    13,   2, {NULL},   0, 0, S_KART_SPIN2},    // S_KART_SPIN1	N
+	{SPR_PLAY,    14,   2, {NULL},   0, 0, S_KART_SPIN3},    // S_KART_SPIN2	O
+	{SPR_PLAY,    15,   2, {NULL},   0, 0, S_KART_SPIN4},    // S_KART_SPIN3	P
+	{SPR_PLAY,    16,   2, {NULL},   0, 0, S_KART_SPIN5},    // S_KART_SPIN4	Q
+	{SPR_PLAY,    17,   2, {NULL},   0, 0, S_KART_SPIN6},    // S_KART_SPIN5	R
+	{SPR_PLAY,    18,   2, {NULL},   0, 0, S_KART_SPIN7},    // S_KART_SPIN6	S
+	{SPR_PLAY,    19,   2, {NULL},   0, 0, S_KART_SPIN8},    // S_KART_SPIN7	T
+	{SPR_PLAY,    20,   2, {NULL},   0, 0, S_KART_SPIN1},    // S_KART_SPIN8	U
+	{SPR_PLAY,    21, 350, {NULL},   0, 0, S_KART_STND},     // S_KART_PAIN		V
+	{SPR_PLAY,    22, 350, {NULL},   0, 0, S_KART_STND},     // S_KART_SQUISH	W
+	/*
 	{SPR_PLAY,     0, 105, {NULL},   0, 0, S_PLAY_TAP1},        // S_PLAY_STND
 	{SPR_PLAY,     1,  16, {NULL},   0, 0, S_PLAY_TAP2},        // S_PLAY_TAP1
 	{SPR_PLAY,     2,  16, {NULL},   0, 0, S_PLAY_TAP1},        // S_PLAY_TAP2
@@ -137,6 +167,7 @@ state_t states[NUMSTATES] =
 	{SPR_PLAY,    42,   3, {NULL},   0, 0, S_PLAY_SUPERTRANS8}, // S_PLAY_SUPERTRANS7
 	{SPR_PLAY,    43,   3, {NULL},   0, 0, S_PLAY_SUPERTRANS9}, // S_PLAY_SUPERTRANS8
 	{SPR_PLAY,    44,  16, {NULL},   0, 0, S_PLAY_RUN1},        // S_PLAY_SUPERTRANS9
+	*/
 
 	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY}, //S_OBJPLACE_DUMMY
 
@@ -2572,18 +2603,18 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 
 	{           // MT_PLAYER
 		-1,             // doomednum
-		S_PLAY_STND,    // spawnstate
+		S_KART_STND,    // spawnstate
 		1,              // spawnhealth
-		S_PLAY_RUN1,    // seestate
+		S_KART_WALK1,    // seestate
 		sfx_None,       // seesound
 		0,              // reactiontime
 		sfx_thok,       // attacksound
-		S_PLAY_PAIN,    // painstate
+		S_KART_PAIN,    // painstate
 		MT_THOK,        // painchance
 		sfx_None,       // painsound
 		S_NULL,         // meleestate
-		S_PLAY_ATK1,    // missilestate
-		S_PLAY_DIE,     // deathstate
+		S_NULL,         // missilestate
+		S_KART_PAIN,    // deathstate
 		S_NULL,         // xdeathstate
 		sfx_None,       // deathsound
 		1,              // speed
diff --git a/src/info.h b/src/info.h
index 6b943cd93..b87f5d735 100644
--- a/src/info.h
+++ b/src/info.h
@@ -592,6 +592,37 @@ typedef enum state
 	// Thok
 	S_THOK,
 
+	// SRB2kart Frames
+	S_KART_STND,
+	S_KART_STND_L,
+	S_KART_STND_R,
+	S_KART_WALK1,
+	S_KART_WALK2,
+	S_KART_WALK_L1,
+	S_KART_WALK_L2,
+	S_KART_WALK_R1,
+	S_KART_WALK_R2,
+	S_KART_RUN1,
+	S_KART_RUN2,
+	S_KART_RUN_L1,
+	S_KART_RUN_L2,
+	S_KART_RUN_R1,
+	S_KART_RUN_R2,
+	S_KART_DRIFT_L1,
+	S_KART_DRIFT_L2,
+	S_KART_DRIFT_R1,
+	S_KART_DRIFT_R2,
+	S_KART_SPIN1,
+	S_KART_SPIN2,
+	S_KART_SPIN3,
+	S_KART_SPIN4,
+	S_KART_SPIN5,
+	S_KART_SPIN6,
+	S_KART_SPIN7,
+	S_KART_SPIN8,
+	S_KART_PAIN,
+	S_KART_SQUISH,
+	/*
 	S_PLAY_STND,
 	S_PLAY_TAP1,
 	S_PLAY_TAP2,
@@ -647,6 +678,7 @@ typedef enum state
 	S_PLAY_SUPERTRANS7,
 	S_PLAY_SUPERTRANS8,
 	S_PLAY_SUPERTRANS9, // This has special significance in the code. If you add more frames, search for it and make the appropriate changes.
+	*/
 
 	// technically the player goes here but it's an infinite tic state
 	S_OBJPLACE_DUMMY,
diff --git a/src/k_kart.c b/src/k_kart.c
index 703bc929d..60166b602 100644
--- a/src/k_kart.c
+++ b/src/k_kart.c
@@ -5,8 +5,16 @@
 ///        All of the SRB2kart-unique stuff.
 
 #include "doomdef.h"
+#include "hu_stuff.h"
+#include "g_game.h"
+#include "m_random.h"
+#include "p_local.h"
 #include "r_draw.h"
 #include "r_local.h"
+#include "s_sound.h"
+#include "st_stuff.h"
+#include "v_video.h"
+#include "z_zone.h"
 
 //{ SRB2kart Color Code
 
@@ -257,9 +265,294 @@ UINT8 K_GetKartColorByName(const char *name)
 
 //}
 
+//{ SRB2kart Net Variables
 
-//{ P_KartPlayerThink - for p_user.c
+void K_RegisterKartStuff(void)
+{
+	CV_RegisterVar(&cv_magnet);
+	CV_RegisterVar(&cv_boo);
+	CV_RegisterVar(&cv_mushroom);
+	CV_RegisterVar(&cv_triplemushroom);
+	CV_RegisterVar(&cv_megashroom);
+	CV_RegisterVar(&cv_goldshroom);
+	CV_RegisterVar(&cv_star);
+	CV_RegisterVar(&cv_triplebanana);
+	CV_RegisterVar(&cv_fakeitem);
+	CV_RegisterVar(&cv_banana);
+	CV_RegisterVar(&cv_greenshell);
+	CV_RegisterVar(&cv_redshell);
+	CV_RegisterVar(&cv_laserwisp);
+	CV_RegisterVar(&cv_triplegreenshell);
+	CV_RegisterVar(&cv_bobomb);
+	CV_RegisterVar(&cv_blueshell);
+	CV_RegisterVar(&cv_jaws);
+	CV_RegisterVar(&cv_fireflower);
+	CV_RegisterVar(&cv_tripleredshell);
+	CV_RegisterVar(&cv_lightning);
+}
+
+//}
+
+//{ SRB2kart Roulette Code
+
+#define NUMKARTITEMS 	18
+#define NUMKARTODDS 	40
+
+fixed_t spawnchance[NUMKARTITEMS * NUMKARTODDS];	// Holds the actual odds.
+fixed_t basechance, chance, prevchance;				// Base chance (item itself), current chance (counter), previous chance
+fixed_t numchoices, pingame, pexiting;
+
+// Ugly ol' 3D array
+static fixed_t K_KartItemOdds_Retro[MAXPLAYERS][NUMKARTITEMS][MAXPLAYERS] =
+{
+	// 1 Active Player
+	{  //1st //
+		{  0 },	// Magnet
+		{  0 },	// Boo
+		{ 40 },	// Mushroom
+		{  0 },	// Triple Mushroom
+		{  0 },	// Mega Mushroom
+		{  0 },	// Gold Mushroom
+		{  0 },	// Star
+		{  0 },	// Triple Banana
+		{  0 },	// Fake Item
+		{  0 },	// Banana
+		{  0 },	// Green Shell
+		{  0 },	// Red Shell
+		{  0 },	// Triple Green Shell
+		{  0 },	// Bob-omb
+		{  0 },	// Blue Shell
+		{  0 },	// Fire Flower
+		{  0 },	// Triple Red Shell
+		{  0 }	// Lightning
+	} //1st //
+};
+
+/**	\brief	Item Roulette for Kart
+
+	\param	player		player
+	\param	getitem		what item we're looking for
+	\param	retrokart	whether or not we're getting old or new item odds
+
+	\return	void
+*/
+static void K_KartGetItemResult(player_t *player, fixed_t getitem, boolean retrokart)
+{
+	switch (getitem)
+	{
+		case  1:	// Magnet
+			player->kartstuff[k_magnet] = 1;
+			break;
+		case  2:	// Boo
+			player->kartstuff[k_boo] = 1;
+			break;
+		case  4:	// Triple Mushroom
+			player->kartstuff[k_mushroom] = 4;
+			break;
+		case  5:	// Mega Mushroom
+			player->kartstuff[k_megashroom] = 1;
+			break;
+		case  6:	// Gold Mushroom
+			player->kartstuff[k_goldshroom] = 1;
+			break;
+		case  7:	// Star
+			player->kartstuff[k_star] = 1;
+			break;
+		case  8:	// Triple Banana
+			player->kartstuff[k_triplebanana] |= 8;
+			break;
+		case  9:	// Fake Item
+			player->kartstuff[k_fakeitem] |= 2;
+			break;
+		case 10:	// Banana
+			player->kartstuff[k_banana] |= 2;
+			break;
+		case 11:	// Green Shell
+			player->kartstuff[k_greenshell] |= 2;
+			break;
+		case 12:	// Red Shell
+			player->kartstuff[k_redshell] |= 2;
+			break;
+		case 13:	// Triple Green Shell	- or -	Laser Wisp
+			if (retrokart)
+				player->kartstuff[k_triplegreenshell] |= 8;
+			else
+				player->kartstuff[k_laserwisp] = 1;
+			break;
+		case 14:	// Bob-omb				- or -	3x Orbinaut (Triple Green Shell)
+			if (retrokart)
+				player->kartstuff[k_bobomb] |= 2;
+			else
+				player->kartstuff[k_triplegreenshell] |= 8;
+			break;
+		case 15:	// Blue Shell			- or -	Specialstage Mines (Bob-omb)
+			if (retrokart)
+				player->kartstuff[k_blueshell] = 1;
+			else
+				player->kartstuff[k_bobomb] |= 2;
+			break;
+		case 16:	// Fire Flower			- or -	Deton (Blue Shell)
+			if (retrokart)
+				player->kartstuff[k_fireflower] = 1;
+			else
+				player->kartstuff[k_blueshell] |= 4;
+			break;
+		case 17:	// Triple Red Shell		- or -	2x Jaws
+			if (retrokart)
+				player->kartstuff[k_tripleredshell] |= 8;
+			else
+				player->kartstuff[k_jaws] = 1;
+			break;
+		case 18:	// Lightning
+			player->kartstuff[k_lightning] = 1;
+			break;
+		default:	// Mushroom - Doing it here as a fail-safe
+			if (getitem != 3)
+				CONS_Printf("ERROR: P_KartGetItemResult - Item roulette gave bad item (%d), giving Mushroom instead.\n", getitem);
+			player->kartstuff[k_mushroom] = 1;
+			break;
+	}
+	
+	player->kartstuff[k_itemroulette] = 0; // Since we're done, clear the roulette number
+	
+	//if (P_IsLocalPlayer(player))
+	//	S_StartSound(NULL, sfx_mkitemF);
+}
+
+/**	\brief	Item Roulette for Kart
+
+	\param	position	player position in the race
+	\param	giveitem	what item we're slotting into the basechance
+
+	\return	void
+*/
+static void K_KartSetItemResult(fixed_t position, fixed_t giveitem)
+{
+	prevchance = chance;
+	basechance = K_KartItemOdds_Retro[pingame][giveitem][position];		// Number of slots in the array, based on odds
+	for (; chance < prevchance + basechance; chance++) 
+	{ 
+		spawnchance[chance] = giveitem;
+		numchoices++;
+	}
+}
+
+/**	\brief	Item Roulette for Kart
+
+	\param	player	player object passed from P_KartPlayerThink
+
+	\return	void
+*/
+static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
+{
+	// This makes the roulette cycle through items - if this is 0, you shouldn't be here.
+	if (player->kartstuff[k_itemroulette])
+		player->kartstuff[k_itemroulette]++;
+	else
+		return;
+		
+	// This makes the roulette produce the random noises.
+	//if ((player->kartstuff[k_itemroulette] % 3) == 1 && P_IsLocalPlayer(player))
+	//	S_StartSound(NULL,sfx_mkitem1 + ((player->kartstuff[k_itemroulette] / 3) % 8));
+
+	// If the roulette finishes or the player presses BT_ATTACK, stop the roulette and calculate the item.
+	// I'm returning via the exact opposite, however, to forgo having another bracket embed. Same result either way, I think.
+	// Finally, if you get past this check, now you can actually start calculating what item you get.
+	if (!(player->kartstuff[k_itemroulette] > (TICRATE*3)-1 || ((cmd->buttons & BT_ATTACK) && player->kartstuff[k_itemroulette] > ((TICRATE*2)/3)-1)))
+		return;
+	
+	// Initializes existing values
+	basechance = chance = prevchance = 0;
+	numchoices = pingame = pexiting = 0;
+	
+	INT32 i;
+	
+	// Initializes existing spawnchance values
+	for (i = 0; i < (NUMKARTITEMS * NUMKARTODDS); i++)
+		spawnchance[i] = 0;
+	
+	// Gotta check how many players are active at this moment.
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		if (playeringame[i] && !players[i].spectator)
+			pingame++;
+		if (players[i].exiting)
+			pexiting++;
+	}
+	
+	if (cmd->buttons & BT_ATTACK)
+		player->pflags |= PF_ATTACKDOWN;
+	
+	player->kartstuff[k_itemclose] = 0;	// Reset the item window closer.
 	
+	// Yes I know I'm defining variables half-way into the function, but they aren't needed until now :/
+	fixed_t prandom = P_RandomFixed();
+	fixed_t ppos = player->kartstuff[k_position] - 1;
+	
+	// Check the game type to differentiate odds.
+	//if (gametype == GT_RETRO)
+	//{
+		if (cv_magnet.value) 							K_KartSetItemResult(ppos, 1);	// Magnet
+		if (cv_boo.value)								K_KartSetItemResult(ppos, 2);	// Boo
+		if (cv_mushroom.value)							K_KartSetItemResult(ppos, 3);	// Mushroom
+		if (cv_mushroom.value)							K_KartSetItemResult(ppos, 4);	// Triple Mushroom
+		if (cv_megashroom.value)						K_KartSetItemResult(ppos, 5);	// Mega Mushroom
+		if (cv_goldshroom.value)						K_KartSetItemResult(ppos, 6);	// Gold Mushroom
+		if (cv_star.value)								K_KartSetItemResult(ppos, 7);	// Star
+		if (cv_triplebanana.value)						K_KartSetItemResult(ppos, 8);	// Triple Banana
+		if (cv_fakeitem.value)							K_KartSetItemResult(ppos, 9);	// Fake Item
+		if (cv_banana.value)							K_KartSetItemResult(ppos, 10);	// Banana
+		if (cv_greenshell.value)						K_KartSetItemResult(ppos, 11);	// Green Shell
+		if (cv_redshell.value)							K_KartSetItemResult(ppos, 12);	// Red Shell
+		if (cv_triplegreenshell.value)					K_KartSetItemResult(ppos, 13);	// Triple Green Shell
+		if (cv_bobomb.value)							K_KartSetItemResult(ppos, 14);	// Bob-omb
+		if (cv_blueshell.value && pexiting == 0)		K_KartSetItemResult(ppos, 15);	// Blue Shell
+		if (cv_fireflower.value)						K_KartSetItemResult(ppos, 16);	// Fire Flower
+		if (cv_tripleredshell.value)					K_KartSetItemResult(ppos, 17);	// Triple Red Shell
+		if (cv_lightning.value && pingame > pexiting)	K_KartSetItemResult(ppos, 18);	// Lightning
+			
+		// Award the player whatever power is rolled
+		if (numchoices > 0)
+			K_KartGetItemResult(player, spawnchance[prandom%numchoices], true);
+		else
+			CONS_Printf("ERROR: P_KartItemRoulette - There were no choices given by the roulette.\n");
+	//}
+	/*else if (gametype == GT_NEO)
+	{
+		if (cv_magnet.value) 							K_KartSetItemResult(ppos, 1)	// Electro-Shield
+		if (cv_boo.value)								K_KartSetItemResult(ppos, 2)	// S3K Ghost
+		if (cv_mushroom.value)							K_KartSetItemResult(ppos, 3)	// Speed Shoe
+		if (cv_mushroom.value)							K_KartSetItemResult(ppos, 4)	// Triple Speed Shoe
+		if (cv_megashroom.value)						K_KartSetItemResult(ppos, 5)	// Size-Up Monitor
+		if (cv_goldshroom.value)						K_KartSetItemResult(ppos, 6)	// Rocket Shoe
+		if (cv_star.value)								K_KartSetItemResult(ppos, 7)	// Invincibility
+		if (cv_triplebanana.value)						K_KartSetItemResult(ppos, 8)	// Triple Banana
+		if (cv_fakeitem.value)							K_KartSetItemResult(ppos, 9)	// Eggman Monitor
+		if (cv_banana.value)							K_KartSetItemResult(ppos, 10)	// Banana
+		if (cv_greenshell.value)						K_KartSetItemResult(ppos, 11)	// 1x Orbinaut
+		if (cv_redshell.value)							K_KartSetItemResult(ppos, 12)	// 1x Jaws
+		if (cv_laserwisp.value)							K_KartSetItemResult(ppos, 13)	// Laser Wisp
+		if (cv_triplegreenshell.value)					K_KartSetItemResult(ppos, 14)	// 3x Orbinaut
+		if (cv_bobomb.value)							K_KartSetItemResult(ppos, 15)	// Specialstage Mines
+		if (cv_blueshell.value && pexiting == 0)		K_KartSetItemResult(ppos, 16)	// Deton
+		if (cv_jaws.value)								K_KartSetItemResult(ppos, 17)	// 2x Jaws
+		if (cv_lightning.value && pingame > pexiting)	K_KartSetItemResult(ppos, 18)	// Size-Down Monitor
+		
+		// Award the player whatever power is rolled
+		if (numchoices > 0)
+			K_KartGetItemResult(player, spawnchance[prandom%numchoices], false)
+		else
+			CONS_Printf("ERROR: P_KartItemRoulette - There were no choices given by the roulette.\n");
+	}
+	else
+		CONS_Printf("ERROR: P_KartItemRoulette - There's no applicable game type!\n");
+	*/
+}
+
+//}
+
+//{ SRB2kart p_user.c Stuff
+
 /**	\brief	Decreases various kart timers and powers per frame. Called in P_PlayerThink in p_user.c
 
 	\param	player	player object passed from P_PlayerThink
@@ -267,7 +560,7 @@ UINT8 K_GetKartColorByName(const char *name)
 
 	\return	void
 */
-void P_KartPlayerThink(player_t *player, ticcmd_t *cmd)
+void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
 {
 	// This spawns the drift sparks when k_driftcharge hits 30. Its own AI handles life/death and color
 	//if ((player->kartstuff[k_drift] == 1 || player->kartstuff[k_drift] == -1) 
@@ -301,7 +594,7 @@ void P_KartPlayerThink(player_t *player, ticcmd_t *cmd)
 	if (player->kartstuff[k_growshrinktimer] == 1 || player->kartstuff[k_growshrinktimer] == -1)
 	{
 		player->mo->destscale = 100;
-		P_RestoreMusic(player);
+		//P_RestoreMusic(player);
 	}
 	
 	if (player->kartstuff[k_bootaketimer] == 0 && player->kartstuff[k_boostolentimer] == 0
@@ -327,9 +620,8 @@ void P_KartPlayerThink(player_t *player, ticcmd_t *cmd)
 	// Restores music if too many sounds are playing (?)
 	if (player->kartstuff[k_sounds] >= 1 && player->kartstuff[k_sounds] < 120)
 		player->kartstuff[k_sounds] += 1;
-	if ((player->kartstuff[k_sounds] < 120 && player->kartstuff[k_sounds] > 116) 
-		&& P_IsLocalPlayer(player))
-		P_RestoreMusic(player);
+	//if (player->kartstuff[k_sounds] < 120 && player->kartstuff[k_sounds] > 116)	//&& P_IsLocalPlayer(player))
+	//	P_RestoreMusic(player);
 	
 	// ???
 	/*
@@ -347,21 +639,21 @@ void P_KartPlayerThink(player_t *player, ticcmd_t *cmd)
 	else 
 		player->kartstuff[k_jmp] = 0;
 		
-	P_KartItemRoulette(player); // Roulette Code
+	K_KartItemRoulette(player, cmd); // Roulette Code
 	
 	// Looping and stopping of the horrible horrible star SFX ~Sryder
 	if (player->mo->health > 0 && player->mo->player->kartstuff[k_startimer])// If you have invincibility
 	{
 		if (!P_IsLocalPlayer(player)) // If it isn't the current player
 		{
-			if (!S_SoundPlaying(NULL, sfx_star)) // and it isn't still playing
-				S_StartSound(player->mo, sfx_star); // play it again
+			//if (!S_SoundPlaying(NULL, sfx_star)) // and it isn't still playing
+			//	S_StartSound(player->mo, sfx_star); // play it again
 		}
 	}
 	else if (player->mo->health <= 0 || player->mo->player->kartstuff[k_startimer] <= 0 || player->mo->player->kartstuff[k_growshrinktimer] > 0) // If you don't have invincibility (or mega is active too)
 	{
-		if (S_SoundPlaying(player->mo, sfx_star)) // But the sound is playing
-			S_StopSoundByID(player->mo, sfx_star); // Stop it
+		//if (S_SoundPlaying(player->mo, sfx_star)) // But the sound is playing
+		//	S_StopSoundByID(player->mo, sfx_star); // Stop it
 	}
 
 	// And now the same for the mega mushroom SFX ~Sryder
@@ -369,20 +661,928 @@ void P_KartPlayerThink(player_t *player, ticcmd_t *cmd)
 	{
 		if (!P_IsLocalPlayer(player)) // If it isn't the current player
 		{
-			if (!S_SoundPlaying(NULL, sfx_mega)) // and it isn't still playing
-				S_StartSound(player->mo, sfx_mega); // play it again
+			//if (!S_SoundPlaying(NULL, sfx_mega)) // and it isn't still playing
+			//	S_StartSound(player->mo, sfx_mega); // play it again
 		}
 	}
 	else // If you aren't big
 	{
-		if (S_SoundPlaying(player->mo, sfx_mega)) // But the sound is playing
-			S_StopSoundByID(player->mo, sfx_mega); // Stop it
+		//if (S_SoundPlaying(player->mo, sfx_mega)) // But the sound is playing
+		//	S_StopSoundByID(player->mo, sfx_mega); // Stop it
+	}
+}
+
+boolean P_SpinPlayerMobj(mobj_t *target, mobj_t *source)
+{
+	player_t *player;
+
+	if (!(target->flags & MF_SHOOTABLE))
+		return false; // shouldn't happen...
+
+	if (target->health <= 0)
+		return false;
+
+	if (!target || !target->player)
+		return false; // Just for players
+
+	player = target->player;
+
+	if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || (player->kartstuff[k_spinouttimer] > 0 && player->kartstuff[k_spinout] > 0)
+		|| player->kartstuff[k_startimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_bootaketimer] > 0)
+		return false;
+
+	if (player)
+	{
+		player->kartstuff[k_mushroomtimer] = 0;
+
+		if (player->kartstuff[k_spinouttype] == 0)
+		{
+			player->kartstuff[k_spinouttimer] = 2*TICRATE;
+
+			if (player->speed < player->normalspeed/4)
+				P_InstaThrust(player->mo, player->mo->angle, player->normalspeed*FRACUNIT/4);
+
+			//S_StartSound(player->mo, sfx_slip); // TODO: add this sound
+		}
+		else
+			player->kartstuff[k_spinouttimer] = 1*TICRATE;
+
+		player->powers[pw_flashing] = flashingtics;
+
+		player->kartstuff[k_spinout] = player->kartstuff[k_spinouttimer];
+
+		if (!(player->mo->state >= &states[S_KART_SPIN1] && player->mo->state <= &states[S_KART_SPIN8])) // Turning the player seems like a bad way to do it, so we'll use states instead
+			P_SetPlayerMobjState(player->mo, S_KART_SPIN1);
+
+		player->kartstuff[k_spinouttype] = 0;
+	}
+	return true;
+}
+
+boolean P_SquishPlayerMobj(mobj_t *target, mobj_t *source)
+{
+	player_t *player;
+
+	if (!(target->flags & MF_SHOOTABLE))
+		return false; // shouldn't happen...
+
+	if (target->health <= 0)
+		return false;
+
+	if (!target || !target->player)
+		return false; // Just for players
+
+	player = target->player;
+
+	if (player->powers[pw_flashing] > 0	|| player->kartstuff[k_squishedtimer] > 0 
+		|| player->kartstuff[k_startimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_bootaketimer] > 0)
+		return false;
+
+	if (player)
+	{
+		player->kartstuff[k_mushroomtimer] = 0;
+
+		player->kartstuff[k_squishedtimer] = 2*TICRATE;
+
+		player->powers[pw_flashing] = flashingtics;
+
+		player->mo->flags |= MF_NOCLIP;
+
+		if (player->mo->state != &states[S_KART_SQUISH]) // Squash
+			P_SetPlayerMobjState(player->mo, S_KART_SQUISH);
+
+		P_PlayRinglossSound(player->mo);
+	}
+	return true;
+}
+
+boolean P_ExplodePlayerMobj(mobj_t *target, mobj_t *source) // A bit of a hack, we just throw the player up higher here and extend their spinout timer
+{
+	player_t *player;
+
+	if (!(target->flags & MF_SHOOTABLE))
+		return false; // shouldn't happen...
+
+	if (target->health <= 0)
+		return false;
+
+	if (!target || !target->player)
+		return false; // Just for players
+
+	player = target->player;
+
+	if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || (player->kartstuff[k_spinouttimer] > 0 && player->kartstuff[k_spinout] > 0)
+		|| player->kartstuff[k_startimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_bootaketimer] > 0)
+		return false;
+
+	if (player)
+	{
+		player->mo->momz = 18*FRACUNIT;
+		player->mo->momx = player->mo->momy = 0;
+
+		player->kartstuff[k_mushroomtimer] = 0;
+
+		player->kartstuff[k_spinouttype] = 1;
+		player->kartstuff[k_spinouttimer] = 2*TICRATE+(TICRATE/2);
+		player->kartstuff[k_spinout] = player->kartstuff[k_spinouttimer];
+
+		player->powers[pw_flashing] = flashingtics;
+
+
+		if (!(player->mo->state >= &states[S_KART_SPIN1] && player->mo->state <= &states[S_KART_SPIN8])) // Turning the player seems like a bad way to do it, so we'll use states instead
+			P_SetPlayerMobjState(player->mo, S_KART_SPIN1);
+
+		player->kartstuff[k_spinouttype] = 0;
+
+		P_PlayRinglossSound(player->mo);
+	}
+	return true;
+
+}
+
+//}
+
+//{ SRB2kart HUD Code
+
+#define NUMPOSNUMS 10
+#define NUMPOSFRAMES 7 // White, three blues, three reds 
+
+//{ 	Patch Definitions
+static patch_t *kp_nodraw;
+static patch_t *kp_noitem;
+static patch_t *kp_timesticker;
+static patch_t *kp_timestickerwide;
+static patch_t *kp_lapsticker;
+static patch_t *kp_lapstickernarrow;
+static patch_t *kp_positionnum[NUMPOSNUMS][NUMPOSFRAMES];
+static patch_t *kp_facenull;
+static patch_t *kp_facefirst;
+static patch_t *kp_facesecond;
+static patch_t *kp_facethird;
+static patch_t *kp_facefourth;
+static patch_t *kp_magnet;
+static patch_t *kp_boo;
+static patch_t *kp_boosteal;
+static patch_t *kp_mushroom;
+static patch_t *kp_doublemushroom;
+static patch_t *kp_triplemushroom;
+static patch_t *kp_megashroom;
+static patch_t *kp_goldshroom;
+static patch_t *kp_star;
+static patch_t *kp_triplebanana;
+static patch_t *kp_fakeitem;
+static patch_t *kp_banana;
+static patch_t *kp_greenshell;
+static patch_t *kp_redshell;
+static patch_t *kp_triplegreenshell;
+static patch_t *kp_bobomb;
+static patch_t *kp_blueshell;
+static patch_t *kp_fireflower;
+static patch_t *kp_tripleredshell;
+static patch_t *kp_lightning;
+static patch_t *kp_itemused1;
+static patch_t *kp_itemused2;
+static patch_t *kp_itemused3;
+static patch_t *kp_itemused4;
+static patch_t *kp_itemused5;
+static patch_t *kp_singlebananaicon;
+static patch_t *kp_doublebananaicon;
+static patch_t *kp_triplebananaicon;
+static patch_t *kp_singlegreenshellicon;
+static patch_t *kp_doublegreenshellicon;
+static patch_t *kp_triplegreenshellicon;
+static patch_t *kp_singleredshellicon;
+static patch_t *kp_doubleredshellicon;
+static patch_t *kp_tripleredshellicon;
+/*
+static patch_t *kp_neonoitem;
+static patch_t *kp_electroshield;
+static patch_t *kp_skghost;
+static patch_t *kp_skghoststeal;
+static patch_t *kp_speedshoe;
+static patch_t *kp_doublespeedshoe;
+static patch_t *kp_triplespeedshoe;
+static patch_t *kp_sizeupmonitor;
+static patch_t *kp_rocketshoe;
+static patch_t *kp_invincibility;
+static patch_t *kp_neotriplebanana;
+static patch_t *kp_eggmanmonitor;
+static patch_t *kp_neobanana;
+static patch_t *kp_orbinaut;
+static patch_t *kp_jaws;
+static patch_t *kp_tripleorbinaut;
+static patch_t *kp_specialstagemine;
+static patch_t *kp_deton;
+static patch_t *kp_laserwisp;
+static patch_t *kp_doublejaws;
+static patch_t *kp_sizedownmonitor;
+static patch_t *kp_neoitemused1;
+static patch_t *kp_neoitemused2;
+static patch_t *kp_neoitemused3;
+static patch_t *kp_neoitemused4;
+static patch_t *kp_neoitemused5;
+*/
+
+void K_LoadKartHUDGraphics(void)
+{
+	INT32 i, j;
+	char buffer[9];
+	
+	// Null Stuff
+	kp_nodraw = 				W_CachePatchName("K_TRNULL", PU_HUDGFX);
+	kp_noitem = 				W_CachePatchName("K_ITNULL", PU_HUDGFX);
+	//kp_neonoitem = 				W_CachePatchName("KNITNULL", PU_HUDGFX);
+	
+	// Stickers
+	kp_timesticker = 			W_CachePatchName("K_STTIME", PU_HUDGFX);
+	kp_timestickerwide = 		W_CachePatchName("K_STTIMW", PU_HUDGFX);
+	kp_lapsticker = 			W_CachePatchName("K_STLAPS", PU_HUDGFX);
+	kp_lapstickernarrow = 		W_CachePatchName("K_STLAPN", PU_HUDGFX);
+	
+	// Position numbers
+	for (i = 0; i < NUMPOSNUMS; i++)
+	{
+		for (j = 0; j < NUMPOSFRAMES; j++)
+		{
+			if (i > 4 && j < 4 && j != 0) continue;	// We don't need blue numbers for ranks past 4th
+			sprintf(buffer, "K_POSN%d%d", i, j);
+			kp_positionnum[i][j] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
+		}
 	}
+	kp_facenull = 				W_CachePatchName("K_PFACE0", PU_HUDGFX);
+	kp_facefirst = 				W_CachePatchName("K_PFACE1", PU_HUDGFX);
+	kp_facesecond = 			W_CachePatchName("K_PFACE2", PU_HUDGFX);
+	kp_facethird = 				W_CachePatchName("K_PFACE3", PU_HUDGFX);
+	kp_facefourth = 			W_CachePatchName("K_PFACE4", PU_HUDGFX);
+	
+	// Kart Item Windows
+	kp_magnet = 				W_CachePatchName("K_ITMAGN", PU_HUDGFX);
+	kp_boo = 					W_CachePatchName("K_ITBOO1", PU_HUDGFX);
+	kp_boosteal =				W_CachePatchName("K_ITBOO2", PU_HUDGFX);
+	kp_mushroom = 				W_CachePatchName("K_ITMUSH", PU_HUDGFX);
+	kp_doublemushroom = 		W_CachePatchName("K_ITDOUB", PU_HUDGFX);
+	kp_triplemushroom = 		W_CachePatchName("K_ITTRIP", PU_HUDGFX);
+	kp_megashroom = 			W_CachePatchName("K_ITMEGA", PU_HUDGFX);
+	kp_goldshroom = 			W_CachePatchName("K_ITGOLD", PU_HUDGFX);
+	kp_star = 					W_CachePatchName("K_ITSTAR", PU_HUDGFX);
+	kp_triplebanana = 			W_CachePatchName("K_ITTBAN", PU_HUDGFX);
+	kp_fakeitem = 				W_CachePatchName("K_ITFAKE", PU_HUDGFX);
+	kp_banana = 				W_CachePatchName("K_ITBANA", PU_HUDGFX);
+	kp_greenshell = 			W_CachePatchName("K_ITGREE", PU_HUDGFX);
+	kp_redshell = 				W_CachePatchName("K_ITREDS", PU_HUDGFX);
+	kp_triplegreenshell = 		W_CachePatchName("K_ITTGRE", PU_HUDGFX);
+	kp_bobomb = 				W_CachePatchName("K_ITBOBO", PU_HUDGFX);
+	kp_blueshell = 				W_CachePatchName("K_ITBLUE", PU_HUDGFX);
+	kp_fireflower = 			W_CachePatchName("K_ITFIRE", PU_HUDGFX);
+	kp_tripleredshell = 		W_CachePatchName("K_ITTRED", PU_HUDGFX);
+	kp_lightning = 				W_CachePatchName("K_ITLIGH", PU_HUDGFX);
+	
+	// Item-used - Closing the item window after an item is used
+	kp_itemused1 = 				W_CachePatchName("K_ITUSE1", PU_HUDGFX);
+	kp_itemused2 = 				W_CachePatchName("K_ITUSE2", PU_HUDGFX);
+	kp_itemused3 = 				W_CachePatchName("K_ITUSE3", PU_HUDGFX);
+	kp_itemused4 = 				W_CachePatchName("K_ITUSE4", PU_HUDGFX);
+	kp_itemused5 = 				W_CachePatchName("K_ITUSE5", PU_HUDGFX);
+	
+	// Triple-item HUD icons
+	kp_singlebananaicon = 		W_CachePatchName("K_TRBAN1", PU_HUDGFX);
+	kp_doublebananaicon = 		W_CachePatchName("K_TRBAN2", PU_HUDGFX);
+	kp_triplebananaicon = 		W_CachePatchName("K_TRBAN3", PU_HUDGFX);
+	kp_singlegreenshellicon = 	W_CachePatchName("K_TRGRE1", PU_HUDGFX);
+	kp_doublegreenshellicon = 	W_CachePatchName("K_TRGRE2", PU_HUDGFX);
+	kp_triplegreenshellicon = 	W_CachePatchName("K_TRGRE3", PU_HUDGFX);
+	kp_singleredshellicon = 	W_CachePatchName("K_TRRED1", PU_HUDGFX);
+	kp_doubleredshellicon = 	W_CachePatchName("K_TRRED2", PU_HUDGFX);
+	kp_tripleredshellicon = 	W_CachePatchName("K_TRRED3", PU_HUDGFX);
+
+	/*
+	// Neo-Kart item windows
+	kp_electroshield = 			W_CachePatchName("KNITELEC", PU_HUDGFX);
+	kp_skghost = 				W_CachePatchName("KTITSKG1", PU_HUDGFX);
+	kp_skghoststeal = 			W_CachePatchName("KTITSKG2", PU_HUDGFX);
+	kp_speedshoe = 				W_CachePatchName("KTITSPEE", PU_HUDGFX);
+	kp_triplespeedshoe = 		W_CachePatchName("KTITTSPE", PU_HUDGFX);
+	kp_sizeupmonitor = 			W_CachePatchName("KTITSUPM", PU_HUDGFX);
+	kp_rocketshoe = 			W_CachePatchName("KTITROCK", PU_HUDGFX);
+	kp_invincibility = 			W_CachePatchName("KTITINVI", PU_HUDGFX);
+	kp_neotriplebanana = 		W_CachePatchName("KTITTBAN", PU_HUDGFX);
+	kp_eggmanmonitor = 			W_CachePatchName("KTITEGGM", PU_HUDGFX);
+	kp_neobanana = 				W_CachePatchName("KTITBANA", PU_HUDGFX);
+	kp_orbinaut = 				W_CachePatchName("KTITORBI", PU_HUDGFX);
+	kp_jaws = 					W_CachePatchName("KTITJAWS", PU_HUDGFX);
+	kp_tripleorbinaut = 		W_CachePatchName("KTITTORB", PU_HUDGFX);
+	kp_specialstagemine = 		W_CachePatchName("KTITSPEC", PU_HUDGFX);
+	kp_deton = 					W_CachePatchName("KTITDETO", PU_HUDGFX);
+	kp_laserwisp = 				W_CachePatchName("KTITLASE", PU_HUDGFX);
+	kp_doublejaws = 			W_CachePatchName("KTITDJAW", PU_HUDGFX);
+	kp_sizedownmonitor = 		W_CachePatchName("KTITSDOW", PU_HUDGFX);
+	
+	// Item-used - Closing the item window after an item is used (Neo-Kart)
+	kp_neoitemused1 = 			W_CachePatchName("KNITUSE1", PU_HUDGFX);
+	kp_neoitemused2 = 			W_CachePatchName("KNITUSE2", PU_HUDGFX);
+	kp_neoitemused3 = 			W_CachePatchName("KNITUSE3", PU_HUDGFX);
+	kp_neoitemused4 = 			W_CachePatchName("KNITUSE4", PU_HUDGFX);
+	kp_neoitemused5 = 			W_CachePatchName("KNITUSE5", PU_HUDGFX);
+	*/
 }
 
 //}
 
+static INT32 STRINGY(INT32 y)
+{
+	// Copied from st_stuff.c
+	if (splitscreen)
+	{
+		y >>= 1;
+		if (stplyr != &players[displayplayer])
+			y += BASEVIDHEIGHT / 2;
+	}
+	return y;
+}
+
+static INT32 SCX(INT32 x)
+{
+	return FixedInt(FixedMul(x<<FRACBITS, vid.fdupx));
+}
+
+INT32 ITEM_X, ITEM_Y;	// Item Window
+INT32 TRIP_X, TRIP_Y;	// Triple Item Icon
+INT32 TIME_X, TIME_Y;	// Time Sticker
+INT32 LAPS_X, LAPS_Y;	// Lap Sticker
+INT32 POSI_X, POSI_Y;	// Position Number
+INT32 FACE_X, FACE_Y;	// Top-four Faces
+INT32 METE_X, METE_Y;	// Speed Meter
+
+static void K_initKartHUD(void)
+{
+	/*
+		BASEVIDWIDTH  = 320
+		BASEVIDHEIGHT = 200
+		
+		Item window graphic is 41 x 33
+		
+		Time Sticker graphic is 116 x 11
+		Time Font is a solid block of (8 x [12) x 14], equal to 96 x 14
+		Therefore, timestamp is 116 x 14 altogether
+		
+		Lap Sticker is 80 x 11
+		Lap flag is 22 x 20
+		Lap Font is a solid block of (3 x [12) x 14], equal to 36 x 14
+		Therefore, lapstamp is 80 x 20 altogether
+		
+		Position numbers are 43 x 53
+		
+		Faces are 32 x 32 
+		Faces draw downscaled at 16 x 16
+		Therefore, the allocated space for them is 16 x 67 altogether
+		
+		----
+		
+		ORIGINAL CZ64 SPLITSCREEN:
+		
+		Item window:
+		if (!splitscreen) 	{ ICONX = 139; 				ICONY = 20; }
+		else 				{ ICONX = BASEVIDWIDTH-315; ICONY = 60; }
+		
+		Time: 			   236, STRINGY(			   12)
+		Lap:  BASEVIDWIDTH-304, STRINGY(BASEVIDHEIGHT-189)
+		
+	*/	
+	
+	if (!splitscreen)						// Local Single-Player
+	{
+		switch (cv_karthud.value)		// Item Window
+		{
+			default:
+				// Item Window
+				ITEM_X = BASEVIDWIDTH - 52;	// 268
+				ITEM_Y = 34;				//  34
+				// Triple Item Object
+				TRIP_X = 143;				// 143
+				TRIP_Y = BASEVIDHEIGHT- 34;	// 166
+				// Level Timer
+				TIME_X = BASEVIDWIDTH -148;	// 172
+				TIME_Y = 9;					//   9
+				// Level Laps
+				LAPS_X = 9;					//   9
+				LAPS_Y = BASEVIDHEIGHT- 29;	// 171
+				// Position Number
+				POSI_X = BASEVIDWIDTH - 52;	// 268
+				POSI_Y = BASEVIDHEIGHT- 62;	// 138
+				// Top-Four Faces
+				FACE_X = 9;					//   9
+				FACE_Y = 92;				//  92
+				break;
+		}
+	}
+	else							// Local Multi-Player
+	{
+		ITEM_X = 9;					//   9
+		ITEM_Y = 48;				//  48
+		
+		TRIP_X = 143;				// 143
+		TRIP_Y = BASEVIDHEIGHT- 34;	// 166
+		
+		TIME_X = BASEVIDWIDTH -114;	// 206  / Sticker is 196 (Base - 124) - Inside the boundry by 8px
+		TIME_Y = 6;					//   6  / Sticker is  +2
+		
+		LAPS_X = 9;					//   9
+		LAPS_Y = BASEVIDHEIGHT- 31;	// 169
+		
+		POSI_X = BASEVIDWIDTH - 51;	// 269
+		POSI_Y = BASEVIDHEIGHT-128;	//  72
+		
+		FACE_X = 15;				//  15
+		FACE_Y = 72;				//  72
+	}
+
+	// To correct the weird render location
+	POSI_X = SCX(POSI_X);
+	POSI_Y = SCX(POSI_Y);
+}
+
+static void K_drawKartItemClose(void)
+{
+	// ITEM_X = BASEVIDWIDTH-50;	// 270
+	// ITEM_Y = 24;					//  24
+	
+	// Why write V_DrawScaledPatch calls over and over when they're all the same?
+	// Set to 'no draw' just in case.
+	patch_t *localpatch = kp_nodraw;
+	
+	/*if ()
+		switch (stplyr->kartstuff[k_itemclose])
+		{
+			case  1: localpatch = kp_neoitemused5; break;
+			case  3: localpatch = kp_neoitemused4; break;
+			case  5: localpatch = kp_neoitemused3; break;
+			case  7: localpatch = kp_neoitemused2; break;
+			case  9: localpatch = kp_neoitemused1; break;
+			default: break;
+		}
+	else*/
+		switch (stplyr->kartstuff[k_itemclose])
+		{
+			case  1: localpatch = kp_itemused5; break;
+			case  3: localpatch = kp_itemused4; break;
+			case  5: localpatch = kp_itemused3; break;
+			case  7: localpatch = kp_itemused2; break;
+			case  9: localpatch = kp_itemused1; break;
+			default: break;
+		}
+	
+	if (localpatch != kp_nodraw)
+		V_DrawScaledPatch(ITEM_X, STRINGY(ITEM_Y), V_SNAPTORIGHT|V_SNAPTOTOP, localpatch);
+}
+
+static void K_drawKartItemRoulette(void)
+{
+	// ITEM_X = BASEVIDWIDTH-50;	// 270
+	// ITEM_Y = 24;					//  24
+	
+	// Why write V_DrawScaledPatch calls over and over when they're all the same?
+	// Set to 'no item' just in case.
+	patch_t *localpatch = kp_nodraw;
+	
+	/*if ()
+				switch(stplyr->kartstuff[k_itemroulette] % 53)
+		{
+			// Each case is handled in threes, to give three frames of in-game time to see the item on the roulette
+			// I'm also skipping by threes for the power order as to what item shows on the roulette
+			case  0: case  1: case  2: localpatch = kp_electroshield; break;	// Electro-Shield
+			case  3: case  4: case  5: localpatch = kp_triplespeedshoe; break;	// Triple Speed Shoe
+			case  6: case  7: case  8: localpatch = kp_invincibility; break;	// Invincibility
+			case  9: case 10: case 11: localpatch = kp_neobanana; break;		// Banana
+			case 12: case 13: case 14: localpatch = kp_tripleorbinaut; break;	// 3x Orbinaut
+			case 15: case 16: case 17: localpatch = kp_laserwisp; break;		// Laser Wisp
+			case 18: case 19: case 20: localpatch = kp_skghost; break;			// S3K Ghost
+			case 21: case 22: case 23: localpatch = kp_sizeupmonitor; break;	// Size-Up Monitor
+			case 24: case 25: case 26: localpatch = kp_neotriplebanana; break;	// Triple Banana
+			case 27: case 28: case 29: localpatch = kp_orbinaut; break;			// 1x Orbinaut
+			case 30: case 31: case 32: localpatch = kp_specialstagemine; break;	// Specialstage Mines
+			case 33: case 34: case 35: localpatch = kp_doublejaws; break;		// 2x Jaws
+			case 36: case 37: case 38: localpatch = kp_speedshoe; break;		// Speed Shoe
+			case 39: case 40: case 41: localpatch = kp_rocketshoe; break;		// Rocket Shoe
+			case 42: case 43: case 44: localpatch = kp_eggmanmonitor; break;	// Eggman Monitor
+			case 45: case 46: case 47: localpatch = kp_jaws; break;				// 1x Jaws
+			case 48: case 49: case 50: localpatch = kp_deton; break;			// Deton
+			case 51: case 52: case 53: localpatch = kp_sizedownmonitor; break;	// Size-Down Monitor
+			default: break;		
+		}
+	else*/
+		switch(stplyr->kartstuff[k_itemroulette] % 53)
+		{
+			// Each case is handled in threes, to give three frames of in-game time to see the item on the roulette
+			// I'm also skipping by threes for the power order as to what item shows on the roulette
+			case  0: case  1: case  2: localpatch = kp_magnet; break;			// Magnet
+			case  3: case  4: case  5: localpatch = kp_triplemushroom; break;	// Triple Mushroom
+			case  6: case  7: case  8: localpatch = kp_star; break;				// Star
+			case  9: case 10: case 11: localpatch = kp_banana; break;			// Banana
+			case 12: case 13: case 14: localpatch = kp_triplegreenshell; break;	// Triple Green Shell
+			case 15: case 16: case 17: localpatch = kp_fireflower; break;		// Fire Flower
+			case 18: case 19: case 20: localpatch = kp_boo; break;				// Boo
+			case 21: case 22: case 23: localpatch = kp_megashroom; break;		// Mega Mushroom
+			case 24: case 25: case 26: localpatch = kp_triplebanana; break;		// Triple Banana
+			case 27: case 28: case 29: localpatch = kp_greenshell; break;		// Green Shell
+			case 30: case 31: case 32: localpatch = kp_bobomb; break;			// Bob-omb
+			case 33: case 34: case 35: localpatch = kp_tripleredshell; break;	// Triple Red Shell
+			case 36: case 37: case 38: localpatch = kp_mushroom; break;			// Mushroom
+			case 39: case 40: case 41: localpatch = kp_goldshroom; break;		// Gold Mushroom
+			case 42: case 43: case 44: localpatch = kp_fakeitem; break;			// Fake Item
+			case 45: case 46: case 47: localpatch = kp_redshell; break;			// Red Shell
+			case 48: case 49: case 50: localpatch = kp_blueshell; break;		// Blue Shell
+			case 51: case 52: case 53: localpatch = kp_lightning; break;		// Lightning
+			default: break;		
+		}
+	
+	V_DrawScaledPatch(ITEM_X, STRINGY(ITEM_Y), V_SNAPTORIGHT|V_SNAPTOTOP, localpatch);
+}
+
+static void K_drawKartRetroItem(void)
+{
+	// ITEM_X = BASEVIDWIDTH-50;	// 270
+	// ITEM_Y = 24;					//  24
+	
+	// Why write V_DrawScaledPatch calls over and over when they're all the same?
+	// Set to 'no item' just in case.
+	patch_t *localpatch = kp_nodraw;
+	
+	// I'm doing this a little weird and drawing mostly in reverse order
+	// The only actual reason is to make triple/double/single mushrooms line up this way in the code below
+	// This shouldn't have any actual baring over how it functions
+	// Boo is first, because we're drawing it on top of the player's current item
+	if 		((stplyr->kartstuff[k_bootaketimer] > 0 
+		|| stplyr->kartstuff[k_boostolentimer] > 0) && (leveltime & 2)) 	localpatch = kp_boosteal;
+	else if (stplyr->kartstuff[k_boostolentimer] > 0 && !(leveltime & 2))	localpatch = kp_noitem;
+	else if (stplyr->kartstuff[k_lightning] == 1)							localpatch = kp_lightning;
+	else if (stplyr->kartstuff[k_tripleredshell] & 8)						localpatch = kp_tripleredshell;
+	else if (stplyr->kartstuff[k_fireflower] == 1)							localpatch = kp_fireflower;
+	else if (stplyr->kartstuff[k_blueshell] == 1)							localpatch = kp_blueshell;
+	else if (stplyr->kartstuff[k_bobomb] & 2)								localpatch = kp_bobomb;
+	else if (stplyr->kartstuff[k_triplegreenshell] & 8)						localpatch = kp_triplegreenshell;
+	else if (stplyr->kartstuff[k_redshell] & 2)								localpatch = kp_redshell;
+	else if (stplyr->kartstuff[k_greenshell] & 2)							localpatch = kp_greenshell;
+	else if (stplyr->kartstuff[k_banana] & 2)								localpatch = kp_banana;
+	else if (stplyr->kartstuff[k_fakeitem] & 2)								localpatch = kp_fakeitem;
+	else if (stplyr->kartstuff[k_triplebanana] & 8)							localpatch = kp_triplebanana;
+	else if (stplyr->kartstuff[k_star] == 1)								localpatch = kp_star;
+	else if (stplyr->kartstuff[k_goldshroom] == 1 
+		|| (stplyr->kartstuff[k_goldshroomtimer] > 1 && (leveltime & 1)))	localpatch = kp_goldshroom;
+	else if (stplyr->kartstuff[k_goldshroomtimer] > 1 && !(leveltime & 1))	localpatch = kp_noitem;
+	else if (stplyr->kartstuff[k_megashroom] == 1 
+		|| (stplyr->kartstuff[k_growshrinktimer] > 1 && (leveltime & 1)))	localpatch = kp_megashroom;
+	else if (stplyr->kartstuff[k_growshrinktimer] > 1 && !(leveltime & 1))	localpatch = kp_noitem;
+	else if (stplyr->kartstuff[k_mushroom] & 4)								localpatch = kp_triplemushroom;
+	else if (stplyr->kartstuff[k_mushroom] & 2)								localpatch = kp_doublemushroom;
+	else if (stplyr->kartstuff[k_mushroom] == 1)							localpatch = kp_mushroom;
+	else if (stplyr->kartstuff[k_boo] & 8)									localpatch = kp_boo;
+	else if (stplyr->kartstuff[k_magnet] & 8)								localpatch = kp_magnet;
+	
+	V_DrawScaledPatch(ITEM_X, STRINGY(ITEM_Y), V_SNAPTORIGHT|V_SNAPTOTOP, localpatch);
+}
+
+/*
+static void K_drawKartNeoItem(void)
+{
+	// ITEM_X = BASEVIDWIDTH-50;	// 270
+	// ITEM_Y = 24;					//  24
+	
+	// Why write V_DrawScaledPatch calls over and over when they're all the same?
+	// Set to 'no item' just in case.
+	patch_t *localpatch = kp_noitem;
+	
+	// I'm doing this a little weird and drawing mostly in reverse order
+	// The only actual reason is to make triple/double/single mushrooms line up this way in the code below
+	// This shouldn't have any actual baring over how it functions
+	// Boo is first, because we're drawing it on top of the player's current item
+	if 		((stplyr->kartstuff[k_bootaketimer] > 0 
+		|| stplyr->kartstuff[k_boostolentimer] > 0) && (leveltime & 2)) 	localpatch = kp_skghoststeal;
+	else if (stplyr->kartstuff[k_boostolentimer] > 0 && !(leveltime & 2))	localpatch = kp_neonoitem;
+	else if (stplyr->kartstuff[k_lightning] == 1)							localpatch = kp_sizedownmonitor;
+	else if (stplyr->kartstuff[k_jaws] & 4)									localpatch = kp_doublejaws;
+	else if (stplyr->kartstuff[k_laserwisp] == 1)							localpatch = kp_laserwisp;
+	else if (stplyr->kartstuff[k_blueshell] == 1)							localpatch = kp_deton;
+	else if (stplyr->kartstuff[k_bobomb] & 2)								localpatch = kp_specialstagemine;
+	else if (stplyr->kartstuff[k_triplegreenshell] & 8)						localpatch = kp_tripleorbinaut;
+	else if (stplyr->kartstuff[k_redshell] & 2)								localpatch = kp_jaws;
+	else if (stplyr->kartstuff[k_greenshell] & 2)							localpatch = kp_orbinaut;
+	else if (stplyr->kartstuff[k_banana] & 2)								localpatch = kp_neobanana;
+	else if (stplyr->kartstuff[k_fakeitem] & 2)								localpatch = kp_eggmanmonitor;
+	else if (stplyr->kartstuff[k_triplebanana] & 8)							localpatch = kp_neotriplebanana;
+	else if (stplyr->kartstuff[k_star] == 1)								localpatch = kp_invincibility;
+	else if (stplyr->kartstuff[k_goldshroom] == 1 
+		|| (stplyr->kartstuff[k_goldshroomtimer] > 1 && (leveltime & 1)))	localpatch = kp_rocketshoe;
+	else if (stplyr->kartstuff[k_goldshroomtimer] > 1 && !(leveltime & 1))	localpatch = kp_neonoitem;
+	else if (stplyr->kartstuff[k_megashroom] == 1 
+		|| (stplyr->kartstuff[k_growshrinktimer] > 1 && (leveltime & 1)))	localpatch = kp_sizeupmonitor;
+	else if (stplyr->kartstuff[k_growshrinktimer] > 1 && !(leveltime & 1))	localpatch = kp_neonoitem;
+	else if (stplyr->kartstuff[k_mushroom] & 4)								localpatch = kp_triplespeedshoe;
+	else if (stplyr->kartstuff[k_mushroom] & 2)								localpatch = kp_doublespeedshoe;
+	else if (stplyr->kartstuff[k_mushroom] == 1)							localpatch = kp_speedshoe;
+	else if (stplyr->kartstuff[k_boo] & 8)									localpatch = kp_skghost;
+	else if (stplyr->kartstuff[k_magnet] & 8)								localpatch = kp_electroshield;
+	
+	V_DrawScaledPatch(ITEM_X, STRINGY(ITEM_Y), V_SNAPTORIGHT|V_TRANSLUCENT, localpatch);
+}
+*/
+
+static void K_drawKartTripleItem(void)
+{
+	// TRIP_X = 143;				// 143
+	// TRIP_Y = BASEVIDHEIGHT-34;	// 166
+				
+	// Why write V_DrawScaledPatch calls over and over when they're all the same?
+	// Set to 'no draw' just in case.
+	patch_t *localpatch = kp_nodraw;
+	INT32 thisitem;
+	
+	/*if ()
+	{
+		thisitem = stplyr->kartstuff[k_triplebanana];
+		if 		(thisitem & 1) localpatch = kp_singleneobananaicon;
+		else if (thisitem & 2) localpatch = kp_doubleneobananaicon;
+		else if (thisitem & 4) localpatch = kp_tripleneobananaicon;
+		
+		thisitem = stplyr->kartstuff[k_triplegreenshell];
+		if 		(thisitem & 1) localpatch = kp_singleorbitauricon;
+		else if (thisitem & 2) localpatch = kp_doubleorbitauricon;
+		else if (thisitem & 4) localpatch = kp_tripleorbitauricon;
+		
+		thisitem = stplyr->kartstuff[k_jaws];
+		if 		(thisitem & 1) localpatch = kp_singlejawsicon;
+		else if (thisitem & 2) localpatch = kp_doublejawsicon;
+	}
+	else*/
+	//{
+		thisitem = stplyr->kartstuff[k_triplebanana];
+		if 		(thisitem & 1) localpatch = kp_singlebananaicon;
+		else if (thisitem & 2) localpatch = kp_doublebananaicon;
+		else if (thisitem & 4) localpatch = kp_triplebananaicon;
+		
+		thisitem = stplyr->kartstuff[k_triplegreenshell];
+		if 		(thisitem & 1) localpatch = kp_singlegreenshellicon;
+		else if (thisitem & 2) localpatch = kp_doublegreenshellicon;
+		else if (thisitem & 4) localpatch = kp_triplegreenshellicon;
+		
+		thisitem = stplyr->kartstuff[k_tripleredshell];
+		if 		(thisitem & 1) localpatch = kp_singleredshellicon;
+		else if (thisitem & 2) localpatch = kp_doubleredshellicon;
+		else if (thisitem & 4) localpatch = kp_tripleredshellicon;
+	//}
+	
+	if (localpatch != kp_nodraw)
+		V_DrawScaledPatch(TRIP_X, STRINGY(TRIP_Y), V_SNAPTORIGHT|V_TRANSLUCENT, localpatch);
+}
+
+static void K_drawKartTimestamp(void)
+{
+	// TIME_X = BASEVIDWIDTH-124;	// 196
+	// TIME_Y = 6;					//   6
+
+	INT32 TIME_XB;
+
+	V_DrawScaledPatch(TIME_X, STRINGY(TIME_Y), 0, kp_timestickerwide);
+
+	TIME_XB = TIME_X+33;
+
+	if (stplyr->realtime/(60*TICRATE) < 100) // 99:99:99 only
+	{
+		// zero minute
+		if (stplyr->realtime/(60*TICRATE) < 10)
+		{
+			V_DrawKartString(TIME_XB, STRINGY(TIME_Y+3), 0, va("0"));
+			// minutes time       0 __ __
+			V_DrawKartString(TIME_XB+12, STRINGY(TIME_Y+3), 0, va("%d", stplyr->realtime/(60*TICRATE)));
+		}
+		// minutes time       0 __ __
+		else
+			V_DrawKartString(TIME_XB, STRINGY(TIME_Y+3), 0, va("%d", stplyr->realtime/(60*TICRATE)));
+
+		// apostrophe location     _'__ __
+		V_DrawKartString(TIME_XB+24, STRINGY(TIME_Y+3), 0, va("'"));
+
+		// zero second        _ 0_ __
+		if ((stplyr->realtime/TICRATE % 60) < 10)
+		{
+			V_DrawKartString(TIME_XB+36, STRINGY(TIME_Y+3), 0, va("0"));
+		// seconds time       _ _0 __
+			V_DrawKartString(TIME_XB+48, STRINGY(TIME_Y+3), 0, va("%d", stplyr->realtime/TICRATE % 60));
+		}
+		// zero second        _ 00 __
+		else
+			V_DrawKartString(TIME_XB+36, STRINGY(TIME_Y+3), 0, va("%d", stplyr->realtime/TICRATE % 60));
+
+		// quotation mark location    _ __"__
+		V_DrawKartString(TIME_XB+60, STRINGY(TIME_Y+3), 0, va("\""));
+
+		// zero tick          _ __ 0_
+		if (G_TicsToCentiseconds(stplyr->realtime) < 10)
+		{
+			V_DrawKartString(TIME_XB+72, STRINGY(TIME_Y+3), 0, va("0"));
+		// tics               _ __ _0
+			V_DrawKartString(TIME_XB+84, STRINGY(TIME_Y+3), 0, va("%d", G_TicsToCentiseconds(stplyr->realtime)));
+		}
+		// zero tick          _ __ 00
+		if (G_TicsToCentiseconds(stplyr->realtime) >= 10)
+			V_DrawKartString(TIME_XB+72, STRINGY(TIME_Y+3), 0, va("%d", G_TicsToCentiseconds(stplyr->realtime)));
+	}
+	else
+		V_DrawKartString(TIME_XB, STRINGY(TIME_Y+3), 0, va("99'59\"99"));
+}
+
+static void K_DrawKartPositionNum(INT32 num)
+{
+	// POSI_X = BASEVIDWIDTH - 51;	// 269
+	// POSI_Y = BASEVIDHEIGHT- 64;	// 136
+	
+	INT32 X = POSI_X+SCX(43); // +43 to offset where it's being drawn if there are more than one
+	INT32 W = SHORT(kp_positionnum[0][0]->width);
+	patch_t *localpatch = kp_positionnum[0][0];
+	
+	// Special case for 0
+	if (!num)
+	{
+		V_DrawTranslucentPatch(X-(W*vid.dupx), POSI_Y, V_NOSCALESTART|V_TRANSLUCENT|V_SNAPTORIGHT|V_SNAPTOBOTTOM, kp_positionnum[0][0]);
+		return;
+	}
+
+	I_Assert(num >= 0); // This function does not draw negative numbers
+	
+	// Draw the number
+	while (num)
+	{
+		X -= (W*vid.dupx);
+		
+		// Check for the final lap
+		if (stplyr->laps+1 == cv_numlaps.value)
+		{
+			// Alternate frame every three frames
+			switch (leveltime % 9)
+			{
+				case 1: case 2: case 3:
+					if (stplyr->kartstuff[k_position] >= 4)
+						localpatch = kp_positionnum[num % 10][1];
+					else
+						localpatch = kp_positionnum[num % 10][4];
+					break;
+				case 4: case 5: case 6:
+					if (stplyr->kartstuff[k_position] >= 4)
+						localpatch = kp_positionnum[num % 10][2];
+					else
+						localpatch = kp_positionnum[num % 10][5];
+					break;
+				case 7: case 8: case 9:
+					if (stplyr->kartstuff[k_position] >= 4)
+						localpatch = kp_positionnum[num % 10][3];
+					else
+						localpatch = kp_positionnum[num % 10][6];
+					break;
+				default:
+					localpatch = kp_positionnum[num % 10][0];
+					break;
+			}
+		}
+		else
+			localpatch = kp_positionnum[num % 10][0];
+			
+		V_DrawTranslucentPatch(X, POSI_Y, V_NOSCALESTART|V_TRANSLUCENT|V_SNAPTORIGHT|V_SNAPTOBOTTOM, localpatch);
+		num /= 10;
+	}
+}
+
+static void K_DrawKartPositionFaces(void)
+{
+	// FACE_X = 15;				//  15
+	// FACE_Y = 72;				//  72
+	
+	INT32 Y = FACE_Y+9; // +9 to offset where it's being drawn if there are more than one
+	INT32 i, j, ranklines;
+	boolean completed[MAXPLAYERS];
+	INT32 rankplayer[MAXPLAYERS];
+	INT32 rankcolor[MAXPLAYERS];
+	UINT32 myplayer;
+	UINT8 *colormap;
+	patch_t *localpatch = kp_facenull;
+	
+	ranklines = 0;
+	memset(completed, 0, sizeof (completed));
+	memset(rankplayer, 0, sizeof (rankplayer));
+	memset(rankcolor, 0, sizeof (rankcolor));
+	myplayer = demoplayback ? displayplayer : consoleplayer;
+	
+	for (i = 0; i < MAXPLAYERS; i++)
+		rankplayer[i] = -1;
+	
+	for (j = 0; j < MAXPLAYERS; j++)
+	{
+		if (!playeringame[j])
+			continue;
+
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			if (playeringame[i] && completed[i] == false 
+				&& (rankplayer[ranklines] < 0 || players[i].kartstuff[k_position] < players[rankplayer[ranklines]].kartstuff[k_position]))
+			{
+				rankplayer[ranklines] = i;
+				rankcolor[ranklines] = players[i].skincolor;
+			}
+		}
+		completed[rankplayer[ranklines]] = true;
+		ranklines++;
+	}
+	
+	if (ranklines > 4) ranklines = 4; // Only draw the top 4 players
+
+	Y -= (9*ranklines);
+
+	for (i = 0; i < ranklines; i++)
+	{
+		if (players[rankplayer[i]].spectator) continue; // Spectators are ignored
+
+		if (rankcolor[i] == 0)
+		{
+			colormap = colormaps;
+			if (rankplayer[i] != myplayer)
+				V_DrawSmallTranslucentPatch(FACE_X, Y, 0, faceprefix[players[rankplayer[i]].skin]);
+			else
+				V_DrawSmallScaledPatch(FACE_X, Y, 0, faceprefix[players[rankplayer[i]].skin]);
+		}
+		else
+		{
+			colormap = R_GetTranslationColormap(players[rankplayer[i]].skin, players[rankplayer[i]].mo->color, GTC_CACHE);
+			if (rankplayer[i] != myplayer)
+				V_DrawSmallTranslucentMappedPatch(FACE_X, Y, 0, faceprefix[players[rankplayer[i]].skin], colormap);
+			else
+				V_DrawSmallMappedPatch(FACE_X, Y, 0, faceprefix[players[rankplayer[i]].skin], colormap);
+		}
+		// Draws the little number over the face
+		switch (ranklines)
+		{
+			case 1: localpatch = kp_facefirst; break;
+			case 2: localpatch = kp_facesecond; break;
+			case 3: localpatch = kp_facethird; break;
+			case 4: localpatch = kp_facefourth; break;
+			default: break;
+		}
+		if (rankplayer[i] != myplayer)
+			V_DrawSmallTranslucentPatch(FACE_X, Y, 0, localpatch);
+		else
+			V_DrawSmallScaledPatch(FACE_X, Y, 0, localpatch);
+		Y += 18;
+	}
+}
+
+void K_drawKartHUD(void)
+{
+	// Define the X and Y for each drawn object
+	// This is handled by console/menu values
+	K_initKartHUD();
+	
+	// If the item window is closing, draw it closing!
+	if (stplyr->kartstuff[k_itemclose])
+		K_drawKartItemClose();
+	
+	// If the item-roulette is going, draw that 
+	// Otherwise, draw the item window normally (separated for retro/neo, to prevent this block from becoming a mess
+	if (stplyr->kartstuff[k_itemroulette])
+		K_drawKartItemRoulette();
+	// else if ()
+	//	K_drawKartNeoItem();
+	else
+		K_drawKartRetroItem();
+	
+	// Draw the little triple-item icons at the bottom
+	if (!splitscreen)
+	{
+		K_drawKartTripleItem();
+		K_DrawKartPositionFaces();
+	}
+	
+	// Draw the timestamp
+	K_drawKartTimestamp();
+	
+	// Draw the lap counter
+	V_DrawScaledPatch(LAPS_X, STRINGY(LAPS_Y), 0, kp_lapsticker);
+	if (stplyr->exiting)
+		V_DrawKartString(LAPS_X+33, STRINGY(LAPS_Y+3), 0, "FIN");
+	else
+		V_DrawKartString(LAPS_X+33, STRINGY(LAPS_Y+3), 0, va("%d/%d", stplyr->laps+1, cv_numlaps.value));
+	
+	// Draw the numerical position
+	K_DrawKartPositionNum(stplyr->kartstuff[k_position]);
+	
+	// Why is this here?????
+	/*
+	if (leveltime > 157 && leveltime < (TICRATE+1)*7)
+	{
+		if (!(mapmusic & 2048)) // TODO: Might not need this here
+			mapmusic = mapheaderinfo[gamemap-1].musicslot;
+
+		S_ChangeMusic(mapmusic & 2047, true);
+	}*/
+}
 
+//}
 
 
 
diff --git a/src/k_kart.h b/src/k_kart.h
index 0312638b6..f2ee8babd 100644
--- a/src/k_kart.h
+++ b/src/k_kart.h
@@ -6,83 +6,22 @@
 #ifndef __K_KART__
 #define __K_KART__
 
+#include "doomdef.h"
+#include "d_player.h" // Need for player_t
+
 extern const char *KartColor_Names[MAXSKINCOLORS];
 void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color);
 UINT8 K_GetKartColorByName(const char *name);
 
-//{ SRB2kart Player structure - kartstuff
-
-typedef enum
-{
-	// Basic gameplay things
-	k_position,			// Used for Kart positions, mostly for deterministic stuff
-	k_playerahead,		// Is someone ahead of me or not?
-	k_oldposition,		// Used for taunting when you pass someone
-	k_prevcheck,		// Previous checkpoint distance; for p_user.c (was "pw_pcd")
-	k_nextcheck,		// Next checkpoint distance; for p_user.c (was "pw_ncd")
-	k_waypoint,			// Waypoints.
-	k_starpostwp,		// Temporarily stores player waypoint for... some reason. Used when respawning and finishing.
-	
-	k_throwdir, 		// Held dir of controls; 1 = forward, 0 = none, -1 = backward (was "player->heldDir")
-	k_turndir,			// Turn direction for drifting; -1 = Left, 1 = Right, 0 = none
-	k_sounds,			// Used this to avoid sounds being played every tic
-	
-	k_boosting,			// Determines if you're currently shroom-boosting to change how drifting works
-	k_spinout,			// Separate confirmation to prevent endless wipeout loops
-	k_spinouttype,		// Determines whether to thrust forward or not while spinning out; 0 = move forwards, 1 = stay still
-	
-	k_drift,			// Drifting Left or Right, plus a bigger counter = sharper turn
-	k_driftcharge,		// Charge your drift so you can release a burst of speed
-	k_jmp,				// In Mario Kart, letting go of the jump button stops the drift
-	k_lakitu,			// > 0 = Lakitu fishing, < 0 = Lakitu lap counter (was "player->airtime") // NOTE: Check for ->lakitu, replace with this
-	
-	k_itemroulette,		// Used for the roulette when deciding what item to give you (was "pw_kartitem")
-	k_itemslot,			// If you have X item, and kartitem chose X too, save it
-	k_itemclose,		// Used to animate the item window closing (was "pw_psychic")
-
-	// Some items use timers for their duration or effects
-	k_magnettimer,		// Duration of Magnet's item-break and item box pull
-	k_bootaketimer,		// You are stealing an item, this is your timer
-	k_boostolentimer,	// You are being stolen from, this is your timer
-	k_mushroomtimer,	// Duration of the Mushroom Boost itself
-	k_growshrinktimer,	// > 0 = Big, < 0 = small
-	k_squishedtimer,	// Squished frame timer
-	k_goldshroomtimer,	// Gold Mushroom duration timer
-	k_startimer,		// Invincibility timer
-	k_spinouttimer,		// Wipe-out from a banana peel or oil slick (was "pw_bananacam")
-	k_laserwisptimer,	// The duration and relative angle of the laser
-	k_fireflowertimer,	// Duration of Fire Flower
-
-	// Each item needs its own power slot, for the HUD and held use
-	k_magnet,			// 0x1 = Magnet in inventory
-	k_boo,				// 0x1 = Boo in inventory
-	k_mushroom,			// 0x1 = 1 Mushroom in inventory, 0x2 = 2 Mushrooms in inventory
-						// 0x4 = 3 Mushrooms in inventory
-	k_megashroom,		// 0x1 = Mega Mushroom in inventory
-	k_goldshroom,		// 0x1 = Gold Mushroom in inventory
-	k_star,				// 0x1 = Star in inventory
-	k_triplebanana,		// 0x1 = 1 Banana following, 0x2 = 2 Bananas following
-						// 0x4 = 3 Bananas following, 0x8 = Triple Banana in inventory
-	k_fakeitem,			// 0x1 = Fake Item being held, 0x2 = Fake Item in inventory
-	k_banana,			// 0x1 = Banana being held, 0x2 = Banana in inventory
-	k_greenshell,		// 0x1 = Green Shell being held, 0x2 = Green Shell in inventory
-	k_redshell,			// 0x1 = Red Shell being held, 0x2 = Red Shell in inventory
-	k_laserwisp,		// 0x1 = Laser Wisp in inventory
-	k_triplegreenshell,	// 0x1 = 1 Green Shell orbiting, 0x2 = 2 Green Shells orbiting
-						// 0x4 = 3 Green Shells orbiting, 0x8 = Triple Green Shell in inventory
-	k_bobomb,			// 0x1 = Bob-omb being held, 0x2 = Bob-omb in inventory
-	k_blueshell,		// 0x1 = Blue Shell in inventory
-	k_jaws,				// 0x1 = 1 Jaws orbiting, 0x2 = 2 Jaws orbiting, 
-						// 0x4 = 2x Jaws in inventory
-	k_fireflower,		// 0x1 = Fire Flower in inventory
-	k_tripleredshell,	// 0x1 = 1 Red Shell orbiting, 0x2 = 2 Red Shells orbiting
-						// 0x4 = 3 Red Shells orbiting, 0x8 = Triple Red Shell in inventory
-	k_lightning,		// 0x1 = Lightning in inventory
+void K_RegisterKartStuff(void);
 
-	NUMKARTSTUFF
-} kartstufftype_t;
+void K_KartPlayerThink(player_t *player, ticcmd_t *cmd);
+boolean P_SpinPlayerMobj(mobj_t *target, mobj_t *source);
+boolean P_SquishPlayerMobj(mobj_t *target, mobj_t *source);
+boolean P_ExplodePlayerMobj(mobj_t *target, mobj_t *source);
 
-//}
+void K_LoadKartHUDGraphics(void);
+void K_drawKartHUD(void);
 
 // =========================================================================
 #endif  // __K_KART__
diff --git a/src/m_cheat.c b/src/m_cheat.c
index 89334596e..ee4ff1930 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -1279,7 +1279,7 @@ void Command_ObjectPlace_f(void)
 		op_oldmomy = players[0].mo->momy;
 		op_oldmomz = players[0].mo->momz;
 		op_oldheight = players[0].mo->height;
-		op_oldstate = S_PLAY_STND;
+		op_oldstate = S_KART_STND; // SRB2kart - was S_PLAY_STND
 		op_oldcolor = players[0].mo->color; // save color too in case of super/fireflower
 
 		// Remove ALL flags and motion.
diff --git a/src/p_inter.c b/src/p_inter.c
index 884b22ad3..d172a09b0 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -26,6 +26,7 @@
 #include "m_cheat.h" // objectplace
 #include "m_misc.h"
 #include "v_video.h" // video flags for CEchos
+#include "k_kart.h" // SRB2kart
 
 // CTF player names
 #define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
@@ -309,6 +310,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			toucher->momy = -toucher->momy;
 			P_DamageMobj(special, toucher, toucher, 1);
 		}
+		/*
 		else if (((toucher->z < special->z && !(toucher->eflags & MFE_VERTICALFLIP))
 		|| (toucher->z + toucher->height > special->z + special->height && (toucher->eflags & MFE_VERTICALFLIP)))
 		&& player->charability == CA_FLY
@@ -319,6 +321,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 
 			P_DamageMobj(special, toucher, toucher, 1);
 		}
+		*/																						// SRB2kart - Removed: No more fly states
 		else
 			P_DamageMobj(toucher, special, special, 1);
 
@@ -351,6 +354,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 
 			P_DamageMobj(special, toucher, toucher, 1);
 		}
+		/*
 		else if (((toucher->z < special->z && !(toucher->eflags & MFE_VERTICALFLIP))
 		|| (toucher->z + toucher->height > special->z + special->height && (toucher->eflags & MFE_VERTICALFLIP))) // Flame is bad at logic - JTE
 		&& player->charability == CA_FLY
@@ -362,6 +366,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 
 			P_DamageMobj(special, toucher, toucher, 1);
 		}
+		*/																						// SRB2kart - Removed: No more fly states
 		else
 			P_DamageMobj(toucher, special, special, 1);
 
@@ -887,7 +892,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 
 					P_ResetPlayer(player);
 
-					P_SetPlayerMobjState(toucher, S_PLAY_FALL1);
+					P_SetPlayerMobjState(toucher, S_KART_STND); // SRB2kart - was S_PLAY_FALL1
 				}
 			}
 			return;
@@ -1224,7 +1229,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				if (player->pflags & PF_GLIDING)
 				{
 					player->pflags &= ~(PF_GLIDING|PF_JUMPED);
-					P_SetPlayerMobjState(toucher, S_PLAY_FALL1);
+					P_SetPlayerMobjState(toucher, S_KART_STND); // SRB2kart - was S_PLAY_FALL1
 				}
 
 				// Play a bounce sound?
@@ -1233,7 +1238,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			return;
 
 		case MT_BLACKEGGMAN_GOOPFIRE:
-			if (toucher->state != &states[S_PLAY_PAIN] && !player->powers[pw_flashing])
+			if (!player->powers[pw_flashing]) // SRB2kart
 			{
 				toucher->momx = 0;
 				toucher->momy = 0;
@@ -1291,7 +1296,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 					if (player->pflags & PF_GLIDING)
 					{
 						player->pflags &= ~(PF_GLIDING|PF_JUMPED);
-						P_SetPlayerMobjState(toucher, S_PLAY_FALL1);
+						P_SetPlayerMobjState(toucher, S_KART_STND); // SRB2kart - was S_PLAY_FALL1
 					}
 
 					// Play a bounce sound?
@@ -1347,7 +1352,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			{
 				player->pflags |= PF_MACESPIN;
 				S_StartSound(toucher, sfx_spin);
-				P_SetPlayerMobjState(toucher, S_PLAY_ATK1);
+				P_SetPlayerMobjState(toucher, S_KART_STND); // SRB2kart - was S_PLAY_ATK1
 			}
 			else
 				player->pflags |= PF_ITEMHANG;
@@ -1408,7 +1413,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			}
 			return;
 
-		case MT_EXTRALARGEBUBBLE:
+		case MT_EXTRALARGEBUBBLE: 
+			return; // SRB2kart - don't need bubbles mucking with the player
 			if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL)
 				return;
 			if (maptol & TOL_NIGHTS)
@@ -1432,11 +1438,13 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			if (player->powers[pw_underwater] < underwatertics + 1)
 				player->powers[pw_underwater] = underwatertics + 1;
 
+			/* 
 			if (!player->climbing)
 			{
 				P_SetPlayerMobjState(toucher, S_PLAY_GASP);
 				P_ResetPlayer(player);
 			}
+			*/
 
 			toucher->momx = toucher->momy = toucher->momz = 0;
 			break;
@@ -2687,9 +2695,11 @@ static inline void P_SuperDamage(player_t *player, mobj_t *inflictor, mobj_t *so
 
 	P_InstaThrust(player->mo, ang, fallbackspeed);
 
+	/* // SRB2kart - This shouldn't be reachable, but this frame is invalid.
 	if (player->charflags & SF_SUPERANIMS)
-		P_SetPlayerMobjState(player->mo, S_PLAY_SUPERHIT);
+		P_SetPlayerMobjState(player->mo, S_PLAY_SUPERHIT); 
 	else
+	*/
 		P_SetPlayerMobjState(player->mo, player->mo->info->painstate);
 
 	P_ResetPlayer(player);
@@ -2967,6 +2977,47 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
 				return false; // Don't get hurt by fire generated from friends.
 		}
 
+		//{ SRB2kart - special damage sources
+		
+		player->kartstuff[k_mushroomtimer] = 0;
+		
+		// Thunder
+		if (damage == 64 && player != source->player)
+		{
+			// Don't flip out while super!
+			if (!player->kartstuff[k_startimer] && player->kartstuff[k_growshrinktimer] <= 0)
+			{
+				// Start slipping!
+				P_SpinPlayerMobj(player->mo, source);
+
+				// Start shrinking!
+				player->mo->destscale = 70;
+				player->kartstuff[k_growshrinktimer] -= (100+20*(16-(player->kartstuff[k_position])));
+			}
+			// Mega Mushroom? Let's take that away.
+			if (player->kartstuff[k_growshrinktimer] > 0)
+			{
+				player->kartstuff[k_growshrinktimer] = 2;
+			}
+			// Invincible or not, we still need this.
+			//P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THUNDERSHIELD);  // TODO: Add this
+			return true;
+		}
+		else if (damage == 64 && player == source->player)
+			return false;
+
+		// Blue Thunder
+		if (damage == 65 && player->kartstuff[k_position] == 1)
+		{
+			// Just need to do this now! Being thrown upwards is done by the explosion.
+			//P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THUNBERSHIELD);  // TODO: Add this
+			//P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BLUEEXPLODE);  // TODO: Add this
+			return true;
+		}
+		else if (damage == 65 && player->kartstuff[k_position] > 1)
+			return false;
+		//}
+
 		// Sudden-Death mode
 		if (source && source->type == MT_PLAYER)
 		{
@@ -2988,6 +3039,14 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
 		// Instant-Death
 		if (damage == 10000)
 			P_KillPlayer(player, source, damage);
+		else if (player->kartstuff[k_startimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->powers[pw_flashing])
+			return false;
+		else
+		{
+			damage = player->mo->health - 1;
+			P_RingDamage(player, inflictor, source, damage);
+		}
+		/* // SRB2kart - don't need these
 		else if (metalrecording)
 		{
 			if (!inflictor)
@@ -3052,6 +3111,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
 				P_ShieldDamage(player, inflictor, source, damage);
 			}
 		}
+		*/
 
 		if (inflictor && ((inflictor->flags & MF_MISSILE) || inflictor->player) && player->powers[pw_super] && ALL7EMERALDS(player->powers[pw_emeralds]))
 		{
diff --git a/src/p_map.c b/src/p_map.c
index 71adf2e16..d4e9355c6 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -201,6 +201,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 		pflags = object->player->pflags & (PF_JUMPED|PF_SPINNING|PF_THOKKED); // I still need these.
 		P_ResetPlayer(object->player);
 
+		/* // SRB2kart - Springs don't need to change player state in kart.
 		if (P_MobjFlip(object)*vertispeed > 0)
 			P_SetPlayerMobjState(object, S_PLAY_SPRING);
 		else if (P_MobjFlip(object)*vertispeed < 0)
@@ -218,6 +219,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 			object->player->pflags |= PF_JUMPED;
 			P_SetPlayerMobjState(object, S_PLAY_ATK1);
 		}
+		*/
 	}
 	return true;
 }
@@ -262,12 +264,14 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
 			if (flipval*object->momz > FixedMul(speed, spring->scale))
 				object->momz = flipval*FixedMul(speed, spring->scale);
 
+			/* // SRB2kart - don't need state change
 			if (p && !p->powers[pw_tailsfly]) // doesn't reset anim for Tails' flight
 			{
 				P_ResetPlayer(p);
 				if (p->panim != PA_FALL)
 					P_SetPlayerMobjState(object, S_PLAY_FALL1);
 			}
+			*/
 			break;
 		case MT_STEAM: // Steam
 			if (zdist > FixedMul(16*FRACUNIT, spring->scale))
@@ -277,12 +281,14 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
 
 			object->momz = flipval*FixedMul(speed, FixedSqrt(FixedMul(spring->scale, object->scale))); // scale the speed with both objects' scales, just like with springs!
 
+			/* // SRB2kart - don't need state change
 			if (p)
 			{
 				P_ResetPlayer(p);
 				if (p->panim != PA_FALL)
 					P_SetPlayerMobjState(object, S_PLAY_FALL1);
 			}
+			*/
 			break;
 		default:
 			break;
@@ -299,8 +305,8 @@ static void P_DoTailsCarry(player_t *sonic, player_t *tails)
 	if ((sonic->pflags & PF_CARRIED) && sonic->mo->tracer == tails->mo)
 		return;
 
-	if (!tails->powers[pw_tailsfly] && !(tails->charability == CA_FLY && (tails->mo->state >= &states[S_PLAY_SPC1] && tails->mo->state <= &states[S_PLAY_SPC4])))
-		return;
+	//if (!tails->powers[pw_tailsfly] && !(tails->charability == CA_FLY && (tails->mo->state >= &states[S_PLAY_SPC1] && tails->mo->state <= &states[S_PLAY_SPC4])))
+	//	return; // SRB2kart - no changey statey
 
 	if (tails->bot == 1)
 		return;
@@ -1929,9 +1935,11 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
 
 				// Don't 'step up' while springing,
 				// Only step up "if needed".
+				/* // SRB2kart - don't need
 				if (thing->state == &states[S_PLAY_SPRING]
 				&& P_MobjFlip(thing)*thing->momz > FixedMul(FRACUNIT, thing->scale))
 					maxstep = 0;
+				*/
 			}
 
 			if (thing->type == MT_SKIM)
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 4122619d1..253e0edaa 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -164,6 +164,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
 #endif
 
 	// Catch state changes for Super Sonic
+	/* // SRB2kart - don't need
 	if (player->powers[pw_super] && (player->charflags & SF_SUPERANIMS))
 	{
 		switch (state)
@@ -213,7 +214,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
 		}
 	}
 	// You were in pain state after taking a hit, and you're moving out of pain state now?
-	else if (mobj->state == &states[mobj->info->painstate] && player->powers[pw_flashing] == flashingtics && state != mobj->info->painstate)
+	else */if (mobj->state == &states[mobj->info->painstate] && player->powers[pw_flashing] == flashingtics && state != mobj->info->painstate)
 	{
 		// Start flashing, since you've landed.
 		player->powers[pw_flashing] = flashingtics-1;
@@ -222,21 +223,19 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
 
 	// Set animation state
 	// The pflags version of this was just as convoluted.
-	if ((state >= S_PLAY_STND && state <= S_PLAY_TAP2) || (state >= S_PLAY_TEETER1 && state <= S_PLAY_TEETER2) || state == S_PLAY_CARRY
-	|| state == S_PLAY_SUPERSTAND || state == S_PLAY_SUPERTEETER)
+	// Rewriten for SRB2kart ... though I don't know what this is.
+	if ((state >= S_KART_STND && state <= S_KART_STND_R) || state == S_KART_SQUISH || (state >= S_KART_SPIN1 && state <= S_KART_SPIN8))
 		player->panim = PA_IDLE;
-	else if ((state >= S_PLAY_RUN1 && state <= S_PLAY_RUN8)
-	|| (state >= S_PLAY_SUPERWALK1 && state <= S_PLAY_SUPERWALK2))
+	else if (state >= S_KART_WALK1 && state <= S_KART_WALK_R2)
 		player->panim = PA_WALK;
-	else if ((state >= S_PLAY_SPD1 && state <= S_PLAY_SPD4)
-	|| (state >= S_PLAY_SUPERFLY1 && state <= S_PLAY_SUPERFLY2))
+	else if (state >= S_KART_RUN1 && state <= S_KART_DRIFT_R2)
 		player->panim = PA_RUN;
-	else if (state >= S_PLAY_ATK1 && state <= S_PLAY_ATK4)
-		player->panim = PA_ROLL;
-	else if (state >= S_PLAY_FALL1 && state <= S_PLAY_FALL2)
-		player->panim = PA_FALL;
-	else if (state >= S_PLAY_ABL1 && state <= S_PLAY_ABL2)
-		player->panim = PA_ABILITY;
+	//else if (state >= S_PLAY_ATK1 && state <= S_PLAY_ATK4)
+	//	player->panim = PA_ROLL;
+	//else if (state >= S_PLAY_FALL1 && state <= S_PLAY_FALL2)
+	//	player->panim = PA_FALL;
+	//else if (state >= S_PLAY_ABL1 && state <= S_PLAY_ABL2)
+	//	player->panim = PA_ABILITY;
 	else
 		player->panim = PA_ETC;
 
@@ -1322,11 +1321,11 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
 
 	if (mo->player)
 	{
-		if (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
-		|| (mo->state >= &states[S_PLAY_SPC1] && mo->state <= &states[S_PLAY_SPC4])))
-			gravityadd = gravityadd/3; // less gravity while flying
-		if (mo->player->pflags & PF_GLIDING)
-			gravityadd = gravityadd/3; // less gravity while gliding
+		//if (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]			// SRB2kart
+		//|| (mo->state >= &states[S_PLAY_SPC1] && mo->state <= &states[S_PLAY_SPC4])))
+		//	gravityadd = gravityadd/3; // less gravity while flying
+		//if (mo->player->pflags & PF_GLIDING)
+		//	gravityadd = gravityadd/3; // less gravity while gliding
 		if (mo->player->climbing)
 			gravityadd = 0;
 		if (mo->player->pflags & PF_NIGHTSMODE)
@@ -1486,7 +1485,7 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy)
 		{
 			// if in a walking frame, stop moving
 			if (player->panim == PA_WALK)
-				P_SetPlayerMobjState(mo, S_PLAY_STND);
+				P_SetPlayerMobjState(mo, S_KART_STND); // SRB2kart - was S_PLAY_STND
 			mo->momx = player->cmomx;
 			mo->momy = player->cmomy;
 		}
@@ -2672,8 +2671,8 @@ static void P_PlayerZMovement(mobj_t *mo)
 			goto nightsdone;
 		}
 		// Get up if you fell.
-		if (mo->state == &states[mo->info->painstate] || mo->state == &states[S_PLAY_SUPERHIT])
-			P_SetPlayerMobjState(mo, S_PLAY_STND);
+		if (mo->state == &states[mo->info->painstate]) // SRB2kart
+			P_SetPlayerMobjState(mo, S_KART_STND);
 
 #ifdef ESLOPE
 		if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)) {
@@ -2776,25 +2775,25 @@ static void P_PlayerZMovement(mobj_t *mo)
 						mo->tics = -1;
 					}
 					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_SPC1] && mo->state <= &states[S_PLAY_SPC4]))
+					|| mo->player->powers[pw_tailsfly]) // SRB2kart
 					{
 						if (mo->player->cmomx || mo->player->cmomy)
 						{
 							if (mo->player->speed >= FixedMul(mo->player->runspeed, mo->scale) && mo->player->panim != PA_RUN)
-								P_SetPlayerMobjState(mo, S_PLAY_SPD1);
+								P_SetPlayerMobjState(mo, S_KART_RUN1);
 							else if ((mo->player->rmomx || mo->player->rmomy) && mo->player->panim != PA_WALK)
-								P_SetPlayerMobjState(mo, S_PLAY_RUN1);
+								P_SetPlayerMobjState(mo, S_KART_WALK1);
 							else if (!mo->player->rmomx && !mo->player->rmomy && mo->player->panim != PA_IDLE)
-								P_SetPlayerMobjState(mo, S_PLAY_STND);
+								P_SetPlayerMobjState(mo, S_KART_STND);
 						}
 						else
 						{
 							if (mo->player->speed >= FixedMul(mo->player->runspeed, mo->scale) && mo->player->panim != PA_RUN)
-								P_SetPlayerMobjState(mo, S_PLAY_SPD1);
+								P_SetPlayerMobjState(mo, S_KART_RUN1);
 							else if ((mo->momx || mo->momy) && mo->player->panim != PA_WALK)
-								P_SetPlayerMobjState(mo, S_PLAY_RUN1);
+								P_SetPlayerMobjState(mo, S_KART_WALK1);
 							else if (!mo->momx && !mo->momy && mo->player->panim != PA_IDLE)
-								P_SetPlayerMobjState(mo, S_PLAY_STND);
+								P_SetPlayerMobjState(mo, S_KART_STND);
 						}
 					}
 
@@ -3739,7 +3738,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
 		{
 			mobj->player->secondjump = 0;
 			mobj->player->powers[pw_tailsfly] = 0;
-			P_SetPlayerMobjState(mobj, S_PLAY_RUN1);
+			P_SetPlayerMobjState(mobj, S_KART_WALK1); // SRB2kart - was S_PLAY_RUN1
 		}
 		mobj->eflags &= ~MFE_JUSTHITFLOOR;
 	}
@@ -8448,7 +8447,7 @@ void P_AfterPlayerSpawn(INT32 playernum)
 	else
 		p->viewz = p->mo->z + p->viewheight;
 
-	P_SetPlayerMobjState(p->mo, S_PLAY_STND);
+	P_SetPlayerMobjState(p->mo, S_KART_STND); // SRB2kart - was S_PLAY_STND
 	p->pflags &= ~PF_SPINNING;
 
 	if (playernum == consoleplayer)
diff --git a/src/p_spec.c b/src/p_spec.c
index fbcb8b4f0..a958a4b17 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -2743,7 +2743,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 				mo->player->rmomx = mo->player->rmomy = 1;
 				mo->player->cmomx = mo->player->cmomy = 0;
 				P_ResetPlayer(mo->player);
-				P_SetPlayerMobjState(mo, S_PLAY_STND);
+				P_SetPlayerMobjState(mo, S_KART_STND); // SRB2kart - was S_PLAY_STND
 
 				// Reset bot too.
 				if (bot) {
@@ -2754,7 +2754,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 					bot->player->rmomx = bot->player->rmomy = 1;
 					bot->player->cmomx = bot->player->cmomy = 0;
 					P_ResetPlayer(bot->player);
-					P_SetPlayerMobjState(bot, S_PLAY_STND);
+					P_SetPlayerMobjState(bot, S_KART_STND); // SRB2kart - was S_PLAY_STND
 				}
 			}
 			break;
@@ -3700,7 +3700,7 @@ DoneSection2:
 					if (!(player->pflags & PF_SPINNING))
 						player->pflags |= PF_SPINNING;
 
-					P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+					//P_SetPlayerMobjState(player->mo, S_PLAY_ATK1); // SRB2kart
 				}
 
 				player->powers[pw_flashing] = TICRATE/3;
@@ -3841,8 +3841,8 @@ DoneSection2:
 				player->mo->momz = mobjinfo[MT_FAN].mass;
 
 			P_ResetPlayer(player);
-			if (player->panim != PA_FALL)
-				P_SetPlayerMobjState(player->mo, S_PLAY_FALL1);
+			//if (player->panim != PA_FALL) 					// SRB2kart
+			//	P_SetPlayerMobjState(player->mo, S_PLAY_FALL1);
 			break;
 
 		case 6: // Super Sonic transformer
@@ -3851,6 +3851,7 @@ DoneSection2:
 			break;
 
 		case 7: // Make player spin
+			/* // SRB2kart - no.
 			if (!(player->pflags & PF_SPINNING) && P_IsObjectOnGround(player->mo) && (player->charability2 == CA2_SPINDASH))
 			{
 				player->pflags |= PF_SPINNING;
@@ -3860,7 +3861,7 @@ DoneSection2:
 				if (abs(player->rmomx) < FixedMul(5*FRACUNIT, player->mo->scale)
 				&& abs(player->rmomy) < FixedMul(5*FRACUNIT, player->mo->scale))
 					P_InstaThrust(player->mo, player->mo->angle, FixedMul(10*FRACUNIT, player->mo->scale));
-			}
+			}*/
 			break;
 
 		case 8: // Zoom Tube Start
@@ -3928,11 +3929,11 @@ DoneSection2:
 				player->pflags &= ~PF_GLIDING;
 				player->climbing = 0;
 
-				if (!(player->mo->state >= &states[S_PLAY_ATK1] && player->mo->state <= &states[S_PLAY_ATK4]))
-				{
-					P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
-					S_StartSound(player->mo, sfx_spin);
-				}
+				//if (!(player->mo->state >= &states[S_PLAY_ATK1] && player->mo->state <= &states[S_PLAY_ATK4])) // SRB2kart
+				//{
+				//	P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+				//	S_StartSound(player->mo, sfx_spin);
+				//}
 			}
 			break;
 
@@ -4000,11 +4001,11 @@ DoneSection2:
 				player->pflags |= PF_SPINNING;
 				player->pflags &= ~PF_JUMPED;
 
-				if (!(player->mo->state >= &states[S_PLAY_ATK1] && player->mo->state <= &states[S_PLAY_ATK4]))
-				{
-					P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
-					S_StartSound(player->mo, sfx_spin);
-				}
+				//if (!(player->mo->state >= &states[S_PLAY_ATK1] && player->mo->state <= &states[S_PLAY_ATK4])) // SRB2kart
+				//{
+				//	P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+				//	S_StartSound(player->mo, sfx_spin);
+				//}
 			}
 			break;
 
@@ -4305,7 +4306,7 @@ DoneSection2:
 				player->pflags &= ~PF_SLIDING;
 				player->climbing = 0;
 				P_SetThingPosition(player->mo);
-				P_SetPlayerMobjState(player->mo, S_PLAY_CARRY);
+				//P_SetPlayerMobjState(player->mo, S_PLAY_CARRY); // SRB2kart
 			}
 			break;
 		case 12: // Camera noclip
diff --git a/src/p_telept.c b/src/p_telept.c
index 4921040b4..318ac718a 100644
--- a/src/p_telept.c
+++ b/src/p_telept.c
@@ -96,7 +96,7 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
 		P_ClearStarPost(starpostnum);
 
 		P_ResetPlayer(thing->player);
-		P_SetPlayerMobjState(thing, S_PLAY_STND);
+		P_SetPlayerMobjState(thing, S_KART_STND); // SRB2kart - was S_PLAY_STND
 
 		P_FlashPal(thing->player, PAL_MIXUP, 10);
 	}
@@ -169,7 +169,7 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle
 			thing->player->rmomx = thing->player->rmomy = 0;
 			thing->player->speed = 0;
 			P_ResetPlayer(thing->player);
-			P_SetPlayerMobjState(thing, S_PLAY_STND);
+			P_SetPlayerMobjState(thing, S_KART_STND); // SRB2kart - was S_PLAY_STND
 		}
 
 		if (flash)
diff --git a/src/p_user.c b/src/p_user.c
index 2f6911fe1..fb1a91b98 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -42,6 +42,8 @@
 #include "b_bot.h"
 // Objectplace
 #include "m_cheat.h"
+// SRB2kart
+#include "k_kart.h"
 
 #ifdef HW3SOUND
 #include "hardware/hw3sound.h"
@@ -605,7 +607,7 @@ static void P_DeNightserizePlayer(player_t *player)
 
 	if (player->mo->tracer)
 		P_RemoveMobj(player->mo->tracer);
-	P_SetPlayerMobjState(player->mo, S_PLAY_FALL1);
+	//P_SetPlayerMobjState(player->mo, S_PLAY_FALL1); // SRB2kart
 	player->pflags |= PF_NIGHTSFALL;
 
 	// If in a special stage, add some preliminary exit time.
@@ -958,6 +960,7 @@ void P_GivePlayerLives(player_t *player, INT32 numlives)
 // Transform into Super Sonic!
 void P_DoSuperTransformation(player_t *player, boolean giverings)
 {
+	return; // SRB2kart - this is not a thing we need
 	player->powers[pw_super] = 1;
 	if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC) && P_IsLocalPlayer(player))
 	{
@@ -968,7 +971,7 @@ void P_DoSuperTransformation(player_t *player, boolean giverings)
 	S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi
 
 	// Transformation animation
-	P_SetPlayerMobjState(player->mo, S_PLAY_SUPERTRANS1);
+	//P_SetPlayerMobjState(player->mo, S_PLAY_SUPERTRANS1);
 
 	player->mo->momx = player->mo->momy = player->mo->momz = 0;
 
@@ -1590,12 +1593,14 @@ void P_DoPlayerExit(player_t *player)
 		player->exiting = (14*TICRATE)/5 + 2; // Accidental death safeguard???
 
 	//player->pflags &= ~PF_GLIDING;
+	/*	// SRB2kart - don't need
 	if (player->climbing)
 	{
 		player->climbing = 0;
 		player->pflags |= PF_JUMPED;
 		P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
 	}
+	*/
 	player->powers[pw_underwater] = 0;
 	player->powers[pw_spacetime] = 0;
 	P_RestoreMusic(player);
@@ -2275,6 +2280,7 @@ static void P_DoPlayerHeadSigns(player_t *player)
 //
 static void P_DoClimbing(player_t *player)
 {
+	return; // SRB2kart - don't need
 	ticcmd_t *cmd = &player->cmd;
 	fixed_t platx;
 	fixed_t platy;
@@ -2653,6 +2659,7 @@ static void P_DoClimbing(player_t *player)
 		else
 			climb = false;
 
+		/* // SRB2kart - don't need
 		if (player->climbing && climb && (player->mo->momx || player->mo->momy || player->mo->momz)
 			&& !(player->mo->state >= &states[S_PLAY_CLIMB2] && player->mo->state <= &states[S_PLAY_CLIMB5]))
 			P_SetPlayerMobjState(player->mo, S_PLAY_CLIMB2);
@@ -2677,12 +2684,13 @@ static void P_DoClimbing(player_t *player)
 			player->pflags |= PF_JUMPED;
 			P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
 		}
+		*/
 	}
 	else
 	{
 		player->climbing = 0;
 		player->pflags |= PF_JUMPED;
-		P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+		//P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
 	}
 
 	if (cmd->sidemove != 0 || cmd->forwardmove != 0)
@@ -2690,6 +2698,7 @@ static void P_DoClimbing(player_t *player)
 	else
 		climb = false;
 
+	/*
 	if (player->climbing && climb && (player->mo->momx || player->mo->momy || player->mo->momz)
 		&& !(player->mo->state >= &states[S_PLAY_CLIMB2] && player->mo->state <= &states[S_PLAY_CLIMB5]))
 		P_SetPlayerMobjState(player->mo, S_PLAY_CLIMB2);
@@ -2715,11 +2724,12 @@ static void P_DoClimbing(player_t *player)
 
 	if (player->climbing == 0)
 		P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+	*/
 
 	if (player->climbing && P_IsObjectOnGround(player->mo))
 	{
 		P_ResetPlayer(player);
-		P_SetPlayerMobjState(player->mo, S_PLAY_STND);
+		P_SetPlayerMobjState(player->mo, S_KART_STND); // SRB2kart
 	}
 }
 
@@ -2849,6 +2859,7 @@ static boolean PIT_CheckSolidsTeeter(mobj_t *thing)
 //
 static void P_DoTeeter(player_t *player)
 {
+	return; // SRB2kart - don't need
 	msecnode_t *node;
 	boolean teeter = false;
 	boolean roverfloor; // solid 3d floors?
@@ -3142,6 +3153,7 @@ teeterdone:
 			tmthing = oldtmthing; // restore old tmthing, goodness knows what the game does with this before mobj thinkers
 		}
 	}
+	/*
 	if (teeter)
 	{
 		if ((player->mo->state == &states[S_PLAY_STND] || player->mo->state == &states[S_PLAY_TAP1] || player->mo->state == &states[S_PLAY_TAP2] || player->mo->state == &states[S_PLAY_SUPERSTAND]))
@@ -3149,6 +3161,7 @@ teeterdone:
 	}
 	else if (checkedforteeter && (player->mo->state == &states[S_PLAY_TEETER1] || player->mo->state == &states[S_PLAY_TEETER2] || player->mo->state == &states[S_PLAY_SUPERTEETER]))
 		P_SetPlayerMobjState(player->mo, S_PLAY_STND);
+	*/
 }
 
 //
@@ -3393,10 +3406,11 @@ firenormal:
 //
 static void P_DoSuperStuff(player_t *player)
 {
+	return; // SRB2kart - don't neeeeed
 	mobj_t *spark;
 	ticcmd_t *cmd = &player->cmd;
-	if (player->mo->state >= &states[S_PLAY_SUPERTRANS1] && player->mo->state <= &states[S_PLAY_SUPERTRANS9])
-		return; // don't do anything right now, we're in the middle of transforming!
+	//if (player->mo->state >= &states[S_PLAY_SUPERTRANS1] && player->mo->state <= &states[S_PLAY_SUPERTRANS9])
+	//	return; // don't do anything right now, we're in the middle of transforming!
 
 	if (player->pflags & PF_NIGHTSMODE)
 		return; // NiGHTS Super doesn't mix with normal super
@@ -3413,7 +3427,7 @@ static void P_DoSuperStuff(player_t *player)
 		if (!((ALL7EMERALDS(emeralds)) && (player->charflags & SF_SUPER)) && !(ALL7EMERALDS(player->powers[pw_emeralds])))
 		{
 			player->powers[pw_super] = 0;
-			P_SetPlayerMobjState(player->mo, S_PLAY_STND);
+			P_SetPlayerMobjState(player->mo, S_KART_STND);
 			P_RestoreMusic(player);
 			P_SpawnShieldOrb(player);
 
@@ -3487,6 +3501,7 @@ static void P_DoSuperStuff(player_t *player)
 			if (gametype != GT_COOP)
 				player->powers[pw_flashing] = flashingtics-1;
 
+/*
 			if (player->mo->health > 0)
 			{
 				if ((player->pflags & PF_JUMPED) || (player->pflags & PF_SPINNING))
@@ -3504,6 +3519,7 @@ static void P_DoSuperStuff(player_t *player)
 					player->mo->health = 1;
 				}
 			}
+*/
 
 			// Inform the netgame that the champion has fallen in the heat of battle.
 			if (gametype != GT_COOP)
@@ -3710,10 +3726,12 @@ void P_DoJump(player_t *player, boolean soundandstate)
 		if (!player->spectator)
 			S_StartSound(player->mo, sfx_jump); // Play jump sound!
 
+		/* // SRB2kart - don't need jump frames
 		if (!(player->charability2 == CA2_SPINDASH))
 			P_SetPlayerMobjState(player->mo, S_PLAY_SPRING);
 		else
 			P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+		*/
 	}
 }
 
@@ -3724,6 +3742,7 @@ void P_DoJump(player_t *player, boolean soundandstate)
 //
 static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 {
+	return; // SRB2kart - what's a spindash?
 	if (player->pflags & PF_STASIS)
 		return;
 
@@ -3750,7 +3769,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 			player->pflags |= PF_STARTDASH|PF_SPINNING;
 			player->dashspeed = FixedMul(FRACUNIT, player->mo->scale);
 			player->dashtime = 0;
-			P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+			//P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
 			player->pflags |= PF_USEDOWN;
 		}
 		else if ((cmd->buttons & BT_USE) && (player->pflags & PF_STARTDASH))
@@ -3779,7 +3798,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 			) && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING))
 		{
 			player->pflags |= PF_SPINNING;
-			P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+			//P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
 			if (!player->spectator)
 				S_StartSound(player->mo, sfx_spin);
 			player->pflags |= PF_USEDOWN;
@@ -3800,7 +3819,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 		{
 			player->skidtime = 0;
 			player->pflags &= ~PF_SPINNING;
-			P_SetPlayerMobjState(player->mo, S_PLAY_STND);
+			P_SetPlayerMobjState(player->mo, S_KART_STND);
 			player->mo->momx = player->cmomx;
 			player->mo->momy = player->cmomy;
 		}
@@ -3822,8 +3841,8 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 		player->dashspeed = 0;
 	}
 
-	if (onground && (player->pflags & PF_SPINNING) && !(player->panim == PA_ROLL))
-		P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+	//if (onground && (player->pflags & PF_SPINNING) && !(player->panim == PA_ROLL))
+	//	P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
 }
 
 //
@@ -3833,6 +3852,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 //
 void P_DoJumpShield(player_t *player)
 {
+	return; // SRB2kart - Would be useful for feathers, but those are impossible to balance, so nuts to it.
 	if (player->pflags & PF_THOKKED)
 		return;
 
@@ -3843,7 +3863,7 @@ void P_DoJumpShield(player_t *player)
 	player->jumping = 0;
 	player->pflags |= PF_THOKKED;
 	player->pflags &= ~PF_SPINNING;
-	P_SetPlayerMobjState(player->mo, S_PLAY_FALL1);
+	//P_SetPlayerMobjState(player->mo, S_PLAY_FALL1);
 	S_StartSound(player->mo, sfx_wdjump);
 }
 
@@ -3994,6 +4014,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 			player->secondjump = 0;
 			player->pflags &= ~PF_THOKKED;
 		}
+		/* // SRB2kart - no jumpy power things
 		else if (player->pflags & PF_MACESPIN && player->mo->tracer)
 		{
 			player->pflags &= ~PF_MACESPIN;
@@ -4070,7 +4091,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 						; // Can't do anything if you're a fish out of water!
 					else if (!(player->pflags & PF_THOKKED) && !(player->powers[pw_tailsfly]))
 					{
-						P_SetPlayerMobjState(player->mo, S_PLAY_ABL1); // Change to the flying animation
+						//P_SetPlayerMobjState(player->mo, S_PLAY_ABL1); // Change to the flying animation
 
 						player->powers[pw_tailsfly] = tailsflytics + 1; // Set the fly timer
 
@@ -4096,7 +4117,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 							player->pflags &= ~PF_THOKKED;
 						}
 
-						P_SetPlayerMobjState(player->mo, S_PLAY_ABL1);
+						//P_SetPlayerMobjState(player->mo, S_PLAY_ABL1);
 						P_InstaThrust(player->mo, player->mo->angle, FixedMul(glidespeed, player->mo->scale));
 						player->pflags &= ~(PF_SPINNING|PF_STARTDASH);
 					}
@@ -4178,6 +4199,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
 		}
 		else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_JUMP && !player->powers[pw_super])
 			P_DoJumpShield(player);
+		*/
 	}
 
 	if (cmd->buttons & BT_JUMP)
@@ -4330,14 +4352,14 @@ static void P_2dMovement(player_t *player)
 			else if (player->exiting)
 			{
 				player->pflags &= ~PF_GLIDING;
-				P_SetPlayerMobjState(player->mo, S_PLAY_RUN1);
+				P_SetPlayerMobjState(player->mo, S_KART_WALK1); // SRB2kart - was S_PLAY_RUN1
 				player->skidtime = 0;
 			}
 		}
 		if (player->pflags & PF_SPINNING && !player->exiting)
 		{
 			player->pflags &= ~PF_SPINNING;
-			P_SetPlayerMobjState(player->mo, S_PLAY_STND);
+			P_SetPlayerMobjState(player->mo, S_KART_STND); // SRB2kart - was S_PLAY_STND
 		}
 	}
 
@@ -4521,14 +4543,14 @@ static void P_3dMovement(player_t *player)
 			else if (player->exiting)
 			{
 				player->pflags &= ~PF_GLIDING;
-				P_SetPlayerMobjState(player->mo, S_PLAY_RUN1);
+				P_SetPlayerMobjState(player->mo, S_KART_WALK1); // SRB2kart - was S_PLAY_RUN1
 				player->skidtime = 0;
 			}
 		}
 		if (player->pflags & PF_SPINNING && !player->exiting)
 		{
 			player->pflags &= ~PF_SPINNING;
-			P_SetPlayerMobjState(player->mo, S_PLAY_STND);
+			P_SetPlayerMobjState(player->mo, S_KART_STND); // SRB2kart - was S_PLAY_STND
 		}
 	}
 
@@ -6234,6 +6256,7 @@ static void P_SkidStuff(player_t *player)
 	fixed_t pmy = player->rmomy + player->cmomy;
 
 	// Knuckles glides into the dirt.
+	/* // SRB2kart - don't need
 	if (player->pflags & PF_GLIDING && player->skidtime)
 	{
 		// Fell off a ledge...
@@ -6271,7 +6294,7 @@ static void P_SkidStuff(player_t *player)
 		}
 	}
 	// Skidding!
-	else if (onground && !(player->mo->eflags & MFE_GOOWATER) && !(player->pflags & (PF_JUMPED|PF_SPINNING|PF_SLIDING)) && !(player->charflags & SF_NOSKID))
+	else*/if (onground && !(player->mo->eflags & MFE_GOOWATER) && !(player->pflags & (PF_JUMPED|PF_SPINNING|PF_SLIDING)) && !(player->charflags & SF_NOSKID))
 	{
 		if (player->skidtime)
 		{
@@ -6307,7 +6330,7 @@ static void P_SkidStuff(player_t *player)
 				player->skidtime = TICRATE/2;
 				S_StartSound(player->mo, sfx_skid);
 				if (player->panim != PA_WALK)
-					P_SetPlayerMobjState(player->mo, S_PLAY_RUN4); // this switches to S_PLAY_SUPERWALK1 for superanims
+					P_SetPlayerMobjState(player->mo, S_KART_WALK2); // SRB2kart - was S_PLAY_RUN4
 				player->mo->tics = player->skidtime;
 			}
 		}
@@ -6332,11 +6355,13 @@ static void P_MovePlayer(player_t *player)
 	if (countdowntimeup)
 		return;
 
+	/* // SRB2kart - junk
 	if (player->mo->state >= &states[S_PLAY_SUPERTRANS1] && player->mo->state <= &states[S_PLAY_SUPERTRANS9])
 	{
 		player->mo->momx = player->mo->momy = player->mo->momz = 0;
 		return;
 	}
+	*/
 
 	cmd = &player->cmd;
 	runspd = FixedMul(player->runspeed, player->mo->scale);
@@ -6480,28 +6505,121 @@ static void P_MovePlayer(player_t *player)
 		// If the player is moving fast enough,
 		// break into a run!
 		if (player->speed >= runspd && player->panim == PA_WALK && !player->skidtime && (onground || player->powers[pw_super]))
-			P_SetPlayerMobjState (player->mo, S_PLAY_SPD1);
+			P_SetPlayerMobjState (player->mo, S_KART_RUN1); // SRB2kart - was S_PLAY_SPD1
 
 		// Otherwise, just walk.
 		else if ((player->rmomx || player->rmomy) && player->panim == PA_IDLE)
-			P_SetPlayerMobjState (player->mo, S_PLAY_RUN1);
+			P_SetPlayerMobjState (player->mo, S_KART_WALK1); // SRB2kart - was S_PLAY_RUN1
 	}
 
+	//{ SRB2kart
+	// Kart frames
+	{
+		if (player->kartstuff[k_squishedtimer] > 0)
+		{
+			if (player->mo->state != &states[S_KART_SQUISH])
+				P_SetPlayerMobjState(player->mo, S_KART_SQUISH);
+		}
+		else if (player->kartstuff[k_spinouttimer] > 0)
+		{
+			if (!(player->mo->state >= &states[S_KART_SPIN1] && player->mo->state <= &states[S_KART_SPIN8]))
+				P_SetPlayerMobjState(player->mo, S_KART_SPIN1);
+		}
+		else if (player->kartstuff[k_spinouttimer] == 0 && player->kartstuff[k_squishedtimer] == 0)
+		{
+			// Standing frames - S_KART_STND   S_KART_STND_L   S_KART_STND_R
+			if (player->speed == 0)
+			{
+				if (cmd->buttons & BT_WEAPONNEXT && !(player->mo->state == &states[S_KART_STND_R]))
+					P_SetPlayerMobjState(player->mo, S_KART_STND_R);
+				else if (cmd->buttons & BT_WEAPONPREV && !(player->mo->state == &states[S_KART_STND_L]))
+					P_SetPlayerMobjState(player->mo, S_KART_STND_L);
+				else if (!(cmd->buttons & BT_WEAPONNEXT || cmd->buttons & BT_WEAPONPREV) && !(player->mo->state == &states[S_KART_STND]))
+					P_SetPlayerMobjState(player->mo, S_KART_STND);
+			}
+			// Drifting Left - S_KART_DRIFT_L1
+			else if (player->kartstuff[k_drift] < 0 && onground)
+			{
+				if (!(player->mo->state == &states[S_KART_DRIFT_L1] || player->mo->state == &states[S_KART_DRIFT_L2]))
+					P_SetPlayerMobjState(player->mo, S_KART_DRIFT_L1);
+			}
+			// Drifting Right - S_KART_DRIFT_R1
+			else if (player->kartstuff[k_drift] > 0 && onground)
+			{
+				if (!(player->mo->state == &states[S_KART_DRIFT_R1] || player->mo->state == &states[S_KART_DRIFT_R2]))
+					P_SetPlayerMobjState(player->mo, S_KART_DRIFT_R1);
+			}
+			// Run frames - S_KART_RUN1   S_KART_RUN_L1   S_KART_RUN_R1
+			else if (player->speed > runspd)
+			{
+				if (cmd->buttons & BT_WEAPONNEXT && !(player->mo->state == &states[S_KART_RUN_R1] || player->mo->state == &states[S_KART_RUN_R2]))
+					P_SetPlayerMobjState(player->mo, S_KART_RUN_R1);
+				else if (cmd->buttons & BT_WEAPONPREV && !(player->mo->state == &states[S_KART_RUN_L1] || player->mo->state == &states[S_KART_RUN_L2]))
+					P_SetPlayerMobjState(player->mo, S_KART_RUN_L1);
+				else if (!(cmd->buttons & BT_WEAPONNEXT || cmd->buttons & BT_WEAPONPREV) && !(player->mo->state == &states[S_KART_RUN1] || player->mo->state == &states[S_KART_RUN2]))
+					P_SetPlayerMobjState(player->mo, S_KART_RUN1);
+			}
+			// Walk frames - S_KART_WALK1   S_KART_WALK_L1   S_KART_WALK_R1
+			else if (player->speed <= runspd)
+			{
+				if (cmd->buttons & BT_WEAPONNEXT && !(player->mo->state == &states[S_KART_WALK_R1] || player->mo->state == &states[S_KART_WALK_R2]))
+					P_SetPlayerMobjState(player->mo, S_KART_WALK_R1);
+				else if (cmd->buttons & BT_WEAPONPREV && !(player->mo->state == &states[S_KART_WALK_L1] || player->mo->state == &states[S_KART_WALK_L2]))
+					P_SetPlayerMobjState(player->mo, S_KART_WALK_L1);
+				else if (!(cmd->buttons & BT_WEAPONNEXT || cmd->buttons & BT_WEAPONPREV) && !(player->mo->state == &states[S_KART_WALK1] || player->mo->state == &states[S_KART_WALK2]))
+					P_SetPlayerMobjState(player->mo, S_KART_WALK1);
+			}
+		}
+	}
+	//}
+
 	// If your running animation is playing, and you're
 	// going too slow, switch back to the walking frames.
 	if (player->panim == PA_RUN && player->speed < runspd)
-		P_SetPlayerMobjState(player->mo, S_PLAY_RUN1);
+		P_SetPlayerMobjState(player->mo, S_KART_WALK1); // SRB2kart - was S_PLAY_RUN1
 
 	// If Springing, but travelling DOWNWARD, change back!
-	if (player->mo->state == &states[S_PLAY_SPRING] && P_MobjFlip(player->mo)*player->mo->momz < 0)
-		P_SetPlayerMobjState(player->mo, S_PLAY_FALL1);
+	//if (player->mo->state == &states[S_PLAY_SPRING] && P_MobjFlip(player->mo)*player->mo->momz < 0)
+	//	P_SetPlayerMobjState(player->mo, S_PLAY_FALL1);
 	// If Springing but on the ground, change back!
-	else if (onground && (player->mo->state == &states[S_PLAY_SPRING] || player->panim == PA_FALL || player->mo->state == &states[S_PLAY_CARRY]) && !player->mo->momz)
-		P_SetPlayerMobjState(player->mo, S_PLAY_STND);
+	//else if (onground && (player->mo->state == &states[S_PLAY_SPRING] || player->panim == PA_FALL || player->mo->state == &states[S_PLAY_CARRY]) && !player->mo->momz)
+	//	P_SetPlayerMobjState(player->mo, S_PLAY_STND);
 
 	// If you are stopped and are still walking, stand still!
 	if (!player->mo->momx && !player->mo->momy && !player->mo->momz && player->panim == PA_WALK)
-		P_SetPlayerMobjState(player->mo, S_PLAY_STND);
+		P_SetPlayerMobjState(player->mo, S_KART_STND); // SRB2kart - was S_PLAY_STND
+
+	//{ SRB2kart
+	// Engine Sounds.
+	/* // -- Need to load these sounds into game first
+	if (!player->exiting)
+	{
+		if (player->speed == 0 && onground && player->speed == 0 && leveltime % 6 == 0 && kartmode)
+			S_StartSound(player->mo, sfx_kart1);
+
+		if ((player->speed < runspd && player->speed != 0) && leveltime % 8 == 0 && kartmode)
+			S_StartSound(player->mo, sfx_kart2);
+
+		if ((player->speed > runspd) && leveltime % 8 == 0 && kartmode)
+			S_StartSound(player->mo, sfx_kart3);
+
+		// Drifting sound
+		if (kartmode)
+		{
+			// Leveltime being 50 might take a while at times. We'll start it up once, isntantly.
+			if ((player->powers[pw_drift] == 1 || player->powers[pw_drift] == -1) && onground && !S_SoundPlaying(NULL, sfx_mkdrft))
+				S_StartSound(player->mo, sfx_mkdrft);
+			// Start looping the sound now.
+			else if (leveltime % 50 == 0 && ((player->powers[pw_drift] == 1 || player->powers[pw_drift] == -1) && onground))
+				S_StartSound(player->mo, sfx_mkdrft);
+			// Ok, we'll stop now.
+			else if ((player->powers[pw_drift] == 0)
+			&& (player == &players[consoleplayer] || (splitscreen && player == &players[secondarydisplayplayer])))
+				S_StopSoundByID(player->mo, sfx_mkdrft);
+		}
+	}
+	*/
+	//}
 
 
 //////////////////
@@ -6516,7 +6634,7 @@ static void P_MovePlayer(player_t *player)
 		player->jumping = 0;
 		player->secondjump = 0;
 		player->pflags &= ~PF_THOKKED;
-		P_SetPlayerMobjState(player->mo, S_PLAY_STND);
+		P_SetPlayerMobjState(player->mo, S_KART_STND); // SRB2kart - was S_PLAY_STND
 	}
 
 	// Cap the speed limit on a spindash
@@ -6528,6 +6646,7 @@ static void P_MovePlayer(player_t *player)
 
 	if (!(player->charability == CA_GLIDEANDCLIMB) || player->gotflag) // If you can't glide, then why the heck would you be gliding?
 	{
+		/* // SRB2kart - ???
 		if (player->pflags & PF_GLIDING || player->climbing)
 		{
 			if (onground)
@@ -6538,6 +6657,7 @@ static void P_MovePlayer(player_t *player)
 				P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
 			}
 		}
+		*/
 		player->pflags &= ~PF_GLIDING;
 		player->glidetime = 0;
 		player->climbing = 0;
@@ -6545,6 +6665,7 @@ static void P_MovePlayer(player_t *player)
 
 	// Glide MOMZ
 	// AKA my own gravity. =)
+	/* // SRB2kart - gliding is illegal, go to jail
 	if (player->pflags & PF_GLIDING)
 	{
 		fixed_t leeway;
@@ -6619,6 +6740,7 @@ static void P_MovePlayer(player_t *player)
 				player->mo->momz = 0;
 		}
 	}
+	*/
 
 	// If you're running fast enough, you can create splashes as you run in shallow water.
 	if (!player->climbing
@@ -6653,6 +6775,7 @@ static void P_MovePlayer(player_t *player)
 	//TAILS FLYING//
 	////////////////
 
+	/* // SRB2kart - nah
 	if (!(player->charability == CA_FLY || player->charability == CA_SWIM)) // why are you flying when you cannot fly?!
 	{
 		if (player->powers[pw_tailsfly]
@@ -6740,12 +6863,13 @@ static void P_MovePlayer(player_t *player)
 		if (demorecording)
 			G_GhostAddSpin();
 	}
-
+	*/
 
 	////////////////////////////
 	//SPINNING AND SPINDASHING//
 	////////////////////////////
 
+	/* // SRB2kart - nadah
 	// If the player isn't on the ground, make sure they aren't in a "starting dash" position.
 	if (!onground)
 	{
@@ -6759,13 +6883,15 @@ static void P_MovePlayer(player_t *player)
 		P_ElementalFireTrail(player);
 
 	P_DoSpinDash(player, cmd);
-
+	*/
 	// jumping
 	P_DoJumpStuff(player, cmd);
 
+	/*
 	// If you're not spinning, you'd better not be spindashing!
 	if (!(player->pflags & PF_SPINNING))
 		player->pflags &= ~PF_STARTDASH;
+	*/
 
 	//////////////////
 	//ANALOG CONTROL//
@@ -6814,7 +6940,7 @@ static void P_MovePlayer(player_t *player)
 		}
 		// Otherwise, face the direction you're travelling.
 		else if (player->panim == PA_WALK || player->panim == PA_RUN || player->panim == PA_ROLL
-		|| ((player->mo->state >= &states[S_PLAY_ABL1] && player->mo->state <= &states[S_PLAY_SPC4]) && player->charability == CA_FLY))
+		|| (/*(player->mo->state >= &states[S_PLAY_ABL1] && player->mo->state <= &states[S_PLAY_SPC4]) && */player->charability == CA_FLY)) // SRB2kart - idk
 			player->mo->angle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy);
 
 		// Update the local angle control.
@@ -6830,6 +6956,7 @@ static void P_MovePlayer(player_t *player)
 	//STUFF!                 //
 	///////////////////////////
 
+	/* // SRB2kart - what's a shield? Never heard of it. Never happened. Nope.
 	if (cmd->buttons & BT_USE) // Spin button effects
 	{
 		if (player->pflags & PF_JUMPED) // If the player is jumping
@@ -6959,25 +7086,30 @@ static void P_MovePlayer(player_t *player)
 		if (player->mo->eflags & MFE_VERTICALFLIP && player->mo->height != oldheight) // adjust z height for reverse gravity, similar to how it's done for scaling
 			player->mo->z -= player->mo->height - oldheight;
 	}
+	*/
 
 	// Crush test...
 	if ((player->mo->ceilingz - player->mo->floorz < player->mo->height)
 		&& !(player->mo->flags & MF_NOCLIP))
 	{
+		/* // SRB2kart - no, we're not making the playerspin
 		if ((player->charability2 == CA2_SPINDASH) && !(player->pflags & PF_SPINNING))
 		{
 			player->pflags |= PF_SPINNING;
 			P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
 		}
-		else if (player->mo->ceilingz - player->mo->floorz < player->mo->height)
+		else */if (player->mo->ceilingz - player->mo->floorz < player->mo->height)
 		{
 			if ((netgame || multiplayer) && player->spectator)
 				P_DamageMobj(player->mo, NULL, NULL, 42000); // Respawn crushed spectators
 			else
 			{
+				P_SquishPlayerMobj(player->mo, NULL); // SRB2kart - we don't kill when squished, we squish when squished.
+				/*
 				mobj_t *killer = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_NULL);
 				killer->threshold = 44; // Special flag that it was crushing which killed you.
 				P_DamageMobj(player->mo, killer, killer, 10000);
+				*/
 			}
 
 			if (player->playerstate == PST_DEAD)
@@ -7228,6 +7360,8 @@ static void P_DoZoomTube(player_t *player)
 //
 static void P_DoRopeHang(player_t *player)
 {
+	return; // SRB2kart - errr
+	/*
 	INT32 sequence;
 	fixed_t speed;
 	thinker_t *th;
@@ -7379,6 +7513,7 @@ static void P_DoRopeHang(player_t *player)
 		player->mo->momy = speedy;
 		player->mo->momz = speedz;
 	}
+	*/
 }
 
 #if 0
@@ -8691,6 +8826,7 @@ void P_PlayerThink(player_t *player)
 		}
 	}
 #endif
+	/*
 	if (player->pflags & PF_GLIDING)
 	{
 		if (player->panim != PA_ABILITY)
@@ -8698,6 +8834,7 @@ void P_PlayerThink(player_t *player)
 	}
 	else if ((player->pflags & PF_JUMPED) && !player->powers[pw_super] && player->panim != PA_ROLL && player->charability2 == CA2_SPINDASH)
 		P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+	*/
 
 	if (player->flashcount)
 		player->flashcount--;
@@ -8924,24 +9061,25 @@ void P_PlayerThink(player_t *player)
 		player->mo->reactiontime--;
 	else if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT)
 	{
-		if (player->pflags & PF_ROPEHANG)
-		{
-			if (!P_AnalogMove(player))
-				player->mo->angle = (cmd->angleturn<<16 /* not FRACBITS */);
+		// SRB2kart - don't need no rope hangin'
+		//if (player->pflags & PF_ROPEHANG)
+		//{
+		//	if (!P_AnalogMove(player))
+		//		player->mo->angle = (cmd->angleturn<<16 /* not FRACBITS */);
 
-			ticruned++;
-			if ((cmd->angleturn & TICCMD_RECEIVED) == 0)
-				ticmiss++;
+		//	ticruned++;
+		//	if ((cmd->angleturn & TICCMD_RECEIVED) == 0)
+		//		ticmiss++;
 
-			P_DoRopeHang(player);
-			P_SetPlayerMobjState(player->mo, S_PLAY_CARRY);
-			P_DoJumpStuff(player, &player->cmd);
-		}
-		else
+		//	P_DoRopeHang(player);
+		//	P_SetPlayerMobjState(player->mo, S_PLAY_CARRY);
+		//	P_DoJumpStuff(player, &player->cmd);
+		//}
+		//else
 		{
 			P_DoZoomTube(player);
-			if (!(player->panim == PA_ROLL) && player->charability2 == CA2_SPINDASH)
-				P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+			//if (!(player->panim == PA_ROLL) && player->charability2 == CA2_SPINDASH) // SRB2kart
+			//	P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
 		}
 		player->rmomx = player->rmomy = 0; // no actual momentum from your controls
 		P_ResetScore(player);
@@ -9070,7 +9208,7 @@ void P_PlayerThink(player_t *player)
 
 	if (player->powers[pw_ingoop])
 	{
-		if (player->mo->state == &states[S_PLAY_STND])
+		if (player->mo->state == &states[S_KART_STND]) // SRB2kart - was S_PLAY_STND
 			player->mo->tics = 2;
 
 		player->powers[pw_ingoop]--;
@@ -9125,7 +9263,7 @@ void P_PlayerThink(player_t *player)
 
 	player->pflags &= ~PF_SLIDING;
 	
-	P_KartPlayerThink(player); // SRB2kart
+	K_KartPlayerThink(player, cmd); // SRB2kart
 
 /*
 //	Colormap verification
@@ -9318,19 +9456,22 @@ void P_PlayerAfterThink(player_t *player)
 	if (P_IsLocalPlayer(player) && (player->pflags & PF_WPNDOWN) && player->currentweapon != oldweapon)
 		S_StartSound(NULL, sfx_wepchg);
 
+	/* // SRB2kart
 	if (player->pflags & PF_GLIDING)
 	{
 		if (player->panim != PA_ABILITY)
 			P_SetPlayerMobjState(player->mo, S_PLAY_ABL1);
 	}
-	else if (player->pflags & PF_SLIDING)
+	else */
+	if (player->pflags & PF_SLIDING)
 		P_SetPlayerMobjState(player->mo, player->mo->info->painstate);
-	else if (player->pflags & PF_JUMPED
+	/*else if (player->pflags & PF_JUMPED
 	&& ((!player->powers[pw_super] && player->panim != PA_ROLL)
 	|| player->mo->state == &states[player->mo->info->painstate])
 	&& player->charability2 == CA2_SPINDASH)
-		P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+		P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);*/
 
+	/* // SRB2kart - fight! fight! fight!
 	if (player->pflags & PF_CARRIED && player->mo->tracer)
 	{
 		player->mo->height = FixedDiv(P_GetPlayerHeight(player), FixedDiv(14*FRACUNIT,10*FRACUNIT));
@@ -9423,7 +9564,7 @@ void P_PlayerAfterThink(player_t *player)
 			}
 		}
 	}
-	else if (player->pflags & PF_MACESPIN && player->mo->tracer && player->mo->tracer->target)
+	else */if (player->pflags & PF_MACESPIN && player->mo->tracer && player->mo->tracer->target)
 	{
 		player->mo->height = P_GetPlayerSpinHeight(player);
 		// tracer is what you're hanging onto....
diff --git a/src/st_stuff.c b/src/st_stuff.c
index aac6b09d2..844aeadcf 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -28,6 +28,7 @@
 #include "m_menu.h"
 #include "m_cheat.h"
 #include "p_setup.h" // NiGHTS grading
+#include "k_kart.h" // SRB2kart
 
 //random index
 #include "m_random.h"
@@ -123,6 +124,10 @@ static patch_t *minicaps;
 static patch_t *gotrflag;
 static patch_t *gotbflag;
 
+// SRB2kart
+
+//
+
 static boolean facefreed[MAXPLAYERS];
 
 hudinfo_t hudinfo[NUMHUDITEMS] =
@@ -337,6 +342,8 @@ void ST_LoadGraphics(void)
 
 	for (i = 0; i < 7; ++i)
 		ngradeletters[i] = W_CachePatchName(va("GRADE%d", i), PU_HUDGFX);
+
+	K_LoadKartHUDGraphics();
 }
 
 // made separate so that skins code can reload custom face graphics
@@ -1731,6 +1738,7 @@ static void ST_doItemFinderIconsAndSound(void)
 //
 static void ST_overlayDrawer(void)
 {
+	/* SRB2kart doesn't need this stuff
 	//hu_showscores = auto hide score/time/rings when tab rankings are shown
 	if (!(hu_showscores && (netgame || multiplayer)))
 	{
@@ -1758,6 +1766,7 @@ static void ST_overlayDrawer(void)
 				ST_drawLives();
 		}
 	}
+	*/
 
 	// GAME OVER pic
 	if (G_GametypeUsesLives() && stplyr->lives <= 0 && !(hu_showscores && (netgame || multiplayer)))
@@ -1772,13 +1781,15 @@ static void ST_overlayDrawer(void)
 		V_DrawScaledPatch((BASEVIDWIDTH - SHORT(p->width))/2, STRINGY(BASEVIDHEIGHT/2 - (SHORT(p->height)/2)), 0, p);
 	}
 
-
 	if (!hu_showscores) // hide the following if TAB is held
 	{
 		// Countdown timer for Race Mode
 		if (countdown)
 			V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(176), 0, va("%d", countdown/TICRATE));
 
+		K_drawKartHUD();
+
+		/* SRB2kart doesn't need this stuff, I think
 		// If you are in overtime, put a big honkin' flashin' message on the screen.
 		if (G_RingSlingerGametype() && cv_overtime.value
 			&& (leveltime > (timelimitintics + TICRATE/2)) && cv_timelimit.value && (leveltime/TICRATE % 2 == 0))
@@ -1821,6 +1832,7 @@ static void ST_overlayDrawer(void)
 
 		if (stplyr->powers[pw_gravityboots] > 3*TICRATE || (stplyr->powers[pw_gravityboots] && leveltime & 1))
 			V_DrawScaledPatch(hudinfo[HUD_GRAVBOOTSICO].x, STRINGY(hudinfo[HUD_GRAVBOOTSICO].y), V_SNAPTORIGHT, gravboots);
+		*/
 
 		if(!P_IsLocalPlayer(stplyr))
 		{
diff --git a/src/v_video.c b/src/v_video.c
index 3cc6d195f..8121f1fc5 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -1225,6 +1225,101 @@ void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string)
 	}
 }
 
+// SRB2kart
+void V_DrawKartString(INT32 x, INT32 y, INT32 option, const char *string)
+{
+	INT32 w, c, cx = x, cy = y, dupx, dupy, scrwidth = BASEVIDWIDTH, center = 0;
+	const char *ch = string;
+	INT32 charflags = 0;
+	const UINT8 *colormap = NULL;
+	INT32 spacewidth = 12, charwidth = 0;
+
+	INT32 lowercase = (option & V_ALLOWLOWERCASE);
+	option &= ~V_FLIP; // which is also shared with V_ALLOWLOWERCASE...
+
+	if (option & V_NOSCALESTART)
+	{
+		dupx = vid.dupx;
+		dupy = vid.dupy;
+		scrwidth = vid.width;
+	}
+	else
+		dupx = dupy = 1;
+
+	charflags = (option & V_CHARCOLORMASK);
+
+	switch (option & V_SPACINGMASK)
+	{
+		case V_MONOSPACE:
+			spacewidth = 12;
+		case V_OLDSPACING:
+			charwidth = 12;
+			break;
+		case V_6WIDTHSPACE:
+			spacewidth = 6;
+		default:
+			break;
+	}
+
+	for (;;ch++)
+	{
+		if (!*ch)
+			break;
+		if (*ch & 0x80) //color parsing -x 2.16.09
+		{
+			// manually set flags override color codes
+			if (!(option & V_CHARCOLORMASK))
+				charflags = ((*ch & 0x7f) << V_CHARCOLORSHIFT) & V_CHARCOLORMASK;
+			continue;
+		}
+		if (*ch == '\n')
+		{
+			cx = x;
+
+			if (option & V_RETURN8)
+				cy += 8*dupy;
+			else
+				cy += 12*dupy;
+
+			continue;
+		}
+
+		c = *ch;
+		if (!lowercase)
+			c = toupper(c);
+		c -= KART_FONTSTART;
+
+		// character does not exist or is a space
+		if (c < 0 || c >= KART_FONTSIZE || !kart_font[c])
+		{
+			cx += spacewidth * dupx;
+			continue;
+		}
+
+		if (charwidth)
+		{
+			w = charwidth * dupx;
+			center = w/2 - SHORT(kart_font[c]->width)*dupx/2;
+		}
+		else
+			w = SHORT(kart_font[c]->width) * dupx;
+
+		if (cx + w > scrwidth)
+			break;
+		if (cx < 0) //left boundary check
+		{
+			cx += w;
+			continue;
+		}
+
+		colormap = V_GetStringColormap(charflags);
+		V_DrawFixedPatch((cx + center)<<FRACBITS, cy<<FRACBITS, FRACUNIT, option, kart_font[c], colormap);
+
+		cx += w;
+	}
+}
+//
+
 void V_DrawCenteredString(INT32 x, INT32 y, INT32 option, const char *string)
 {
 	x -= V_StringWidth(string, option)/2;
diff --git a/src/v_video.h b/src/v_video.h
index 70255d0ef..8ff68b57d 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -157,6 +157,7 @@ char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string);
 
 // draw a string using the hu_font
 void V_DrawString(INT32 x, INT32 y, INT32 option, const char *string);
+void V_DrawKartString(INT32 x, INT32 y, INT32 option, const char *string);	// SRB2kart
 void V_DrawCenteredString(INT32 x, INT32 y, INT32 option, const char *string);
 void V_DrawRightAlignedString(INT32 x, INT32 y, INT32 option, const char *string);
 
-- 
GitLab