src/ai/squirrel/squirrel.cpp
branchnoai
changeset 9404 ef9e171617a3
parent 9396 a05857491d2d
child 9407 39201b99bd91
--- a/src/ai/squirrel/squirrel.cpp	Thu Mar 15 13:28:11 2007 +0000
+++ b/src/ai/squirrel/squirrel.cpp	Thu Mar 15 13:36:45 2007 +0000
@@ -3,8 +3,6 @@
 /** @file squirrel.cpp allows loading squirrel scripts to control an AI */
 
 #include "squirrel.hpp"
-#include <sqstdio.h>
-#include <sqstdaux.h>
 #include "../../debug.h"
 
 #define SQUIRREL_CLASS
@@ -12,109 +10,134 @@
 #include "squirrel_class.hpp"
 #include "../core/ai_base.hpp"
 #include "../core/ai_company.hpp"
+#include "../core/ai_controller.hpp"
 #include "../core/ai_map.hpp"
 #include "../core/ai_town.hpp"
 
-SQInteger Squirrel::SQDestructor(SQUserPointer p, SQInteger size)
-{
-	return 1;
-}
-
-SQInteger Squirrel::SQConstructor(HSQUIRRELVM vm)
-{
-	DEBUG(ai, 0, "[squirrel] Please do NOT define your AI class yourself; use RegisterAI() instead");
-	return SQ_ERROR;
-}
+static FSquirrel iFSquirrel; ///< Tell the AI-core that we have an AI with which we like to play.
 
-SQInteger Squirrel::SQGetTick(HSQUIRRELVM vm)
-{
-	SQUserPointer self;
+/**
+ * Our tiny wrapper between C++ and Squirrel.
+ */
+class AIFactorySquirrel: public AIFactoryBase {
+public:
+	SquirrelEngine *engine;
+	HSQOBJECT SQ_instance;
 
-	if (!SquirrelEngine::GetInstance(vm, &self)) {
-		DEBUG(ai, 0, "[squirrel] Failed to find instance pointer");
-		return SQ_ERROR;
+	const char   *GetAuthor()      { return this->engine->CallStringMethod (this->SQ_instance, "GetAuthor"); }
+	const char   *GetName()        { return this->engine->CallStringMethod (this->SQ_instance, "GetName"); }
+	const char   *GetDescription() { return this->engine->CallStringMethod (this->SQ_instance, "GetDescription"); }
+	int           GetVersion()     { return this->engine->CallIntegerMethod(this->SQ_instance, "GetVersion"); }
+	const char   *GetDate()        { return this->engine->CallStringMethod (this->SQ_instance, "GetDate"); }
+	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);
+};
+
+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;
 	}
-
-	/* Return the value */
-	sq_pushinteger(vm, ((Squirrel *)self)->GetTick());
-	return 1;
 }
 
-SQInteger Squirrel::SQRegisterAI(HSQUIRRELVM vm)
+SQInteger FSquirrel::FactoryConstructor(HSQUIRRELVM vm)
 {
-	const SQChar *classname = NULL;
-	sq_getstring(vm, -1, &classname);
-
-	/* Check if the class really exists */
-	int oldtop = sq_gettop(vm);
-	sq_pushroottable(vm);
-	sq_pushstring(vm, classname, -1);
-	if (SQ_FAILED(sq_get(vm, -2))) {
-		DEBUG(ai, 0, "[squirrel] Failed to find class '%s'", classname);
-		return SQ_ERROR;
-	}
-	sq_settop(vm, oldtop);
+	AIFactorySquirrel *fbase = new AIFactorySquirrel();
+	SQInteger res = 0;
 
-	/* Retreive the 'this' pointer from the global space */
-	Squirrel *self = (Squirrel *)sq_getforeignptr(vm);
-	if (self == NULL) {
-		DEBUG(ai, 0, "[squirrel] Currently only one RegisterAI call is allowed!");
-		return SQ_ERROR;
-	}
-	/* Make sure we only register one AI in this script */
-	sq_setforeignptr(vm, NULL);
+	SquirrelEngine::GetInstance(vm, &fbase->SQ_instance);
+	fbase->engine = (SquirrelEngine *)SquirrelEngine::GetGlobalPointer(vm);
 
-	/* Create the new class */
-	if (!self->engine->CreateClassInstance(classname, self, &self->SQ_instance)) {
-		return SQ_ERROR;
-	}
+	/* 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");
 
-	return 0;
+	/* Only register if all methods were known */
+	if (res == 0) fbase->RegisterSquirrel();
+
+	return res;
 }
 
-void Squirrel::RegisterClasses()
+void FSquirrel::Initializer()
 {
-	HSQUIRRELVM vm = this->engine->GetVM();
-	SQInteger top = sq_gettop(vm);
+	this->engine = new SquirrelEngine();
 
-	/* Store 'this' so we can find it back later on */
-	sq_setforeignptr(vm, this);
-
-	this->engine->AddClassBegin("AIController");
-
-	/* Create a constructor, so we can assign the right 'this' */
-	this->engine->AddMethod("constructor", &Squirrel::SQConstructor, 1, "x");
-	/* Assign other functions as AIController won't be done via the normal way */
-	this->engine->AddMethod("GetTick", &Squirrel::SQGetTick, 1, "x");
-
+	/* Create the AIFactory class, and bind the constructor */
+	this->engine->AddClassBegin("AIFactory");
+	this->engine->AddMethod("constructor", &FSquirrel::FactoryConstructor, 1, "x");
 	this->engine->AddClassEnd();
 
-	/* Register the 'RegisterAI()' function */
-	sq_pushroottable(vm);
-	this->engine->AddMethod("RegisterAI", &Squirrel::SQRegisterAI, 2, "ts");
+	/* Set a dummy AIController, so script can load */
+	this->engine->AddClassBegin("AIController");
+	this->engine->AddClassEnd();
+	/* Mark the engine as global pointer */
+	this->engine->SetGlobalPointer(this->engine);
 
+	/* Now load all scripts we can find */
+	this->engine->LoadScript("ai/SQNoAI/main.nut");
+}
+
+FSquirrel::~FSquirrel()
+{
+	delete this->engine;
+}
+
+AIController *AIFactorySquirrel::CreateInstance()
+{
+	const char *class_name = this->engine->CallStringMethod(this->SQ_instance, "CreateInstance");
+	AIControllerSquirrel *controller = new AIControllerSquirrel("ai/SQNoAI/main.nut", 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 */
+	SQAIControllerRegister(this->engine);
 	SQAIBaseRegister(this->engine);
 	SQAICompanyRegister(this->engine);
 	SQAIMapRegister(this->engine);
 	SQAITownRegister(this->engine);
 
-	/* Reset top */
-	sq_settop(vm, top);
+	this->engine->SetGlobalPointer(this->engine);
 }
 
-Squirrel::Squirrel(const char *script)
+AIControllerSquirrel::AIControllerSquirrel(const char *script, const char *class_name)
 {
 	this->engine = new SquirrelEngine();
 	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");
 }
 
-Squirrel::~Squirrel()
+AIControllerSquirrel::~AIControllerSquirrel()
 {
 	delete this->engine;
 }
 
-/* virtual */ void Squirrel::GameLoop()
+/* virtual */ void AIControllerSquirrel::GameLoop()
 {
 	this->engine->CallMethod(this->SQ_instance, "GameLoop");
 }