diff --git a/src/info.h b/src/info.h
index 20458be586399a7d0860b077be407e1ba2b92728..8ef6f816a9878e860b9a464e74b5a20b97731507 100644
--- a/src/info.h
+++ b/src/info.h
@@ -209,7 +209,6 @@ void A_BrakLobShot();
 void A_NapalmScatter();
 void A_SpawnFreshCopy();
 void A_ItemPop();
-void A_CapsulePop();
 void A_KartItems();
 void A_Hover();
 void A_Lakitu();
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 18a4ec5ff415be7bee7f5b828fca47ece86ac247..a5bdbbdb7501fed60b714a989bdbe5709469060f 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -236,6 +236,16 @@ void A_BrakFireShot(mobj_t *actor);
 void A_BrakLobShot(mobj_t *actor);
 void A_NapalmScatter(mobj_t *actor);
 void A_SpawnFreshCopy(mobj_t *actor);
+// SRB2kart 16/03/27
+void A_ItemPop(mobj_t *actor);
+void A_AirBox(mobj_t *actor);
+void A_CapsulePop(mobj_t *actor);
+void A_KartItems(mobj_t *actor);
+void A_Hover(mobj_t *actor);
+void A_Lakitu(mobj_t *actor);
+void A_RedShellChase(mobj_t *actor);
+void A_BobombExplode(mobj_t *actor);
+//
 
 //
 // ENEMY THINKING
@@ -844,6 +854,11 @@ void A_Look(mobj_t *actor)
 	if (!P_LookForPlayers(actor, locvar1 & 65535, false , FixedMul((locvar1 >> 16)*FRACUNIT, actor->scale)))
 		return;
 
+	// SRB2kart 16/03/27
+	if (leveltime < 4*TICRATE && gametype == GT_RACE)
+		return;
+	//
+
 	// go into chase state
 	if (!locvar2)
 	{
@@ -3004,7 +3019,9 @@ void A_RingShield(mobj_t *actor)
 		P_SpawnShieldOrb(player);
 	}
 
-	S_StartSound(player->mo, actor->info->seesound);
+	// SRB2kart 16/03/27
+	if (!player->exiting)
+		S_StartSound(player->mo, actor->info->seesound);
 }
 
 // Function: A_RingBox
@@ -3030,8 +3047,11 @@ void A_RingBox(mobj_t *actor)
 
 	player = actor->target->player;
 
-	P_GivePlayerRings(player, actor->info->reactiontime);
-	if (actor->info->seesound)
+	// SRB2kart 16/03/27
+	if (!player->exiting)
+		P_GivePlayerRings(player, actor->info->reactiontime);
+	
+	if (!player->exiting && actor->info->seesound)
 		S_StartSound(player->mo, actor->info->seesound);
 }
 
@@ -3059,7 +3079,7 @@ void A_Invincibility(mobj_t *actor)
 	player = actor->target->player;
 	player->powers[pw_invulnerability] = invulntics + 1;
 
-	if (P_IsLocalPlayer(player) && !player->powers[pw_super])
+	if (P_IsLocalPlayer(player) && !player->powers[pw_super] && !player->exiting)
 	{
 		S_StopMusic();
 		if (mariomode)
@@ -3067,6 +3087,10 @@ void A_Invincibility(mobj_t *actor)
 			S_ChangeMusic(mus_minvnc, false);
 			G_GhostAddColor(GHC_INVINCIBLE);
 		}
+		else if (retrokart)						// SRB2kart 16/03/27
+			S_ChangeMusic(mus_rinvnc, true);
+		else if (neokart)
+			S_ChangeMusic(mus_rinvnc, true);
 		else
 			S_ChangeMusic(mus_invinc, false);
 	}
@@ -3753,6 +3777,7 @@ void A_ThrownRing(mobj_t *actor)
 	INT32 stop;
 	player_t *player;
 	fixed_t dist;
+	fixed_t SHELL_DIST;		// SRB2kart 16/03/27
 #ifdef HAVE_BLUA
 	if (LUA_CallAction("A_ThrownRing", actor))
 		return;
@@ -3819,13 +3844,13 @@ void A_ThrownRing(mobj_t *actor)
 		// sure to stop the attraction!
 		if ((!actor->tracer->health) || (actor->tracer->player && (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT
 		    && P_AproxDistance(P_AproxDistance(actor->tracer->x-actor->x,
-		    actor->tracer->y-actor->y), actor->tracer->z-actor->z) > FixedMul(RING_DIST/4, actor->tracer->scale)))
+		    actor->tracer->y-actor->y), actor->tracer->z-actor->z) > FixedMul(RING_DIST, actor->tracer->scale)))	// SRB2kart 16/03/27
 		{
 			P_SetTarget(&actor->tracer, NULL);
 		}
 
-		if (actor->tracer && (actor->tracer->health)
-			&& (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT)// Already found someone to follow.
+		if (actor->tracer && (actor->tracer->health) && (retrokart || neokart))	// SRB2kart 16/03/27
+			//&& (actor->tracer->player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT)// Already found someone to follow.
 		{
 			const INT32 temp = actor->threshold;
 			actor->threshold = 32000;
@@ -3875,6 +3900,13 @@ void A_ThrownRing(mobj_t *actor)
 			if (gametype == GT_CTF
 				&& actor->target->player->ctfteam == player->ctfteam)
 				continue;
+			
+			// SRB2kart 16/03/27
+			if (actor->target->player->position < player->position) // Red Shells only go after people ahead of you
+				continue;
+
+			SHELL_DIST = 2048;
+			SHELL_DIST = SHELL_DIST*FRACUNIT;
 		}
 
 		dist = P_AproxDistance(P_AproxDistance(player->mo->x-actor->x,
@@ -3894,7 +3926,7 @@ void A_ThrownRing(mobj_t *actor)
 			continue; // out of sight
 
 		if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT
-			&& dist < FixedMul(RING_DIST/4, player->mo->scale))
+			&& dist < FixedMul(SHELL_DIST/4, player->mo->scale))		// SRB2kart 16/03/27
 			P_SetTarget(&actor->tracer, player->mo);
 		return;
 	}
@@ -5257,9 +5289,14 @@ void A_RingExplode(mobj_t *actor)
 		return;
 #endif
 
+	// SRB2kart 16/03/27
+	for (d = 0; d < 16; d++)
+		P_SpawnParaloop(actor->x, actor->y, actor->z, 32*FRACUNIT, 32, MT_EXPLOSION, d*(ANGLE_45/4), true, false); // 32 <-> 64
+	/* 
 	for (d = 0; d < 16; d++)
 		P_SpawnParaloop(actor->x, actor->y, actor->z + actor->height, FixedMul(actor->info->painchance, actor->scale), 16, MT_NIGHTSPARKLE, S_NULL, d*(ANGLE_22h), true);
-
+	*/
+	
 	S_StartSound(actor, sfx_prloop);
 
 	for (th = thinkercap.next; th != &thinkercap; th = th->next)
@@ -7512,7 +7549,17 @@ void A_MoveAbsolute(mobj_t *actor)
 		return;
 #endif
 
-	P_InstaThrust(actor, FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale));
+	// SRB2kart 16/03/27
+	INT32 newangle;
+	if (actor->flags & MF_AMBUSH)
+		newangle = actor->angle+FixedAngle(locvar1*FRACUNIT);
+	else
+		newangle = FixedAngle(locvar1*FRACUNIT);
+
+	P_InstaThrust(actor, newangle, locvar2*FRACUNIT);
+	//
+
+	//P_InstaThrust(actor, FixedAngle(locvar1*FRACUNIT), FixedMul(locvar2*FRACUNIT, actor->scale));
 }
 
 // Function: A_Thrust
@@ -8006,6 +8053,330 @@ void A_ToggleFlameJet(mobj_t* actor)
 	}
 }
 
+// 													SRB2kart 16/03/27
+// Function: A_ItemPop
+//
+// Description: Used by Kart monitors when they explode.
+//
+// var1 = unused
+// var2 = unused
+//
+void A_ItemPop(mobj_t *actor)
+{
+	mobj_t *remains;
+	mobjtype_t item = 0;
+
+	// 16/03/27 	TODO: Make Item boxes not 'solid', or make it less obvious when the player
+	//					  hits more than one at once. It's very noticable if a player hits a
+	//					  cluster of boxes, and you can see momentum changing from collision.
+
+	// de-solidify
+	P_UnsetThingPosition(actor);
+	actor->flags &= ~MF_SOLID;
+	actor->flags |= MF_NOCLIP;
+	P_SetThingPosition(actor);
+
+	remains = P_SpawnMobj(actor->x, actor->y, actor->z, MT_ITEMEXPLOSION);
+	remains->type = actor->type; // Transfer type information
+	P_UnsetThingPosition(remains);
+	if (sector_list)
+	{
+		P_DelSeclist(sector_list);
+		sector_list = NULL;
+	}
+	remains->flags = actor->flags; // Transfer flags
+	P_SetThingPosition(remains);
+	remains->flags2 = actor->flags2; // Transfer flags2
+	remains->fuse = actor->fuse; // Transfer respawn timer
+	remains->threshold = 68;
+	remains->skin = NULL;
+
+	actor->flags2 |= MF2_BOSSNOTRAP; // Dummy flag to mark this as an exploded TV until it respawns
+	tmthing = remains;
+
+	if (actor->info->deathsound) S_StartSound(remains, actor->info->deathsound);
+
+	switch (actor->type)
+	{
+		case MT_QUESTIONBOX2: // Random!
+		{
+			if (actor->target && actor->target->player
+				&& !(actor->target->player->powers[pw_shell]      & 2 || actor->target->player->powers[pw_tripleshell] & 8
+				||   actor->target->player->powers[pw_redshell]   & 2 || actor->target->player->powers[pw_tripleredshell] & 8
+				||   actor->target->player->powers[pw_banana]     & 2 || actor->target->player->powers[pw_triplebanana] & 8
+				||   actor->target->player->powers[pw_fakeitem]   & 2 || actor->target->player->powers[pw_kitchensink]
+				||   actor->target->player->powers[pw_bomb]       & 2 || actor->target->player->powers[pw_blueshell]
+				||   actor->target->player->powers[pw_shroom]
+				||   actor->target->player->powers[pw_star]            || actor->target->player->powers[pw_goldshroom]
+				||   actor->target->player->powers[pw_thunder]         || actor->target->player->powers[pw_megamushroom]
+				||   actor->target->player->powers[pw_kartitem]        || actor->target->player->powers[pw_itemslot]
+				||   actor->target->player->powers[pw_boo]             || actor->target->player->powers[pw_bootake]
+				|| actor->target->player->powers[pw_boostolen]         || actor->target->player->powers[pw_greenboo])
+			   )
+				actor->target->player->powers[pw_kartitem] = 1;
+			else if(cv_debug && !(actor->target && actor->target->player))
+				CONS_Printf("ERROR: Powerup has no target!\n");
+
+			remains->flags &= ~MF_AMBUSH;
+			break;
+		}
+		default:
+			item = actor->info->damage;
+			break;
+	}
+
+	P_RemoveMobj(actor);
+}
+
+// Function: A_Hover
+//
+// Description: Makes the Thing hover on the ground.
+//
+// var1 = slow hover
+// var2 = unused
+//
+void A_Hover(mobj_t *actor)
+{
+	fixed_t thefloor;
+	thefloor = actor->floorz;
+
+	if (actor->z < thefloor + (16*FRACUNIT))
+		actor->momz += FRACUNIT;
+	else if (actor->z < thefloor + (32*FRACUNIT))
+		actor->momz += FRACUNIT/2;
+	else
+		actor->momz += 16;
+}
+
+// Function: A_Lakitu
+//
+// Description: Lowers the object down, or it rises up.
+//
+// var1 = 1 is to descend, 2 is to ascend and disappear
+// var2 = unused
+//
+void A_Lakitu(mobj_t *actor)
+{
+	fixed_t thefloor;
+	thefloor = actor->target->player->mo->z;
+	if (!actor->target->player)
+	{
+		P_SetMobjState(actor, S_DISS);
+		return;
+	}
+
+	if (var1 == 1 || var1 > 3)
+	{
+		if (actor->target->eflags & MFE_VERTICALFLIP)
+		{
+			if (actor->z < thefloor - (86*FRACUNIT))
+				actor->momz += FRACUNIT/3;
+			if (actor->z > thefloor - (60*FRACUNIT))
+				actor->momz = 0;
+			if (leveltime >= 52 && var1 == 1)
+				P_SetMobjState(actor, S_LAKITUSL2);
+		}
+		else
+		{
+			if (actor->z > thefloor + (86*FRACUNIT))
+				actor->momz -= FRACUNIT/3;
+			if (actor->z < thefloor + (60*FRACUNIT))
+				actor->momz = 0;
+			if (leveltime >= 52 && var1 == 1)
+				P_SetMobjState(actor, S_LAKITUSL2);
+		}
+
+		if (actor->momz == 0 && var1 == 4)
+			P_SetMobjState(actor, S_LAKITULAP1B);
+		if (actor->momz == 0 && var1 == 5)
+			P_SetMobjState(actor, S_LAKITULAP2B);
+		if (actor->momz == 0 && var1 == 6)
+			P_SetMobjState(actor, S_LAKITULAP3B);
+		if (actor->momz == 0 && var1 == 7)
+			P_SetMobjState(actor, S_LAKITULAP4B);
+		if (actor->momz == 0 && var1 == 8)
+			P_SetMobjState(actor, S_LAKITULAP5B);
+		if (actor->momz == 0 && var1 == 9)
+			P_SetMobjState(actor, S_LAKITULAP6B);
+		if (actor->momz == 0 && var1 == 10)
+			P_SetMobjState(actor, S_LAKITULAP7B);
+		if (actor->momz == 0 && var1 == 11)
+			P_SetMobjState(actor, S_LAKITULAP8B);
+		if (actor->momz == 0 && var1 == 12)
+			P_SetMobjState(actor, S_LAKITULAPFB);
+	}
+	else if (var1 == 2 || var1 == 3)
+	{
+		if (actor->target->eflags & MFE_VERTICALFLIP)
+			actor->momz -= FRACUNIT;
+		else
+			actor->momz += FRACUNIT;
+
+		if (leveltime > 175 && actor->target->player->airtime == 0)
+			P_SetMobjState(actor, S_DISS);
+	}
+	if (actor->target->player != &players[displayplayer] && !splitscreen)
+		actor->flags2 |= MF2_DONTDRAW;
+	else
+		actor->flags2 &= ~MF2_DONTDRAW;
+}
+
+// Function: A_RedShellChase
+//
+// Description: Chase routine for Red Shells
+//
+// var1 = unused
+// var2 = unused
+//
+void A_RedShellChase(mobj_t *actor)
+{
+
+	INT32 c = 0;
+	INT32 stop;
+	player_t *player;
+
+	if (actor->tracer)
+	{
+		if (!actor->tracer->health)
+		{
+			P_SetTarget(&actor->tracer, NULL);
+		}
+
+		if (actor->tracer && (actor->tracer->health))
+		{
+			P_Thrust(actor, R_PointToAngle2(actor->x, actor->y, actor->tracer->x, actor->tracer->y), actor->info->speed);
+			return;
+		}
+	}
+
+	// first time init, this allow minimum lastlook changes
+	if (actor->lastlook == -1)
+		actor->lastlook = P_Random();
+
+	actor->lastlook %= MAXPLAYERS;
+
+	stop = (actor->lastlook - 1) & PLAYERSMASK;
+
+	if (actor->lastlook >= 0)
+	{
+		for (; ; actor->lastlook = (actor->lastlook + 1) & PLAYERSMASK)
+		{
+			if (!playeringame[actor->lastlook])
+				continue;
+
+			if (c++ == 2)
+				return;
+
+			player = &players[actor->lastlook];
+
+			if (!player->mo)
+				continue;
+
+			if (player->mo->health <= 0)
+				continue; // dead
+
+			if ((netgame || multiplayer) && player->spectator)
+				continue; // spectator
+
+			if (actor->target && actor->target->player)
+			{
+				if (player->mo == actor->target)
+					continue;
+
+				// Don't home in on teammates.
+				if (gametype == GT_CTF
+					&& actor->target->player->ctfteam == player->ctfteam)
+					continue;
+
+				if (gametype == GT_RACE) // Only in races, in match and CTF you should go after any nearby players
+				{
+					//                 USER               TARGET
+					if (actor->target->player->position != (player->position + 1)) // Red Shells only go after the person directly ahead of you -Sryder
+						continue;
+				}
+
+				if (!(gametype == GT_RACE))
+				{
+					if (P_AproxDistance(P_AproxDistance(player->mo->x-actor->x,
+						player->mo->y-actor->y), player->mo->z-actor->z) > RING_DIST)
+						continue;
+				}
+			}
+
+			if ((gametype == GT_RACE) || (gametype != GT_RACE // If in match etc. only home in when you get close enough, in race etc. home in all the time
+				&& P_AproxDistance(P_AproxDistance(player->mo->x-actor->x,
+				player->mo->y-actor->y), player->mo->z-actor->z) < RING_DIST))
+				P_SetTarget(&actor->tracer, player->mo);
+			return;
+
+			// Moved to bottom so it doesn't not check the last player
+			// done looking
+			if (actor->lastlook == stop)
+			{
+				if (gametype == GT_RACE)
+					actor->lastlook = -2;
+				return;
+			}
+		}
+	}
+
+	return;
+
+}
+
+// Function: A_BobombExplode
+//
+// Description: Slightly altered Ring Explode, allows you to use var1 to specify the object spawned
+//
+// var1 = Object spawned.
+// var2 = unused
+//
+void A_BobombExplode(mobj_t *actor)
+{
+	mobj_t *mo2;
+	thinker_t *th;
+	INT32 d;
+	INT32 locvar1 = var1;
+	mobjtype_t type;
+
+	type = (mobjtype_t)locvar1;
+
+	for (d = 0; d < 16; d++)
+		P_SpawnKartExplosion(actor->x, actor->y, actor->z, actor->info->painchance + 32*FRACUNIT, 32, type, d*(ANGLE_45/4), false, false); // 32 <-> 64
+
+	S_StartSound(actor, sfx_prloop);
+
+	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	{
+		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+			continue;
+
+		mo2 = (mobj_t *)th;
+
+		if (mo2 == actor) // Don't explode yourself! Endless loop!
+			continue;
+
+		if (P_AproxDistance(P_AproxDistance(mo2->x - actor->x, mo2->y - actor->y), mo2->z - actor->z) > actor->info->painchance)
+			continue;
+
+		if ((mo2->flags & MF_SHOOTABLE) && !(mo2->flags & MF_SCENERY))
+		{
+			actor->flags2 |= MF2_DEBRIS;
+
+			if (mo2->player) // Looks like we're going to have to need a seperate function for this too
+				P_ExplodePlayerMobj(mo2, actor->target);
+			else
+				P_DamageMobj(mo2, actor, actor->target, 1);
+
+			
+
+			continue;
+		}
+	}
+	return;
+}
+//
+
 // Function: A_OrbitNights
 //
 // Description: Used by Chaos Emeralds to orbit around Nights (aka Super Sonic.)