(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
--- 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;
+}