diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index aa2b2fd6b8eb5328fe93226448340b4bf1257386..f40caeeaf68f9f28bbea38a5aaf3513683db7adb 100755
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -1377,8 +1377,9 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
 	netbuffer->u.serverinfo.time = (tic_t)LONG(servertime);
 	netbuffer->u.serverinfo.leveltime = (tic_t)LONG(leveltime);
 
-	netbuffer->u.serverinfo.numberofplayer = (UINT8)D_NumPlayers();
-	netbuffer->u.serverinfo.maxplayer = (UINT8)cv_maxplayers.value;
+	// Exclude bots from both counts
+	netbuffer->u.serverinfo.numberofplayer = (UINT8)(D_NumPlayers() - D_NumBots());
+	netbuffer->u.serverinfo.maxplayer = (UINT8)(cv_maxplayers.value - D_NumBots());
 
 	netbuffer->u.serverinfo.refusereason = GetRefuseReason(node);
 
@@ -4077,7 +4078,7 @@ ConnectionRefused (SINT8 node, INT32 rejoinernum)
 		{
 			return va(
 					"Maximum players reached: %d",
-					cv_maxplayers.value);
+					cv_maxplayers.value - D_NumBots());
 		}
 	}
 
@@ -5609,6 +5610,19 @@ INT32 D_NumPlayers(void)
 	return num;
 }
 
+/** Similar to the above, but counts only bots.
+  * Purpose is to remove bots from both the player count and the
+  * max player count on the server view
+*/
+INT32 D_NumBots(void)
+{
+	INT32 num = 0, ix;
+	for (ix = 0; ix < MAXPLAYERS; ix++)
+		if (playeringame[ix] && players[ix].bot)
+			num++;
+	return num;
+}
+
 tic_t GetLag(INT32 node)
 {
 	return gametic - nettics[node];
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index 8767445d4ee366027dca934b757ee5be43e8f524..baadafb0e57898cb864a70db858c174844a2cd8f 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -447,6 +447,7 @@ extern char motd[254], server_context[8];
 extern UINT8 playernode[MAXPLAYERS];
 
 INT32 D_NumPlayers(void);
+INT32 D_NumBots(void);
 void D_ResetTiccmds(void);
 
 tic_t GetLag(INT32 node);
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 8fec7bd63c3fbfd0124769584625a50bcce0dfa7..6e258c82a97427dd976933a42f5772e45a4a3004 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -3541,7 +3541,6 @@ static int lib_gAddPlayer(lua_State *L)
 		return 1;
 	}
 
-
 	newplayernum = i;
 
 	CL_ClearPlayer(newplayernum);
@@ -3553,9 +3552,6 @@ static int lib_gAddPlayer(lua_State *L)
 	newplayer->jointime = 0;
 	newplayer->quittime = 0;
 
-	// Set the bot name (defaults to Bot #)
-	strcpy(player_names[newplayernum], va("Bot %d", botcount));
-
 	// Read the skin argument (defaults to Sonic)
 	if (!lua_isnoneornil(L, 1))
 	{
@@ -3567,7 +3563,10 @@ static int lib_gAddPlayer(lua_State *L)
 	if (!lua_isnoneornil(L, 2))
 		newplayer->skincolor = R_GetColorByName(luaL_checkstring(L, 2));
 	else
-		newplayer->skincolor = skins[newplayer->skin].prefcolor;
+		newplayer->skincolor = skins[skinnum].prefcolor;
+
+	// Set the bot default name as the skin
+	strcpy(player_names[newplayernum], skins[skinnum].realname);
 
 	// Read the bot name, if given
 	if (!lua_isnoneornil(L, 3))
@@ -3583,14 +3582,19 @@ static int lib_gAddPlayer(lua_State *L)
 	// Set the skin (can't do this until AFTER bot type is set!)
 	SetPlayerSkinByNum(newplayernum, skinnum);
 
-
 	if (netgame)
 	{
 		char joinmsg[256];
 
+		// Truncate bot name
+		player_names[newplayernum][sizeof(*player_names) - 7] = '\0'; // The length of colored [BOT] + 1
+
 		strcpy(joinmsg, M_GetText("\x82*Bot %s has joined the game (player %d)"));
 		strcpy(joinmsg, va(joinmsg, player_names[newplayernum], newplayernum));
 		HU_AddChatText(joinmsg, false);
+
+		// Append blue [BOT] tag at the end
+		strlcat(player_names[newplayernum], "\x84[BOT]", sizeof(*player_names));
 	}
 
 	LUA_PushUserdata(L, newplayer, META_PLAYER);