(svn r10631) [NoAI] -Add: AIEvent, to take care of events; for now it only reports when vehicles are crashed
--- a/bin/ai/regression/regression.nut Thu Jul 19 22:26:26 2007 +0000
+++ b/bin/ai/regression/regression.nut Thu Jul 19 22:39:43 2007 +0000
@@ -149,6 +149,45 @@
print(" GetLoanAmount(): " + company.GetLoanAmount());
}
+function Regression::Event()
+{
+ print("");
+ print("--Event--");
+ AIEventController.Test();
+ local e = AIEventController.GetNextEvent();
+ print(" GetNextEvent: " + e);
+ print(" GetEventType: " + e.GetEventType());
+ local c = AIEventTest.Convert(e);
+ print(" Convert: " + c);
+ print(" GetTest: " + c.GetTest());
+
+ print(" DisableEvent(1): done");
+ AIEventController.DisableEvent(1);
+ AIEventController.Test();
+ e = AIEventController.GetNextEvent();
+ print(" GetNextEvent: " + e);
+
+ print(" EnableEvent(1): done");
+ AIEventController.EnableEvent(1);
+ AIEventController.Test();
+ e = AIEventController.GetNextEvent();
+ print(" GetNextEvent: " + e);
+
+ {
+ print(" DisableAllEvents():done");
+ AIEventController.DisableAllEvents();
+ AIEventController.Test();
+ e = AIEventController.GetNextEvent();
+ print(" GetNextEvent: " + e);
+ }
+
+ print(" EnableEvent(1): done");
+ AIEventController.EnableEvent(1);
+ AIEventController.Test();
+ e = AIEventController.GetNextEvent();
+ print(" GetNextEvent: " + e);
+}
+
function Regression::Industry()
{
local industry = AIIndustry();
@@ -796,6 +835,7 @@
this.Airport();
this.Cargo();
this.Company();
+ this.Event();
this.Industry();
this.IndustryList();
this.Map();
--- a/bin/ai/regression/regression.txt Thu Jul 19 22:26:26 2007 +0000
+++ b/bin/ai/regression/regression.txt Thu Jul 19 22:39:43 2007 +0000
@@ -246,6 +246,20 @@
GetBankBalance(): 284436
GetLoanAmount(): 300000
+--Event--
+ GetNextEvent: (instance : 0x0xb431e0)
+ GetEventType: 1
+ Convert: (instance : 0x0xb41280)
+ GetTest: 42
+ DisableEvent(1): done
+ GetNextEvent: (null : 0x00000000)
+ EnableEvent(1): done
+ GetNextEvent: (instance : 0x0xb431e0)
+ DisableAllEvents():done
+ GetNextEvent: (null : 0x00000000)
+ EnableEvent(1): done
+ GetNextEvent: (instance : 0x0xb431e0)
+
--Industry--
GetMaxIndustryID(): 71
GetIndustryCount(): 69
--- a/bin/ai/wrightai/main.nut Thu Jul 19 22:26:26 2007 +0000
+++ b/bin/ai/wrightai/main.nut Thu Jul 19 22:39:43 2007 +0000
@@ -13,7 +13,6 @@
route_2 = null;
distance_of_route = {};
vehicle_to_depot = {};
- vehicle_depot_tile = {};
delay_build_airport_route = 1000;
function Start();
@@ -52,7 +51,7 @@
local loan = money - this.company.GetBankBalance(AICompany.MY_COMPANY) + this.company.GetLoanInterval() + this.company.GetLoanAmount();
loan = loan - loan % this.company.GetLoanInterval();
- print(this.name + ": Need a loan to get " + money + ": " + loan);
+ print(this.name + ": [INFO] Need a loan to get " + money + ": " + loan);
this.company.SetLoanAmount(loan);
}
@@ -237,8 +236,8 @@
print(this.name + ": [INFO] Removing airports as nobody serves them anymore.");
this.airport.RemoveAirport(this.route_1.GetValue(i));
this.airport.RemoveAirport(this.route_2.GetValue(i));
- this.route_1.RemoteItem(i);
- this.route_2.RemoteItem(i);
+ this.route_1.RemoveItem(i);
+ this.route_2.RemoveItem(i);
/* XXX -- We should free the towns_used entries too */
}
this.vehicle_to_depot.rawdelete(i);
@@ -277,6 +276,26 @@
}
}
+function WrightAI::HandleEvents()
+{
+ while (AIEventController.IsEventWaiting()) {
+ local e = AIEventController.GetNextEvent();
+ switch (e.GetEventType()) {
+ case AIEvent.AI_ET_CRASHED_VEHICLE:
+ local ec = AIEventVehicleCrash.Convert(e);
+ local v = ec.GetVehicleID();
+ print(this.name + ": [INFO] We have a crashed vehicle (" + v + "), buying a new one as replacement");
+ this.BuildAircraft(this.route_1.GetValue(v), this.route_2.GetValue(v));
+ this.route_1.RemoveItem(v);
+ this.route_2.RemoveItem(v);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
function WrightAI::Start()
{
/* Sleep 1 tick, as we can't execute anything in tick 0 */
@@ -316,6 +335,10 @@
if (ticker % 5000 == 0) {
this.company.SetLoanAmount(0);
}
+ /* Check for events once in a while */
+ if (ticker % 100 == 0) {
+ this.HandleEvents();
+ }
/* Make sure we do not create infinite loops */
Sleep(1);
}
--- a/projects/openttd.vcproj Thu Jul 19 22:26:26 2007 +0000
+++ b/projects/openttd.vcproj Thu Jul 19 22:39:43 2007 +0000
@@ -1096,6 +1096,12 @@
RelativePath=".\..\src\ai\api\ai_controller.hpp">
</File>
<File
+ RelativePath=".\..\src\ai\api\ai_event.hpp">
+ </File>
+ <File
+ RelativePath=".\..\src\ai\api\ai_event_types.hpp">
+ </File>
+ <File
RelativePath=".\..\src\ai\api\ai_execmode.hpp">
</File>
<File
@@ -1205,6 +1211,12 @@
RelativePath=".\..\src\ai\api\ai_controller.cpp">
</File>
<File
+ RelativePath=".\..\src\ai\api\ai_event.cpp">
+ </File>
+ <File
+ RelativePath=".\..\src\ai\api\ai_event_types.cpp">
+ </File>
+ <File
RelativePath=".\..\src\ai\api\ai_execmode.cpp">
</File>
<File
--- a/projects/openttd_vs80.vcproj Thu Jul 19 22:26:26 2007 +0000
+++ b/projects/openttd_vs80.vcproj Thu Jul 19 22:39:43 2007 +0000
@@ -1680,6 +1680,14 @@
>
</File>
<File
+ RelativePath=".\..\src\ai\api\ai_event.hpp"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\ai\api\ai_event_types.hpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\ai\api\ai_execmode.hpp"
>
</File>
@@ -1824,6 +1832,14 @@
>
</File>
<File
+ RelativePath=".\..\src\ai\api\ai_event.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\ai\api\ai_event_types.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\ai\api\ai_execmode.cpp"
>
</File>
--- a/source.list Thu Jul 19 22:26:26 2007 +0000
+++ b/source.list Thu Jul 19 22:39:43 2007 +0000
@@ -338,6 +338,8 @@
ai/api/ai_cargo.hpp
ai/api/ai_company.hpp
ai/api/ai_controller.hpp
+ai/api/ai_event.hpp
+ai/api/ai_event_types.hpp
ai/api/ai_execmode.hpp
ai/api/ai_industry.hpp
ai/api/ai_industrylist.hpp
@@ -375,6 +377,8 @@
ai/api/ai_cargo.cpp
ai/api/ai_company.cpp
ai/api/ai_controller.cpp
+ai/api/ai_event.cpp
+ai/api/ai_event_types.cpp
ai/api/ai_execmode.cpp
ai/api/ai_industry.cpp
ai/api/ai_industrylist.cpp
--- a/src/ai/ai.cpp Thu Jul 19 22:26:26 2007 +0000
+++ b/src/ai/ai.cpp Thu Jul 19 22:39:43 2007 +0000
@@ -59,6 +59,16 @@
_current_player = OWNER_NONE;
}
+void AI_Event(PlayerID player, AIEvent *event)
+{
+ DEBUG(ai, 4, "Event (%d) for player %d\n", event->GetEventType(), player);
+
+ PlayerID old_player = _current_player;
+ _current_player = player;
+ AIEventController::InsertEvent(event);
+ _current_player = old_player;
+}
+
/**
* A new AI sees the day of light. You can do here what ever you think is needed.
*/
@@ -167,6 +177,7 @@
void AI_StartNewAI(PlayerID player) { DEBUG(ai, 0, "Threading is disabled and therefor the AI too."); }
void AI_PlayerDied(PlayerID player) {}
void AI_RunGameLoop() {}
+void AI_Event(PlayerID player, AIEvent *event) {}
void AI_Initialize() {}
void AI_Uninitialize() {}
bool AI_AllowNewAI() { return false; }
--- a/src/ai/ai.h Thu Jul 19 22:26:26 2007 +0000
+++ b/src/ai/ai.h Thu Jul 19 22:39:43 2007 +0000
@@ -5,6 +5,8 @@
#ifndef AI_H
#define AI_H
+#include "api/ai_event_types.hpp"
+
void AI_StartNewAI(PlayerID player);
void AI_PlayerDied(PlayerID player);
void AI_RunGameLoop();
@@ -12,6 +14,7 @@
void AI_Uninitialize();
bool AI_AllowNewAI();
void AI_ForceAI(const char *forced_ai);
+void AI_Event(PlayerID player, AIEvent *event);
void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2);
--- a/src/ai/ai_squirrel.cpp Thu Jul 19 22:26:26 2007 +0000
+++ b/src/ai/ai_squirrel.cpp Thu Jul 19 22:39:43 2007 +0000
@@ -28,6 +28,8 @@
#include "api/ai_cargo.hpp.sq"
#include "api/ai_company.hpp.sq"
#include "api/ai_controller.hpp.sq"
+#include "api/ai_event.hpp.sq"
+#include "api/ai_event_types.hpp.sq"
#include "api/ai_execmode.hpp.sq"
#include "api/ai_industry.hpp.sq"
#include "api/ai_industrylist.hpp.sq"
@@ -214,6 +216,10 @@
SQAICargoRegister(this->engine);
SQAICompanyRegister(this->engine);
SQAIControllerRegister(this->engine);
+ SQAIEventControllerRegister(this->engine);
+ SQAIEventRegister(this->engine);
+ SQAIEventTestRegister(this->engine);
+ SQAIEventVehicleCrashRegister(this->engine);
SQAIExecModeRegister(this->engine);
SQAIIndustryListDistanceManhattanToTileRegister(this->engine);
SQAIIndustryListDistanceSquareToTileRegister(this->engine);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/api/ai_event.cpp Thu Jul 19 22:39:43 2007 +0000
@@ -0,0 +1,115 @@
+#include "ai_event.hpp"
+/* TODO -- This include has to go */
+#include "ai_event_types.hpp"
+
+#include <queue>
+#include <set>
+
+struct AIEventData {
+ std::queue<AIEvent *> stack;
+ std::set<AIEvent::AIEventType> events;
+ bool events_disabled;
+
+ AIEventData() :
+ events_disabled(false)
+ {}
+};
+
+/* static */ void AIEventController::CreateEventPointer()
+{
+ assert(AIObject::GetEventPointer() == NULL);
+
+ AIObject::GetEventPointer() = new AIEventData();
+}
+
+/* static */ void AIEventController::FreeEventPointer()
+{
+ AIEventData *data = (AIEventData *)AIObject::GetEventPointer();
+
+ /* Free up the event-list */
+ data->events.clear();
+
+ /* Free all waiting events (if any) */
+ while (!data->stack.empty()) {
+ AIEvent *e = data->stack.front();
+ data->stack.pop();
+ delete e;
+ }
+
+ /* Now kill our data pointer */
+ delete data;
+}
+
+/* static */ bool AIEventController::IsEventWaiting()
+{
+ if (AIObject::GetEventPointer() == NULL) AIEventController::CreateEventPointer();
+ AIEventData *data = (AIEventData *)AIObject::GetEventPointer();
+
+ return !data->stack.empty();
+}
+
+/* static */ AIEvent *AIEventController::GetNextEvent()
+{
+ if (AIObject::GetEventPointer() == NULL) AIEventController::CreateEventPointer();
+ AIEventData *data = (AIEventData *)AIObject::GetEventPointer();
+
+ if (data->stack.empty()) return NULL;
+
+ AIEvent *e = data->stack.front();
+ data->stack.pop();
+ return e;
+}
+
+/* static */ void AIEventController::DisableEvent(AIEvent::AIEventType event)
+{
+ if (AIObject::GetEventPointer() == NULL) AIEventController::CreateEventPointer();
+ AIEventData *data = (AIEventData *)AIObject::GetEventPointer();
+
+ if (data->events_disabled) data->events.erase(event);
+ else data->events.insert(event);
+}
+
+/* static */ void AIEventController::EnableEvent(AIEvent::AIEventType event)
+{
+ if (AIObject::GetEventPointer() == NULL) AIEventController::CreateEventPointer();
+ AIEventData *data = (AIEventData *)AIObject::GetEventPointer();
+
+ if (!data->events_disabled) data->events.erase(event);
+ else data->events.insert(event);
+}
+
+/* static */ void AIEventController::DisableAllEvents()
+{
+ if (AIObject::GetEventPointer() == NULL) AIEventController::CreateEventPointer();
+ AIEventData *data = (AIEventData *)AIObject::GetEventPointer();
+
+ data->events_disabled = true;
+ data->events.clear();
+}
+
+/* static */ void AIEventController::EnableAllEvents()
+{
+ if (AIObject::GetEventPointer() == NULL) AIEventController::CreateEventPointer();
+ AIEventData *data = (AIEventData *)AIObject::GetEventPointer();
+
+ data->events_disabled = false;
+ data->events.clear();
+}
+
+/* static */ void AIEventController::InsertEvent(AIEvent *event)
+{
+ if (AIObject::GetEventPointer() == NULL) AIEventController::CreateEventPointer();
+ AIEventData *data = (AIEventData *)AIObject::GetEventPointer();
+
+ /* If events_disabled is true, the list shows only the enabled events.
+ * If events_disabled is false, the list shows only the disabled events. */
+ if (data->events_disabled && data->events.count(event->GetEventType()) == 0) return;
+ if (!data->events_disabled && data->events.count(event->GetEventType()) != 0) return;
+
+ data->stack.push(event);
+}
+
+/* static */ void AIEventController::Test()
+{
+ AIEventController::InsertEvent(new AIEventTest(42));
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/api/ai_event.hpp Thu Jul 19 22:39:43 2007 +0000
@@ -0,0 +1,116 @@
+/* $Id$ */
+
+/** @file ai_event.hpp Everything to handle events from the game */
+
+#ifndef AI_EVENT_HPP
+#define AI_EVENT_HPP
+
+#include "ai_object.hpp"
+
+/**
+ * A single event that can be triggered by the game.
+ * You can lookup the type, and than convert it to the real event-class.
+ * That way you can request more detailed information about the event.
+ */
+class AIEvent : public AIObject {
+public:
+ /**
+ * The type of event. Needed to lookup the detailed class.
+ */
+ enum AIEventType {
+ AI_ET_INVALID = 0,
+ AI_ET_TEST,
+ AI_ET_CRASHED_VEHICLE,
+ };
+
+ AIEvent(AIEvent::AIEventType type) :
+ type(type)
+ {}
+
+ /**
+ * Get the event-type.
+ */
+ AIEventType GetEventType() { return this->type; }
+
+ /**
+ * The name of the class, needed by several sub-processes.
+ */
+ static const char *GetClassName() { return "AIEvent"; }
+
+protected:
+ /**
+ * The type of this event.
+ */
+ AIEventType type;
+};
+
+/**
+ * Class that handles all event related functions.
+ * @note it is not needed to create an instance of AIEvent to access it, as
+ * all members are static, and all data is stored AI-wide.
+ */
+class AIEventController : public AIObject {
+public:
+ /**
+ * The name of the class, needed by several sub-processes.
+ */
+ static const char *GetClassName() { return "AIEventController"; }
+
+ /**
+ * Check if there is an event waiting.
+ * @return true if there is an event on the stack.
+ */
+ static bool IsEventWaiting();
+
+ /**
+ * Get the next event.
+ * @return a class of the event-child issues.
+ */
+ static AIEvent *GetNextEvent();
+
+ /**
+ * No longer report an event of this type.
+ * @param event the event to no longer report.
+ */
+ static void DisableEvent(AIEvent::AIEventType event);
+
+ /**
+ * Report events of this type.
+ * @param event the event to report again.
+ */
+ static void EnableEvent(AIEvent::AIEventType event);
+
+ /**
+ * Disable all events.
+ */
+ static void DisableAllEvents();
+
+ /**
+ * Enable all events.
+ */
+ static void EnableAllEvents();
+
+ /**
+ * Insert an event to the queue for the player.
+ */
+ static void InsertEvent(AIEvent *event);
+
+ /**
+ * Give a test event to the system.
+ */
+ static void Test();
+
+ /**
+ * Free the event pointer.
+ * @note DO NOT CALL YOURSELF; leave it to the internal AI programming.
+ */
+ static void FreeEventPointer();
+
+private:
+ /**
+ * Create the event pointer.
+ */
+ static void CreateEventPointer();
+};
+
+#endif /* AI_EVENT_HPP */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/api/ai_event.hpp.sq Thu Jul 19 22:39:43 2007 +0000
@@ -0,0 +1,58 @@
+#include "ai_event.hpp"
+
+namespace SQConvert {
+ /* Allow enums to be used as Squirrel parameters */
+ template <> AIEvent::AIEventType GetParam(ForceType<AIEvent::AIEventType>, HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (AIEvent::AIEventType)tmp; }
+ template <> int Return<AIEvent::AIEventType>(HSQUIRRELVM vm, AIEvent::AIEventType res) { sq_pushinteger(vm, (int32)res); return 1; }
+
+ /* Allow AIEvent to be used as Squirrel parameter */
+ template <> AIEvent *GetParam(ForceType<AIEvent *>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEvent *)instance; }
+ template <> AIEvent &GetParam(ForceType<AIEvent &>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEvent *)instance; }
+ template <> const AIEvent *GetParam(ForceType<const AIEvent *>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEvent *)instance; }
+ template <> const AIEvent &GetParam(ForceType<const AIEvent &>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEvent *)instance; }
+ template <> int Return<AIEvent *>(HSQUIRRELVM vm, AIEvent *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIEvent", res, NULL, DefSQDestructorCallback<AIEvent>); return 1; }
+}; // namespace SQConvert
+
+void SQAIEventRegister(Squirrel *engine) {
+ DefSQClass <AIEvent> SQAIEvent("AIEvent");
+ SQAIEvent.PreRegister(engine);
+ SQAIEvent.AddConstructor<void (AIEvent::*)(AIEvent::AIEventType type), 2>(engine, "xi");
+
+ SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_INVALID, "AI_ET_INVALID");
+ SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_TEST, "AI_ET_TEST");
+ SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_CRASHED_VEHICLE, "AI_ET_CRASHED_VEHICLE");
+
+ SQAIEvent.DefSQStaticMethod(engine, &AIEvent::GetClassName, "GetClassName", 1, "x");
+
+ SQAIEvent.DefSQMethod(engine, &AIEvent::GetEventType, "GetEventType", 1, "x");
+
+ SQAIEvent.PostRegister(engine);
+}
+
+namespace SQConvert {
+ /* Allow AIEventController to be used as Squirrel parameter */
+ template <> AIEventController *GetParam(ForceType<AIEventController *>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEventController *)instance; }
+ template <> AIEventController &GetParam(ForceType<AIEventController &>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEventController *)instance; }
+ template <> const AIEventController *GetParam(ForceType<const AIEventController *>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEventController *)instance; }
+ template <> const AIEventController &GetParam(ForceType<const AIEventController &>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEventController *)instance; }
+ template <> int Return<AIEventController *>(HSQUIRRELVM vm, AIEventController *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIEventController", res, NULL, DefSQDestructorCallback<AIEventController>); return 1; }
+}; // namespace SQConvert
+
+void SQAIEventControllerRegister(Squirrel *engine) {
+ DefSQClass <AIEventController> SQAIEventController("AIEventController");
+ SQAIEventController.PreRegister(engine);
+ SQAIEventController.AddConstructor<void (AIEventController::*)(), 1>(engine, "x");
+
+ SQAIEventController.DefSQStaticMethod(engine, &AIEventController::GetClassName, "GetClassName", 1, "x");
+ SQAIEventController.DefSQStaticMethod(engine, &AIEventController::IsEventWaiting, "IsEventWaiting", 1, "x");
+ SQAIEventController.DefSQStaticMethod(engine, &AIEventController::GetNextEvent, "GetNextEvent", 1, "x");
+ SQAIEventController.DefSQStaticMethod(engine, &AIEventController::DisableEvent, "DisableEvent", 2, "xi");
+ SQAIEventController.DefSQStaticMethod(engine, &AIEventController::EnableEvent, "EnableEvent", 2, "xi");
+ SQAIEventController.DefSQStaticMethod(engine, &AIEventController::DisableAllEvents, "DisableAllEvents", 1, "x");
+ SQAIEventController.DefSQStaticMethod(engine, &AIEventController::EnableAllEvents, "EnableAllEvents", 1, "x");
+ SQAIEventController.DefSQStaticMethod(engine, &AIEventController::InsertEvent, "InsertEvent", 2, "xx");
+ SQAIEventController.DefSQStaticMethod(engine, &AIEventController::Test, "Test", 1, "x");
+ SQAIEventController.DefSQStaticMethod(engine, &AIEventController::FreeEventPointer, "FreeEventPointer", 1, "x");
+
+ SQAIEventController.PostRegister(engine);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/api/ai_event_types.cpp Thu Jul 19 22:39:43 2007 +0000
@@ -0,0 +1,6 @@
+#include "ai_event_types.hpp"
+
+bool AIEventVehicleCrash::CloneCrashedVehicle(TileIndex depot)
+{
+ return false;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/api/ai_event_types.hpp Thu Jul 19 22:39:43 2007 +0000
@@ -0,0 +1,93 @@
+/* $Id$ */
+
+/** @file ai_event_types.hpp The detailed types of all events */
+
+#ifndef AI_EVENT_TYPES_HPP
+#define AI_EVENT_TYPES_HPP
+
+#include "ai_object.hpp"
+#include "ai_event.hpp"
+
+/**
+ * A simple test event, to see if the event system is working. Triggered via
+ * AIEventController::Test();
+ */
+class AIEventTest : public AIEvent {
+public:
+ /**
+ * The name of the class, needed by several sub-processes.
+ */
+ static const char *GetClassName() { return "AIEventTest"; }
+
+ /**
+ * Constructor for this event class.
+ */
+ AIEventTest(uint test) :
+ AIEvent(AI_ET_TEST),
+ test(test)
+ {}
+
+ /**
+ * Convert an AIEvent to the real instance.
+ */
+ static AIEventTest *Convert(AIEvent *instance) { return (AIEventTest *)instance; }
+
+ /**
+ * Return the test value.
+ */
+ uint GetTest() { return this->test; }
+
+private:
+ uint test;
+};
+
+/**
+ * A vehicle crashed, and because of that this event is triggered.
+ * It contains both the crash site as the vehicle crashed. It has a nice
+ * helper that creates a new vehicle in a depot with the same type
+ * and orders as the crashed one. In case the vehicle type isn't available
+ * anymore, it will find the next best.
+ */
+class AIEventVehicleCrash : public AIEvent {
+public:
+ /**
+ * The name of the class, needed by several sub-processes.
+ */
+ static const char *GetClassName() { return "AIEventVehicleCrash"; }
+
+ /**
+ * Constructor for this event class.
+ */
+ AIEventVehicleCrash(VehicleID vehicle, TileIndex crash_site) :
+ AIEvent(AI_ET_CRASHED_VEHICLE),
+ crash_site(crash_site),
+ vehicle(vehicle)
+ {}
+
+ /**
+ * Convert an AIEvent to the real instance.
+ */
+ static AIEventVehicleCrash *Convert(AIEvent *instance) { return (AIEventVehicleCrash *)instance; }
+
+ /**
+ * Get the vehicleID of the crashed vehicle.
+ */
+ VehicleID GetVehicleID() { return vehicle; }
+
+ /**
+ * Find the tile the vehicle crashed.
+ */
+ TileIndex GetCrashSite() { return crash_site; }
+
+ /**
+ * Clone the crashed vehicle and send it on its way again/
+ * @param depot the depot to build the vehicle in.
+ */
+ bool CloneCrashedVehicle(TileIndex depot);
+
+private:
+ TileIndex crash_site;
+ VehicleID vehicle;
+};
+
+#endif /* AI_EVENT_TYPES_HPP */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/api/ai_event_types.hpp.sq Thu Jul 19 22:39:43 2007 +0000
@@ -0,0 +1,47 @@
+#include "ai_event_types.hpp"
+
+namespace SQConvert {
+ /* Allow AIEventTest to be used as Squirrel parameter */
+ template <> AIEventTest *GetParam(ForceType<AIEventTest *>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEventTest *)instance; }
+ template <> AIEventTest &GetParam(ForceType<AIEventTest &>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEventTest *)instance; }
+ template <> const AIEventTest *GetParam(ForceType<const AIEventTest *>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEventTest *)instance; }
+ template <> const AIEventTest &GetParam(ForceType<const AIEventTest &>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEventTest *)instance; }
+ template <> int Return<AIEventTest *>(HSQUIRRELVM vm, AIEventTest *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIEventTest", res, NULL, DefSQDestructorCallback<AIEventTest>); return 1; }
+}; // namespace SQConvert
+
+void SQAIEventTestRegister(Squirrel *engine) {
+ DefSQClass <AIEventTest> SQAIEventTest("AIEventTest");
+ SQAIEventTest.PreRegister(engine, "AIEvent");
+ SQAIEventTest.AddConstructor<void (AIEventTest::*)(uint test), 2>(engine, "xi");
+
+ SQAIEventTest.DefSQStaticMethod(engine, &AIEventTest::GetClassName, "GetClassName", 1, "x");
+ SQAIEventTest.DefSQStaticMethod(engine, &AIEventTest::Convert, "Convert", 2, "xx");
+
+ SQAIEventTest.DefSQMethod(engine, &AIEventTest::GetTest, "GetTest", 1, "x");
+
+ SQAIEventTest.PostRegister(engine);
+}
+
+namespace SQConvert {
+ /* Allow AIEventVehicleCrash to be used as Squirrel parameter */
+ template <> AIEventVehicleCrash *GetParam(ForceType<AIEventVehicleCrash *>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEventVehicleCrash *)instance; }
+ template <> AIEventVehicleCrash &GetParam(ForceType<AIEventVehicleCrash &>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEventVehicleCrash *)instance; }
+ template <> const AIEventVehicleCrash *GetParam(ForceType<const AIEventVehicleCrash *>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEventVehicleCrash *)instance; }
+ template <> const AIEventVehicleCrash &GetParam(ForceType<const AIEventVehicleCrash &>, HSQUIRRELVM vm, int index) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEventVehicleCrash *)instance; }
+ template <> int Return<AIEventVehicleCrash *>(HSQUIRRELVM vm, AIEventVehicleCrash *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIEventVehicleCrash", res, NULL, DefSQDestructorCallback<AIEventVehicleCrash>); return 1; }
+}; // namespace SQConvert
+
+void SQAIEventVehicleCrashRegister(Squirrel *engine) {
+ DefSQClass <AIEventVehicleCrash> SQAIEventVehicleCrash("AIEventVehicleCrash");
+ SQAIEventVehicleCrash.PreRegister(engine, "AIEvent");
+ SQAIEventVehicleCrash.AddConstructor<void (AIEventVehicleCrash::*)(VehicleID vehicle, TileIndex crash_site), 3>(engine, "xii");
+
+ SQAIEventVehicleCrash.DefSQStaticMethod(engine, &AIEventVehicleCrash::GetClassName, "GetClassName", 1, "x");
+ SQAIEventVehicleCrash.DefSQStaticMethod(engine, &AIEventVehicleCrash::Convert, "Convert", 2, "xx");
+
+ SQAIEventVehicleCrash.DefSQMethod(engine, &AIEventVehicleCrash::GetVehicleID, "GetVehicleID", 1, "x");
+ SQAIEventVehicleCrash.DefSQMethod(engine, &AIEventVehicleCrash::GetCrashSite, "GetCrashSite", 1, "x");
+ SQAIEventVehicleCrash.DefSQMethod(engine, &AIEventVehicleCrash::CloneCrashedVehicle, "CloneCrashedVehicle", 2, "xi");
+
+ SQAIEventVehicleCrash.PostRegister(engine);
+}
--- a/src/ai/api/ai_object.cpp Thu Jul 19 22:26:26 2007 +0000
+++ b/src/ai/api/ai_object.cpp Thu Jul 19 22:39:43 2007 +0000
@@ -72,15 +72,22 @@
return AIObject::GetDoCommandStruct(_current_player)->new_sign_id;
}
-void **AIObject::GetEventPointer()
+void *&AIObject::GetEventPointer()
{
- return &AIObject::GetDoCommandStruct(_current_player)->event_data;
+ return AIObject::GetDoCommandStruct(_current_player)->event_data;
}
AIObject::AIDoCommandStruct *AIObject::GetDoCommandStruct(PlayerID player)
{
/* Storage for data on per-AI level */
static AIObject::AIDoCommandStruct command_struct[MAX_PLAYERS];
+ static bool initialized = false;
+
+ /* Make sure all memory is NULL when we start */
+ if (!initialized) {
+ initialized = true;
+ memset(&command_struct, 0, sizeof(command_struct));
+ }
return &command_struct[player];
}
@@ -91,6 +98,8 @@
command_struct->mode = NULL;
command_struct->delay = 1;
command_struct->costs = CommandCost();
+ if (command_struct->event_data != NULL) AIEventController::FreeEventPointer();
+ command_struct->event_data = NULL;
}
bool AIObject::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint procc)
--- a/src/ai/api/ai_object.hpp Thu Jul 19 22:26:26 2007 +0000
+++ b/src/ai/api/ai_object.hpp Thu Jul 19 22:39:43 2007 +0000
@@ -96,7 +96,7 @@
/**
* Get the pointer to store event data in.
*/
- static void **GetEventPointer();
+ static void *&GetEventPointer();
public:
/**
--- a/src/aircraft_cmd.cpp Thu Jul 19 22:26:26 2007 +0000
+++ b/src/aircraft_cmd.cpp Thu Jul 19 22:39:43 2007 +0000
@@ -33,6 +33,7 @@
#include "date.h"
#include "spritecache.h"
#include "cargotype.h"
+#include "ai/ai.h"
void Aircraft::UpdateDeltaXY(Direction direction)
{
@@ -1438,6 +1439,8 @@
newsitem = STR_A034_PLANE_CRASH_DIE_IN_FIREBALL;
}
+ AI_Event(v->owner, new AIEventVehicleCrash(v->index, v->tile));
+
SetDParam(1, st->index);
AddNewsItem(newsitem,
NEWS_FLAGS(NM_THIN, NF_VIEWPORT|NF_VEHICLE, NT_ACCIDENT, 0),
--- a/src/roadveh_cmd.cpp Thu Jul 19 22:26:26 2007 +0000
+++ b/src/roadveh_cmd.cpp Thu Jul 19 22:39:43 2007 +0000
@@ -36,6 +36,7 @@
#include "yapf/yapf.h"
#include "date.h"
#include "cargotype.h"
+#include "ai/ai.h"
static const uint16 _roadveh_images[63] = {
0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14,
@@ -688,6 +689,8 @@
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+ AI_Event(v->owner, new AIEventVehicleCrash(v->index, v->tile));
+
SetDParam(0, pass);
AddNewsItem(
(pass == 1) ?
--- a/src/train_cmd.cpp Thu Jul 19 22:26:26 2007 +0000
+++ b/src/train_cmd.cpp Thu Jul 19 22:39:43 2007 +0000
@@ -40,6 +40,7 @@
#include "date.h"
#include "cargotype.h"
#include "group.h"
+#include "ai/ai.h"
static bool TrainCheckIfLineEnds(Vehicle *v);
static void TrainController(Vehicle *v, bool update_image);
@@ -2764,6 +2765,7 @@
/* any dead -> no crash */
if (tcc.num == 0) return;
+ AI_Event(v->owner, new AIEventVehicleCrash(v->index, v->tile));
SetDParam(0, tcc.num);
AddNewsItem(STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL,
NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, 0),