# HG changeset patch # User truelight # Date 1173903727 0 # Node ID 4255a0a2d272c3f0ea35636a44c4d8252d523a5c # Parent c8aa2ae117f5d50567ab497f861ce0420795c693 (svn r9179) [NoAI] -Add: added templates that makes adding classes to squirrel very easy -Update: SQNoAI does now exactly what NoAI does diff -r c8aa2ae117f5 -r 4255a0a2d272 bin/ai/SQNoAI/main.nut --- 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 */ diff -r c8aa2ae117f5 -r 4255a0a2d272 projects/openttd.vcproj --- 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"> + + + + + + + + + + @@ -1499,6 +1507,10 @@ RelativePath=".\..\src\ai\squirrel\squirrel.hpp" > + + 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 */ diff -r c8aa2ae117f5 -r 4255a0a2d272 src/ai/core/ai_company.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 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 */ diff -r c8aa2ae117f5 -r 4255a0a2d272 src/ai/core/ai_map.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 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 */ diff -r c8aa2ae117f5 -r 4255a0a2d272 src/ai/core/ai_town.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 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 */ diff -r c8aa2ae117f5 -r 4255a0a2d272 src/ai/squirrel/convert.cpp --- /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 (HSQUIRRELVM vm, uint8 res) { sq_pushinteger(vm, res); return 1; } +template <> int SQConvert::Return(HSQUIRRELVM vm, uint16 res) { sq_pushinteger(vm, res); return 1; } +template <> int SQConvert::Return(HSQUIRRELVM vm, uint32 res) { sq_pushinteger(vm, res); return 1; } +template <> int SQConvert::Return (HSQUIRRELVM vm, int8 res) { sq_pushinteger(vm, res); return 1; } +template <> int SQConvert::Return (HSQUIRRELVM vm, int16 res) { sq_pushinteger(vm, res); return 1; } +template <> int SQConvert::Return (HSQUIRRELVM vm, int32 res) { sq_pushinteger(vm, res); return 1; } +template <> int SQConvert::Return (HSQUIRRELVM vm, bool res) { sq_pushbool (vm, res); return 1; } +template <> int SQConvert::Return(HSQUIRRELVM vm, char *res) { sq_pushstring (vm, res, strlen(res)); free(res); return 1; } + +template <> uint8 SQConvert::GetParam(ForceType , HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return tmp; } +template <> uint16 SQConvert::GetParam(ForceType , HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return tmp; } +template <> uint32 SQConvert::GetParam(ForceType , HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return tmp; } +template <> int8 SQConvert::GetParam(ForceType , HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return tmp; } +template <> int16 SQConvert::GetParam(ForceType , HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return tmp; } +template <> int32 SQConvert::GetParam(ForceType , HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return tmp; } +template <> bool SQConvert::GetParam(ForceType , HSQUIRRELVM vm, int index) { SQBool tmp; sq_getbool (vm, index, &tmp); return tmp; } +template <> const char *SQConvert::GetParam(ForceType, HSQUIRRELVM vm, int index) { const SQChar *tmp; sq_getstring (vm, index, &tmp); return tmp; } diff -r c8aa2ae117f5 -r 4255a0a2d272 src/ai/squirrel/convert.hpp --- /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 class ForceType { }; + + /** + * To return a value to squirrel, we call this function. It converts to the right format. + */ + template static int Return(HSQUIRRELVM vm, T t); + + /** + * To get a param from squirrel, we call this function. It converts to the right format. + */ + template static T GetParam(ForceType, HSQUIRRELVM vm, int index); + + /** + * The real C++ caller for function with a return value and 0 params. + */ + template + 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 + static int SQCall(CL *instance, RT (CL::*func)(P1), HSQUIRRELVM vm) + { + return Return(vm, (instance->*func)( + GetParam(ForceType(), vm, 2) + )); + } + + /** + * The real C++ caller for function with a return value and 2 params. + */ + template + static int SQCall(CL *instance, RT (CL::*func)(P1, P2), HSQUIRRELVM vm) + { + return Return(vm, (instance->*func)( + GetParam(ForceType(), vm, 2), + GetParam(ForceType(), vm, 3) + )); + } + + /** + * The real C++ caller for function with a return value and 3 params. + */ + template + static int SQCall(CL *instance, RT (CL::*func)(P1, P2, P3), HSQUIRRELVM vm) + { + return Return(vm, (instance->*func)( + GetParam(ForceType(), vm, 2), + GetParam(ForceType(), vm, 3), + GetParam(ForceType(), 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 + 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 */ diff -r c8aa2ae117f5 -r 4255a0a2d272 src/ai/squirrel/squirrel.cpp --- 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 #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); } diff -r c8aa2ae117f5 -r 4255a0a2d272 src/ai/squirrel/squirrel.hpp --- 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 class Squirrel: public AIController { diff -r c8aa2ae117f5 -r 4255a0a2d272 src/ai/squirrel/squirrel_class.hpp --- /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 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 + 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, 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 */