diff --git a/src/b_bot.cpp b/src/b_bot.cpp
index dc6f2cdc4..d2acdcab6 100644
--- a/src/b_bot.cpp
+++ b/src/b_bot.cpp
@@ -24,12 +24,14 @@ IMPLEMENT_POINTY_CLASS(DBot)
 END_POINTERS
 
 DBot::DBot ()
+: DThinker(STAT_BOT)
 {
 	Clear ();
 }
 
 void DBot::Clear ()
 {
+	player = NULL;
 	angle = 0;
 	dest = NULL;
 	prev = NULL;
@@ -64,6 +66,10 @@ void DBot::Serialize (FArchive &arc)
 		arc << savedyaw
 			<< savedpitch;
 	}
+	else if (SaveVersion >= 4516)
+	{
+		arc << player;
+	}
 
 	arc << angle
 		<< dest
@@ -88,6 +94,22 @@ void DBot::Serialize (FArchive &arc)
 		<< oldy;
 }
 
+void DBot::Tick ()
+{
+	Super::Tick ();
+
+	if (player->mo == NULL || bglobal.freeze)
+	{
+		return;
+	}
+
+	BotThinkCycles.Clock();
+	bglobal.m_Thinking = true;
+	bglobal.Think (player->mo, &netcmds[player - players][((gametic + 1)/ticdup)%BACKUPTICS]);
+	bglobal.m_Thinking = false;
+	BotThinkCycles.Unclock();
+}
+
 CVAR (Int, bot_next_color, 11, 0)
 CVAR (Bool, bot_observer, false, 0)
 
diff --git a/src/b_bot.h b/src/b_bot.h
index 1862faee5..7740e5e00 100644
--- a/src/b_bot.h
+++ b/src/b_bot.h
@@ -14,6 +14,7 @@
 #include "d_ticcmd.h"
 #include "r_defs.h"
 #include "a_pickups.h"
+#include "stats.h"
 
 #define FORWARDWALK		0x1900
 #define FORWARDRUN		0x3200
@@ -89,20 +90,22 @@ public:
 	void ClearPlayer (int playernum, bool keepTeam);
 
 	//(B_Game.c)
-	void Main (int buf);
+	void Main ();
 	void Init ();
 	void End();
 	bool SpawnBot (const char *name, int color = NOCOLOR);
-	bool LoadBots ();
-	void ForgetBots ();
 	void TryAddBot (BYTE **stream, int player);
 	void RemoveAllBots (bool fromlist);
-	void DestroyAllBots ();
+	bool LoadBots ();
+	void ForgetBots ();
 
 	//(B_Func.c)
 	bool Check_LOS (AActor *mobj1, AActor *mobj2, angle_t vangle);
+	void StartTravel ();
+	void FinishTravel ();
 
 	//(B_Think.c)
+	void Think (AActor *actor, ticcmd_t *cmd);
 	void WhatToGet (AActor *actor, AActor *item);
 
 	//(B_move.c)
@@ -144,7 +147,6 @@ private:
 	bool SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FCheckPosition &tm);
 
 	//(B_Think.c)
-	void Think (AActor *actor, ticcmd_t *cmd);
 	void ThinkForMove (AActor *actor, ticcmd_t *cmd);
 	void Set_enemy (AActor *actor);
 
@@ -155,16 +157,18 @@ protected:
 	bool	 observer; //Consoleplayer is observer.
 };
 
-class DBot : public DObject
+class DBot : public DThinker
 {
-	DECLARE_CLASS(DBot,DObject)
+	DECLARE_CLASS(DBot,DThinker)
 	HAS_OBJECT_POINTERS
 public:
 	DBot ();
 
 	void Clear ();
 	void Serialize (FArchive &arc);
+	void Tick ();
 
+	player_t	*player;
 	angle_t		angle;		// The wanted angle that the bot try to get every tic.
 							//  (used to get a smooth view movement)
 	TObjPtr<AActor>		dest;		// Move Destination.
@@ -205,6 +209,7 @@ public:
 
 //Externs
 extern FCajunMaster bglobal;
+extern cycle_t BotThinkCycles, BotSupportCycles;
 
 EXTERN_CVAR (Float, bot_flag_return_time)
 EXTERN_CVAR (Int, bot_next_color)
diff --git a/src/b_func.cpp b/src/b_func.cpp
index 0303de8c6..349155a81 100644
--- a/src/b_func.cpp
+++ b/src/b_func.cpp
@@ -402,7 +402,7 @@ AActor *FCajunMaster::Find_enemy (AActor *bot)
 			&& bot != client->mo)
 		{
 			if (Check_LOS (bot, client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up. 
-			//if(P_CheckSight( bot, players[count].mo))
+			//if(P_CheckSight(bot, players[count].mo))
 			{
 				temp = P_AproxDistance (client->mo->x - bot->x,
 										client->mo->y - bot->y);
@@ -552,3 +552,25 @@ bool FCajunMaster::SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FChec
 	actor->flags = savedFlags;
 	return res;
 }
+
+void FCajunMaster::StartTravel ()
+{
+	for (int i = 0; i < MAXPLAYERS; ++i)
+	{
+		if (players[i].Bot != NULL)
+		{
+			players[i].Bot->ChangeStatNum (STAT_TRAVELLING);
+		}
+	}
+}
+
+void FCajunMaster::FinishTravel ()
+{
+	for (int i = 0; i < MAXPLAYERS; ++i)
+	{
+		if (players[i].Bot != NULL)
+		{
+			players[i].Bot->ChangeStatNum (STAT_BOT);
+		}
+	}
+}
diff --git a/src/b_game.cpp b/src/b_game.cpp
index 853ba7f23..44aff03fa 100644
--- a/src/b_game.cpp
+++ b/src/b_game.cpp
@@ -94,71 +94,46 @@ FCajunMaster::~FCajunMaster()
 	ForgetBots();
 }
 
-//This function is called every tick (from g_game.c),
-//send bots into thinking (+more).
-void FCajunMaster::Main (int buf)
+//This function is called every tick (from g_game.c).
+void FCajunMaster::Main ()
 {
-	int i;
-
 	BotThinkCycles.Reset();
 
-	if (demoplayback)
+	if (demoplayback || gamestate != GS_LEVEL || consoleplayer != Net_Arbitrator)
 		return;
 
-	if (gamestate != GS_LEVEL)
-		return;
-
-	m_Thinking = true;
-
-	//Think for bots.
-	if (botnum)
+	//Add new bots?
+	if (wanted_botnum > botnum && !freeze)
 	{
-		BotThinkCycles.Clock();
-		for (i = 0; i < MAXPLAYERS; i++)
+		if (t_join == ((wanted_botnum - botnum) * SPAWN_DELAY))
 		{
-			if (playeringame[i] && players[i].mo && !freeze && players[i].Bot != NULL)
-				Think (players[i].mo, &netcmds[i][buf]);
+			if (!SpawnBot (getspawned[spawn_tries]))
+				wanted_botnum--;
+			spawn_tries++;
 		}
-		BotThinkCycles.Unclock();
+
+		t_join--;
 	}
 
-	if (consoleplayer == Net_Arbitrator)
+	//Check if player should go observer. Or un observe
+	if (bot_observer && !observer && !netgame)
 	{
-		//Add new bots?
-		if (wanted_botnum > botnum && !freeze)
-		{
-			if (t_join == ((wanted_botnum - botnum) * SPAWN_DELAY))
-			{
-				if (!SpawnBot (getspawned[spawn_tries]))
-					wanted_botnum--;
-				spawn_tries++;
-			}
-
-			t_join--;
-		}
-
-		//Check if player should go observer. Or un observe
-		if (bot_observer && !observer && !netgame)
-		{
-			Printf ("%s is now observer\n", players[consoleplayer].userinfo.GetName());
-			observer = true;
-			players[consoleplayer].mo->UnlinkFromWorld ();
-			players[consoleplayer].mo->flags = MF_DROPOFF|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTDMATCH|MF_NOGRAVITY|MF_FRIENDLY;
-			players[consoleplayer].mo->flags2 |= MF2_FLY;
-			players[consoleplayer].mo->LinkToWorld ();
-		}
-		else if (!bot_observer && observer && !netgame) //Go back
-		{
-			Printf ("%s returned to the fray\n", players[consoleplayer].userinfo.GetName());
-			observer = false;
-			players[consoleplayer].mo->UnlinkFromWorld ();
-			players[consoleplayer].mo->flags = MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY;
-			players[consoleplayer].mo->flags2 &= ~MF2_FLY;
-			players[consoleplayer].mo->LinkToWorld ();
-		}
+		Printf ("%s is now observer\n", players[consoleplayer].userinfo.GetName());
+		observer = true;
+		players[consoleplayer].mo->UnlinkFromWorld ();
+		players[consoleplayer].mo->flags = MF_DROPOFF|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOTDMATCH|MF_NOGRAVITY|MF_FRIENDLY;
+		players[consoleplayer].mo->flags2 |= MF2_FLY;
+		players[consoleplayer].mo->LinkToWorld ();
+	}
+	else if (!bot_observer && observer && !netgame) //Go back
+	{
+		Printf ("%s returned to the fray\n", players[consoleplayer].userinfo.GetName());
+		observer = false;
+		players[consoleplayer].mo->UnlinkFromWorld ();
+		players[consoleplayer].mo->flags = MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY;
+		players[consoleplayer].mo->flags2 &= ~MF2_FLY;
+		players[consoleplayer].mo->LinkToWorld ();
 	}
-
-	m_Thinking = false;
 }
 
 void FCajunMaster::Init ()
@@ -199,18 +174,13 @@ void FCajunMaster::End ()
 
 	//Arrange wanted botnum and their names, so they can be spawned next level.
 	getspawned.Clear();
-	for (i = 0; i < MAXPLAYERS; i++)
-	{
-		if (playeringame[i] && players[i].Bot != NULL)
-		{
-			if (deathmatch)
-			{
-				getspawned.Push(players[i].userinfo.GetName());
-			}
-		}
-	}
 	if (deathmatch)
 	{
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			getspawned.Push(players[i].userinfo.GetName());
+		}
+
 		wanted_botnum = botnum;
 	}
 }
@@ -400,7 +370,7 @@ bool FCajunMaster::DoAddBot (BYTE *info, botskill_t skill)
 
 	multiplayer = true; //Prevents cheating and so on; emulates real netgame (almost).
 	players[bnum].Bot = new DBot;
-	GC::WriteBarrier (players[bnum].Bot);
+	players[bnum].Bot->player = &players[bnum];
 	players[bnum].Bot->skill = skill;
 	playeringame[bnum] = true;
 	players[bnum].mo = NULL;
@@ -426,7 +396,7 @@ void FCajunMaster::RemoveAllBots (bool fromlist)
 
 	for (i = 0; i < MAXPLAYERS; ++i)
 	{
-		if (playeringame[i] && players[i].Bot != NULL)
+		if (players[i].Bot != NULL)
 		{
 			// If a player is looking through this bot's eyes, make him
 			// look through his own eyes instead.
@@ -456,18 +426,6 @@ void FCajunMaster::RemoveAllBots (bool fromlist)
 	botnum = 0;
 }
 
-void FCajunMaster::DestroyAllBots ()
-{
-	for (int i = 0; i < MAXPLAYERS; ++i)
-	{
-		if (players[i].Bot != NULL)
-		{
-			players[i].Bot->Destroy ();
-			players[i].Bot = NULL;
-		}
-	}
-}
-
 
 //------------------
 //Reads data for bot from
diff --git a/src/g_game.cpp b/src/g_game.cpp
index e419e09fc..734500e55 100644
--- a/src/g_game.cpp
+++ b/src/g_game.cpp
@@ -1128,11 +1128,8 @@ void G_Ticker ()
 	// check, not just the player's x position like BOOM.
 	DWORD rngsum = FRandom::StaticSumSeeds ();
 
-	if ((gametic % ticdup) == 0)
-	{
-		//Added by MC: For some of that bot stuff. The main bot function.
-		bglobal.Main (buf);
-	}
+	//Added by MC: For some of that bot stuff. The main bot function.
+	bglobal.Main ();
 
 	for (i = 0; i < MAXPLAYERS; i++)
 	{
@@ -1395,7 +1392,6 @@ void G_PlayerReborn (int player)
 
 	if (gamestate != GS_TITLELEVEL)
 	{
-
 		// [GRB] Give inventory specified in DECORATE
 		actor->GiveDefaultInventory ();
 		p->ReadyWeapon = p->PendingWeapon;
@@ -1406,6 +1402,7 @@ void G_PlayerReborn (int player)
 	{
 		botskill_t skill = p->Bot->skill;
 		p->Bot->Clear ();
+		p->Bot->player = p;
 		p->Bot->skill = skill;
 	}
 }
diff --git a/src/g_level.cpp b/src/g_level.cpp
index 2a2d6471a..761ea4f48 100644
--- a/src/g_level.cpp
+++ b/src/g_level.cpp
@@ -1164,6 +1164,8 @@ void G_StartTravel ()
 			}
 		}
 	}
+
+	bglobal.StartTravel ();
 }
 
 //==========================================================================
@@ -1261,6 +1263,8 @@ void G_FinishTravel ()
 			}
 		}
 	}
+
+	bglobal.FinishTravel ();
 }
  
 //==========================================================================
diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp
index fc3e863a2..1aab998a9 100644
--- a/src/g_shared/a_pickups.cpp
+++ b/src/g_shared/a_pickups.cpp
@@ -1024,7 +1024,7 @@ void AInventory::Touch (AActor *toucher)
 	//Added by MC: Check if item taken was the roam destination of any bot
 	for (int i = 0; i < MAXPLAYERS; i++)
 	{
-		if (playeringame[i] && players[i].Bot != NULL && this == players[i].Bot->dest)
+		if (players[i].Bot != NULL && this == players[i].Bot->dest)
 			players[i].Bot->dest = NULL;
 	}
 }
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index c7bfcea21..4ef075720 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -84,7 +84,6 @@ static void PlayerLandedOnThing (AActor *mo, AActor *onmobj);
 
 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
 
-extern cycle_t BotSupportCycles;
 extern int BotWTG;
 EXTERN_CVAR (Int,  cl_rockettrails)
 
diff --git a/src/p_setup.cpp b/src/p_setup.cpp
index 53b288798..6b5d9403f 100644
--- a/src/p_setup.cpp
+++ b/src/p_setup.cpp
@@ -4175,7 +4175,6 @@ static void P_Shutdown ()
 	P_FreeLevelData ();
 	P_FreeExtraLevelData ();
 	ST_Clear();
-	bglobal.DestroyAllBots ();
 }
 
 #if 0
diff --git a/src/p_user.cpp b/src/p_user.cpp
index 72b92b7d1..bf656d2b9 100644
--- a/src/p_user.cpp
+++ b/src/p_user.cpp
@@ -3066,7 +3066,6 @@ void player_t::Serialize (FArchive &arc)
 	if (SaveVersion < 4514 && IsBot)
 	{
 		Bot = new DBot;
-		GC::WriteBarrier (Bot);
 
 		arc	<< Bot->angle
 			<< Bot->dest
@@ -3089,6 +3088,12 @@ void player_t::Serialize (FArchive &arc)
 			<< Bot->oldx
 			<< Bot->oldy;
 	}
+
+	if (SaveVersion < 4516 && Bot != NULL)
+	{
+		Bot->player = this;
+	}
+
 	if (arc.IsLoading ())
 	{
 		// If the player reloaded because they pressed +use after dying, we
diff --git a/src/statnums.h b/src/statnums.h
index 344a328c8..25f644d1d 100644
--- a/src/statnums.h
+++ b/src/statnums.h
@@ -63,6 +63,7 @@ enum
 	STAT_SECTOREFFECT,						// All sector effects that cause floor and ceiling movement
 	STAT_ACTORMOVER,						// actor movers
 	STAT_SCRIPTS,							// The ACS thinker. This is to ensure that it can't tick before all actors called PostBeginPlay
+	STAT_BOT,								// Bot thinker
 };
 
 #endif
\ No newline at end of file
diff --git a/src/version.h b/src/version.h
index f091f416a..15d01d315 100644
--- a/src/version.h
+++ b/src/version.h
@@ -76,7 +76,7 @@ const char *GetVersionString();
 
 // Use 4500 as the base git save version, since it's higher than the
 // SVN revision ever got.
-#define SAVEVER 4515
+#define SAVEVER 4516
 
 #define SAVEVERSTRINGIFY2(x) #x
 #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)