(svn r9144) [NoAI] -Change: moved command functions to AIObject, and made AIBase depend on AIObject noai
authortruelight
Tue, 13 Mar 2007 18:36:29 +0000
branchnoai
changeset 9361 7bb2bd22b16e
parent 9360 c20d0a9e0a5c
child 9362 3aebc515446a
(svn r9144) [NoAI] -Change: moved command functions to AIObject, and made AIBase depend on AIObject
-Change: split AIBase into AIBase and AIController, where the last should be extended by the real AI
-Remove: removed the SP queue-code, as it is no longer needed with the new message system
projects/openttd.vcproj
projects/openttd_vs80.vcproj
source.list
src/ai/NoAI/NoAI.cpp
src/ai/NoAI/NoAI.hpp
src/ai/core/ai.cpp
src/ai/core/ai_base.hpp
src/ai/core/ai_controller.hpp
src/ai/core/ai_object.hpp
src/ai/core/base/random.cpp
src/ai/core/object/commands.cpp
--- a/projects/openttd.vcproj	Tue Mar 13 15:47:26 2007 +0000
+++ b/projects/openttd.vcproj	Tue Mar 13 18:36:29 2007 +0000
@@ -904,9 +904,18 @@
 				RelativePath=".\..\src\ai\core\ai_base.hpp">
 			</File>
 			<File
+				RelativePath=".\..\src\ai\core\ai_controller.hpp">
+			</File>
+			<File
+				RelativePath=".\..\src\ai\core\ai_object.hpp">
+			</File>
+			<File
 				RelativePath=".\..\src\ai\core\base\random.cpp">
 			</File>
 			<File
+				RelativePath=".\..\src\ai\core\object\commands.cpp">
+			</File>
+			<File
 				RelativePath=".\..\src\ai\NoAI\NoAI.cpp">
 			</File>
 			<File
--- a/projects/openttd_vs80.vcproj	Tue Mar 13 15:47:26 2007 +0000
+++ b/projects/openttd_vs80.vcproj	Tue Mar 13 18:36:29 2007 +0000
@@ -1428,10 +1428,22 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\ai\core\ai_controller.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\ai\core\ai_object.hpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\ai\core\base\random.cpp"
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\ai\core\object\commands.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\ai\NoAI\NoAI.cpp"
 				>
 			</File>
--- a/source.list	Tue Mar 13 15:47:26 2007 +0000
+++ b/source.list	Tue Mar 13 18:36:29 2007 +0000
@@ -271,7 +271,10 @@
 ai/core/ai.cpp
 ai/core/ai.h
 ai/core/ai_base.hpp
+ai/core/ai_controller.hpp
+ai/core/ai_object.hpp
 ai/core/base/random.cpp
+ai/core/object/commands.cpp
 ai/NoAI/NoAI.cpp
 ai/NoAI/NoAI.hpp
 
--- a/src/ai/NoAI/NoAI.cpp	Tue Mar 13 15:47:26 2007 +0000
+++ b/src/ai/NoAI/NoAI.cpp	Tue Mar 13 18:36:29 2007 +0000
@@ -2,7 +2,6 @@
 
 /** @file NoAI.cpp a simple C++ AI that will never be an AI */
 
-#include "../../stdafx.h"
 #include "NoAI.hpp"
 
 /* virtual */ void NoAI::GameLoop()
--- a/src/ai/NoAI/NoAI.hpp	Tue Mar 13 15:47:26 2007 +0000
+++ b/src/ai/NoAI/NoAI.hpp	Tue Mar 13 18:36:29 2007 +0000
@@ -5,10 +5,13 @@
 #ifndef NOAI_HPP
 #define NOAI_HPP
 
+#include "../core/ai_controller.hpp"
 #include "../core/ai_base.hpp"
 
-class NoAI: public AIBase
-{
+class NoAI: public AIController {
+private:
+	AIBase base;
+
 public:
 	/* virtual */ void GameLoop();
 };
--- a/src/ai/core/ai.cpp	Tue Mar 13 15:47:26 2007 +0000
+++ b/src/ai/core/ai.cpp	Tue Mar 13 18:36:29 2007 +0000
@@ -12,174 +12,19 @@
 #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 AIController *_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();
+	_ai_player[player]->IncreaseTick();
+	_ai_player[player]->GameLoop();
 }
 
 
@@ -210,7 +55,6 @@
 		FOR_ALL_PLAYERS(p) {
 			if (p->is_active && p->is_ai) {
 				/* Run the script */
-				AI_DequeueCommands(p->index);
 				AI_RunTick(p->index);
 			}
 		}
@@ -229,7 +73,7 @@
 	if (_networking && !_network_server) return;
 
 	/* Called if a new AI is booted */
-	_ai_player[player].object = new NoAI();
+	_ai_player[player] = new NoAI();
 }
 
 /**
@@ -240,7 +84,7 @@
 	if (!_ai_enabled) return;
 
 	/* Called if this AI died */
-	delete _ai_player[player].object;
+	delete _ai_player[player];
 }
 
 /**
--- a/src/ai/core/ai_base.hpp	Tue Mar 13 15:47:26 2007 +0000
+++ b/src/ai/core/ai_base.hpp	Tue Mar 13 18:36:29 2007 +0000
@@ -1,31 +1,14 @@
 /* $Id$ */
 
-/** @file deceleration of class for AIBase class */
+/** @file declaration of class for AIBase class */
 
 #ifndef AI_BASE_HPP
 #define AI_BASE_HPP
 
-class AIBase {
-protected:
-	uint tick;
-
-public:
-	AIBase() :
-		tick(0)
-	{}
+#include "ai_object.hpp"
 
-	virtual ~AIBase() { }
-
-	/**
-	 * This function is called every tick.
-	 */
-	virtual void GameLoop() = 0;
-
-	/**
-	 * Increase the internal ticker.
-	 */
-	void IncreaseTick() { this->tick++; }
-
+class AIBase: public AIObject {
+public:
 	/**
 	 * Get a random value.
 	 * @return A random value between 0 and MAX(uint32)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/core/ai_controller.hpp	Tue Mar 13 18:36:29 2007 +0000
@@ -0,0 +1,32 @@
+/* $Id$ */
+
+/** @file declaration of class for AIController class */
+
+#ifndef AI_CONTROLLER_HPP
+#define AI_CONTROLLER_HPP
+
+#include "../../stdafx.h"
+
+class AIController {
+public:
+	uint tick;
+
+public:
+	AIController() :
+		tick(0)
+	{}
+
+	virtual ~AIController() { }
+
+	/**
+	 * This function is called every tick.
+	 */
+	virtual void GameLoop() = 0;
+
+	/**
+	 * Increase the internal ticker.
+	 */
+	void IncreaseTick() { this->tick++; }
+};
+
+#endif /* AI_CONTROLLER_HPP */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/core/ai_object.hpp	Tue Mar 13 18:36:29 2007 +0000
@@ -0,0 +1,25 @@
+/* $Id$ */
+
+/** @file declaration of class for AIObject class */
+
+#ifndef AI_OBJECT_HPP
+#define AI_OBJECT_HPP
+
+#include "../../stdafx.h"    // Needed for functions.h
+#include "../../functions.h" // Needed for command.h
+#include "../../command.h"   // Needed for CommandCallback
+
+class AIObject {
+protected:
+	/**
+	 * Executes a raw DoCommandCc for the AI.
+	 */
+	int32 DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback *callback);
+
+	/**
+	 * Executes a raw DoCommand for the AI.
+	 */
+	int32 DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc) { return this->DoCommandCc(tile, p1, p2, flags, procc, NULL); }
+};
+
+#endif /* AI_OBJECT_HPP */
--- a/src/ai/core/base/random.cpp	Tue Mar 13 15:47:26 2007 +0000
+++ b/src/ai/core/base/random.cpp	Tue Mar 13 18:36:29 2007 +0000
@@ -2,10 +2,6 @@
 
 /** @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()
@@ -13,7 +9,7 @@
 	/* 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();
+	return ::Random();
 }
 
 uint32 AIBase::RandomRange(uint max)
@@ -21,7 +17,7 @@
 	/* 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);
+	return ::RandomRange(max);
 }
 
 bool AIBase::Chance(uint out, uint max)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/core/object/commands.cpp	Tue Mar 13 18:36:29 2007 +0000
@@ -0,0 +1,52 @@
+/* $Id$ */
+
+/** @file commands.cpp handles the commands-related functions of the AIObject class */
+
+#include "../ai_object.hpp"
+#include "../../../player.h"
+
+int32 AIObject::DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback *callback)
+{
+	PlayerID old_lp;
+	int32 res = 0;
+	const char* tmp_cmdtext;
+
+	/* 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
+		/* For SinglePlayer we execute the command immediatly */
+		DoCommandP(tile, p1, p2, callback, procc);
+	}
+
+	/* Set _local_player back */
+	_local_player = old_lp;
+
+	return res;
+}