--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/squirrel.cpp Thu Mar 15 22:28:14 2007 +0000
@@ -0,0 +1,216 @@
+/* $Id$ */
+
+/** @file squirrel.cpp allows loading squirrel scripts to control an AI */
+
+#include "../../stdafx.h"
+#include "../../debug.h"
+#include "../../openttd.h"
+#include "../../string.h"
+#include "../../fios.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef _UNICODE
+/* Disable unicode for squirrel to allow compilation with MINGW
+ * and simplify coding for WIN32 (squirrel headers miss a lot of "string" functions)
+ */
+#undef _UNICODE
+#endif
+#include <squirrel.h>
+#include "../../squirrel.hpp"
+#include "../../squirrel_helper.hpp"
+#include "../../squirrel_class.hpp"
+#include "../core/ai_factory.hpp"
+#include "../core/ai_controller.hpp"
+#include "squirrel.hpp"
+
+/* Convert all AI related classes to Squirrel data */
+#define DEFINE_SQUIRREL_CLASS
+#include "../core/ai_base.hpp"
+#include "../core/ai_cargo.hpp"
+#include "../core/ai_controller.hpp"
+#include "../core/ai_company.hpp"
+#include "../core/ai_industry.hpp"
+#include "../core/ai_map.hpp"
+#include "../core/ai_town.hpp"
+
+static FSquirrel iFSquirrel; ///< Tell the AI-core that we have an AI with which we like to play.
+
+/**
+ * Our tiny wrapper between C++ and Squirrel.
+ */
+class AIFactorySquirrel: public AIFactoryBase {
+public:
+ Squirrel *engine;
+ HSQOBJECT SQ_instance;
+ char *script_name;
+
+ ~AIFactorySquirrel();
+
+ /* virtual */ const char *GetAuthor() { return this->engine->CallStringMethod (this->SQ_instance, "GetAuthor"); }
+ /* virtual */ const char *GetName() { return this->engine->CallStringMethod (this->SQ_instance, "GetName"); }
+ /* virtual */ const char *GetDescription() { return this->engine->CallStringMethod (this->SQ_instance, "GetDescription"); }
+ /* virtual */ int GetVersion() { return this->engine->CallIntegerMethod(this->SQ_instance, "GetVersion"); }
+ /* virtual */ const char *GetDate() { return this->engine->CallStringMethod (this->SQ_instance, "GetDate"); }
+ /* virtual */ AIController *CreateInstance();
+
+ /**
+ * Register Squirrel script to the Factory.
+ */
+ void RegisterSquirrel() { this->RegisterFactory(this->GetName()); }
+
+ /**
+ * Check if a method exists in the script.
+ */
+ void CheckMethods(AIFactorySquirrel *fbase, SQInteger *res, const char *name);
+};
+
+AIFactorySquirrel::~AIFactorySquirrel()
+{
+ free(this->script_name);
+}
+
+void AIFactorySquirrel::CheckMethods(AIFactorySquirrel *fbase, SQInteger *res, const char *name)
+{
+ if (!fbase->engine->MethodExists(fbase->SQ_instance, name)) {
+ char error[1024];
+ snprintf(error, sizeof(error), "Missing method '%s' for FactoryClass", name);
+ fbase->engine->ThrowError(error);
+ *res = SQ_ERROR;
+ }
+}
+
+SQInteger FSquirrel::FactoryConstructor(HSQUIRRELVM vm)
+{
+ AIFactorySquirrel *fbase = new AIFactorySquirrel();
+ SQInteger res = 0;
+
+ Squirrel::GetInstance(vm, &fbase->SQ_instance);
+ fbase->engine = ((FSquirrel *)Squirrel::GetGlobalPointer(vm))->engine;
+
+ /* Check if all needed fields are there */
+ fbase->CheckMethods(fbase, &res, "GetAuthor");
+ fbase->CheckMethods(fbase, &res, "GetName");
+ fbase->CheckMethods(fbase, &res, "GetDescription");
+ fbase->CheckMethods(fbase, &res, "GetVersion");
+ fbase->CheckMethods(fbase, &res, "GetDate");
+ fbase->CheckMethods(fbase, &res, "CreateInstance");
+
+ /* Abort if one method was missing */
+ if (res != 0) return res;
+
+ fbase->RegisterSquirrel();
+ fbase->script_name = strdup(((FSquirrel *)Squirrel::GetGlobalPointer(vm))->current_script);
+
+ return 0;
+}
+
+extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
+extern bool FiosIsHiddenFile(const struct dirent *ent);
+
+
+void FSquirrel::ScanDir(const char *dirname)
+{
+ struct stat sb;
+ struct dirent *dirent;
+ DIR *dir;
+ char d_name[256];
+ char script_name[256];
+ dir = ttd_opendir(dirname);
+ /* Dir not found, so do nothing */
+ if (dir == NULL) return;
+
+ /* Walk all dirs trying to find a dir in which 'main.nut' exists */
+ while ((dirent = readdir(dir)) != NULL) {
+ ttd_strlcpy(d_name, FS2OTTD(dirent->d_name), sizeof(d_name));
+
+ /* Found file must be directory, but not '.' or '..' */
+ if (FiosIsValidFile("ai", dirent, &sb) && (sb.st_mode & S_IFDIR) &&
+ (!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) &&
+ strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) {
+ /* Create the full-length script-name */
+ strcpy(script_name, dirname);
+ strcat(script_name, PATHSEP);
+ strcat(script_name, d_name);
+ strcat(script_name, PATHSEP);
+ strcat(script_name, "main.nut");
+ /* If it exists, load it up */
+ if (FileExists(script_name)) {
+ DEBUG(ai, 6, "[squirrel] Loading script '%s' for AI handling", script_name);
+ this->current_script = script_name;
+ this->engine->LoadScript(this->current_script);
+ }
+ }
+ }
+ closedir(dir);
+}
+
+void FSquirrel::Initializer()
+{
+ this->engine = new Squirrel();
+
+ /* Create the AIFactory class, and bind the constructor */
+ this->engine->AddClassBegin("AIFactory");
+ this->engine->AddMethod("constructor", &FSquirrel::FactoryConstructor, 1, "x");
+ this->engine->AddClassEnd();
+
+ /* Set a dummy AIController, so script can load */
+ this->engine->AddClassBegin("AIController");
+ this->engine->AddClassEnd();
+ /* Mark this class as global pointer */
+ this->engine->SetGlobalPointer(this);
+
+ /* Scan the AI dir for scripts */
+ this->ScanDir("ai");
+}
+
+FSquirrel::~FSquirrel()
+{
+ delete this->engine;
+}
+
+AIController *AIFactorySquirrel::CreateInstance()
+{
+ const char *class_name = this->engine->CallStringMethod(this->SQ_instance, "CreateInstance");
+ AIControllerSquirrel *controller = new AIControllerSquirrel(this->script_name, class_name);
+
+ return controller;
+}
+
+void AIControllerSquirrel::RegisterClasses()
+{
+ /* Ignore AIFactory if we are really starting an AI */
+ this->engine->AddClassBegin("AIFactory");
+ this->engine->AddClassEnd();
+
+ /* Register all classes */
+ SQAIBaseRegister(this->engine);
+ SQAICargoRegister(this->engine);
+ SQAICompanyRegister(this->engine);
+ SQAIControllerRegister(this->engine);
+ SQAIIndustryRegister(this->engine);
+ SQAIMapRegister(this->engine);
+ SQAITownRegister(this->engine);
+
+ this->engine->SetGlobalPointer(this->engine);
+}
+
+AIControllerSquirrel::AIControllerSquirrel(const char *script, const char *class_name)
+{
+ this->engine = new Squirrel();
+ this->RegisterClasses();
+ this->engine->LoadScript(script);
+ /* Create the main-class */
+ this->engine->CreateClassInstance(class_name, this, &this->SQ_instance);
+ this->engine->CallMethod(this->SQ_instance, "constructor");
+}
+
+AIControllerSquirrel::~AIControllerSquirrel()
+{
+ delete this->engine;
+}
+
+/* virtual */ void AIControllerSquirrel::GameLoop()
+{
+ this->engine->CallMethod(this->SQ_instance, "GameLoop");
+}