diff --git a/src/console.c b/src/console.c
index 2270c51f53487bed67e8d9d32138fe3ff1531aff..ab3570181504894240b3bbc3773a1b32cce69bfc 100644
--- a/src/console.c
+++ b/src/console.c
@@ -1618,6 +1618,7 @@ void CON_Drawer(void)
 
 	if (con_curlines > 0)
 		CON_DrawConsole();
-	else if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE || gamestate == GS_CREDITS)
+	else if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE || gamestate == GS_CREDITS
+		|| gamestate == GS_VOTING)
 		CON_DrawHudlines();
 }
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 634c6b81453cad55bf9ea5315998dd58a62a75b9..c97966f9ba00b6664413a44af6e29adfcb011ba4 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -2070,6 +2070,8 @@ static void CL_ConnectToServer(boolean viams)
 
 	if (gamestate == GS_INTERMISSION)
 		Y_EndIntermission(); // clean up intermission graphics etc
+	if (gamestate == GS_VOTING)
+		Y_EndVote();
 
 	DEBFILE(va("waiting %d nodes\n", doomcom->numnodes));
 	G_SetGamestate(GS_WAITINGPLAYERS);
@@ -3393,6 +3395,8 @@ void SV_StopServer(void)
 
 	if (gamestate == GS_INTERMISSION)
 		Y_EndIntermission();
+	if (gamestate == GS_VOTING)
+		Y_EndVote();
 	gamestate = wipegamestate = GS_NULL;
 
 	localtextcmd[0] = 0;
diff --git a/src/d_main.c b/src/d_main.c
index f94331cd22bce32434012adc8355d7c4f26f6229..3dd9a6741151ecbffa485853730759b310c374c0 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -335,6 +335,12 @@ static void D_Display(void)
 			HU_Drawer();
 			break;
 
+		case GS_VOTING:
+			Y_VoteDrawer();
+			HU_Erase();
+			HU_Drawer();
+			break;
+
 		case GS_TIMEATTACK:
 			break;
 
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index b8eb5ec82d1a7d61bed694535a1a848ce6bcc582..9d9e72694ac188bda630768bac97c02b7c4e083f 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -422,8 +422,8 @@ consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NUL
 static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NULL}};
 consvar_t cv_inttime = {"inttime", "20", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 
-static CV_PossibleValue_t advancemap_cons_t[] = {{0, "Off"}, {1, "Next"}, {2, "Random"}, {0, NULL}};
-consvar_t cv_advancemap = {"advancemap", "Next", CV_NETVAR, advancemap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+static CV_PossibleValue_t advancemap_cons_t[] = {{0, "Off"}, {1, "Next"}, {2, "Random"}, {3, "Vote"}, {0, NULL}};
+consvar_t cv_advancemap = {"advancemap", "Vote", CV_NETVAR, advancemap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 static CV_PossibleValue_t playersforexit_cons_t[] = {{0, "One"}, {1, "All"}, {0, NULL}};
 consvar_t cv_playersforexit = {"playersforexit", "One", CV_NETVAR, playersforexit_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 
diff --git a/src/g_game.c b/src/g_game.c
index cb20dbe81e94825da6fd0050a08c93b3cf42d129..41360a4b42f0c6084477e4b0288e90a6c7a056a5 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -1761,6 +1761,9 @@ void G_DoLoadLevel(boolean resetplayer)
 	if (gamestate == GS_INTERMISSION)
 		Y_EndIntermission();
 
+	if (gamestate == GS_VOTING)
+		Y_EndVote();
+
 	G_SetGamestate(GS_LEVEL);
 
 	for (i = 0; i < MAXPLAYERS; i++)
@@ -2138,6 +2141,12 @@ void G_Ticker(boolean run)
 			HU_Ticker();
 			break;
 
+		case GS_VOTING:
+			if (run)
+				Y_VoteTicker();
+			HU_Ticker();
+			break;
+
 		case GS_TIMEATTACK:
 			break;
 
@@ -3025,7 +3034,7 @@ INT16 G_TOLFlag(INT32 pgametype)
   *         has those flags.
   * \author Graue <graue@oceanbase.org>
   */
-static INT16 RandMap(INT16 tolflags, INT16 pprevmap)
+INT16 RandMap(INT16 tolflags, INT16 pprevmap)
 {
 	INT16 *okmaps = Z_Malloc(NUMMAPS * sizeof(INT16), PU_STATIC, NULL);
 	INT32 numokmaps = 0;
@@ -3184,7 +3193,7 @@ static void G_DoCompleted(void)
 		P_AllocMapHeader(nextmap);
 
 	if (skipstats && !modeattacking) // Don't skip stats if we're in record attack
-		G_AfterIntermission();
+		G_AfterIntermission(false);
 	else
 	{
 		G_SetGamestate(GS_INTERMISSION);
@@ -3192,15 +3201,21 @@ static void G_DoCompleted(void)
 	}
 }
 
-void G_AfterIntermission(void)
+void G_AfterIntermission(boolean vote)
 {
 	HU_ClearCEcho();
+	G_NextLevel();
 
 	if (mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking) // Start a custom cutscene.
 		F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false);
 	else
 	{
-		if (nextmap < 1100-1)
+		if (cv_advancemap.value == 3 && !vote)
+		{
+			G_SetGamestate(GS_VOTING);
+			Y_StartVote();
+		}
+		else if (nextmap < 1100-1)
 			G_NextLevel();
 		else
 			Y_EndGame();
@@ -5810,6 +5825,8 @@ void G_StopDemo(void)
 
 	if (gamestate == GS_INTERMISSION)
 		Y_EndIntermission(); // cleanup
+	if (gamestate == GS_VOTING)
+		Y_EndVote();
 
 	G_SetGamestate(GS_NULL);
 	wipegamestate = GS_NULL;
diff --git a/src/g_game.h b/src/g_game.h
index dfc7b0dfabc626f481b8d211bb0642d201dd0556..4e4365be2a218a36814d33ffdd7ed85e4e2fe4e0 100644
--- a/src/g_game.h
+++ b/src/g_game.h
@@ -173,7 +173,7 @@ void G_ExitLevel(void);
 void G_NextLevel(void);
 void G_Continue(void);
 void G_UseContinue(void);
-void G_AfterIntermission(void);
+void G_AfterIntermission(boolean vote);
 
 void G_Ticker(boolean run);
 boolean G_Responder(event_t *ev);
@@ -218,5 +218,6 @@ FUNCMATH INT32 G_TicsToMilliseconds(tic_t tics);
 
 // Don't split up TOL handling
 INT16 G_TOLFlag(INT32 pgametype);
+INT16 RandMap(INT16 tolflags, INT16 pprevmap);
 
 #endif
diff --git a/src/g_state.h b/src/g_state.h
index 81548b7cec7857c71a40c71ea71a98a3df4a390c..75ce2c30393d9d003c60b5aa3584ff880abdc727 100644
--- a/src/g_state.h
+++ b/src/g_state.h
@@ -23,6 +23,7 @@ typedef enum
 	// Fadable gamestates
 	GS_LEVEL,           // Playing, in a level.
 	GS_INTERMISSION,    // Gazing at the intermission screen.
+	GS_VOTING,          // SRB2Kart: MP voting screen
 	GS_CONTINUING,      // continue screen
 
 	GS_TITLESCREEN,     // title screen
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index 24e4da10060fe953468af74679435ac819a8aaa7..f66eb27c4827b20050dd9f2e269495171ed6e056 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -1145,7 +1145,8 @@ void HU_Drawer(void)
 	if (!Playing()
 	 || gamestate == GS_INTERMISSION || gamestate == GS_CUTSCENE
 	 || gamestate == GS_CREDITS      || gamestate == GS_EVALUATION
-	 || gamestate == GS_GAMEEND)
+	 || gamestate == GS_GAMEEND
+	 || gamestate == GS_VOTING) // SRB2kart
 		return;
 
 	// draw multiplayer rankings
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 53ab044db68d5af60fd8d97f1a9b2f80cc9c4983..1a10ce3662693ee99084367ba25ce9e694a2f450 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -3364,6 +3364,8 @@ boolean P_LoadGame(INT16 mapoverride)
 {
 	if (gamestate == GS_INTERMISSION)
 		Y_EndIntermission();
+	if (gamestate == GS_VOTING)
+		Y_EndVote();
 	G_SetGamestate(GS_NULL); // should be changed in P_UnArchiveMisc
 
 	P_UnArchiveSPGame(mapoverride);
diff --git a/src/y_inter.c b/src/y_inter.c
index 5bfed538edf2900b3d2efcf26cd3731a44418836..4d520a2cff01939673342e8ae3e73329b9a735ba 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -36,6 +36,8 @@
 
 #include "m_cond.h" // condition sets
 
+#include "m_random.h" // M_RandomKey
+
 #ifdef HWRENDER
 #include "hardware/hw_main.h"
 #endif
@@ -164,6 +166,47 @@ static void Y_CalculateMatchWinners(void);
 static void Y_FollowIntermission(void);
 static void Y_UnloadData(void);
 
+// SRB2Kart: voting stuff
+
+typedef struct
+{
+	char str[40];
+	patch_t *pic;
+	UINT16 num;
+} y_votelvlinfo_t;
+
+typedef struct
+{
+	UINT8 *color;
+	INT32 *character;
+	UINT8 delay;
+	INT8 selection;
+	boolean voted;
+} y_voteplayers_t;
+
+typedef struct
+{
+	UINT8 level; // 0 to 3; 3 is random
+	UINT8 playernum;
+} y_vote_t;
+
+typedef struct
+{
+	y_votelvlinfo_t levels[4];
+	y_voteplayers_t playerinfo[MAXPLAYERS];
+	y_vote_t votes[MAXPLAYERS];
+	UINT8 numvotes;
+	INT32 timeleft;
+} y_votedata;
+
+static y_votedata votedata;
+static INT32 votetic;
+static INT32 voteendtic = -1;
+static patch_t *cursor = NULL;
+
+static void Y_UnloadVoteData(void);
+static void Y_FollowVote(void);
+
 // Stuff copy+pasted from st_stuff.c
 static INT32 SCX(INT32 x)
 {
@@ -2008,7 +2051,7 @@ static void Y_FollowIntermission(void)
 	if (nextmap < 1100-1)
 	{
 		// normal level
-		G_AfterIntermission();
+		G_AfterIntermission(false);
 		return;
 	}
 
@@ -2076,3 +2119,332 @@ static void Y_UnloadData(void)
 			break;
 	}
 }
+
+// SRB2Kart: Voting!
+
+//
+// Y_StartVote
+//
+// MK online style voting screen, appears after intermission
+//
+void Y_StartVote(void)
+{
+	INT32 i = 0;
+
+	votetic = -1;
+
+#ifdef PARANOIA
+	if (voteendtic != -1)
+		I_Error("voteendtic is dirty");
+#endif
+
+	bgpatch = W_CachePatchName("INTERSCR", PU_STATIC);
+	widebgpatch = W_CachePatchName("INTERSCW", PU_STATIC);
+	cursor = W_CachePatchName("M_CURSOR", PU_STATIC);
+
+	//votedata.timeleft = 30*TICRATE;
+	votedata.numvotes = 0;
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		votedata.playerinfo[i].color = &players[i].skincolor;
+		votedata.playerinfo[i].character = &players[i].skin;
+		votedata.playerinfo[i].delay = 0;
+		votedata.playerinfo[i].selection = 0;
+		votedata.playerinfo[i].voted = false;
+
+		votedata.votes[i].level = 0;
+		votedata.votes[i].playernum = 0;
+	}
+
+	for (i = 0; i < 4; i++)
+	{
+		INT32 j;
+		lumpnum_t lumpnum;
+
+		votedata.levels[i].num = RandMap(G_TOLFlag(gametype), prevmap);
+
+		for (j = 0; j < 4; j++)
+		{
+			INT32 loopcount = 0;
+			if (i == j)
+				continue;
+			while (votedata.levels[i].num == votedata.levels[j].num && loopcount < 5)
+			{
+				votedata.levels[i].num = RandMap(G_TOLFlag(gametype), prevmap);
+				loopcount++;
+			}
+		}
+
+		if (!mapheaderinfo[votedata.levels[i].num])
+			P_AllocMapHeader(votedata.levels[i].num);
+
+		if (i == 3) // Random is actually pre-calculated for ease of coding, shhhhh :V
+		{
+			//snprintf(votedata.levels[i].str, sizeof votedata.levels[i].str, "%.32s", "RANDOM");
+			//votedata.levels[i].str[sizeof votedata.levels[i].str - 1] = '\0';
+			votedata.levels[i].pic = W_CachePatchName("RANDOMLV", PU_STATIC);
+		}
+		else
+		{
+			// set up the str
+			/*if (mapheaderinfo[votedata.levels[i].num]->zonttl)
+			{
+				if (mapheaderinfo[votedata.levels[i].num]->actnum)
+					snprintf(votedata.levels[i].str,
+						sizeof votedata.levels[i].str,
+						"%.32s %.32s %d",
+						mapheaderinfo[votedata.levels[i].num]->lvlttl, mapheaderinfo[votedata.levels[i].num-1]->zonttl, mapheaderinfo[votedata.levels[i].num-1]->actnum);
+				else
+					snprintf(votedata.levels[i].str,
+						sizeof votedata.levels[i].str,
+						"%.32s %.32s",
+						mapheaderinfo[votedata.levels[i].num]->lvlttl, mapheaderinfo[votedata.levels[i].num-1]->zonttl);
+			}
+			else
+			{
+				if (mapheaderinfo[votedata.levels[i].num]->actnum)
+					snprintf(votedata.levels[i].str,
+						sizeof votedata.levels[i].str,
+						"%.32s %d",
+						mapheaderinfo[votedata.levels[i].num]->lvlttl, mapheaderinfo[votedata.levels[i].num-1]->actnum);
+				else
+					snprintf(votedata.levels[i].str,
+						sizeof votedata.levels[i].str,
+						"%.32s",
+						mapheaderinfo[votedata.levels[i].num]->lvlttl);
+			}
+
+			votedata.levels[i].str[sizeof votedata.levels[i].str - 1] = '\0';*/
+
+			//  A 160x100 image of the level as entry MAPxxP
+			lumpnum = W_CheckNumForName(va("%sP", G_BuildMapName(votedata.levels[i].num)));
+
+			if (lumpnum != LUMPERROR)
+				votedata.levels[i].pic = W_CachePatchName(va("%sP", G_BuildMapName(votedata.levels[i].num+1)), PU_STATIC);
+			else
+				votedata.levels[i].pic = W_CachePatchName("BLANKLVL", PU_STATIC);
+		}
+	}
+}
+
+//
+// Y_VoteTicker
+//
+// Vote screen thinking :eggthinking:
+//
+void Y_VoteTicker(void)
+{
+	UINT8 numplayers;
+	INT32 i;
+
+	numplayers = 0;
+
+	if (paused || P_AutoPause())
+		return;
+
+	votetic++;
+
+	if (votetic >= voteendtic)
+	{
+		Y_EndVote();
+		Y_FollowVote();
+		return;
+	}
+
+	if (votetic < TICRATE)
+		return;
+
+	/*if (votedata.timeleft > 0)
+		votedata.timeleft--;*/
+
+	for (i = 0; i < MAXPLAYERS; i++)
+	{
+		boolean pressed = false;
+
+		if (!playeringame[i] || players[i].spectator)
+			continue;
+
+		numplayers++;
+
+		if (votedata.playerinfo[i].voted)
+			continue;
+
+		if (votedata.playerinfo[i].delay > 0)
+		{
+			votedata.playerinfo[i].delay--;
+			continue;
+		}
+
+		if (players[i].cmd.buttons & BT_FORWARD && !pressed)
+		{
+			votedata.playerinfo[i].selection--;
+			pressed = true;
+		}
+
+		if (players[i].cmd.buttons & BT_BACKWARD && !pressed)
+		{
+			votedata.playerinfo[i].selection++;
+			pressed = true;
+		}
+
+		if (votedata.playerinfo[i].selection < 0)
+			votedata.playerinfo[i].selection = 3;
+		if (votedata.playerinfo[i].selection > 3)
+			votedata.playerinfo[i].selection = 0;
+
+		if (players[i].cmd.buttons & BT_ACCELERATE && !pressed)
+		{
+			votedata.votes[votedata.numvotes].level = votedata.playerinfo[i].selection;
+			votedata.votes[votedata.numvotes].playernum = i;
+			votedata.playerinfo[i].voted = true;
+			pressed = true;
+			votedata.numvotes++;
+		}
+
+		if (pressed)
+		{
+			if (i == consoleplayer)
+				S_StartSound(NULL, sfx_menu1);
+			votedata.playerinfo[i].delay = NEWTICRATE/7;
+		}
+
+		/*if (votedata.timeleft <= 0 && !votedata.playerinfo[i].voted)
+		{
+			votedata.votes[votedata.numvotes].level = 3; // too slow? you pick random
+			votedata.votes[votedata.numvotes].playernum = i;
+			votedata.playerinfo[i].voted = true;
+			votedata.numvotes++;
+		}*/
+	}
+
+	/*if (votedata.numvotes >= numplayers)
+		votedata.timeleft = 0;
+
+	if (votedata.timeleft == 0 && voteendtic == -1)
+	{
+		nextmap = (votedata.votes[P_RandomKey(votedata.numvotes)].level);
+		voteendtic = votetic+(10*TICRATE);
+	}*/
+
+	if (!votetic)
+		S_ChangeMusicInternal("racent", true);
+}
+
+//
+// Y_VoteDrawer
+//
+// Draws the voting screen!
+//
+void Y_VoteDrawer(void)
+{
+	INT32 i, x, y = 0;
+
+	if (rendermode == render_none)
+		return;
+
+	V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
+
+	if (widebgpatch && rendermode == render_soft && vid.width / vid.dupx == 400)
+		V_DrawScaledPatch(0, 0, V_SNAPTOLEFT, widebgpatch);
+	else
+		V_DrawScaledPatch(0, 0, 0, bgpatch);
+
+	for (i = 0; i < 4; i++)
+	{
+		if (i == votedata.playerinfo[consoleplayer].selection)
+		{
+			y += 50;
+			V_DrawScaledPatch(BASEVIDWIDTH-142, y+21, 0, cursor);
+			//V_DrawFill(BASEVIDWIDTH-102, y-2, 84, 54, 103);
+			V_DrawSmallScaledPatch(BASEVIDWIDTH-100, y, 0, votedata.levels[i].pic);
+			//V_DrawRightAlignedThinString(BASEVIDWIDTH-20, 42+y, V_YELLOWMAP, votedata.levels[i].str);
+		}
+		else
+		{
+			V_DrawTinyScaledPatch(BASEVIDWIDTH-80, y, 0, votedata.levels[i].pic);
+			y += 62;
+		}
+	}
+
+	x = 20;
+	y = 0;
+
+	for (i = 0; i < votedata.numvotes; i++)
+	{
+		V_DrawTinyScaledPatch(x, y, 0, votedata.levels[votedata.votes[i].level].pic);
+
+		if (votedata.playerinfo[votedata.votes[i].playernum].color == 0)
+			V_DrawSmallScaledPatch(x+48, y+18, 0, faceprefix[*votedata.playerinfo[votedata.votes[i].playernum].character]);
+		else
+		{
+			UINT8 *colormap = R_GetTranslationColormap(*votedata.playerinfo[votedata.votes[i].playernum].character, *votedata.playerinfo[votedata.votes[i].playernum].color, GTC_CACHE);
+			V_DrawSmallMappedPatch(x+48, y+18, 0, faceprefix[*votedata.playerinfo[votedata.votes[i].playernum].character], colormap);
+		}
+
+		y += 25;
+
+		if (y > BASEVIDHEIGHT-25)
+		{
+			x += 20;
+			y = 0;
+		}
+	}
+
+	/*if (votedata.timeleft)
+		V_DrawCenteredString(BASEVIDWIDTH/2, 188, V_YELLOWMAP,
+			va("Vote ends in %d seconds", votedata.timeleft/TICRATE));*/
+}
+
+//
+// Y_EndVote
+//
+void Y_EndVote(void)
+{
+	Y_UnloadVoteData();
+	voteendtic = -1;
+}
+
+//
+// Y_UnloadVoteData
+//
+static void Y_UnloadVoteData(void)
+{
+	if (rendermode != render_soft)
+		return;
+
+	UNLOAD(bgpatch);
+	UNLOAD(widebgpatch);
+	UNLOAD(cursor);
+
+	UNLOAD(votedata.levels[3].pic);
+	UNLOAD(votedata.levels[2].pic);
+	UNLOAD(votedata.levels[1].pic);
+	UNLOAD(votedata.levels[0].pic);
+}
+
+//
+// Y_FollowVote
+//
+static void Y_FollowVote(void)
+{
+	if (modeattacking)
+	{
+		M_EndModeAttackRun();
+		return;
+	}
+
+	if (nextmap < 1100-1)
+	{
+		G_AfterIntermission(true);
+		return;
+	}
+
+	if (mapheaderinfo[gamemap-1]->cutscenenum && !modeattacking)
+	{
+		F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false);
+		return;
+	}
+
+	Y_EndGame();
+}
\ No newline at end of file
diff --git a/src/y_inter.h b/src/y_inter.h
index 358debf7b9c3a0f264b4b2102416af5bc95ba6f1..3f63b3ee462ad52abeffc6176487a2227848179e 100644
--- a/src/y_inter.h
+++ b/src/y_inter.h
@@ -17,6 +17,11 @@ void Y_StartIntermission(void);
 void Y_EndIntermission(void);
 void Y_EndGame(void);
 
+void Y_StartVote(void);
+void Y_VoteTicker(void);
+void Y_VoteDrawer(void);
+void Y_EndVote(void);
+
 typedef enum
 {
 	int_none,