(svn r9142) [NoAI] -Add: added initial code for AI-layer system noai
authortruelight
Tue, 13 Mar 2007 15:47:26 +0000
branchnoai
changeset 9360 c20d0a9e0a5c
parent 9359 e915dd81a279
child 9361 7bb2bd22b16e
(svn r9142) [NoAI] -Add: added initial code for AI-layer system
-Cleanup: ai.h only declares functions, no longer structs and other stuff
-Add: added example AI called NoAI
-Add: added first AIBase:: functions (random-related)
Many thanks to Rubidium and Celestar for their comments and suggestions!
projects/openttd.vcproj
projects/openttd_vs80.vcproj
source.list
src/ai/NoAI/NoAI.cpp
src/ai/NoAI/NoAI.hpp
src/ai/ai.cpp
src/ai/ai.h
src/ai/core/ai.cpp
src/ai/core/ai.h
src/ai/core/ai_base.hpp
src/ai/core/base/random.cpp
src/economy.cpp
src/misc.cpp
src/network/network_client.cpp
src/oldloader.cpp
src/openttd.cpp
src/players.cpp
--- a/projects/openttd.vcproj	Tue Mar 13 13:07:17 2007 +0000
+++ b/projects/openttd.vcproj	Tue Mar 13 15:47:26 2007 +0000
@@ -895,7 +895,22 @@
 			Name="AI Files"
 			Filter="">
 			<File
-				RelativePath=".\..\src\ai\ai.cpp">
+				RelativePath=".\..\src\ai\core\ai.cpp">
+			</File>
+			<File
+				RelativePath=".\..\src\ai\core\ai.h">
+			</File>
+			<File
+				RelativePath=".\..\src\ai\core\ai_base.hpp">
+			</File>
+			<File
+				RelativePath=".\..\src\ai\core\base\random.cpp">
+			</File>
+			<File
+				RelativePath=".\..\src\ai\NoAI\NoAI.cpp">
+			</File>
+			<File
+				RelativePath=".\..\src\ai\NoAI\NoAI.hpp">
 			</File>
 		</Filter>
 		<Filter
--- a/projects/openttd_vs80.vcproj	Tue Mar 13 13:07:17 2007 +0000
+++ b/projects/openttd_vs80.vcproj	Tue Mar 13 15:47:26 2007 +0000
@@ -1416,7 +1416,27 @@
 			Name="AI Files"
 			>
 			<File
-				RelativePath=".\..\src\ai\ai.cpp"
+				RelativePath=".\..\src\ai\core\ai.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\ai\core\ai.h"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\ai\core\ai_base.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\ai\core\base\random.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\ai\NoAI\NoAI.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\ai\NoAI\NoAI.hpp"
 				>
 			</File>
 		</Filter>
--- a/source.list	Tue Mar 13 13:07:17 2007 +0000
+++ b/source.list	Tue Mar 13 15:47:26 2007 +0000
@@ -268,7 +268,12 @@
 table/water_land.h
 
 # AI Files
-ai/ai.cpp
+ai/core/ai.cpp
+ai/core/ai.h
+ai/core/ai_base.hpp
+ai/core/base/random.cpp
+ai/NoAI/NoAI.cpp
+ai/NoAI/NoAI.hpp
 
 # NewGRF
 newgrf.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/NoAI/NoAI.cpp	Tue Mar 13 15:47:26 2007 +0000
@@ -0,0 +1,10 @@
+/* $Id$ */
+
+/** @file NoAI.cpp a simple C++ AI that will never be an AI */
+
+#include "../../stdafx.h"
+#include "NoAI.hpp"
+
+/* virtual */ void NoAI::GameLoop()
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/NoAI/NoAI.hpp	Tue Mar 13 15:47:26 2007 +0000
@@ -0,0 +1,16 @@
+/* $Id$ */
+
+/** @file NoAI.hpp declarations of the class for a simple C++ AI that will never be an AI */
+
+#ifndef NOAI_HPP
+#define NOAI_HPP
+
+#include "../core/ai_base.hpp"
+
+class NoAI: public AIBase
+{
+public:
+	/* virtual */ void GameLoop();
+};
+
+#endif /* NOAI_HPP */
--- a/src/ai/ai.cpp	Tue Mar 13 13:07:17 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,240 +0,0 @@
-/* $Id$ */
-
-#include "../stdafx.h"
-#include "../openttd.h"
-#include "../variables.h"
-#include "../command.h"
-#include "../network/network.h"
-#include "../helpers.hpp"
-#include "ai.h"
-
-/**
- * Dequeues commands put in the queue via AI_PutCommandInQueue.
- */
-static void AI_DequeueCommands(PlayerID player)
-{
-	AICommand *com, *entry_com;
-
-	entry_com = _ai_player[player].queue;
-
-	/* It happens that DoCommandP issues a new DoCommandAI which adds a new command
-	 *  to this very same queue (don't argue about this, if it currently doesn't
-	 *  happen I can tell you it will happen with AIScript -- TrueLight). If we
-	 *  do not make the queue NULL, that commands will be dequeued immediatly.
-	 *  Therefor we safe the entry-point to entry_com, and make the queue NULL, so
-	 *  the new queue can be safely built up. */
-	_ai_player[player].queue = NULL;
-	_ai_player[player].queue_tail = NULL;
-
-	/* Dequeue all commands */
-	while ((com = entry_com) != NULL) {
-		_current_player = player;
-
-		_cmd_text = com->text;
-		DoCommandP(com->tile, com->p1, com->p2, com->callback, com->procc);
-
-		/* Free item */
-		entry_com = com->next;
-		free(com->text);
-		free(com);
-	}
-}
-
-/**
- * Needed for SP; we need to delay DoCommand with 1 tick, because else events
- *  will make infinite loops (AIScript).
- */
-static void AI_PutCommandInQueue(PlayerID player, TileIndex tile, uint32 p1, uint32 p2, uint procc, CommandCallback* callback)
-{
-	AICommand *com;
-
-	if (_ai_player[player].queue_tail == NULL) {
-		/* There is no item in the queue yet, create the queue */
-		_ai_player[player].queue = MallocT<AICommand>(1);
-		_ai_player[player].queue_tail = _ai_player[player].queue;
-	} else {
-		/* Add an item at the end */
-		_ai_player[player].queue_tail->next = MallocT<AICommand>(1);
-		_ai_player[player].queue_tail = _ai_player[player].queue_tail->next;
-	}
-
-	/* This is our new item */
-	com = _ai_player[player].queue_tail;
-
-	/* Assign the info */
-	com->tile  = tile;
-	com->p1    = p1;
-	com->p2    = p2;
-	com->procc = procc;
-	com->callback = callback;
-	com->next  = NULL;
-	com->text  = NULL;
-
-	/* Copy the cmd_text, if needed */
-	if (_cmd_text != NULL) {
-		com->text = strdup(_cmd_text);
-		_cmd_text = NULL;
-	}
-}
-
-/**
- * Executes a raw DoCommand for the AI.
- */
-int32 AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback* callback)
-{
-	PlayerID old_lp;
-	int32 res = 0;
-	const char* tmp_cmdtext;
-
-	/* If you enable DC_EXEC with DC_QUERY_COST you are a really strange
-	 *   person.. should we check for those funny jokes?
-	 */
-
-	/* The test already resets _cmd_text, so backup the pointer */
-	tmp_cmdtext = _cmd_text;
-
-	/* First, do a test-run to see if we can do this */
-	res = DoCommand(tile, p1, p2, flags & ~DC_EXEC, procc);
-	/* The command failed, or you didn't want to execute, or you are quering, return */
-	if (CmdFailed(res) || !(flags & DC_EXEC) || (flags & DC_QUERY_COST)) {
-		return res;
-	}
-
-	/* Restore _cmd_text */
-	_cmd_text = tmp_cmdtext;
-
-	/* If we did a DC_EXEC, and the command did not return an error, execute it
-	 * over the network */
-	if (flags & DC_AUTO)     procc |= CMD_AUTO;
-	if (flags & DC_NO_WATER) procc |= CMD_NO_WATER;
-
-	/* NetworkSend_Command needs _local_player to be set correctly, so
-	 * adjust it, and put it back right after the function */
-	old_lp = _local_player;
-	_local_player = _current_player;
-
-#ifdef ENABLE_NETWORK
-	/* Send the command */
-	if (_networking) {
-		/* Network is easy, send it to his handler */
-		NetworkSend_Command(tile, p1, p2, procc, callback);
-	} else {
-#else
-	{
-#endif
-		/* If we execute BuildCommands directly in SP, we have a big problem with events
-		 *  so we need to delay is for 1 tick */
-		AI_PutCommandInQueue(_current_player, tile, p1, p2, procc, callback);
-	}
-
-	/* Set _local_player back */
-	_local_player = old_lp;
-
-	return res;
-}
-
-
-int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
-{
-	return AI_DoCommandCc(tile, p1, p2, flags, procc, NULL);
-}
-
-
-/**
- * Run 1 tick of the AI. Don't overdo it, keep it realistic.
- */
-static void AI_RunTick(PlayerID player)
-{
-	extern void AiNewDoGameLoop(Player *p);
-
-//	Player *p = GetPlayer(player);
-	_current_player = player;
-
-	/* TODO -- Call the AI here */
-}
-
-
-/**
- * The gameloop for AIs.
- *  Handles one tick for all the AIs.
- */
-void AI_RunGameLoop()
-{
-	/* Don't do anything if ai is disabled */
-	if (!_ai.enabled) return;
-
-	/* Don't do anything if we are a network-client, or the AI has been disabled */
-	if (_networking && (!_network_server || !_patches.ai_in_multiplayer)) return;
-
-	/* New tick */
-	_ai.tick++;
-
-	/* Make sure the AI follows the difficulty rule.. */
-	assert(_opt.diff.competitor_speed <= 4);
-	if ((_ai.tick & ((1 << (4 - _opt.diff.competitor_speed)) - 1)) != 0) return;
-
-	/* Check for AI-client (so joining a network with an AI) */
-	if (!_networking || _network_server) {
-		/* Check if we want to run AIs (server or SP only) */
-		const Player* p;
-
-		FOR_ALL_PLAYERS(p) {
-			if (p->is_active && p->is_ai) {
-				/* This should always be true, else something went wrong... */
-				assert(_ai_player[p->index].active);
-
-				/* Run the script */
-				AI_DequeueCommands(p->index);
-				AI_RunTick(p->index);
-			}
-		}
-	}
-
-	_current_player = OWNER_NONE;
-}
-
-/**
- * A new AI sees the day of light. You can do here what ever you think is needed.
- */
-void AI_StartNewAI(PlayerID player)
-{
-	assert(IsValidPlayer(player));
-
-	/* Called if a new AI is booted */
-	_ai_player[player].active = true;
-}
-
-/**
- * This AI player died. Give it some chance to make a final puf.
- */
-void AI_PlayerDied(PlayerID player)
-{
-	/* Called if this AI died */
-	_ai_player[player].active = false;
-}
-
-/**
- * Initialize some AI-related stuff.
- */
-void AI_Initialize()
-{
-	/* First, make sure all AIs are DEAD! */
-	AI_Uninitialize();
-
-	memset(&_ai, 0, sizeof(_ai));
-	memset(&_ai_player, 0, sizeof(_ai_player));
-
-	_ai.enabled = true;
-}
-
-/**
- * Deinitializer for AI-related stuff.
- */
-void AI_Uninitialize()
-{
-	const Player* p;
-
-	FOR_ALL_PLAYERS(p) {
-		if (p->is_active && p->is_ai) AI_PlayerDied(p->index);
-	}
-}
--- a/src/ai/ai.h	Tue Mar 13 13:07:17 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-#ifndef AI_H
-#define AI_H
-
-#include "../functions.h"
-#include "../network/network.h"
-#include "../player.h"
-#include "../command.h"
-
-/* How DoCommands look like for an AI */
-struct AICommand {
-	uint32 tile;
-	uint32 p1;
-	uint32 p2;
-	uint32 procc;
-	CommandCallback* callback;
-
-	char *text;
-	uint uid;
-
-	AICommand *next;
-};
-
-/* The struct for an AIScript Player */
-struct AIPlayer {
-	bool active;            ///< Is this AI active?
-	AICommand *queue;       ///< The commands that he has in his queue
-	AICommand *queue_tail;  ///< The tail of this queue
-};
-
-/* The struct to keep some data about the AI in general */
-struct AIStruct {
-	/* General */
-	bool enabled;           ///< Is AI enabled?
-	uint tick;              ///< The current tick (something like _frame_counter, only for AIs)
-};
-
-VARDEF AIStruct _ai;
-VARDEF AIPlayer _ai_player[MAX_PLAYERS];
-
-// ai.c
-void AI_StartNewAI(PlayerID player);
-void AI_PlayerDied(PlayerID player);
-void AI_RunGameLoop();
-void AI_Initialize();
-void AI_Uninitialize();
-int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
-int32 AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback* callback);
-
-/** Is it allowed to start a new AI.
- * This function checks some boundries to see if we should launch a new AI.
- * @return True if we can start a new AI.
- */
-static inline bool AI_AllowNewAI()
-{
-	/* If disabled, no AI */
-	if (!_ai.enabled)
-		return false;
-
-	/* If in network, but no server, no AI */
-	if (_networking && !_network_server)
-		return false;
-
-	/* If in network, and server, possible AI */
-	if (_networking && _network_server) {
-		/* Do we want AIs in multiplayer? */
-		if (!_patches.ai_in_multiplayer)
-			return false;
-	}
-
-	return true;
-}
-
-#define AI_CHANCE16(a,b)    ((uint16)     AI_Random()  <= (uint16)((65536 * a) / b))
-#define AI_CHANCE16R(a,b,r) ((uint16)(r = AI_Random()) <= (uint16)((65536 * a) / b))
-
-/**
- * The random-function that should be used by ALL AIs.
- */
-static inline uint AI_RandomRange(uint max)
-{
-	/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
-	 *   but we pick InteractiveRandomRange if we are a network_server or network-client.
-	 */
-	if (_networking)
-		return InteractiveRandomRange(max);
-	else
-		return RandomRange(max);
-}
-
-/**
- * The random-function that should be used by ALL AIs.
- */
-static inline uint32 AI_Random()
-{
-/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
-	 *   but we pick InteractiveRandomRange if we are a network_server or network-client.
-	 */
-	if (_networking)
-		return InteractiveRandom();
-	else
-		return Random();
-}
-
-#endif /* AI_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/core/ai.cpp	Tue Mar 13 15:47:26 2007 +0000
@@ -0,0 +1,291 @@
+/* $Id$ */
+
+/** @file ai.cpp handles the communication between the AI layer and the OpenTTD core */
+
+#include "../../stdafx.h"
+#include "../../openttd.h"
+#include "../../variables.h"
+#include "../../command.h"
+#include "../../network/network.h"
+#include "../../helpers.hpp"
+#include "ai.h"
+#include "ai_base.hpp"
+#include "../NoAI/NoAI.hpp"
+
+/**
+ * How DoCommands-struct look like for an AI.
+ */
+struct AICommand {
+	uint32 tile;
+	uint32 p1;
+	uint32 p2;
+	uint32 procc;
+	CommandCallback* callback;
+
+	char *text;
+	uint uid;
+
+	AICommand *next;
+};
+
+/* The struct for an AIScript Player */
+struct AIPlayer {
+	AICommand *queue;       ///< The commands that he has in his queue
+	AICommand *queue_tail;  ///< The tail of this queue
+	AIBase *object;         ///< The class object for this AI
+};
+
+static AIPlayer _ai_player[MAX_PLAYERS];
+static uint _ai_frame_counter;
+static bool _ai_enabled;
+
+/**
+ * Dequeues commands put in the queue via AI_PutCommandInQueue.
+ */
+static void AI_DequeueCommands(PlayerID player)
+{
+	AICommand *com, *entry_com;
+
+	entry_com = _ai_player[player].queue;
+
+	/* It happens that DoCommandP issues a new DoCommandAI which adds a new command
+	 *  to this very same queue (don't argue about this, if it currently doesn't
+	 *  happen I can tell you it will happen with AIScript -- TrueLight). If we
+	 *  do not make the queue NULL, that commands will be dequeued immediatly.
+	 *  Therefor we safe the entry-point to entry_com, and make the queue NULL, so
+	 *  the new queue can be safely built up. */
+	_ai_player[player].queue = NULL;
+	_ai_player[player].queue_tail = NULL;
+
+	/* Dequeue all commands */
+	while ((com = entry_com) != NULL) {
+		_current_player = player;
+
+		_cmd_text = com->text;
+		DoCommandP(com->tile, com->p1, com->p2, com->callback, com->procc);
+
+		/* Free item */
+		entry_com = com->next;
+		free(com->text);
+		free(com);
+	}
+}
+
+/**
+ * Needed for SP; we need to delay DoCommand with 1 tick, because else events
+ *  will make infinite loops (AIScript).
+ */
+static void AI_PutCommandInQueue(PlayerID player, TileIndex tile, uint32 p1, uint32 p2, uint procc, CommandCallback* callback)
+{
+	AICommand *com;
+
+	if (_ai_player[player].queue_tail == NULL) {
+		/* There is no item in the queue yet, create the queue */
+		_ai_player[player].queue = MallocT<AICommand>(1);
+		_ai_player[player].queue_tail = _ai_player[player].queue;
+	} else {
+		/* Add an item at the end */
+		_ai_player[player].queue_tail->next = MallocT<AICommand>(1);
+		_ai_player[player].queue_tail = _ai_player[player].queue_tail->next;
+	}
+
+	/* This is our new item */
+	com = _ai_player[player].queue_tail;
+
+	/* Assign the info */
+	com->tile  = tile;
+	com->p1    = p1;
+	com->p2    = p2;
+	com->procc = procc;
+	com->callback = callback;
+	com->next  = NULL;
+	com->text  = NULL;
+
+	/* Copy the cmd_text, if needed */
+	if (_cmd_text != NULL) {
+		com->text = strdup(_cmd_text);
+		_cmd_text = NULL;
+	}
+}
+
+/**
+ * Executes a raw DoCommand for the AI.
+ */
+int32 AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback* callback)
+{
+	PlayerID old_lp;
+	int32 res = 0;
+	const char* tmp_cmdtext;
+
+	/* If you enable DC_EXEC with DC_QUERY_COST you are a really strange
+	 *   person.. should we check for those funny jokes?
+	 */
+
+	/* The test already resets _cmd_text, so backup the pointer */
+	tmp_cmdtext = _cmd_text;
+
+	/* First, do a test-run to see if we can do this */
+	res = DoCommand(tile, p1, p2, flags & ~DC_EXEC, procc);
+	/* The command failed, or you didn't want to execute, or you are quering, return */
+	if (CmdFailed(res) || !(flags & DC_EXEC) || (flags & DC_QUERY_COST)) {
+		return res;
+	}
+
+	/* Restore _cmd_text */
+	_cmd_text = tmp_cmdtext;
+
+	/* If we did a DC_EXEC, and the command did not return an error, execute it
+	 * over the network */
+	if (flags & DC_AUTO)     procc |= CMD_AUTO;
+	if (flags & DC_NO_WATER) procc |= CMD_NO_WATER;
+
+	/* NetworkSend_Command needs _local_player to be set correctly, so
+	 * adjust it, and put it back right after the function */
+	old_lp = _local_player;
+	_local_player = _current_player;
+
+#ifdef ENABLE_NETWORK
+	/* Send the command */
+	if (_networking) {
+		/* Network is easy, send it to his handler */
+		NetworkSend_Command(tile, p1, p2, procc, callback);
+	} else {
+#else
+	{
+#endif
+		/* If we execute BuildCommands directly in SP, we have a big problem with events
+		 *  so we need to delay is for 1 tick */
+		AI_PutCommandInQueue(_current_player, tile, p1, p2, procc, callback);
+	}
+
+	/* Set _local_player back */
+	_local_player = old_lp;
+
+	return res;
+}
+
+
+int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
+{
+	return AI_DoCommandCc(tile, p1, p2, flags, procc, NULL);
+}
+
+
+/**
+ * Run 1 tick of the AI. Don't overdo it, keep it realistic.
+ */
+static void AI_RunTick(PlayerID player)
+{
+	_current_player = player;
+
+	_ai_player[player].object->IncreaseTick();
+	_ai_player[player].object->GameLoop();
+}
+
+
+/**
+ * The gameloop for AIs.
+ *  Handles one tick for all the AIs.
+ */
+void AI_RunGameLoop()
+{
+	/* Don't do anything if ai is disabled */
+	if (!_ai_enabled) return;
+
+	/* Don't do anything if we are a network-client, or the AI has been disabled */
+	if (_networking && (!_network_server || !_patches.ai_in_multiplayer)) return;
+
+	/* New tick */
+	_ai_frame_counter++;
+
+	/* Make sure the AI follows the difficulty rule.. */
+	assert(_opt.diff.competitor_speed <= 4);
+	if ((_ai_frame_counter & ((1 << (4 - _opt.diff.competitor_speed)) - 1)) != 0) return;
+
+	/* Check for AI-client (so joining a network with an AI) */
+	if (!_networking || _network_server) {
+		/* Check if we want to run AIs (server or SP only) */
+		const Player* p;
+
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active && p->is_ai) {
+				/* Run the script */
+				AI_DequeueCommands(p->index);
+				AI_RunTick(p->index);
+			}
+		}
+	}
+
+	_current_player = OWNER_NONE;
+}
+
+/**
+ * A new AI sees the day of light. You can do here what ever you think is needed.
+ */
+void AI_StartNewAI(PlayerID player)
+{
+	assert(IsValidPlayer(player));
+	if (!_ai_enabled) return;
+	if (_networking && !_network_server) return;
+
+	/* Called if a new AI is booted */
+	_ai_player[player].object = new NoAI();
+}
+
+/**
+ * This AI player died. Give it some chance to make a final puf.
+ */
+void AI_PlayerDied(PlayerID player)
+{
+	if (!_ai_enabled) return;
+
+	/* Called if this AI died */
+	delete _ai_player[player].object;
+}
+
+/**
+ * Initialize some AI-related stuff.
+ */
+void AI_Initialize()
+{
+	/* First, make sure all AIs are DEAD! */
+	AI_Uninitialize();
+
+	memset(&_ai_player, 0, sizeof(_ai_player));
+	_ai_frame_counter = 0;
+	_ai_enabled = true;
+}
+
+/**
+ * Deinitializer for AI-related stuff.
+ */
+void AI_Uninitialize()
+{
+	const Player* p;
+
+	FOR_ALL_PLAYERS(p) {
+		if (p->is_active && p->is_ai) AI_PlayerDied(p->index);
+	}
+}
+
+/**
+ * Is it allowed to start a new AI.
+ * This function checks some boundries to see if we should launch a new AI.
+ * @return True if we can start a new AI.
+ */
+bool AI_AllowNewAI()
+{
+	/* If disabled, no AI */
+	if (!_ai_enabled) return false;
+
+	/* If in network, but no server, no AI */
+	if (_networking && !_network_server) return false;
+
+	/* If in network, and server, possible AI */
+	if (_networking && _network_server) {
+		/* Do we want AIs in multiplayer? */
+		if (!_patches.ai_in_multiplayer) return false;
+	}
+
+	return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/core/ai.h	Tue Mar 13 15:47:26 2007 +0000
@@ -0,0 +1,16 @@
+/* $Id$ */
+
+/** @file declaration of functions for the AI system */
+
+#ifndef AI_H
+#define AI_H
+
+// ai.c
+void AI_StartNewAI(PlayerID player);
+void AI_PlayerDied(PlayerID player);
+void AI_RunGameLoop();
+void AI_Initialize();
+void AI_Uninitialize();
+bool AI_AllowNewAI();
+
+#endif /* AI_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/core/ai_base.hpp	Tue Mar 13 15:47:26 2007 +0000
@@ -0,0 +1,51 @@
+/* $Id$ */
+
+/** @file deceleration of class for AIBase class */
+
+#ifndef AI_BASE_HPP
+#define AI_BASE_HPP
+
+class AIBase {
+protected:
+	uint tick;
+
+public:
+	AIBase() :
+		tick(0)
+	{}
+
+	virtual ~AIBase() { }
+
+	/**
+	 * This function is called every tick.
+	 */
+	virtual void GameLoop() = 0;
+
+	/**
+	 * Increase the internal ticker.
+	 */
+	void IncreaseTick() { this->tick++; }
+
+	/**
+	 * Get a random value.
+	 * @return A random value between 0 and MAX(uint32)
+	 */
+	uint32 Random();
+
+	/**
+	 * Get a random value in a range.
+	 * @param max The maximum value it will return.
+	 * @return A random value between 0 .. max.
+	 */
+	uint32 RandomRange(uint max);
+
+	/**
+	 * Take a chance of 'out' out of 'max'.
+	 * @param out How many times is should return true.
+	 * @param max What the max value of 'out' can be.
+	 * @return True if the chance worked out.
+	 */
+	bool Chance(uint out, uint max);
+};
+
+#endif /* AI_BASE_HPP */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/core/base/random.cpp	Tue Mar 13 15:47:26 2007 +0000
@@ -0,0 +1,30 @@
+/* $Id$ */
+
+/** @file random.cpp handles the random functions of the AIBase class */
+
+#include "../../../stdafx.h"
+#include "../../../openttd.h"
+#include "../../../variables.h"
+#include "../../../functions.h"
+#include "../ai_base.hpp"
+
+uint32 AIBase::Random()
+{
+	/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
+	 *   but we pick InteractiveRandomRange if we are a network_server or network-client. */
+	if (_networking) return InteractiveRandom();
+	return Random();
+}
+
+uint32 AIBase::RandomRange(uint max)
+{
+	/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
+	 *   but we pick InteractiveRandomRange if we are a network_server or network-client. */
+	if (_networking) return InteractiveRandomRange(max);
+	return RandomRange(max);
+}
+
+bool AIBase::Chance(uint out, uint max)
+{
+	return this->Random() <= (uint16)((65536 * out) / max);
+}
--- a/src/economy.cpp	Tue Mar 13 13:07:17 2007 +0000
+++ b/src/economy.cpp	Tue Mar 13 15:47:26 2007 +0000
@@ -27,7 +27,7 @@
 #include "network/network_data.h"
 #include "variables.h"
 #include "vehicle_gui.h"
-#include "ai/ai.h"
+#include "ai/core/ai.h"
 #include "train.h"
 #include "aircraft.h"
 #include "newgrf_engine.h"
@@ -471,8 +471,7 @@
 			/* Register the player as not-active */
 			p->is_active = false;
 
-			if (!IsHumanPlayer(owner) && (!_networking || _network_server) && _ai.enabled)
-				AI_PlayerDied(owner);
+			if (!IsHumanPlayer(owner)) AI_PlayerDied(owner);
 		}
 	}
 }
--- a/src/misc.cpp	Tue Mar 13 13:07:17 2007 +0000
+++ b/src/misc.cpp	Tue Mar 13 15:47:26 2007 +0000
@@ -17,7 +17,7 @@
 #include "engine.h"
 #include "vehicle_gui.h"
 #include "variables.h"
-#include "ai/ai.h"
+#include "ai/core/ai.h"
 #include "date.h"
 #include "cargotype.h"
 
--- a/src/network/network_client.cpp	Tue Mar 13 13:07:17 2007 +0000
+++ b/src/network/network_client.cpp	Tue Mar 13 15:47:26 2007 +0000
@@ -19,7 +19,6 @@
 #include "../window.h"
 #include "../console.h"
 #include "../variables.h"
-#include "../ai/ai.h"
 #include "../helpers.hpp"
 
 // This file handles all the client-commands
--- a/src/oldloader.cpp	Tue Mar 13 13:07:17 2007 +0000
+++ b/src/oldloader.cpp	Tue Mar 13 15:47:26 2007 +0000
@@ -17,7 +17,7 @@
 #include "debug.h"
 #include "depot.h"
 #include "network/network.h"
-#include "ai/ai.h"
+#include "ai/core/ai.h"
 #include "date.h"
 
 enum {
@@ -834,8 +834,7 @@
 	if (p->location_of_house == 0xFFFF)
 		p->location_of_house = 0;
 
-	if (p->is_ai && (!_networking || _network_server) && _ai.enabled)
-		AI_StartNewAI(p->index);
+	if (p->is_ai) AI_StartNewAI(p->index);
 
 	return true;
 }
--- a/src/openttd.cpp	Tue Mar 13 13:07:17 2007 +0000
+++ b/src/openttd.cpp	Tue Mar 13 15:47:26 2007 +0000
@@ -47,7 +47,7 @@
 #include "signs.h"
 #include "depot.h"
 #include "waypoint.h"
-#include "ai/ai.h"
+#include "ai/core/ai.h"
 #include "train.h"
 #include "yapf/yapf.h"
 #include "settings.h"
--- a/src/players.cpp	Tue Mar 13 13:07:17 2007 +0000
+++ b/src/players.cpp	Tue Mar 13 15:47:26 2007 +0000
@@ -23,7 +23,7 @@
 #include "network/network.h"
 #include "variables.h"
 #include "engine.h"
-#include "ai/ai.h"
+#include "ai/core/ai.h"
 #include "date.h"
 #include "window.h"
 #include "player_face.h"
@@ -485,8 +485,7 @@
 	InvalidateWindow(WC_TOOLBAR_MENU, 0);
 	InvalidateWindow(WC_CLIENT_LIST, 0);
 
-	if (is_ai && (!_networking || _network_server) && _ai.enabled)
-		AI_StartNewAI(p->index);
+	if (is_ai) AI_StartNewAI(p->index);
 
 	memset(p->num_engines, 0, sizeof(p->num_engines));
 
@@ -1264,8 +1263,7 @@
 		UpdatePlayerMoney32(p);
 
 		/* This is needed so an AI is attached to a loaded AI */
-		if (p->is_ai && (!_networking || _network_server) && _ai.enabled)
-			AI_StartNewAI(p->index);
+		if (p->is_ai) AI_StartNewAI(p->index);
 	}
 }