(svn r9179) [NoAI] -Add: added templates that makes adding classes to squirrel very easy
-Update: SQNoAI does now exactly what NoAI does
--- a/bin/ai/SQNoAI/main.nut Wed Mar 14 12:42:37 2007 +0000
+++ b/bin/ai/SQNoAI/main.nut Wed Mar 14 20:22:07 2007 +0000
@@ -1,12 +1,45 @@
/* Extend our own AI from AIController so we can access basic things. */
class SQNoAI extends AIController {
+ base = AIBase();
+ company = AICompany();
+ map = AIMap();
+ town = AITown();
+
function GameLoop();
}
/* Define the GameLoop. This is called every tick. */
function SQNoAI::GameLoop()
{
- print("GameLoop " + this.GetTick());
+ if (this.GetTick() == 1) {
+ this.company.SetCompanyName("SQNoAI");
+ print("Map size: " + this.map.GetMapSizeX() + " by " +
+ this.map.GetMapSizeY() + ", " + this.map.GetMapSize() + " tiles");
+ }
+
+ if (this.GetTick() % 10 == 0) {
+ local company_name = this.company.GetCompanyName();
+ print(company_name + " has loaned " + this.company.GetLoanAmount());
+ }
+
+ if (this.GetTick() % 14 == 0) {
+ local level = (this.company.GetMaxLoanAmount() / this.company.GetLoanInterval()) + 1;
+ this.company.SetLoanAmount(this.base.RandomRange(level) * this.company.GetLoanInterval());
+ }
+
+ if (this.GetTick() % 13 == 0) {
+ local town_id = this.base.RandomRange(this.town.GetMaxTownID());
+ if (!this.town.IsValidTown(town_id)) {
+ print("He, an invalid town ID... could happen :(");
+ } else {
+ local town_name = this.town.GetName(town_id);
+ local t = this.town.GetLocation(town_id);
+
+ print("Town " + town_name + " [" + town_id + " of " + this.town.GetTownCount() +
+ "] at (" + this.map.GetTileX(t) + ", " + this.map.GetTileY(t) + ") with " +
+ this.town.GetPopulation(town_id) + " inhabitants");
+ }
+ }
}
/* Tell OpenTTD we have an AI */
--- a/projects/openttd.vcproj Wed Mar 14 12:42:37 2007 +0000
+++ b/projects/openttd.vcproj Wed Mar 14 20:22:07 2007 +0000
@@ -954,11 +954,20 @@
RelativePath=".\..\src\ai\NoAI\NoAI.hpp">
</File>
<File
+ RelativePath=".\..\src\ai\squirrel\convert.cpp">
+ </File>
+ <File
+ RelativePath=".\..\src\ai\squirrel\convert.hpp">
+ </File>
+ <File
RelativePath=".\..\src\ai\squirrel\squirrel.cpp">
</File>
<File
RelativePath=".\..\src\ai\squirrel\squirrel.hpp">
</File>
+ <File
+ RelativePath=".\..\src\ai\squirrel\squirrel_class.hpp">
+ </File>
</Filter>
<Filter
Name="NewGRF"
--- a/projects/openttd_vs80.vcproj Wed Mar 14 12:42:37 2007 +0000
+++ b/projects/openttd_vs80.vcproj Wed Mar 14 20:22:07 2007 +0000
@@ -1492,6 +1492,14 @@
>
</File>
<File
+ RelativePath=".\..\src\ai\squirrel\convert.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\ai\squirrel\convert.hpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\ai\squirrel\squirrel.cpp"
>
</File>
@@ -1499,6 +1507,10 @@
RelativePath=".\..\src\ai\squirrel\squirrel.hpp"
>
</File>
+ <File
+ RelativePath=".\..\src\ai\squirrel\squirrel_class.hpp"
+ >
+ </File>
</Filter>
<Filter
Name="NewGRF"
--- a/source.list Wed Mar 14 12:42:37 2007 +0000
+++ b/source.list Wed Mar 14 20:22:07 2007 +0000
@@ -289,8 +289,11 @@
# AIs
ai/NoAI/NoAI.cpp
ai/NoAI/NoAI.hpp
+ai/squirrel/convert.cpp
+ai/squirrel/convert.hpp
ai/squirrel/squirrel.cpp
ai/squirrel/squirrel.hpp
+ai/squirrel/squirrel_class.hpp
# NewGRF
newgrf.cpp
--- a/src/ai/core/ai_base.hpp Wed Mar 14 12:42:37 2007 +0000
+++ b/src/ai/core/ai_base.hpp Wed Mar 14 20:22:07 2007 +0000
@@ -39,4 +39,15 @@
bool Chance(uint out, uint max);
};
+#ifdef SQUIRREL_CLASS
+void SQAIBaseRegister(HSQUIRRELVM vm) {
+ DefSQClass <AIBase> SQAIBase("AIBase");
+ SQAIBase.PreRegister(vm);
+ SQAIBase.DefSQFunction(vm, &AIBase::Random, "Random");
+ SQAIBase.DefSQFunction(vm, &AIBase::RandomRange, "RandomRange");
+ SQAIBase.DefSQFunction(vm, &AIBase::Chance, "Chance");
+ SQAIBase.PostRegister(vm);
+}
+#endif /* SQUIRREL_CLASS */
+
#endif /* AI_BASE_HPP */
--- a/src/ai/core/ai_company.hpp Wed Mar 14 12:42:37 2007 +0000
+++ b/src/ai/core/ai_company.hpp Wed Mar 14 20:22:07 2007 +0000
@@ -71,4 +71,20 @@
bool SetLoanAmount(int32 loan);
};
+#ifdef SQUIRREL_CLASS
+void SQAICompanyRegister(HSQUIRRELVM vm) {
+ DefSQClass <AICompany> SQAICompany("AICompany");
+ SQAICompany.PreRegister(vm);
+ SQAICompany.DefSQFunction(vm, &AICompany::SetCompanyName, "SetCompanyName");
+ SQAICompany.DefSQFunction(vm, &AICompany::GetCompanyName, "GetCompanyName");
+ SQAICompany.DefSQFunction(vm, &AICompany::GetCompanyValue, "GetCompanyValue");
+ SQAICompany.DefSQFunction(vm, &AICompany::GetBankBalance, "GetBankBalance");
+ SQAICompany.DefSQFunction(vm, &AICompany::GetLoanAmount, "GetLoanAmount");
+ SQAICompany.DefSQFunction(vm, &AICompany::GetMaxLoanAmount, "GetMaxLoanAmount");
+ SQAICompany.DefSQFunction(vm, &AICompany::GetLoanInterval, "GetLoanInterval");
+ SQAICompany.DefSQFunction(vm, &AICompany::SetLoanAmount, "SetLoanAmount");
+ SQAICompany.PostRegister(vm);
+}
+#endif /* SQUIRREL_CLASS */
+
#endif /* AI_COMPANY_HPP */
--- a/src/ai/core/ai_map.hpp Wed Mar 14 12:42:37 2007 +0000
+++ b/src/ai/core/ai_map.hpp Wed Mar 14 20:22:07 2007 +0000
@@ -56,4 +56,18 @@
uint32 GetTileY(TileIndex t);
};
+#ifdef SQUIRREL_CLASS
+void SQAIMapRegister(HSQUIRRELVM vm) {
+ DefSQClass <AIMap> SQAIMap("AIMap");
+ SQAIMap.PreRegister(vm);
+ SQAIMap.DefSQFunction(vm, &AIMap::IsValidTile, "IsValidTile");
+ SQAIMap.DefSQFunction(vm, &AIMap::GetMapSize, "GetMapSize");
+ SQAIMap.DefSQFunction(vm, &AIMap::GetMapSizeX, "GetMapSizeX");
+ SQAIMap.DefSQFunction(vm, &AIMap::GetMapSizeY, "GetMapSizeY");
+ SQAIMap.DefSQFunction(vm, &AIMap::GetTileX, "GetTileX");
+ SQAIMap.DefSQFunction(vm, &AIMap::GetTileY, "GetTileY");
+ SQAIMap.PostRegister(vm);
+}
+#endif /* SQUIRREL_CLASS */
+
#endif /* AI_MAP_HPP */
--- a/src/ai/core/ai_town.hpp Wed Mar 14 12:42:37 2007 +0000
+++ b/src/ai/core/ai_town.hpp Wed Mar 14 20:22:07 2007 +0000
@@ -58,4 +58,18 @@
TileIndex GetLocation(TownID town_id);
};
+#ifdef SQUIRREL_CLASS
+void SQAITownRegister(HSQUIRRELVM vm) {
+ DefSQClass <AITown> SQAITown("AITown");
+ SQAITown.PreRegister(vm);
+ SQAITown.DefSQFunction(vm, &AITown::GetMaxTownID, "GetMaxTownID");
+ SQAITown.DefSQFunction(vm, &AITown::GetTownCount, "GetTownCount");
+ SQAITown.DefSQFunction(vm, &AITown::IsValidTown, "IsValidTown");
+ SQAITown.DefSQFunction(vm, &AITown::GetName, "GetName");
+ SQAITown.DefSQFunction(vm, &AITown::GetPopulation, "GetPopulation");
+ SQAITown.DefSQFunction(vm, &AITown::GetLocation, "GetLocation");
+ SQAITown.PostRegister(vm);
+}
+#endif /* SQUIRREL_CLASS */
+
#endif /* AI_TOWN_HPP */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/squirrel/convert.cpp Wed Mar 14 20:22:07 2007 +0000
@@ -0,0 +1,24 @@
+/* $Id$ */
+
+/** @file convert.cpp parts of the implementation of the class for convert code */
+
+#include "squirrel.hpp"
+#include "convert.hpp"
+
+template <> int SQConvert::Return<uint8> (HSQUIRRELVM vm, uint8 res) { sq_pushinteger(vm, res); return 1; }
+template <> int SQConvert::Return<uint16>(HSQUIRRELVM vm, uint16 res) { sq_pushinteger(vm, res); return 1; }
+template <> int SQConvert::Return<uint32>(HSQUIRRELVM vm, uint32 res) { sq_pushinteger(vm, res); return 1; }
+template <> int SQConvert::Return<int8> (HSQUIRRELVM vm, int8 res) { sq_pushinteger(vm, res); return 1; }
+template <> int SQConvert::Return<int16> (HSQUIRRELVM vm, int16 res) { sq_pushinteger(vm, res); return 1; }
+template <> int SQConvert::Return<int32> (HSQUIRRELVM vm, int32 res) { sq_pushinteger(vm, res); return 1; }
+template <> int SQConvert::Return<bool> (HSQUIRRELVM vm, bool res) { sq_pushbool (vm, res); return 1; }
+template <> int SQConvert::Return<char *>(HSQUIRRELVM vm, char *res) { sq_pushstring (vm, res, strlen(res)); free(res); return 1; }
+
+template <> uint8 SQConvert::GetParam(ForceType<uint8> , HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return tmp; }
+template <> uint16 SQConvert::GetParam(ForceType<uint16> , HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return tmp; }
+template <> uint32 SQConvert::GetParam(ForceType<uint32> , HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return tmp; }
+template <> int8 SQConvert::GetParam(ForceType<int8> , HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return tmp; }
+template <> int16 SQConvert::GetParam(ForceType<int16> , HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return tmp; }
+template <> int32 SQConvert::GetParam(ForceType<int32> , HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return tmp; }
+template <> bool SQConvert::GetParam(ForceType<bool> , HSQUIRRELVM vm, int index) { SQBool tmp; sq_getbool (vm, index, &tmp); return tmp; }
+template <> const char *SQConvert::GetParam(ForceType<const char *>, HSQUIRRELVM vm, int index) { const SQChar *tmp; sq_getstring (vm, index, &tmp); return tmp; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/squirrel/convert.hpp Wed Mar 14 20:22:07 2007 +0000
@@ -0,0 +1,95 @@
+/* $Id$ */
+
+/** @file convert.hpp declarations and parts of the implementation of the class for convert code */
+
+#ifndef SQUIRREL_CONVERT_HPP
+#define SQUIRREL_CONVERT_HPP
+
+/**
+ * The Squirrel convert class. It doesn't have an instance, the methods only are used.
+ */
+class SQConvert {
+public:
+ /**
+ * Special class to make it possible for the compiler to pick the correct GetParam().
+ */
+ template <typename T> class ForceType { };
+
+ /**
+ * To return a value to squirrel, we call this function. It converts to the right format.
+ */
+ template <typename T> static int Return(HSQUIRRELVM vm, T t);
+
+ /**
+ * To get a param from squirrel, we call this function. It converts to the right format.
+ */
+ template <typename T> static T GetParam(ForceType<T>, HSQUIRRELVM vm, int index);
+
+ /**
+ * The real C++ caller for function with a return value and 0 params.
+ */
+ template <typename CL, typename RT>
+ static int SQCall(CL *instance, RT (CL::*func)(), HSQUIRRELVM vm)
+ {
+ return Return(vm, (instance->*func)());
+ }
+
+ /**
+ * The real C++ caller for function with a return value and 1 param.
+ */
+ template <typename CL, typename RT, typename P1>
+ static int SQCall(CL *instance, RT (CL::*func)(P1), HSQUIRRELVM vm)
+ {
+ return Return(vm, (instance->*func)(
+ GetParam(ForceType<P1>(), vm, 2)
+ ));
+ }
+
+ /**
+ * The real C++ caller for function with a return value and 2 params.
+ */
+ template <typename CL, typename RT, typename P1, typename P2>
+ static int SQCall(CL *instance, RT (CL::*func)(P1, P2), HSQUIRRELVM vm)
+ {
+ return Return(vm, (instance->*func)(
+ GetParam(ForceType<P1>(), vm, 2),
+ GetParam(ForceType<P2>(), vm, 3)
+ ));
+ }
+
+ /**
+ * The real C++ caller for function with a return value and 3 params.
+ */
+ template <typename CL, typename RT, typename P1, typename P2, typename P3>
+ static int SQCall(CL *instance, RT (CL::*func)(P1, P2, P3), HSQUIRRELVM vm)
+ {
+ return Return(vm, (instance->*func)(
+ GetParam(ForceType<P1>(), vm, 2),
+ GetParam(ForceType<P2>(), vm, 3),
+ GetParam(ForceType<P3>(), vm, 4)
+ ));
+ }
+
+ /**
+ * A general template for all callback functions from Squirrel.
+ * In here the function_proc is recovered, and the SQCall is called that
+ * can handle this exact amount of params.
+ */
+ template <typename CL, typename Func>
+ static SQInteger DefSQCallback(HSQUIRRELVM vm)
+ {
+ /* Find the amount of params we got */
+ int nparam = sq_gettop(vm);
+ SQUserPointer ptr = NULL;
+ SQUserPointer instance = NULL;
+
+ /* Get the 'real' instance of this class */
+ sq_getinstanceup(vm, 1, &instance, 0);
+ /* Get the real function pointer */
+ sq_getuserdata(vm, nparam, &ptr, 0);
+ /* Deligate it to a template that can handle this specific function */
+ return SQCall((CL *)instance, *(Func *)ptr, vm);
+ }
+};
+
+#endif /* SQUIRREL_CONVERT_HPP */
--- a/src/ai/squirrel/squirrel.cpp Wed Mar 14 12:42:37 2007 +0000
+++ b/src/ai/squirrel/squirrel.cpp Wed Mar 14 20:22:07 2007 +0000
@@ -8,6 +8,14 @@
#include <stdarg.h>
#include "../../debug.h"
+#define SQUIRREL_CLASS
+#include "convert.hpp"
+#include "squirrel_class.hpp"
+#include "../core/ai_base.hpp"
+#include "../core/ai_company.hpp"
+#include "../core/ai_map.hpp"
+#include "../core/ai_town.hpp"
+
/**
* Here we handle errors that come from squirrel.
*/
@@ -63,16 +71,16 @@
SQInteger Squirrel::SQGetTick(HSQUIRRELVM vm)
{
- Squirrel *self;
+ SQUserPointer ptr;
/* Find the 'self' pointer */
- if (SQ_FAILED(sq_getinstanceup(vm, 1, (SQUserPointer *)&self, 0))) {
+ if (SQ_FAILED(sq_getinstanceup(vm, 1, &ptr, 0))) {
DEBUG(ai, 0, "[squirrel] Failed to find the instance-pointer");
return SQ_ERROR;
}
/* Return the value */
- sq_pushinteger(vm, self->GetTick());
+ sq_pushinteger(vm, ((Squirrel *)ptr)->GetTick());
return 1;
}
@@ -174,6 +182,11 @@
sq_pushroottable(this->vm);
this->SQAddMethod("RegisterAI", &Squirrel::SQRegisterAI, 2, "ts");
+ SQAIBaseRegister(this->vm);
+ SQAICompanyRegister(this->vm);
+ SQAIMapRegister(this->vm);
+ SQAITownRegister(this->vm);
+
/* Reset top */
sq_settop(this->vm, top);
}
--- a/src/ai/squirrel/squirrel.hpp Wed Mar 14 12:42:37 2007 +0000
+++ b/src/ai/squirrel/squirrel.hpp Wed Mar 14 20:22:07 2007 +0000
@@ -6,7 +6,6 @@
#define SQUIRREL_HPP
#include "../core/ai_controller.hpp"
-#include "../core/ai_base.hpp"
#include <squirrel.h>
class Squirrel: public AIController {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/squirrel/squirrel_class.hpp Wed Mar 14 20:22:07 2007 +0000
@@ -0,0 +1,81 @@
+#ifndef SQUIRREL_CLASS_HPP
+#define SQUIRREL_CLASS_HPP
+
+/**
+ * The template to define classes in Squirrel. It takes care of the creation
+ * and calling of such classes, to make the AI Layer cleaner while having a
+ * powerful script as possible AI language.
+ */
+template <class CL>
+class DefSQClass {
+private:
+ const char *classname;
+
+public:
+ DefSQClass(const char *_classname) :
+ classname(_classname)
+ {}
+
+ /**
+ * The destructor, to delete the real instance.
+ */
+ static SQInteger Destructor(SQUserPointer p, SQInteger size)
+ {
+ /* Remove the real instance too */
+ if (p != NULL) delete (CL *)p;
+ return 0;
+ }
+
+ /**
+ * The constructor, to create the real instance.
+ */
+ static SQInteger Constructor(HSQUIRRELVM vm)
+ {
+ /* Create the real instance */
+ CL *instance = new CL();
+ sq_setinstanceup(vm, -1, instance);
+ sq_setreleasehook(vm, -1, &DefSQClass::Destructor);
+ return 0;
+ }
+
+ /**
+ * This defines a method inside a class for Squirrel.
+ */
+ template <typename Func>
+ void DefSQFunction(HSQUIRRELVM vm, Func function_proc, const char *function_name)
+ {
+// int nparam = 1;
+// const char *params = "x";
+ void *ptr;
+
+ sq_pushstring(vm, function_name, -1);
+ /* Store the real function-pointer in the user-data */
+ ptr = sq_newuserdata(vm, sizeof(function_proc));
+ memcpy(ptr, &function_proc, sizeof(function_proc));
+ sq_newclosure(vm, SQConvert::DefSQCallback<CL, Func>, 1);
+// sq_setparamscheck(vm, nparam, params);
+ sq_createslot(vm, -3);
+ }
+
+ void PreRegister(HSQUIRRELVM vm)
+ {
+ /* Prepare the new class */
+ sq_pushroottable(vm);
+ sq_pushstring(vm, this->classname, -1);
+ sq_newclass(vm, SQFalse);
+
+ /* Register a constructor */
+ sq_pushstring(vm, "constructor", -1);
+ sq_newclosure(vm, &DefSQClass::Constructor, 0);
+// sq_setparamscheck(vm, nparam, params);
+ sq_createslot(vm, -3);
+ }
+
+ void PostRegister(HSQUIRRELVM vm)
+ {
+ /* Create the class and all his methods */
+ sq_createslot(vm, -3);
+ }
+};
+
+#endif /* SQUIRREL_CLASS_HPP */