diff --git a/src/b_bot.c b/src/b_bot.c
index ffdcace6d6d428b88d54b765df66169bcdba541b..4fdfc8714d6ac9290fef9d368720bacfb740e25e 100644
--- a/src/b_bot.c
+++ b/src/b_bot.c
@@ -29,11 +29,16 @@ void B_UpdateBotleader(player_t *player)
 	{
 		if (players[i].bot || players[i].playerstate != PST_LIVE || players[i].spectator || !players[i].mo)
 			continue;
-		if (!player->mo) //Can't do distance calculations if there's no player object, so we'll just take the first we find
+		
+		if (!player->botleader)
 		{
-			player->botleader = &players[i];
+			player->botleader = &players[i]; // set default
 			return;
 		}
+
+		if (!player->mo)
+			return;
+
 		//Update best candidate based on nearest distance
 		dist = R_PointToDist2(player->mo->x, player->mo->y, players[i].mo->x, players[i].mo->y);
 		if (neardist > dist)
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index cca3102d085aac427b5a3469dd00f3085a3fee3d..fe7e7678fe447cfc186b9eaf4134cb6eeeb6db27 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -3763,7 +3763,7 @@ static void Command_ListWADS_f(void)
 		nameonly(tempname = va("%s", wadfiles[i]->filename));
 		if (!i)
 			CONS_Printf("\x82 IWAD\x80: %s\n", tempname);
-		else if (i <= mainwads)
+		else if (i < mainwads)
 			CONS_Printf("\x82 * %.2d\x80: %s\n", i, tempname);
 		else if (!wadfiles[i]->important)
 			CONS_Printf("\x86   %.2d: %s\n", i, tempname);
diff --git a/src/deh_tables.c b/src/deh_tables.c
index 3aece916cbebbaf8220d6aa8a65c960ce96f16b8..e591390c89c29fe8c4807b80dbee80b6d0e41174 100644
--- a/src/deh_tables.c
+++ b/src/deh_tables.c
@@ -5088,6 +5088,7 @@ struct int_const_s const INT_CONST[] = {
 	{"PAL_MIXUP",PAL_MIXUP},
 	{"PAL_RECYCLE",PAL_RECYCLE},
 	{"PAL_NUKE",PAL_NUKE},
+	{"PAL_INVERT",PAL_INVERT},
 	// for P_DamageMobj
 	//// Damage types
 	{"DMG_WATER",DMG_WATER},
diff --git a/src/g_game.c b/src/g_game.c
index 3ab3dae186e688c7a87d64fdaaaa8a1aa57bb55e..f4c9270dace13d6c28eba180db2f768377eef9b7 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -3275,7 +3275,7 @@ boolean G_EnoughPlayersFinished(void)
 
 	for (i = 0; i < MAXPLAYERS; i++)
 	{
-		if (!playeringame[i] || players[i].spectator || players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN)
+		if (!playeringame[i] || players[i].spectator || players[i].bot)
 			continue;
 		if (players[i].quittime > 30 * TICRATE)
 			continue;
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index f4c5e4c3b14cbef8dd9bc39b241b30358166bea9..3107057a1b49008a47e903b45ce201d42e6f5e02 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -2472,7 +2472,7 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer)
 		if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1))
 			V_DrawString(x + 10, y,
 			             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
-			             | (greycheck ? 0 : V_TRANSLUCENT)
+			             | (greycheck ? V_TRANSLUCENT : 0)
 			             | V_ALLOWLOWERCASE, name);
 
 		if (gametyperules & GTR_TEAMFLAGS)
@@ -2733,12 +2733,12 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline
 			if (circuitmap)
 			{
 				if (players[tab[i].num].exiting)
-					V_DrawRightAlignedThinString(x+146, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime)));
+					V_DrawRightAlignedThinString(x+100, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime)));
 				else
-					V_DrawRightAlignedThinString(x+146, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count));
+					V_DrawRightAlignedThinString(x+100, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count));
 			}
 			else
-				V_DrawRightAlignedThinString(x+146, y, (greycheck ? V_TRANSLUCENT : 0), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count)));
+				V_DrawRightAlignedThinString(x+100, y, (greycheck ? V_TRANSLUCENT : 0), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count)));
 		}
 		else
 			V_DrawRightAlignedThinString(x+100, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count));
@@ -2786,7 +2786,7 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor
 		if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1))
 			V_DrawString(x + 10, y,
 			             ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0)
-			             | (greycheck ? 0 : V_TRANSLUCENT)
+			             | (greycheck ? V_TRANSLUCENT : 0)
 			             | V_ALLOWLOWERCASE, name);
 
 		if (G_GametypeUsesLives()) //show lives
@@ -2846,13 +2846,13 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor
 				if (players[tab[i].num].exiting)
 					V_DrawRightAlignedThinString(x+128, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime)));
 				else
-					V_DrawRightAlignedThinString(x+128, y, (greycheck ? 0 : V_TRANSLUCENT), va("%u", tab[i].count));
+					V_DrawRightAlignedThinString(x+128, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count));
 			}
 			else
-				V_DrawRightAlignedThinString(x+128, y, (greycheck ? 0 : V_TRANSLUCENT), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count)));
+				V_DrawRightAlignedThinString(x+128, y, (greycheck ? V_TRANSLUCENT : 0), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count)));
 		}
 		else
-			V_DrawRightAlignedThinString(x+128, y, (greycheck ? 0 : V_TRANSLUCENT), va("%u", tab[i].count));
+			V_DrawRightAlignedThinString(x+128, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count));
 
 		y += 9;
 		if (i == 16)
@@ -3091,7 +3091,7 @@ static void HU_DrawRankings(void)
 		HU_DrawTeamTabRankings(tab, whiteplayer);
 	else if (scorelines <= 9 && !cv_compactscoreboard.value)
 		HU_DrawTabRankings(40, 32, tab, scorelines, whiteplayer);
-	else if (scorelines <= 20 && !cv_compactscoreboard.value)
+	else if (scorelines <= 18 && !cv_compactscoreboard.value)
 		HU_DrawDualTabRankings(32, 32, tab, scorelines, whiteplayer);
 	else
 		HU_Draw32TabRankings(14, 28, tab, scorelines, whiteplayer);
diff --git a/src/m_menu.c b/src/m_menu.c
index fc1e33b67dc16c6e8898a1df754119ecf8cf86ed..3ec49356c4d4c4443f1a122416c80f427a110ed8 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -11588,9 +11588,7 @@ static void M_ServerOptions(INT32 choice)
 		OP_ServerOptionsMenu[ 2].status = IT_STRING | IT_CVAR;
 		OP_ServerOptionsMenu[ 3].status = IT_STRING | IT_CVAR;
 		OP_ServerOptionsMenu[ 4].status = IT_STRING | IT_CVAR;
-		OP_ServerOptionsMenu[36].status = (netgame
-			? IT_GRAYEDOUT
-			: (IT_STRING | IT_CVAR | IT_CV_STRING));
+		OP_ServerOptionsMenu[36].status = IT_STRING | IT_CVAR | IT_CV_STRING;
 		OP_ServerOptionsMenu[37].status = IT_STRING | IT_CVAR;
 		OP_ServerOptionsMenu[38].status = IT_STRING | IT_CVAR;
 	}
diff --git a/src/p_local.h b/src/p_local.h
index 1fcd3050d92fde6fd1056f86d81137be89b93902..28a77afe5c9a5022a5e5f92641df34806f32b91d 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -349,6 +349,7 @@ void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration);
 #define PAL_MIXUP    2
 #define PAL_RECYCLE  3
 #define PAL_NUKE     4
+#define PAL_INVERT   5
 
 //
 // P_ENEMY
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 40ef447f84eeff9336f39a715820b50512b7437b..39c6731b81ab41b378f748eb42fe28762642c350 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -2522,7 +2522,7 @@ boolean P_ZMovement(mobj_t *mo)
 					{
 						P_KillMobj(mo, NULL, NULL, 0);
 					}
-					return false;
+					return !P_MobjWasRemoved(mo); // allows explosion states to run
 				}
 				else
 				{
diff --git a/src/p_setup.c b/src/p_setup.c
index 588815aeead2d932e22fea91951d094de04bc7f1..7f9674e4e08ffe6b7a8b26fc1939fa547b1fccd8 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -3046,48 +3046,55 @@ static void P_AddBinaryMapTags(void)
 {
 	size_t i;
 
-	for (i = 0; i < numlines; i++)
-	{
-		// 96: Apply Tag to Tagged Sectors
+	for (i = 0; i < numlines; i++) {
 		// 97: Apply Tag to Front Sector
 		// 98: Apply Tag to Back Sector
 		// 99: Apply Tag to Front and Back Sectors
-		if (lines[i].special == 96) {
-			size_t j;
-			mtag_t tag = Tag_FGet(&lines[i].frontsector->tags);
-			mtag_t target_tag = Tag_FGet(&lines[i].tags);
-			mtag_t offset_tags[4];
-			memset(offset_tags, 0, sizeof(mtag_t)*4);
-			if (lines[i].flags & ML_EFFECT6) {
-				offset_tags[0] = (INT32)sides[lines[i].sidenum[0]].textureoffset / FRACUNIT;
-				offset_tags[1] = (INT32)sides[lines[i].sidenum[0]].rowoffset / FRACUNIT;
-			}
-			if (lines[i].flags & ML_TFERLINE) {
-				offset_tags[2] = (INT32)sides[lines[i].sidenum[1]].textureoffset / FRACUNIT;
-				offset_tags[3] = (INT32)sides[lines[i].sidenum[1]].rowoffset / FRACUNIT;
-			}
+		if (lines[i].special == 97 || lines[i].special == 99)
+			P_AddBinaryMapTagsFromLine(lines[i].frontsector, &lines[i]);
+		if (lines[i].special == 98 || lines[i].special == 99)
+			P_AddBinaryMapTagsFromLine(lines[i].backsector, &lines[i]);
+	}
 
-			for (j = 0; j < numsectors; j++) {
-				boolean matches_target_tag = target_tag && Tag_Find(&sectors[j].tags, target_tag);
-				size_t k; for (k = 0; k < 4; k++) {
-					if (lines[i].flags & ML_EFFECT5) {
-						if (matches_target_tag || (offset_tags[k] && Tag_Find(&sectors[j].tags, offset_tags[k]))) {
-							Tag_Add(&sectors[j].tags, tag);
-							break;
-						}
-					} else if (matches_target_tag) {
-						if (k == 0)
-							Tag_Add(&sectors[j].tags, tag);
-						if (offset_tags[k])
-							Tag_Add(&sectors[j].tags, offset_tags[k]);
+	// Run this loop after the 97-99 loop to ensure that 96 can search through all of the
+	// 97-99-applied tags.
+	for (i = 0; i < numlines; i++) {
+		size_t j;
+		mtag_t tag, target_tag;
+		mtag_t offset_tags[4];
+
+		// 96: Apply Tag to Tagged Sectors
+		if (lines[i].special != 96)
+			continue;
+
+		tag = Tag_FGet(&lines[i].frontsector->tags);
+		target_tag = Tag_FGet(&lines[i].tags);
+		memset(offset_tags, 0, sizeof(mtag_t)*4);
+		if (lines[i].flags & ML_EFFECT6) {
+			offset_tags[0] = (INT32)sides[lines[i].sidenum[0]].textureoffset / FRACUNIT;
+			offset_tags[1] = (INT32)sides[lines[i].sidenum[0]].rowoffset / FRACUNIT;
+		}
+		if (lines[i].flags & ML_TFERLINE) {
+			offset_tags[2] = (INT32)sides[lines[i].sidenum[1]].textureoffset / FRACUNIT;
+			offset_tags[3] = (INT32)sides[lines[i].sidenum[1]].rowoffset / FRACUNIT;
+		}
+
+		for (j = 0; j < numsectors; j++) {
+			boolean matches_target_tag = target_tag && Tag_Find(&sectors[j].tags, target_tag);
+			size_t k;
+			for (k = 0; k < 4; k++) {
+				if (lines[i].flags & ML_EFFECT5) {
+					if (matches_target_tag || (offset_tags[k] && Tag_Find(&sectors[j].tags, offset_tags[k]))) {
+						Tag_Add(&sectors[j].tags, tag);
+						break;
 					}
+				} else if (matches_target_tag) {
+					if (k == 0)
+						Tag_Add(&sectors[j].tags, tag);
+					if (offset_tags[k])
+						Tag_Add(&sectors[j].tags, offset_tags[k]);
 				}
 			}
-		} else {
-			if (lines[i].special == 97 || lines[i].special == 99)
-				P_AddBinaryMapTagsFromLine(lines[i].frontsector, &lines[i]);
-			if (lines[i].special == 98 || lines[i].special == 99)
-				P_AddBinaryMapTagsFromLine(lines[i].backsector, &lines[i]);
 		}
 	}
 }
diff --git a/src/p_user.c b/src/p_user.c
index f066d4b0c13640e9c32d11fe7d96de21bcc0805b..700f3bb37c1c1c30c4d884abaeda0914c58e2fa3 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -11594,7 +11594,7 @@ void P_PlayerThink(player_t *player)
 
 			for (i = 0; i < MAXPLAYERS; i++)
 			{
-				if (!playeringame[i] || players[i].spectator || players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN)
+				if (!playeringame[i] || players[i].spectator || players[i].bot)
 					continue;
 				if (players[i].lives <= 0)
 					continue;
@@ -11626,7 +11626,7 @@ void P_PlayerThink(player_t *player)
 
 			for (i = 0; i < MAXPLAYERS; i++)
 			{ 
-				if (!playeringame[i] || players[i].spectator || players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN)
+				if (!playeringame[i] || players[i].spectator || players[i].bot)
 					continue;
 				if (players[i].quittime > 30 * TICRATE)
 					continue;
@@ -12750,12 +12750,12 @@ void P_PlayerAfterThink(player_t *player)
 				if (!ptera->movefactor)
 					goto dropoff;
 
-				if (ptera->cusval >= 50)
+				if (ptera->cusval >= 30)
 				{
 					player->powers[pw_carry] = CR_NONE;
 					P_SetTarget(&player->mo->tracer, NULL);
 					P_KillMobj(ptera, player->mo, player->mo, 0);
-					player->mo->momz = 9*FRACUNIT;
+					P_SetObjectMomZ(player->mo, 12*FRACUNIT, false);
 					player->pflags |= PF_APPLYAUTOBRAKE|PF_JUMPED|PF_THOKKED;
 					P_SetMobjState(player->mo, S_PLAY_ROLL);
 					break;
diff --git a/src/st_stuff.c b/src/st_stuff.c
index a328d669e51169ba18d8ae8d046774d3b298eed3..ebf188a06f78978e2039ff1ef053c65be38a72c9 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -2291,7 +2291,7 @@ static void ST_drawTextHUD(void)
 
 			for (i = 0; i < MAXPLAYERS; i++)
 			{
-				if (!playeringame[i] || players[i].spectator)
+				if (!playeringame[i] || players[i].spectator || players[i].bot)
 					continue;
 				if (players[i].lives <= 0)
 					continue;
diff --git a/src/y_inter.c b/src/y_inter.c
index f24436d4082e645fbbd9fe103a7ed33e741a18b7..288a821e6f33209408ce708b1666bc93aabee93d 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -2023,7 +2023,7 @@ static void Y_AwardCoopBonuses(void)
 
 	for (i = 0; i < MAXPLAYERS; ++i)
 	{
-		if (!playeringame[i] || players[i].lives < 1) // not active or game over
+		if (!playeringame[i] || players[i].lives < 1 || players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN) // not active, game over or tails bot
 			bonusnum = 0; // all null
 		else
 			bonusnum = mapheaderinfo[prevmap]->bonustype + 1; // -1 is none
@@ -2073,7 +2073,7 @@ static void Y_AwardSpecialStageBonus(void)
 	{
 		oldscore = players[i].score;
 
-		if (!playeringame[i] || players[i].lives < 1) // not active or game over
+		if (!playeringame[i] || players[i].lives < 1 || players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN) // not active, game over or tails bot
 		{
 			Y_SetNullBonus(&players[i], &localbonuses[0]);
 			Y_SetNullBonus(&players[i], &localbonuses[1]);