aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/script
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sword25/script')
-rw-r--r--engines/sword25/script/lua_extensions.cpp75
-rw-r--r--engines/sword25/script/luabindhelper.cpp427
-rw-r--r--engines/sword25/script/luabindhelper.h128
-rw-r--r--engines/sword25/script/luacallback.cpp180
-rw-r--r--engines/sword25/script/luacallback.h78
-rw-r--r--engines/sword25/script/luascript.cpp569
-rw-r--r--engines/sword25/script/luascript.h116
-rw-r--r--engines/sword25/script/script.h96
8 files changed, 1669 insertions, 0 deletions
diff --git a/engines/sword25/script/lua_extensions.cpp b/engines/sword25/script/lua_extensions.cpp
new file mode 100644
index 0000000000..3c0d4570a2
--- /dev/null
+++ b/engines/sword25/script/lua_extensions.cpp
@@ -0,0 +1,75 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on Broken Sword 2.5 engine
+ *
+ * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
+ *
+ * Licensed under GNU GPL v2
+ *
+ */
+
+#include "sword25/script/luascript.h"
+#include "sword25/script/luabindhelper.h"
+
+namespace Sword25 {
+
+static int warning(lua_State *L) {
+#ifdef DEBUG
+ int __startStackDepth = lua_gettop(L);
+#endif
+
+ luaL_checkstring(L, 1);
+ luaL_where(L, 1);
+ lua_pushstring(L, "WARNING - ");
+ lua_pushvalue(L, 1);
+ lua_concat(L, 3);
+ BS_Log::Log("%s\n", luaL_checkstring(L, -1));
+ lua_pop(L, 1);
+
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(L));
+#endif
+
+ return 0;
+}
+
+static const luaL_reg GLOBAL_FUNCTIONS[] = {
+ {"warning", warning},
+ {0, 0}
+};
+
+bool LuaScriptEngine::registerStandardLibExtensions() {
+ lua_State *L = _state;
+ BS_ASSERT(_state);
+
+ if (!LuaBindhelper::addFunctionsToLib(L, "", GLOBAL_FUNCTIONS))
+ return false;
+
+ return true;
+}
+
+} // End of namespace Sword25
diff --git a/engines/sword25/script/luabindhelper.cpp b/engines/sword25/script/luabindhelper.cpp
new file mode 100644
index 0000000000..5367854218
--- /dev/null
+++ b/engines/sword25/script/luabindhelper.cpp
@@ -0,0 +1,427 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on Broken Sword 2.5 engine
+ *
+ * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
+ *
+ * Licensed under GNU GPL v2
+ *
+ */
+
+#include "sword25/kernel/kernel.h"
+#include "sword25/script/luabindhelper.h"
+#include "sword25/script/luascript.h"
+
+#define BS_LOG_PREFIX "LUABINDHELPER"
+
+namespace {
+const char *METATABLES_TABLE_NAME = "__METATABLES";
+const char *PERMANENTS_TABLE_NAME = "Permanents";
+
+bool registerPermanent(lua_State *L, const Common::String &name) {
+ // A C function has to be on the stack
+ if (!lua_iscfunction(L, -1))
+ return false;
+
+ // Make sure that the Permanents-Table is on top of the stack
+ lua_getfield(L, LUA_REGISTRYINDEX, PERMANENTS_TABLE_NAME);
+ if (lua_isnil(L, -1)) {
+ // Permanents-Table does not yet exist, so it has to be created
+
+ // Pop nil from the stack
+ lua_pop(L, 1);
+
+ // Create Permanents-Table and insert a second reference to it on the stack
+ lua_newtable(L);
+ lua_pushvalue(L, -1);
+
+ // Store the Permanents-Table in the registry. The second reference is left
+ // on the stack to be used in the connection
+ lua_setfield(L, LUA_REGISTRYINDEX, PERMANENTS_TABLE_NAME);
+ }
+
+ // C function with the name of an index in the Permanents-Table
+ lua_insert(L, -2);
+ lua_setfield(L, -2, name.c_str());
+
+ // Remove the Permanents-Table from the stack
+ lua_pop(L, 1);
+
+ return true;
+}
+}
+
+namespace Sword25 {
+
+/**
+ * Registers a set of functions into a Lua library.
+ * @param L A pointer to the Lua VM
+ * @param LibName The name of the library.
+ * If this is an empty string, the functions will be added to the global namespace.
+ * @param Functions An array of function pointers along with their names.
+ * The array must be terminated with the enry (0, 0)
+ * @return Returns true if successful, otherwise false.
+ */
+bool LuaBindhelper::addFunctionsToLib(lua_State *L, const Common::String &libName, const luaL_reg *functions) {
+#ifdef DEBUG
+ int __startStackDepth = lua_gettop(L);
+#endif
+
+ // If the table name is empty, the functions are to be added to the global namespace
+ if (libName.size() == 0) {
+ for (; functions->name; ++functions) {
+ lua_pushstring(L, functions->name);
+ lua_pushcclosure(L, functions->func, 0);
+ lua_settable(L, LUA_GLOBALSINDEX);
+
+ // Function is being permanently registed, so persistence can be ignored
+ lua_pushstring(L, functions->name);
+ lua_gettable(L, LUA_GLOBALSINDEX);
+ registerPermanent(L, functions->name);
+ }
+ } else { // If the table name is not empty, the functions are added to the given table
+ // Ensure that the library table exists
+ if (!createTable(L, libName)) return false;
+
+ // Register each function into the table
+ for (; functions->name; ++functions) {
+ // Function registration
+ lua_pushstring(L, functions->name);
+ lua_pushcclosure(L, functions->func, 0);
+ lua_settable(L, -3);
+
+ // Function is being permanently registed, so persistence can be ignored
+ lua_pushstring(L, functions->name);
+ lua_gettable(L, -2);
+ registerPermanent(L, libName + "." + functions->name);
+ }
+
+ // Remove the library table from the Lua stack
+ lua_pop(L, 1);
+ }
+
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(L));
+#endif
+
+ return true;
+}
+
+/**
+ * Adds a set of constants to the Lua library
+ * @param L A pointer to the Lua VM
+ * @param LibName The name of the library.
+ * If this is an empty string, the functions will be added to the global namespace.
+ * @param Constants An array of the constant values along with their names.
+ * The array must be terminated with the enry (0, 0)
+ * @return Returns true if successful, otherwise false.
+ */
+bool LuaBindhelper::addConstantsToLib(lua_State *L, const Common::String &libName, const lua_constant_reg *constants) {
+#ifdef DEBUG
+ int __startStackDepth = lua_gettop(L);
+#endif
+
+ // If the table is empty, the constants are added to the global namespace
+ if (libName.size() == 0) {
+ for (; constants->Name; ++constants) {
+ lua_pushstring(L, constants->Name);
+ lua_pushnumber(L, constants->Value);
+ lua_settable(L, LUA_GLOBALSINDEX);
+ }
+ }
+ // If the table name is nto empty, the constants are added to that table
+ else {
+ // Ensure that the library table exists
+ if (!createTable(L, libName)) return false;
+
+ // Register each constant in the table
+ for (; constants->Name; ++constants) {
+ lua_pushstring(L, constants->Name);
+ lua_pushnumber(L, constants->Value);
+ lua_settable(L, -3);
+ }
+
+ // Remove the library table from the Lua stack
+ lua_pop(L, 1);
+ }
+
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(L));
+#endif
+
+ return true;
+}
+
+/**
+ * Adds a set of methods to a Lua class
+ * @param L A pointer to the Lua VM
+ * @param ClassName The name of the class
+ * When the class name specified does not exist, it is created.
+ * @param Methods An array of function pointers along with their method names.
+ * The array must be terminated with the enry (0, 0)
+ * @return Returns true if successful, otherwise false.
+ */
+bool LuaBindhelper::addMethodsToClass(lua_State *L, const Common::String &className, const luaL_reg *methods) {
+#ifdef DEBUG
+ int __startStackDepth = lua_gettop(L);
+#endif
+
+ // Load the metatable onto the Lua stack
+ if (!getMetatable(L, className)) return false;
+
+ // Register each method in the Metatable
+ for (; methods->name; ++methods) {
+ lua_pushstring(L, methods->name);
+ lua_pushcclosure(L, methods->func, 0);
+ lua_settable(L, -3);
+
+ // Function is being permanently registed, so persistence can be ignored
+ lua_pushstring(L, methods->name);
+ lua_gettable(L, -2);
+ registerPermanent(L, className + "." + methods->name);
+ }
+
+ // Remove the metatable from the stack
+ lua_pop(L, 1);
+
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(L));
+#endif
+
+ return true;
+}
+
+/**
+ * Sets the garbage collector callback method when items of a particular class are deleted
+ * @param L A pointer to the Lua VM
+ * @param ClassName The name of the class
+ * When the class name specified does not exist, it is created.
+ * @param GCHandler A function pointer
+ * @return Returns true if successful, otherwise false.
+ */
+bool LuaBindhelper::setClassGCHandler(lua_State *L, const Common::String &className, lua_CFunction GCHandler) {
+#ifdef DEBUG
+ int __startStackDepth = lua_gettop(L);
+#endif
+
+ // Load the metatable onto the Lua stack
+ if (!getMetatable(L, className)) return false;
+
+ // Add the GC handler to the Metatable
+ lua_pushstring(L, "__gc");
+ lua_pushcclosure(L, GCHandler, 0);
+ lua_settable(L, -3);
+
+ // Function is being permanently registed, so persistence can be ignored
+ lua_pushstring(L, "__gc");
+ lua_gettable(L, -2);
+ registerPermanent(L, className + ".__gc");
+
+ // Remove the metatable from the stack
+ lua_pop(L, 1);
+
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(L));
+#endif
+
+ return true;
+}
+
+} // End of namespace Sword25
+
+namespace {
+void pushMetatableTable(lua_State *L) {
+ // Push the Metatable table onto the stack
+ lua_getglobal(L, METATABLES_TABLE_NAME);
+
+ // If the table doesn't yet exist, it must be created
+ if (lua_isnil(L, -1)) {
+ // Pop nil from stack
+ lua_pop(L, 1);
+
+ // New table has been created, so add it to the global table and leave reference on stack
+ lua_newtable(L);
+ lua_pushvalue(L, -1);
+ lua_setglobal(L, METATABLES_TABLE_NAME);
+ }
+}
+}
+
+namespace Sword25 {
+
+bool LuaBindhelper::getMetatable(lua_State *L, const Common::String &tableName) {
+ // Push the Metatable table onto the stack
+ pushMetatableTable(L);
+
+ // Versuchen, die gewünschte Metatabelle auf den Stack zu legen. Wenn sie noch nicht existiert, muss sie erstellt werden.
+ lua_getfield(L, -1, tableName.c_str());
+ if (lua_isnil(L, -1)) {
+ // Pop nil from stack
+ lua_pop(L, 1);
+
+ // Create new table
+ lua_newtable(L);
+
+ // Set the __index field in the table
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+
+ // Flag the table as persisted. This ensures that objects within this table get stored
+ lua_pushbooleancpp(L, true);
+ lua_setfield(L, -2, "__persist");
+
+ // Set the table name and push it onto the stack
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -3, tableName.c_str());
+ }
+
+ // Remove the Metatable table from the stack
+ lua_remove(L, -2);
+
+ return true;
+}
+
+bool LuaBindhelper::createTable(lua_State *L, const Common::String &tableName) {
+ const char *partBegin = tableName.c_str();
+
+ while (partBegin - tableName.c_str() < (int)tableName.size()) {
+ const char *partEnd = strchr(partBegin, '.');
+ if (!partEnd)
+ partEnd = partBegin + strlen(partBegin);
+ Common::String subTableName(partBegin, partEnd);
+
+ // Tables with an empty string as the name are not allowed
+ if (subTableName.size() == 0)
+ return false;
+
+ // Verify that the table with the name already exists
+ // The first round will be searched in the global namespace, with later passages
+ // in the corresponding parent table in the stack
+ if (partBegin == tableName.c_str()) {
+ lua_pushstring(L, subTableName.c_str());
+ lua_gettable(L, LUA_GLOBALSINDEX);
+ } else {
+ lua_pushstring(L, subTableName.c_str());
+ lua_gettable(L, -2);
+ if (!lua_isnil(L, -1))
+ lua_remove(L, -2);
+ }
+
+ // If it doesn't exist, create table
+ if (lua_isnil(L, -1)) {
+ // Pop nil from stack
+ lua_pop(L, 1);
+
+ // Create new table
+ lua_newtable(L);
+ lua_pushstring(L, subTableName.c_str());
+ lua_pushvalue(L, -2);
+ if (partBegin == tableName.c_str())
+ lua_settable(L, LUA_GLOBALSINDEX);
+ else {
+ lua_settable(L, -4);
+ lua_remove(L, -2);
+ }
+ }
+
+ partBegin = partEnd + 1;
+ }
+
+ return true;
+}
+
+} // End of namespace Sword25
+
+namespace {
+Common::String getLuaValueInfo(lua_State *L, int stackIndex) {
+ switch (lua_type(L, stackIndex)) {
+ case LUA_TNUMBER:
+ lua_pushstring(L, lua_tostring(L, stackIndex));
+ break;
+
+ case LUA_TSTRING:
+ lua_pushfstring(L, "\"%s\"", lua_tostring(L, stackIndex));
+ break;
+
+ case LUA_TBOOLEAN:
+ lua_pushstring(L, (lua_toboolean(L, stackIndex) ? "true" : "false"));
+ break;
+
+ case LUA_TNIL:
+ lua_pushliteral(L, "nil");
+ break;
+
+ default:
+ lua_pushfstring(L, "%s: %p", luaL_typename(L, stackIndex), lua_topointer(L, stackIndex));
+ break;
+ }
+
+ Common::String result(lua_tostring(L, -1));
+ lua_pop(L, 1);
+
+ return result;
+}
+}
+
+namespace Sword25 {
+
+Common::String LuaBindhelper::stackDump(lua_State *L) {
+ Common::String oss;
+
+ int i = lua_gettop(L);
+ oss += "------------------- Stack Dump -------------------\n";
+
+ while (i) {
+ oss += i + ": " + getLuaValueInfo(L, i) + "\n";
+ i--;
+ }
+
+ oss += "-------------- Stack Dump Finished ---------------\n";
+
+ return oss;
+}
+
+Common::String LuaBindhelper::tableDump(lua_State *L) {
+ Common::String oss;
+
+ oss += "------------------- Table Dump -------------------\n";
+
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ // Get the value of the current element on top of the stack, including the index
+ oss += getLuaValueInfo(L, -2) + " : " + getLuaValueInfo(L, -1) + "\n";
+
+ // Pop value from the stack. The index is then ready for the next call to lua_next()
+ lua_pop(L, 1);
+ }
+
+ oss += "-------------- Table Dump Finished ---------------\n";
+
+ return oss;
+}
+
+} // End of namespace Sword25
diff --git a/engines/sword25/script/luabindhelper.h b/engines/sword25/script/luabindhelper.h
new file mode 100644
index 0000000000..0dbaaa3186
--- /dev/null
+++ b/engines/sword25/script/luabindhelper.h
@@ -0,0 +1,128 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on Broken Sword 2.5 engine
+ *
+ * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
+ *
+ * Licensed under GNU GPL v2
+ *
+ */
+
+#ifndef SWORD25_LUABINDHELPER_H
+#define SWORD25_LUABINDHELPER_H
+
+#include "sword25/kernel/common.h"
+
+namespace Lua {
+
+extern "C"
+{
+#include "sword25/util/lua/lua.h"
+#include "sword25/util/lua/lauxlib.h"
+}
+
+}
+
+using namespace Lua;
+
+namespace Sword25 {
+
+#define lua_pushbooleancpp(L, b) (lua_pushboolean(L, b ? 1 : 0))
+#define lua_tobooleancpp(L, i) (lua_toboolean(L, i) == 0 ? false : true)
+
+struct lua_constant_reg {
+ const char *Name;
+ lua_Number Value;
+};
+
+class LuaBindhelper {
+public:
+ /**
+ * Registers a set of functions into a Lua library.
+ * @param L A pointer to the Lua VM
+ * @param LibName The name of the library.
+ * If this is an empty string, the functions will be added to the global namespace.
+ * @param Functions An array of function pointers along with their names.
+ * The array must be terminated with the enry (0, 0)
+ * @return Returns true if successful, otherwise false.
+ */
+ static bool addFunctionsToLib(lua_State *L, const Common::String &libName, const luaL_reg *functions);
+
+ /**
+ * Adds a set of constants to the Lua library
+ * @param L A pointer to the Lua VM
+ * @param LibName The name of the library.
+ * If this is an empty string, the functions will be added to the global namespace.
+ * @param Constants An array of the constant values along with their names.
+ * The array must be terminated with the enry (0, 0)
+ * @return Returns true if successful, otherwise false.
+ */
+ static bool addConstantsToLib(lua_State *L, const Common::String &libName, const lua_constant_reg *constants);
+
+ /**
+ * Adds a set of methods to a Lua class
+ * @param L A pointer to the Lua VM
+ * @param ClassName The name of the class
+ * When the class name specified does not exist, it is created.
+ * @param Methods An array of function pointers along with their method names.
+ * The array must be terminated with the enry (0, 0)
+ * @return Returns true if successful, otherwise false.
+ */
+ static bool addMethodsToClass(lua_State *L, const Common::String &className, const luaL_reg *methods);
+
+ /**
+ * Sets the garbage collector callback method when items of a particular class are deleted
+ * @param L A pointer to the Lua VM
+ * @param ClassName The name of the class
+ * When the class name specified does not exist, it is created.
+ * @param GCHandler A function pointer
+ * @return Returns true if successful, otherwise false.
+ */
+ static bool setClassGCHandler(lua_State *L, const Common::String &className, lua_CFunction GCHandler);
+
+ /**
+ * Returns a string containing a stack dump of the Lua stack
+ * @param L A pointer to the Lua VM
+ */
+ static Common::String stackDump(lua_State *L);
+
+ /**
+ * Returns a string that describes the contents of a table
+ * @param L A pointer to the Lua VM
+ * @remark The table must be on the Lua stack to be read out.
+ */
+ static Common::String tableDump(lua_State *L);
+
+ static bool getMetatable(lua_State *L, const Common::String &tableName);
+
+private:
+ static bool createTable(lua_State *L, const Common::String &tableName);
+};
+
+} // End of namespace Sword25
+
+#endif
diff --git a/engines/sword25/script/luacallback.cpp b/engines/sword25/script/luacallback.cpp
new file mode 100644
index 0000000000..6d2e634632
--- /dev/null
+++ b/engines/sword25/script/luacallback.cpp
@@ -0,0 +1,180 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on Broken Sword 2.5 engine
+ *
+ * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
+ *
+ * Licensed under GNU GPL v2
+ *
+ */
+
+#include "sword25/script/luacallback.h"
+#include "sword25/script/luabindhelper.h"
+
+namespace Lua {
+
+extern "C"
+{
+#include "sword25/util/lua/lua.h"
+#include "sword25/util/lua/lauxlib.h"
+}
+
+const char *CALLBACKTABLE_NAME = "__CALLBACKS";
+
+}
+
+namespace Sword25 {
+
+#define BS_LOG_PREFIX "LUA"
+
+LuaCallback::LuaCallback(lua_State *L) {
+ // Create callback table
+ lua_newtable(L);
+ lua_setglobal(L, CALLBACKTABLE_NAME);
+}
+
+LuaCallback::~LuaCallback() {
+}
+
+void LuaCallback::registerCallbackFunction(lua_State *L, uint objectHandle) {
+ BS_ASSERT(lua_isfunction(L, -1));
+ ensureObjectCallbackTableExists(L, objectHandle);
+
+ // Store function in the callback object table store
+ lua_pushvalue(L, -2);
+ luaL_ref(L, -2);
+
+ // Pop the function and object callback table from the stack
+ lua_pop(L, 2);
+}
+
+void LuaCallback::unregisterCallbackFunction(lua_State *L, uint objectHandle) {
+ BS_ASSERT(lua_isfunction(L, -1));
+ ensureObjectCallbackTableExists(L, objectHandle);
+
+ // Iterate over all elements of the object callback table and remove the function from it
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ // The value of the current element is the top of the stack, including the index
+
+ // If the value is identical to the function parameters, it is removed from the table
+ if (lua_equal(L, -1, -4)) {
+ lua_pushvalue(L, -2);
+ lua_pushnil(L);
+ lua_settable(L, -5);
+
+ // The function was found, iteration can be stopped
+ lua_pop(L, 2);
+ break;
+ } else {
+ // Pop value from the stack. The index is then ready for the next call to lua_next()
+ lua_pop(L, 1);
+ }
+ }
+
+ // Function and object table are popped from the stack
+ lua_pop(L, 2);
+}
+
+void LuaCallback::removeAllObjectCallbacks(lua_State *L, uint objectHandle) {
+ pushCallbackTable(L);
+
+ // Remove the object callback from the callback table
+ lua_pushnumber(L, objectHandle);
+ lua_pushnil(L);
+ lua_settable(L, -3);
+
+ lua_pop(L, 1);
+}
+
+void LuaCallback::invokeCallbackFunctions(lua_State *L, uint objectHandle) {
+ ensureObjectCallbackTableExists(L, objectHandle);
+
+ // Iterate through the table and perform all the callbacks
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ // The value of the current element is at the top of the stack, including the index
+
+ // If the value is a function, execute it
+ if (lua_type(L, -1) == LUA_TFUNCTION) {
+ // Pre-Function Call
+ // Derived classes can function in this parameter onto the stack.
+ // The return value indicates the number of parameters
+ int argumentCount = preFunctionInvokation(L);
+
+ // Lua_pcall the function and the parameters pop themselves from the stack
+ if (lua_pcall(L, argumentCount, 0, 0) != 0) {
+ // An error has occurred
+ BS_LOG_ERRORLN("An error occured executing a callback function: %s", lua_tostring(L, -1));
+
+ // Pop error message from the stack
+ lua_pop(L, 1);
+ }
+ } else {
+ // Pop value from the stack. The index is then ready for the next call to lua_next()
+ lua_pop(L, 1);
+ }
+ }
+}
+
+void LuaCallback::ensureObjectCallbackTableExists(lua_State *L, uint objectHandle) {
+ pushObjectCallbackTable(L, objectHandle);
+
+ // If the table is nil, it must first be created
+ if (lua_isnil(L, -1)) {
+ // Pop nil from stack
+ lua_pop(L, 1);
+
+ pushCallbackTable(L);
+
+ // Create the table, and put the objectHandle into it
+ lua_newtable(L);
+ lua_pushnumber(L, objectHandle);
+ lua_pushvalue(L, -2);
+ lua_settable(L, -4);
+
+ // Pop the callback table from the stack
+ lua_remove(L, -2);
+ }
+}
+
+void LuaCallback::pushCallbackTable(lua_State *L) {
+ lua_getglobal(L, CALLBACKTABLE_NAME);
+}
+
+void LuaCallback::pushObjectCallbackTable(lua_State *L, uint objectHandle) {
+ pushCallbackTable(L);
+
+ // Push Object Callback table onto the stack
+ lua_pushnumber(L, objectHandle);
+ lua_gettable(L, -2);
+
+ // Pop the callback table from the stack
+ lua_remove(L, -2);
+}
+
+} // End of namespace Sword25
diff --git a/engines/sword25/script/luacallback.h b/engines/sword25/script/luacallback.h
new file mode 100644
index 0000000000..0a5dec17d9
--- /dev/null
+++ b/engines/sword25/script/luacallback.h
@@ -0,0 +1,78 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on Broken Sword 2.5 engine
+ *
+ * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
+ *
+ * Licensed under GNU GPL v2
+ *
+ */
+
+#ifndef SWORD25_LUACALLBACK_H
+#define SWORD25_LUACALLBACK_H
+
+#include "sword25/kernel/common.h"
+
+namespace Lua {
+
+struct lua_State;
+
+}
+
+using namespace Lua;
+
+namespace Sword25 {
+
+class LuaCallback {
+public:
+ LuaCallback(lua_State *L);
+ virtual ~LuaCallback();
+
+ // Funktion muss auf dem Lua-Stack liegen.
+ void registerCallbackFunction(lua_State *L, uint objectHandle);
+
+ // Funktion muss auf dem Lua-Stack liegen.
+ void unregisterCallbackFunction(lua_State *L, uint objectHandle);
+
+ void removeAllObjectCallbacks(lua_State *L, uint objectHandle);
+
+ void invokeCallbackFunctions(lua_State *L, uint objectHandle);
+
+protected:
+ virtual int preFunctionInvokation(lua_State *L) {
+ return 0;
+ }
+
+private:
+ void ensureObjectCallbackTableExists(lua_State *L, uint objectHandle);
+ void pushCallbackTable(lua_State *L);
+ void pushObjectCallbackTable(lua_State *L, uint objectHandle);
+};
+
+} // End of namespace Sword25
+
+#endif
diff --git a/engines/sword25/script/luascript.cpp b/engines/sword25/script/luascript.cpp
new file mode 100644
index 0000000000..82166f7c25
--- /dev/null
+++ b/engines/sword25/script/luascript.cpp
@@ -0,0 +1,569 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on Broken Sword 2.5 engine
+ *
+ * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
+ *
+ * Licensed under GNU GPL v2
+ *
+ */
+
+#define BS_LOG_PREFIX "LUA"
+
+#include "common/array.h"
+#include "common/debug-channels.h"
+
+#include "sword25/sword25.h"
+#include "sword25/package/packagemanager.h"
+#include "sword25/script/luascript.h"
+#include "sword25/script/luabindhelper.h"
+
+#include "sword25/kernel/outputpersistenceblock.h"
+#include "sword25/kernel/inputpersistenceblock.h"
+
+namespace Lua {
+
+extern "C" {
+#include "sword25/util/lua/lua.h"
+#include "sword25/util/lua/lualib.h"
+#include "sword25/util/lua/lauxlib.h"
+#include "sword25/util/pluto/pluto.h"
+}
+
+}
+
+namespace Sword25 {
+
+using namespace Lua;
+
+LuaScriptEngine::LuaScriptEngine(Kernel *KernelPtr) :
+ ScriptEngine(KernelPtr),
+ _state(0),
+ _pcallErrorhandlerRegistryIndex(0) {
+}
+
+LuaScriptEngine::~LuaScriptEngine() {
+ // Lua de-initialisation
+ if (_state)
+ lua_close(_state);
+}
+
+Service *LuaScriptEngine_CreateObject(Kernel *KernelPtr) {
+ return new LuaScriptEngine(KernelPtr);
+}
+
+namespace {
+int panicCB(lua_State *L) {
+ BS_LOG_ERRORLN("Lua panic. Error message: %s", lua_isnil(L, -1) ? "" : lua_tostring(L, -1));
+ return 0;
+}
+
+void debugHook(lua_State *L, lua_Debug *ar) {
+ if (!lua_getinfo(L, "Sn", ar))
+ return;
+
+ debug("LUA: %s %s: %s %d", ar->namewhat, ar->name, ar->short_src, ar->currentline);
+}
+}
+
+bool LuaScriptEngine::init() {
+ // Lua-State initialisation, as well as standard libaries initialisation
+ _state = luaL_newstate();
+ if (!_state || ! registerStandardLibs() || !registerStandardLibExtensions()) {
+ BS_LOG_ERRORLN("Lua could not be initialized.");
+ return false;
+ }
+
+ // Register panic callback function
+ lua_atpanic(_state, panicCB);
+
+ // Error handler for lua_pcall calls
+ // The code below contains a local error handler function
+ const char errorHandlerCode[] =
+ "local function ErrorHandler(message) "
+ " return message .. '\\n' .. debug.traceback('', 2) "
+ "end "
+ "return ErrorHandler";
+
+ // Compile the code
+ if (luaL_loadbuffer(_state, errorHandlerCode, strlen(errorHandlerCode), "PCALL ERRORHANDLER") != 0) {
+ // An error occurred, so dislay the reason and exit
+ BS_LOG_ERRORLN("Couldn't compile luaL_pcall errorhandler:\n%s", lua_tostring(_state, -1));
+ lua_pop(_state, 1);
+
+ return false;
+ }
+ // Running the code, the error handler function sets the top of the stack
+ if (lua_pcall(_state, 0, 1, 0) != 0) {
+ // An error occurred, so dislay the reason and exit
+ BS_LOG_ERRORLN("Couldn't prepare luaL_pcall errorhandler:\n%s", lua_tostring(_state, -1));
+ lua_pop(_state, 1);
+
+ return false;
+ }
+
+ // Place the error handler function in the Lua registry, and remember the index
+ _pcallErrorhandlerRegistryIndex = luaL_ref(_state, LUA_REGISTRYINDEX);
+
+ // Initialise the Pluto-Persistence library
+ luaopen_pluto(_state);
+ lua_pop(_state, 1);
+
+ // Initialize debugging callback
+ if (DebugMan.isDebugChannelEnabled(kDebugScript)) {
+ int mask = 0;
+ if ((gDebugLevel & 1) != 0)
+ mask |= LUA_MASKCALL;
+ if ((gDebugLevel & 2) != 0)
+ mask |= LUA_MASKRET;
+ if ((gDebugLevel & 4) != 0)
+ mask |= LUA_MASKLINE;
+
+ if (mask != 0)
+ lua_sethook(_state, debugHook, mask, 0);
+ }
+
+ BS_LOGLN("Lua initialized.");
+
+ return true;
+}
+
+bool LuaScriptEngine::executeFile(const Common::String &fileName) {
+#ifdef DEBUG
+ int __startStackDepth = lua_gettop(_state);
+#endif
+ debug(2, "LuaScriptEngine::executeFile(%s)", fileName.c_str());
+
+ // Get a pointer to the package manager
+ PackageManager *pPackage = static_cast<PackageManager *>(Kernel::GetInstance()->GetService("package"));
+ BS_ASSERT(pPackage);
+
+ // File read
+ uint fileSize;
+ byte *fileData = pPackage->getFile(fileName, &fileSize);
+ if (!fileData) {
+ BS_LOG_ERRORLN("Couldn't read \"%s\".", fileName.c_str());
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(_state));
+#endif
+ return false;
+ }
+
+ // Run the file content
+ if (!executeBuffer(fileData, fileSize, "@" + pPackage->getAbsolutePath(fileName))) {
+ // Release file buffer
+ delete[] fileData;
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(_state));
+#endif
+ return false;
+ }
+
+ // Release file buffer
+ delete[] fileData;
+
+#ifdef DEBUG
+ BS_ASSERT(__startStackDepth == lua_gettop(_state));
+#endif
+
+ return true;
+}
+
+bool LuaScriptEngine::executeString(const Common::String &code) {
+ return executeBuffer((byte *)code.c_str(), code.size(), "???");
+}
+
+namespace {
+
+void removeForbiddenFunctions(lua_State *L) {
+ static const char *FORBIDDEN_FUNCTIONS[] = {
+ "dofile",
+ 0
+ };
+
+ const char **iterator = FORBIDDEN_FUNCTIONS;
+ while (*iterator) {
+ lua_pushnil(L);
+ lua_setfield(L, LUA_GLOBALSINDEX, *iterator);
+ ++iterator;
+ }
+}
+}
+
+bool LuaScriptEngine::registerStandardLibs() {
+ luaL_openlibs(_state);
+ removeForbiddenFunctions(_state);
+ return true;
+}
+
+bool LuaScriptEngine::executeBuffer(const byte *data, uint size, const Common::String &name) const {
+ // Compile buffer
+ if (luaL_loadbuffer(_state, (const char *)data, size, name.c_str()) != 0) {
+ BS_LOG_ERRORLN("Couldn't compile \"%s\":\n%s", name.c_str(), lua_tostring(_state, -1));
+ lua_pop(_state, 1);
+
+ return false;
+ }
+
+ // Error handling function to be executed after the function is put on the stack
+ lua_rawgeti(_state, LUA_REGISTRYINDEX, _pcallErrorhandlerRegistryIndex);
+ lua_insert(_state, -2);
+
+ // Run buffer contents
+ if (lua_pcall(_state, 0, 0, -2) != 0) {
+ BS_LOG_ERRORLN("An error occured while executing \"%s\":\n%s.",
+ name.c_str(),
+ lua_tostring(_state, -1));
+ lua_pop(_state, 2);
+
+ return false;
+ }
+
+ // Remove the error handler function from the stack
+ lua_pop(_state, 1);
+
+ return true;
+}
+
+void LuaScriptEngine::setCommandLine(const Common::StringArray &commandLineParameters) {
+ lua_newtable(_state);
+
+ for (size_t i = 0; i < commandLineParameters.size(); ++i) {
+ lua_pushnumber(_state, i + 1);
+ lua_pushstring(_state, commandLineParameters[i].c_str());
+ lua_settable(_state, -3);
+ }
+
+ lua_setglobal(_state, "CommandLine");
+}
+
+namespace {
+const char *PERMANENTS_TABLE_NAME = "Permanents";
+
+// This array contains the name of global Lua objects that should not be persisted
+const char *STANDARD_PERMANENTS[] = {
+ "string",
+ "xpcall",
+ "package",
+ "tostring",
+ "print",
+ "os",
+ "unpack",
+ "require",
+ "getfenv",
+ "setmetatable",
+ "next",
+ "assert",
+ "tonumber",
+ "io",
+ "rawequal",
+ "collectgarbage",
+ "getmetatable",
+ "module",
+ "rawset",
+ "warning",
+ "math",
+ "debug",
+ "pcall",
+ "table",
+ "newproxy",
+ "type",
+ "coroutine",
+ "select",
+ "gcinfo",
+ "pairs",
+ "rawget",
+ "loadstring",
+ "ipairs",
+ "_VERSION",
+ "setfenv",
+ "load",
+ "error",
+ "loadfile",
+
+ "pairs_next",
+ "ipairs_next",
+ "pluto",
+ "Cfg",
+ "Translator",
+ "Persistence",
+ "CommandLine",
+ 0
+};
+
+enum PERMANENT_TABLE_TYPE {
+ PTT_PERSIST,
+ PTT_UNPERSIST
+};
+
+bool pushPermanentsTable(lua_State *L, PERMANENT_TABLE_TYPE tableType) {
+ // Permanents-Table
+ lua_newtable(L);
+
+ // All standard permanents are inserted into this table
+ uint Index = 0;
+ while (STANDARD_PERMANENTS[Index]) {
+ // Permanents are placed onto the stack; if it does not exist, it is simply ignored
+ lua_getglobal(L, STANDARD_PERMANENTS[Index]);
+ if (!lua_isnil(L, -1)) {
+ // Name of the element as a unique value on the stack
+ lua_pushstring(L, STANDARD_PERMANENTS[Index]);
+
+ // If it is loaded, then it can be used
+ // In this case, the position of name and object are reversed on the stack
+ if (tableType == PTT_UNPERSIST)
+ lua_insert(L, -2);
+
+ // Make an entry in the table
+ lua_settable(L, -3);
+ } else {
+ // Pop nil value from stack
+ lua_pop(L, 1);
+ }
+
+ ++Index;
+ }
+
+ // All registered C functions to be inserted into the table
+ // BS_LuaBindhelper places in the register a table in which all registered C functions
+ // are stored
+
+ // Table is put on the stack
+ lua_getfield(L, LUA_REGISTRYINDEX, PERMANENTS_TABLE_NAME);
+
+ if (!lua_isnil(L, -1)) {
+ // Iterate over all elements of the table
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ // Value and index duplicated on the stack and changed in the sequence
+ lua_pushvalue(L, -1);
+ lua_pushvalue(L, -3);
+
+ // If it is loaded, then it can be used
+ // In this case, the position of name and object are reversed on the stack
+ if (tableType == PTT_UNPERSIST)
+ lua_insert(L, -2);
+
+ // Make an entry in the results table
+ lua_settable(L, -6);
+
+ // Pop value from the stack. The index is then ready for the next call to lua_next()
+ lua_pop(L, 1);
+ }
+ }
+
+ // Pop the C-Permanents table from the stack
+ lua_pop(L, 1);
+
+ // coroutine.yield must be registered in the extra-Permanents table because they
+ // are inactive coroutine C functions on the stack
+
+ // Function coroutine.yield placed on the stack
+ lua_getglobal(L, "coroutine");
+ lua_pushstring(L, "yield");
+ lua_gettable(L, -2);
+
+ // Store coroutine.yield with it's own unique value in the Permanents table
+ lua_pushstring(L, "coroutine.yield");
+
+ if (tableType == PTT_UNPERSIST)
+ lua_insert(L, -2);
+
+ lua_settable(L, -4);
+
+ // Coroutine table is popped from the stack
+ lua_pop(L, 1);
+
+ return true;
+}
+}
+
+namespace {
+int chunkwriter(lua_State *L, const void *p, size_t sz, void *ud) {
+ Common::Array<byte> & chunkData = *reinterpret_cast<Common::Array<byte> * >(ud);
+ const byte *buffer = reinterpret_cast<const byte *>(p);
+
+ while (sz--)
+ chunkData.push_back(*buffer++);
+
+ return 1;
+}
+}
+
+bool LuaScriptEngine::persist(OutputPersistenceBlock &writer) {
+ // Empty the Lua stack. pluto_persist() xepects that the stack is empty except for its parameters
+ lua_settop(_state, 0);
+
+ // Garbage Collection erzwingen.
+ lua_gc(_state, LUA_GCCOLLECT, 0);
+
+ // Permanents-Table is set on the stack
+ // pluto_persist expects these two items on the Lua stack
+ pushPermanentsTable(_state, PTT_PERSIST);
+ lua_getglobal(_state, "_G");
+
+ // Lua persists and stores the data in a Common::Array
+ Common::Array<byte> chunkData;
+ pluto_persist(_state, chunkwriter, &chunkData);
+
+ // Persistenzdaten in den Writer schreiben.
+ writer.write(&chunkData[0], chunkData.size());
+
+ // Die beiden Tabellen vom Stack nehmen.
+ lua_pop(_state, 2);
+
+ return true;
+}
+
+namespace {
+
+struct ChunkreaderData {
+ void *BufferPtr;
+ size_t Size;
+ bool BufferReturned;
+};
+
+const char *chunkreader(lua_State *L, void *ud, size_t *sz) {
+ ChunkreaderData &cd = *reinterpret_cast<ChunkreaderData *>(ud);
+
+ if (!cd.BufferReturned) {
+ cd.BufferReturned = true;
+ *sz = cd.Size;
+ return reinterpret_cast<const char *>(cd.BufferPtr);
+ } else {
+ return 0;
+ }
+}
+
+void clearGlobalTable(lua_State *L, const char **exceptions) {
+ // Iterate over all elements of the global table
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ // Now the value and the index of the current element is on the stack
+ // This value does not interest us, so it is popped from the stack
+ lua_pop(L, 1);
+
+ // Determine whether the item is set to nil, so you want to remove from the global table.
+ // For this will determine whether the element name is a string and is present in
+ // the list of exceptions
+ bool setElementToNil = true;
+ if (lua_isstring(L, -1)) {
+ const char *indexString = lua_tostring(L, -1);
+ const char **exceptionsWalker = exceptions;
+ while (*exceptionsWalker) {
+ if (strcmp(indexString, *exceptionsWalker) == 0)
+ setElementToNil = false;
+ ++exceptionsWalker;
+ }
+ }
+
+ // If the above test showed that the item should be removed, it is removed by setting the value to nil.
+ if (setElementToNil) {
+ lua_pushvalue(L, -1);
+ lua_pushnil(L);
+ lua_settable(L, LUA_GLOBALSINDEX);
+ }
+ }
+
+ // Pop the Global table from the stack
+ lua_pop(L, 1);
+
+ // Perform garbage collection, so that all removed elements are deleted
+ lua_gc(L, LUA_GCCOLLECT, 0);
+}
+}
+
+bool LuaScriptEngine::unpersist(InputPersistenceBlock &reader) {
+ // Empty the Lua stack. pluto_persist() xepects that the stack is empty except for its parameters
+ lua_settop(_state, 0);
+
+ // Permanents table is placed on the stack. This has already happened at this point, because
+ // to create the table all permanents must be accessible. This is the case only for the
+ // beginning of the function, because the global table is emptied below
+ pushPermanentsTable(_state, PTT_UNPERSIST);
+
+ // All items from global table of _G and __METATABLES are removed.
+ // After a garbage collection is performed, and thus all managed objects deleted
+
+ // __METATABLES is not immediately removed becausen the Metatables are needed
+ // for the finalisers of objects.
+ static const char *clearExceptionsFirstPass[] = {
+ "_G",
+ "__METATABLES",
+ 0
+ };
+ clearGlobalTable(_state, clearExceptionsFirstPass);
+
+ // In the second pass, the Metatables are removed
+ static const char *clearExceptionsSecondPass[] = {
+ "_G",
+ 0
+ };
+ clearGlobalTable(_state, clearExceptionsSecondPass);
+
+ // Persisted Lua data
+ Common::Array<byte> chunkData;
+ reader.read(chunkData);
+
+ // Chunk-Reader initialisation. It is used with pluto_unpersist to restore read data
+ ChunkreaderData cd;
+ cd.BufferPtr = &chunkData[0];
+ cd.Size = chunkData.size();
+ cd.BufferReturned = false;
+
+ pluto_unpersist(_state, chunkreader, &cd);
+
+ // Permanents-Table is removed from stack
+ lua_remove(_state, -2);
+
+ // The read elements in the global table about
+ lua_pushnil(_state);
+ while (lua_next(_state, -2) != 0) {
+ // The referenec to the global table (_G) must not be overwritten, or ticks from Lua total
+ bool isGlobalReference = lua_isstring(_state, -2) && strcmp(lua_tostring(_state, -2), "_G") == 0;
+ if (!isGlobalReference) {
+ lua_pushvalue(_state, -2);
+ lua_pushvalue(_state, -2);
+
+ lua_settable(_state, LUA_GLOBALSINDEX);
+ }
+
+ // Pop value from the stack. The index is then ready for the next call to lua_next()
+ lua_pop(_state, 1);
+ }
+
+ // The table with the loaded data is popped from the stack
+ lua_pop(_state, 1);
+
+ // Force garbage collection
+ lua_gc(_state, LUA_GCCOLLECT, 0);
+
+ return true;
+}
+
+} // End of namespace Sword25
diff --git a/engines/sword25/script/luascript.h b/engines/sword25/script/luascript.h
new file mode 100644
index 0000000000..f557ae45f1
--- /dev/null
+++ b/engines/sword25/script/luascript.h
@@ -0,0 +1,116 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on Broken Sword 2.5 engine
+ *
+ * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
+ *
+ * Licensed under GNU GPL v2
+ *
+ */
+
+#ifndef SWORD25_LUASCRIPT_H
+#define SWORD25_LUASCRIPT_H
+
+#include "common/str.h"
+#include "common/str-array.h"
+#include "sword25/kernel/common.h"
+#include "sword25/script/script.h"
+
+namespace Lua {
+
+struct lua_State;
+
+}
+
+using namespace Lua;
+
+namespace Sword25 {
+
+class Kernel;
+
+class LuaScriptEngine : public ScriptEngine {
+public:
+ LuaScriptEngine(Kernel *KernelPtr);
+ virtual ~LuaScriptEngine();
+
+ /**
+ * Initialises the scripting engine
+ * @return Returns true if successful, otherwise false.
+ */
+ virtual bool init();
+
+ /**
+ * Loads a script file and executes it
+ * @param FileName The filename of the script
+ * @return Returns true if successful, otherwise false.
+ */
+ virtual bool executeFile(const Common::String &fileName);
+
+ /**
+ * Execute a string of script code
+ * @param Code A string of script code
+ * @return Returns true if successful, otherwise false.
+ */
+ virtual bool executeString(const Common::String &code);
+
+ /**
+ * Returns a pointer to the main object of the scripting language
+ * @remark Using this method breaks the encapsulation of the language
+ */
+ virtual void *getScriptObject() {
+ return _state;
+ }
+
+ /**
+ * Makes the command line parameters for the scripting environment available
+ * @param CommandLineParameters An array containing all the command line parameters
+ * @remark How the command line parameters will be used by scripts is
+ * dependant on the particular implementation.
+ */
+ virtual void setCommandLine(const Common::StringArray &commandLineParameters);
+
+ /**
+ * @remark The Lua stack is cleared by this method
+ */
+ virtual bool persist(OutputPersistenceBlock &writer);
+ /**
+ * @remark The Lua stack is cleared by this method
+ */
+ virtual bool unpersist(InputPersistenceBlock &reader);
+
+private:
+ lua_State *_state;
+ int _pcallErrorhandlerRegistryIndex;
+
+ bool registerStandardLibs();
+ bool registerStandardLibExtensions();
+ bool executeBuffer(const byte *data, uint size, const Common::String &name) const;
+};
+
+} // End of namespace Sword25
+
+#endif
diff --git a/engines/sword25/script/script.h b/engines/sword25/script/script.h
new file mode 100644
index 0000000000..2f72cf0cc8
--- /dev/null
+++ b/engines/sword25/script/script.h
@@ -0,0 +1,96 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/*
+ * This code is based on Broken Sword 2.5 engine
+ *
+ * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer
+ *
+ * Licensed under GNU GPL v2
+ *
+ */
+
+#ifndef SWORD25_SCRIPT_H
+#define SWORD25_SCRIPT_H
+
+#include "common/array.h"
+#include "common/str.h"
+#include "sword25/kernel/common.h"
+#include "sword25/kernel/service.h"
+#include "sword25/kernel/persistable.h"
+
+namespace Sword25 {
+
+class Kernel;
+class OutputPersistenceBlock;
+class BS_InputPersistenceBlock;
+
+class ScriptEngine : public Service, public Persistable {
+public:
+ ScriptEngine(Kernel *KernelPtr) : Service(KernelPtr) {};
+ virtual ~ScriptEngine() {};
+
+ // -----------------------------------------------------------------------------
+ // This method must be implemented by the script engine
+ // -----------------------------------------------------------------------------
+
+ /**
+ * Initialises the scrip tengine. Returns true if successful, false otherwise.
+ */
+ virtual bool init() = 0;
+
+ /**
+ * Loads a script file and executes it.
+ * @param FileName The script filename
+ */
+ virtual bool executeFile(const Common::String &fileName) = 0;
+
+ /**
+ * Executes a specified script fragment
+ * @param Code String of script code
+ */
+ virtual bool executeString(const Common::String &code) = 0;
+
+ /**
+ * Returns a pointer to the main object of the script engine
+ * Note: Using this method breaks the encapsulation of the language from the rest of the engine.
+ */
+ virtual void *getScriptObject() = 0;
+
+ /**
+ * Makes the command line parameters for the script environment available
+ * Note: How the command line parameters will be used by scripts is dependant on the
+ * particular implementation.
+ * @param CommandLineParameters List containing the command line parameters
+ */
+ virtual void setCommandLine(const Common::Array<Common::String> &commandLineParameters) = 0;
+
+ virtual bool persist(OutputPersistenceBlock &writer) = 0;
+ virtual bool unpersist(InputPersistenceBlock &reader) = 0;
+};
+
+} // End of namespace Sword25
+
+#endif