2019-06-02 13:11:05 +00:00
|
|
|
/* 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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "common/lua/lua.h"
|
|
|
|
#include "common/lua/lauxlib.h"
|
|
|
|
#include "common/lua/lualib.h"
|
2019-06-02 13:33:34 +00:00
|
|
|
#include "common/debug.h"
|
|
|
|
|
2019-06-02 13:11:05 +00:00
|
|
|
#include "hdb/lua-script.h"
|
|
|
|
|
|
|
|
namespace HDB {
|
|
|
|
|
2019-06-06 13:21:53 +00:00
|
|
|
struct ScriptPatch {
|
|
|
|
const char* scriptName;
|
|
|
|
const char* search;
|
|
|
|
const char* replace;
|
|
|
|
} scriptPatches[] = {
|
|
|
|
{"GLOBAL_LUA", "for i,npc in npcs do", "for i,npc in pairs(npcs) do"},
|
2019-06-06 14:47:54 +00:00
|
|
|
{"GLOBAL_LUA", "setglobal( npcdef.codename..\"_init\", function() return NPC_Init( %npcdef ) end )", "_G[npcdef.codename .. \"_init\"] = function() return NPC_Init( npcdef ) end"},
|
|
|
|
{"GLOBAL_LUA", "setglobal( npcdef.codename..\"_use\", function(x, y, v1, v2) return NPC_Use( %npcdef, x, y, v1, v2 ) end )", "_G[npcdef.codename .. \"_use\"] = function(x, y, v1, v2) return NPC_Use( npcdef, x, y, v1, v2 ) end"},
|
2019-06-08 16:48:45 +00:00
|
|
|
{"MAP00_LUA", "tempfunc = function() emptybed_use( %x, %y, %v1, %v2 ) end", "tempfunc = function() emptybed_use(x, y, v1, v2) end"},
|
2019-06-06 13:21:53 +00:00
|
|
|
{NULL, NULL, NULL},
|
|
|
|
};
|
|
|
|
|
2019-06-02 13:11:05 +00:00
|
|
|
LuaScript::LuaScript() {
|
|
|
|
_state = NULL;
|
2019-06-02 13:33:34 +00:00
|
|
|
_systemInit = false;
|
2019-06-02 13:11:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LuaScript::~LuaScript() {
|
|
|
|
if (_state) {
|
|
|
|
lua_close(_state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-05 08:45:22 +00:00
|
|
|
bool LuaScript::init() {
|
2019-06-05 22:11:38 +00:00
|
|
|
// Load Global Lua Code
|
2019-06-07 12:51:18 +00:00
|
|
|
_globalLuaStream = g_hdb->_fileMan->findFirstData("GLOBAL_LUA", TYPE_BINARY);
|
|
|
|
_globalLuaLength = g_hdb->_fileMan->getLength("GLOBAL_LUA", TYPE_BINARY);
|
2019-06-05 22:11:38 +00:00
|
|
|
if (_globalLuaStream == NULL || _globalLuaLength == 0) {
|
|
|
|
error("LuaScript::initScript: 'global code' failed to load");
|
2019-06-02 13:11:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-04 19:40:57 +00:00
|
|
|
return true;
|
2019-06-05 08:45:22 +00:00
|
|
|
}
|
2019-06-05 22:11:38 +00:00
|
|
|
|
2019-06-04 23:01:57 +00:00
|
|
|
/*
|
|
|
|
Called from Lua, this will pop into the menu
|
|
|
|
*/
|
|
|
|
|
2019-06-05 11:07:18 +00:00
|
|
|
static int cineStart(lua_State *L) {
|
2019-06-18 10:43:57 +00:00
|
|
|
double abortable = lua_tonumber(L, 1);
|
2019-06-18 15:10:47 +00:00
|
|
|
const char *abortFunc = lua_tostring(L, 2);
|
2019-06-18 10:43:57 +00:00
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineStart", 2);
|
|
|
|
|
|
|
|
lua_pop(L, 2);
|
|
|
|
|
|
|
|
g_hdb->_ai->cineStart((bool)abortable, abortFunc);
|
|
|
|
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineStop(lua_State *L) {
|
2019-06-23 21:16:26 +00:00
|
|
|
const char *funcNext = NULL;
|
|
|
|
|
|
|
|
int stackTop = lua_gettop(L);
|
|
|
|
if (stackTop) {
|
|
|
|
funcNext = lua_tostring(L, 1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_hdb->_ai->cineStop(funcNext);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineFadeInBlack(lua_State *L) {
|
2019-06-18 12:06:11 +00:00
|
|
|
double steps = lua_tonumber(L, 1);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineFadeInBlack", 1);
|
|
|
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
g_hdb->_ai->cineFadeIn(false, (int) steps);
|
|
|
|
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineFadeOutBlack(lua_State *L) {
|
2019-06-18 12:06:11 +00:00
|
|
|
double steps = lua_tonumber(L, 1);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineFadeOutBlack", 1);
|
|
|
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
g_hdb->_ai->cineFadeOut(false, (int)steps);
|
|
|
|
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineFadeInWhite(lua_State *L) {
|
2019-06-18 12:06:11 +00:00
|
|
|
double steps = lua_tonumber(L, 1);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineFadeInWhite", 1);
|
|
|
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
g_hdb->_ai->cineFadeIn(true, (int)steps);
|
|
|
|
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineFadeOutWhite(lua_State *L) {
|
2019-06-18 12:06:11 +00:00
|
|
|
double steps = lua_tonumber(L, 1);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineFadeOutWhite", 1);
|
|
|
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
g_hdb->_ai->cineFadeOut(true, (int)steps);
|
|
|
|
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineStartMap(lua_State *L) {
|
|
|
|
warning("STUB: CINE START MAP");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineLockPlayer(lua_State *L) {
|
2019-06-20 12:19:02 +00:00
|
|
|
g_hdb->_ai->cineLockPlayer();
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineUnlockPlayer(lua_State *L) {
|
2019-06-20 12:19:02 +00:00
|
|
|
g_hdb->_ai->cineUnlockPlayer();
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineSetCamera(lua_State *L) {
|
2019-06-18 10:45:14 +00:00
|
|
|
double x = lua_tonumber(L, 1);
|
|
|
|
double y = lua_tonumber(L, 2);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineSetCamera", 2);
|
|
|
|
|
|
|
|
lua_pop(L, 2);
|
|
|
|
|
|
|
|
g_hdb->_ai->cineSetCamera((int) x, (int) y);
|
|
|
|
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineResetCamera(lua_State *L) {
|
2019-06-18 10:46:13 +00:00
|
|
|
g_hdb->_ai->cineResetCamera();
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineMoveCamera(lua_State *L) {
|
2019-06-18 10:47:28 +00:00
|
|
|
double x = lua_tonumber(L, 1);
|
|
|
|
double y = lua_tonumber(L, 2);
|
|
|
|
double speed = lua_tonumber(L, 3);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineMoveCamera", 3);
|
|
|
|
|
|
|
|
lua_pop(L, 3);
|
|
|
|
g_hdb->_ai->cineMoveCamera((int) x, (int) y, (int) speed);
|
|
|
|
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineWait(lua_State *L) {
|
2019-06-18 10:47:53 +00:00
|
|
|
double seconds = lua_tonumber(L, 1);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineWait", 1);
|
|
|
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
g_hdb->_ai->cineWait((int) seconds);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineWaitUntilDone(lua_State *L) {
|
2019-06-18 10:47:53 +00:00
|
|
|
g_hdb->_ai->cineWaitUntilDone();
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cinePlaySound(lua_State *L) {
|
|
|
|
warning("STUB: CINE PLAY SOUND");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cinePlayVoice(lua_State *L) {
|
|
|
|
warning("STUB: CINE PLAY VOICE");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineUseEntity(lua_State *L) {
|
2019-06-19 18:32:53 +00:00
|
|
|
const char *string = lua_tostring(L, 1);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineUseEntity", 1);
|
|
|
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
g_hdb->_ai->cineUse(string);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineSetEntity(lua_State *L) {
|
2019-06-18 19:47:25 +00:00
|
|
|
const char *entName = lua_tostring(L, 1);
|
|
|
|
double x = lua_tonumber(L, 2);
|
|
|
|
double y = lua_tonumber(L, 3);
|
|
|
|
double level = lua_tonumber(L, 4);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineSetEntity", 4);
|
|
|
|
|
|
|
|
lua_pop(L, 4);
|
|
|
|
g_hdb->_ai->cineSetEntity(entName, (int)x, (int)y, (int)level);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineRemoveEntity(lua_State *L) {
|
|
|
|
warning("STUB: CINE REMOVE ENTITY");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineMoveEntity(lua_State *L) {
|
2019-06-20 12:45:29 +00:00
|
|
|
const char *entName = lua_tostring(L, 1);
|
|
|
|
double x = lua_tonumber(L, 2);
|
|
|
|
double y = lua_tonumber(L, 3);
|
|
|
|
double level = lua_tonumber(L, 4);
|
|
|
|
double speed = lua_tonumber(L, 5);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineMoveEntity", 5);
|
|
|
|
|
|
|
|
lua_pop(L, 5);
|
|
|
|
g_hdb->_ai->cineMoveEntity(entName, (int)x, (int)y, (int)level, (int)speed);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineAnimEntity(lua_State *L) {
|
2019-06-23 21:33:35 +00:00
|
|
|
const char *entName = lua_tostring(L, 1);
|
|
|
|
double state = lua_tonumber(L, 2);
|
2019-06-26 13:23:04 +00:00
|
|
|
double loop = lua_tonumber(L, 3);
|
2019-06-23 21:33:35 +00:00
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineAnimEntity", 3);
|
|
|
|
|
|
|
|
lua_pop(L, 3);
|
|
|
|
int s = (int)state;
|
|
|
|
g_hdb->_ai->cineAnimEntity(entName, (AIState)s, (int)loop);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineSetAnimFrame(lua_State *L) {
|
2019-06-23 21:46:13 +00:00
|
|
|
const char *entName = lua_tostring(L, 1);
|
|
|
|
double state = lua_tonumber(L, 2);
|
2019-06-26 13:23:04 +00:00
|
|
|
double frame = lua_tonumber(L, 3);
|
2019-06-23 21:46:13 +00:00
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineSetAnimFrame", 3);
|
|
|
|
|
|
|
|
lua_pop(L, 3);
|
|
|
|
int s = (int)state;
|
|
|
|
g_hdb->_ai->cineSetAnimFrame(entName, (AIState)s, (int)frame);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineDialog(lua_State *L) {
|
2019-06-23 01:22:12 +00:00
|
|
|
const char *title = lua_tostring(L, 1);
|
2019-06-26 17:58:14 +00:00
|
|
|
const char *string = lua_tostring(L, 2);
|
2019-06-23 01:22:12 +00:00
|
|
|
double seconds = lua_tonumber(L, 3);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineDialog", 3);
|
|
|
|
|
|
|
|
lua_pop(L, 3);
|
|
|
|
g_hdb->_ai->cineDialog(title, string, (int)seconds);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineDrawPic(lua_State *L) {
|
|
|
|
warning("STUB: CINE DRAW PIC");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineDrawMaskedPic(lua_State *L) {
|
|
|
|
warning("STUB: CINE DRAW MASKED PIC");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineMovePic(lua_State *L) {
|
|
|
|
warning("STUB: CINE MOVE PIC");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineMoveMaskedPic(lua_State *L) {
|
2019-06-23 20:44:08 +00:00
|
|
|
const char *id = lua_tostring(L, 1);
|
|
|
|
const char *pic = lua_tostring(L, 2);
|
|
|
|
double x1 = lua_tonumber(L, 3);
|
|
|
|
double y1 = lua_tonumber(L, 4);
|
|
|
|
double x2 = lua_tonumber(L, 5);
|
|
|
|
double y2 = lua_tonumber(L, 6);
|
|
|
|
double speed = lua_tonumber(L, 7);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineMoveMaskedPic", 7);
|
|
|
|
|
|
|
|
x1 += kCameraXOff;
|
|
|
|
y1 += kCameraYOff;
|
|
|
|
x2 += kCameraXOff;
|
|
|
|
y2 += kCameraYOff;
|
|
|
|
|
|
|
|
lua_pop(L, 7);
|
|
|
|
|
|
|
|
g_hdb->_ai->cineMoveMaskedPic(id, pic, (int)x1, (int)y1, (int)x2, (int)y2, (int)speed);
|
|
|
|
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineSpawnEntity(lua_State *L) {
|
|
|
|
warning("STUB: CINE SPAWN ENTITY");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineClearForeground(lua_State *L) {
|
2019-06-21 01:09:48 +00:00
|
|
|
double x = lua_tonumber(L, 1);
|
2019-06-26 13:23:04 +00:00
|
|
|
double y = lua_tonumber(L, 2);
|
2019-06-21 01:09:48 +00:00
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineClearForeground", 2);
|
|
|
|
|
|
|
|
lua_pop(L, 2);
|
|
|
|
g_hdb->_ai->cineClearForeground((int)x, (int)y);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineSetForeground(lua_State *L) {
|
2019-06-21 01:09:48 +00:00
|
|
|
double x = lua_tonumber(L, 1);
|
2019-06-26 13:23:04 +00:00
|
|
|
double y = lua_tonumber(L, 2);
|
2019-06-21 01:09:48 +00:00
|
|
|
const char *tileName = lua_tostring(L, 3);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineSetForeground", 3);
|
|
|
|
|
|
|
|
lua_pop(L, 3);
|
|
|
|
int index = g_hdb->_drawMan->getTileIndex(tileName);
|
|
|
|
g_hdb->_drawMan->getTile(index);
|
|
|
|
g_hdb->_ai->cineSetForeground((int)x, (int)y, index);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineSetBackground(lua_State *L) {
|
2019-06-21 01:09:48 +00:00
|
|
|
double x = lua_tonumber(L, 1);
|
2019-06-26 13:23:04 +00:00
|
|
|
double y = lua_tonumber(L, 2);
|
2019-06-21 01:09:48 +00:00
|
|
|
const char *tileName = lua_tostring(L, 3);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("cineSetBackground", 3);
|
|
|
|
|
|
|
|
lua_pop(L, 3);
|
|
|
|
int index = g_hdb->_drawMan->getTileIndex(tileName);
|
|
|
|
g_hdb->_drawMan->getTile(index);
|
|
|
|
g_hdb->_ai->cineSetBackground((int)x, (int)y, index);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineFunction(lua_State *L) {
|
|
|
|
warning("STUB: CINE FUNCTION");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineEntityFace(lua_State *L) {
|
2019-06-20 13:03:44 +00:00
|
|
|
const char *luaName = lua_tostring(L, 1);
|
|
|
|
double dir = lua_tonumber(L, 2);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("CineEntityFace", 2);
|
|
|
|
|
|
|
|
lua_pop(L, 2);
|
|
|
|
g_hdb->_ai->cineEntityFace(luaName, dir);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineTextOut(lua_State *L) {
|
|
|
|
warning("STUB: CINE TEXT OUT");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cineCenterTextOut(lua_State *L) {
|
|
|
|
warning("STUB: CINE CENTER TEXT OUT");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int newDelivery(lua_State *L) {
|
|
|
|
warning("STUB: NEW DELIVERY");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int completeDelivery(lua_State *L) {
|
|
|
|
warning("STUB: COMPLETE DELIVERY");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int deliveriesLeft(lua_State *L) {
|
|
|
|
warning("STUB: DELIVERIES LEFT");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int getEntityXY(lua_State *L) {
|
|
|
|
warning("STUB: GET ENTITYXY");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int setEntity(lua_State *L) {
|
2019-06-18 19:47:25 +00:00
|
|
|
AIEntity *e = NULL;
|
|
|
|
|
|
|
|
const char *entName = lua_tostring(L, 1);
|
|
|
|
double x = lua_tonumber(L, 2);
|
|
|
|
double y = lua_tonumber(L, 3);
|
|
|
|
double level = lua_tonumber(L, 4);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("setEntity", 4);
|
|
|
|
|
|
|
|
lua_pop(L, 4);
|
2019-06-19 12:06:00 +00:00
|
|
|
e = g_hdb->_ai->locateEntity(entName);
|
2019-06-18 19:47:25 +00:00
|
|
|
if (e) {
|
|
|
|
e->x = (int)x * kTileWidth;
|
|
|
|
e->tileX = (int)x;
|
|
|
|
e->y = (int)y * kTileHeight;
|
|
|
|
e->tileY = (int)y;
|
|
|
|
e->level = (int)level;
|
|
|
|
e->goalX = e->goalY = e->xVel = e->yVel = 0;
|
|
|
|
e->state = STATE_STANDDOWN;
|
|
|
|
} else {
|
2019-06-19 12:06:00 +00:00
|
|
|
warning("Couldn't SetEntity on '%s'", entName);
|
2019-06-18 19:47:25 +00:00
|
|
|
}
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int setEntDir(lua_State *L) {
|
|
|
|
warning("STUB: SET ENTITY DIR");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int removeEntity(lua_State *L) {
|
|
|
|
warning("STUB: REMOVE ENTITY");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int animEntity(lua_State *L) {
|
2019-06-20 13:43:19 +00:00
|
|
|
const char *entName = lua_tostring(L, 1);
|
|
|
|
double state = lua_tonumber(L, 2);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("animEntity", 2);
|
|
|
|
|
|
|
|
lua_pop(L, 2);
|
|
|
|
int s = (int)state;
|
|
|
|
g_hdb->_ai->animLuaEntity(entName, (AIState)s);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int setAnimFrame(lua_State *L) {
|
|
|
|
warning("STUB: SET ANIM FRAME");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int useEntity(lua_State *L) {
|
|
|
|
warning("STUB: USE ENTITY");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int entityFace(lua_State *L) {
|
|
|
|
warning("STUB: ENTITY FACE");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int clearForeground(lua_State *L) {
|
|
|
|
warning("STUB: CLEAR FOREGROUND");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int setForeground(lua_State *L) {
|
2019-06-21 00:50:52 +00:00
|
|
|
double x = lua_tonumber(L, 1);
|
|
|
|
double y = lua_tonumber(L, 2);
|
|
|
|
const char *tileName = lua_tostring(L, 3);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("setForeground", 3);
|
|
|
|
|
|
|
|
lua_pop(L, 3);
|
|
|
|
int index = g_hdb->_drawMan->getTileIndex(tileName);
|
|
|
|
g_hdb->_drawMan->getTile(index);
|
|
|
|
g_hdb->_map->setMapFGTileIndex((int)x, (int)y, index);
|
|
|
|
g_hdb->_map->addFGTileAnimation((int)x, (int)y);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int setBackground(lua_State *L) {
|
2019-06-21 00:50:52 +00:00
|
|
|
double x = lua_tonumber(L, 1);
|
|
|
|
double y = lua_tonumber(L, 2);
|
|
|
|
const char *tileName = lua_tostring(L, 3);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("setBackground", 3);
|
|
|
|
|
|
|
|
lua_pop(L, 3);
|
|
|
|
int index = g_hdb->_drawMan->getTileIndex(tileName);
|
|
|
|
g_hdb->_drawMan->getTile(index);
|
|
|
|
g_hdb->_map->setMapBGTileIndex((int)x, (int)y, index);
|
|
|
|
g_hdb->_map->addBGTileAnimation((int)x, (int)y);
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dialog(lua_State *L) {
|
|
|
|
warning("STUB: DIALOG");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dialogChoice(lua_State *L) {
|
|
|
|
warning("STUB: DIALOG CHOICE");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int message(lua_State *L) {
|
|
|
|
warning("STUB: MESSAGE");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int animation(lua_State *L) {
|
|
|
|
warning("STUB: ANIMATION");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int spawnEntity(lua_State *L) {
|
|
|
|
warning("STUB: SPAWN ENTITY");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int addInvItem(lua_State *L) {
|
|
|
|
warning("STUB: ADD INVENTORY ITEM");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int keepInvItem(lua_State *L) {
|
|
|
|
warning("STUB: KEEP INVENTORY ITEM");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int queryInv(lua_State *L) {
|
|
|
|
warning("STUB: QUERY INVENTORY");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int purgeInv(lua_State *L) {
|
|
|
|
warning("STUB: PURGE INVENTORY");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int queryInvItem(lua_State *L) {
|
|
|
|
warning("STUB: QUERY INVENTORY ITEM");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int removeInv(lua_State *L) {
|
|
|
|
warning("STUB: REMOVE INVENTORY");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int removeInvItem(lua_State *L) {
|
|
|
|
warning("STUB: REMOVE INVENTORY ITEM");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int killTrigger(lua_State *L) {
|
|
|
|
warning("STUB: KILL TRIGGER");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int startMusic(lua_State *L) {
|
|
|
|
warning("STUB: START MUSIC");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fadeInMusic(lua_State *L) {
|
|
|
|
warning("STUB: FADE IN MUSIC");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int stopMusic(lua_State *L) {
|
|
|
|
warning("STUB: STOP MUSIC");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fadeOutMusic(lua_State *L) {
|
|
|
|
warning("STUB: FADE OUT MUSIC");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int registerSound(lua_State *L) {
|
|
|
|
warning("STUB: REGISTER SOUND");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int playSound(lua_State *L) {
|
|
|
|
warning("STUB: PLAY SOUND");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int freeSound(lua_State *L) {
|
|
|
|
warning("STUB: FREE SOUND");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int startMap(lua_State *L) {
|
|
|
|
warning("STUB: START MAP");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int saveGlobal(lua_State *L) {
|
|
|
|
warning("STUB: SAVE GLOBAL");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int loadGlobal(lua_State *L) {
|
|
|
|
warning("STUB: LOAD GLOBAL");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int purgeGlobals(lua_State *L) {
|
|
|
|
warning("STUB: PURGE GLOBALS");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int textOut(lua_State *L) {
|
|
|
|
warning("STUB: TEXT OUT");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int centerTextOut(lua_State *L) {
|
|
|
|
warning("STUB: CENTER TEXT OUT");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int turnOnSnow(lua_State *L) {
|
|
|
|
warning("STUB: TURN ON SNOW");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int turnOffSnow(lua_State *L) {
|
|
|
|
warning("STUB: TURN OFF SNOW");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-04 23:01:57 +00:00
|
|
|
static int gotoMenu(lua_State *L) {
|
|
|
|
g_hdb->changeGameState();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-05 11:07:18 +00:00
|
|
|
static int setInfobarDark(lua_State *L) {
|
2019-06-23 16:46:21 +00:00
|
|
|
double value = lua_tonumber(L, 1);
|
|
|
|
|
|
|
|
g_hdb->_lua->checkParameters("setInfobarDark", 1);
|
|
|
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
g_hdb->_window->setInfobarDark((int)value);
|
|
|
|
|
2019-06-05 11:07:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int setPointerState(lua_State *L) {
|
|
|
|
warning("STUB: SET POINTER STATE");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int playVoice(lua_State *L) {
|
|
|
|
warning("STUB: PLAY VOICE");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Lua Initialization Code
|
|
|
|
*/
|
|
|
|
|
2019-06-04 19:40:57 +00:00
|
|
|
struct VarInit {
|
2019-06-05 22:59:40 +00:00
|
|
|
const char *realName;
|
|
|
|
const char *luaName;
|
2019-06-04 19:40:57 +00:00
|
|
|
} luaGlobalStrings[] = {
|
|
|
|
{ "Map00", "MAP00"},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
// For AI States, to be implemented
|
|
|
|
struct NumberInit {
|
|
|
|
int value;
|
2019-06-26 22:27:23 +00:00
|
|
|
const char *luaName;
|
2019-06-04 19:40:57 +00:00
|
|
|
} luaGlobalValues[] = {
|
2019-06-26 22:27:23 +00:00
|
|
|
{ DIR_NONE, "DIR_NONE" },
|
|
|
|
{ DIR_DOWN, "DIR_DOWN" },
|
|
|
|
{ DIR_UP, "DIR_UP" },
|
|
|
|
{ DIR_LEFT, "DIR_LEFT" },
|
|
|
|
{ DIR_RIGHT, "DIR_RIGHT" },
|
|
|
|
{ NULL, NULL }
|
2019-06-04 19:40:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct FuncInit {
|
2019-06-05 22:59:40 +00:00
|
|
|
const char *luaName;
|
2019-06-04 19:40:57 +00:00
|
|
|
int (*function) (lua_State *L);
|
|
|
|
} luaFuncs[] = {
|
2019-06-05 11:07:18 +00:00
|
|
|
{ "Dialog", dialog },
|
|
|
|
{ "DialogChoice", dialogChoice },
|
|
|
|
{ "Message", message },
|
|
|
|
{ "QueryInv", queryInv },
|
|
|
|
{ "QueryInvItem", queryInvItem },
|
|
|
|
{ "RemoveInv", removeInv },
|
|
|
|
{ "RemoveInvItem", removeInvItem },
|
|
|
|
{ "AddInvItem", addInvItem },
|
|
|
|
{ "KeepInvItem", keepInvItem },
|
|
|
|
{ "PurgeInv", purgeInv },
|
|
|
|
{ "StartMusic", startMusic },
|
|
|
|
{ "StopMusic", stopMusic },
|
|
|
|
{ "FadeInMusic", fadeInMusic },
|
|
|
|
{ "FadeOutMusic", fadeOutMusic },
|
|
|
|
{ "RegisterSound", registerSound },
|
|
|
|
{ "PlaySound", playSound },
|
|
|
|
{ "FreeSound", freeSound },
|
|
|
|
{ "StartMap", startMap },
|
|
|
|
{ "Tile_ClearFG", clearForeground },
|
|
|
|
{ "Tile_SetFG", setForeground },
|
|
|
|
{ "Tile_SetBG", setBackground },
|
|
|
|
{ "GetEntityXY", getEntityXY },
|
|
|
|
{ "UseEntity", useEntity },
|
|
|
|
{ "SetEntity", setEntity },
|
|
|
|
{ "SetEntDir", setEntDir },
|
|
|
|
{ "RemoveEntity", removeEntity },
|
|
|
|
{ "AnimEntity", animEntity },
|
|
|
|
{ "SetAnimFrame", setAnimFrame },
|
|
|
|
{ "EntityFace", entityFace },
|
|
|
|
{ "KillTrigger", killTrigger },
|
|
|
|
{ "SpawnEntity", spawnEntity },
|
|
|
|
{ "Animation", animation },
|
|
|
|
{ "NewDelivery", newDelivery },
|
|
|
|
{ "CompleteDelivery", completeDelivery },
|
|
|
|
{ "DeliveriesLeft", deliveriesLeft },
|
|
|
|
{ "SaveGlobal", saveGlobal },
|
|
|
|
{ "LoadGlobal", loadGlobal },
|
|
|
|
{ "PurgeGlobals", purgeGlobals },
|
|
|
|
{ "TextOut", textOut },
|
|
|
|
{ "CenterTextOut", centerTextOut },
|
|
|
|
{ "SnowOn", turnOnSnow },
|
|
|
|
{ "SnowOff", turnOffSnow },
|
|
|
|
{ "GotoMenu", gotoMenu },
|
|
|
|
{ "SetInfobarDark", setInfobarDark },
|
|
|
|
{ "SetPointerState", setPointerState },
|
|
|
|
{ "PlayVoice", playVoice },
|
|
|
|
|
|
|
|
{ "Cine_StartCine", cineStart },
|
|
|
|
{ "Cine_StopCine", cineStop },
|
|
|
|
{ "Cine_StartMap", cineStartMap },
|
|
|
|
{ "Cine_LockPlayer", cineLockPlayer },
|
|
|
|
{ "Cine_UnlockPlayer", cineUnlockPlayer },
|
|
|
|
{ "Cine_SetCamera", cineSetCamera },
|
|
|
|
{ "Cine_ResetCamera", cineResetCamera },
|
|
|
|
{ "Cine_MoveCamera", cineMoveCamera },
|
|
|
|
{ "Cine_Wait", cineWait },
|
|
|
|
{ "Cine_WaitUntilDone", cineWaitUntilDone },
|
|
|
|
{ "Cine_UseEntity", cineUseEntity },
|
|
|
|
{ "Cine_SetEntity", cineSetEntity },
|
|
|
|
{ "Cine_RemoveEntity", cineRemoveEntity },
|
|
|
|
{ "Cine_EntityFace", cineEntityFace },
|
|
|
|
{ "Cine_MoveEntity", cineMoveEntity },
|
|
|
|
{ "Cine_AnimEntity", cineAnimEntity },
|
|
|
|
{ "Cine_SetAnimFrame", cineSetAnimFrame },
|
|
|
|
{ "Cine_Dialog", cineDialog },
|
|
|
|
{ "Cine_DrawPic", cineDrawPic },
|
|
|
|
{ "Cine_DrawMaskedPic", cineDrawMaskedPic },
|
|
|
|
{ "Cine_MovePic", cineMovePic },
|
|
|
|
{ "Cine_MoveMaskedPic", cineMoveMaskedPic },
|
|
|
|
{ "Cine_FadeOutBlack", cineFadeOutBlack },
|
|
|
|
{ "Cine_FadeInBlack", cineFadeInBlack },
|
|
|
|
{ "Cine_FadeOutWhite", cineFadeOutWhite },
|
|
|
|
{ "Cine_FadeInWhite", cineFadeInWhite },
|
|
|
|
{ "Cine_SpawnEntity", cineSpawnEntity },
|
|
|
|
{ "Cine_PlaySound", cinePlaySound },
|
|
|
|
{ "Cine_Tile_ClearFG", cineClearForeground },
|
|
|
|
{ "Cine_Tile_SetFG", cineSetForeground },
|
|
|
|
{ "Cine_Tile_SetBG", cineSetBackground },
|
|
|
|
{ "Cine_Function", cineFunction },
|
|
|
|
{ "Cine_TextOut", cineTextOut },
|
|
|
|
{ "Cine_CenterTextOut", cineCenterTextOut },
|
|
|
|
{ "Cine_PlayVoice", cinePlayVoice },
|
|
|
|
{ NULL, NULL }
|
2019-06-04 19:40:57 +00:00
|
|
|
};
|
|
|
|
|
2019-06-05 23:14:16 +00:00
|
|
|
namespace {
|
|
|
|
int panicCB(lua_State *L) {
|
|
|
|
error("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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-06 13:21:53 +00:00
|
|
|
bool LuaScript::initScript(Common::SeekableReadStream *stream, const char *scriptName, int32 length) {
|
2019-06-04 19:40:57 +00:00
|
|
|
|
|
|
|
if (_systemInit) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize Lua Environment
|
|
|
|
_state = lua_open();
|
|
|
|
if (_state == NULL) {
|
|
|
|
error("Couldn't initialize Lua script.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
luaL_openlibs(_state);
|
|
|
|
|
|
|
|
_systemInit = true;
|
|
|
|
|
|
|
|
// Register Extensions
|
|
|
|
for (int i = 0; luaFuncs[i].luaName; i++) {
|
|
|
|
lua_register(_state, luaFuncs[i].luaName, luaFuncs[i].function);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Register Lua Globals
|
|
|
|
|
|
|
|
for (int i = 0; luaGlobalStrings[i].realName; i++) {
|
|
|
|
lua_pushstring(_state, luaGlobalStrings[i].realName);
|
|
|
|
lua_setglobal(_state, luaGlobalStrings[i].luaName);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int j = 0; luaGlobalValues[j].luaName; j++) {
|
|
|
|
lua_pushnumber(_state, luaGlobalValues[j].value);
|
|
|
|
lua_setglobal(_state, luaGlobalValues[j].luaName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
TODO: Set the last mapName as a global
|
|
|
|
after implementing the map-manager.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Set the lowest printable line
|
|
|
|
lua_pushnumber(_state, 480 - 14);
|
|
|
|
lua_setglobal(_state, "BOTTOM_Y");
|
|
|
|
|
|
|
|
/*
|
|
|
|
TODO: Load the sound names and entity
|
|
|
|
spawn names into Lua once they are implemented.
|
|
|
|
*/
|
|
|
|
|
2019-06-19 11:36:29 +00:00
|
|
|
// Set the Entity Spawn Names in Lua
|
|
|
|
int j = 0;
|
|
|
|
while (aiEntList[j].luaName) {
|
|
|
|
lua_pushnumber(_state, aiEntList[j].type);
|
|
|
|
lua_setglobal(_state, aiEntList[j].luaName);
|
|
|
|
j++;
|
|
|
|
}
|
2019-06-19 10:23:22 +00:00
|
|
|
|
2019-06-05 23:22:09 +00:00
|
|
|
// Register panic callback function
|
2019-06-05 23:14:16 +00:00
|
|
|
lua_atpanic(_state, panicCB);
|
|
|
|
|
2019-06-05 23:22:09 +00:00
|
|
|
// Error handler for lua_pcall calls
|
|
|
|
// The code below contains a local error handler function
|
2019-06-05 23:14:16 +00:00
|
|
|
const char errorHandlerCode[] =
|
|
|
|
"local function ErrorHandler(message) "
|
|
|
|
" return message .. '\\n' .. debug.traceback('', 2) "
|
|
|
|
"end "
|
|
|
|
"return ErrorHandler";
|
|
|
|
|
2019-06-05 23:22:09 +00:00
|
|
|
// Compile the code
|
2019-06-05 23:14:16 +00:00
|
|
|
if (luaL_loadbuffer(_state, errorHandlerCode, strlen(errorHandlerCode), "PCALL ERRORHANDLER") != 0) {
|
|
|
|
// An error occurred, so dislay the reason and exit
|
|
|
|
error("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
|
|
|
|
error("Couldn't prepare luaL_pcall errorhandler:\n%s", lua_tostring(_state, -1));
|
|
|
|
lua_pop(_state, 1);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-05 23:22:09 +00:00
|
|
|
// Place the error handler function in the Lua registry, and remember the index
|
|
|
|
_pcallErrorhandlerRegistryIndex = luaL_ref(_state, LUA_REGISTRYINDEX);
|
|
|
|
|
2019-06-06 07:53:16 +00:00
|
|
|
if (gDebugLevel >= 8) {
|
|
|
|
// Initialize debugging callback
|
|
|
|
lua_sethook(_state, debugHook, LUA_MASKCALL | LUA_MASKLINE, 0);
|
|
|
|
}
|
2019-06-05 23:14:16 +00:00
|
|
|
|
2019-06-05 21:28:11 +00:00
|
|
|
// Load GLOBAL_LUA and execute it
|
2019-06-04 19:40:57 +00:00
|
|
|
|
2019-06-06 13:21:53 +00:00
|
|
|
if (!executeMPC(_globalLuaStream, "global code", "GLOBAL_LUA", _globalLuaLength)) {
|
2019-06-05 22:11:38 +00:00
|
|
|
error("LuaScript::initScript: 'global code' failed to execute");
|
|
|
|
return false;
|
|
|
|
}
|
2019-06-05 22:58:36 +00:00
|
|
|
|
2019-06-04 19:40:57 +00:00
|
|
|
// Load script and execute it
|
|
|
|
|
2019-06-06 13:21:53 +00:00
|
|
|
if (!executeMPC(stream, "level code", scriptName, length)) {
|
2019-06-04 19:40:57 +00:00
|
|
|
error("LuaScript::initScript: 'level code' failed to execute");
|
|
|
|
return false;
|
|
|
|
}
|
2019-06-05 22:58:36 +00:00
|
|
|
|
2019-06-22 21:52:34 +00:00
|
|
|
lua_getglobal(_state, "level_init");
|
|
|
|
|
2019-06-06 07:48:54 +00:00
|
|
|
// Error handling function to be executed after the function is put on the stack
|
|
|
|
lua_rawgeti(_state, LUA_REGISTRYINDEX, _pcallErrorhandlerRegistryIndex);
|
|
|
|
lua_insert(_state, -2);
|
|
|
|
|
|
|
|
if (lua_pcall(_state, 0, 0, -2)) {
|
|
|
|
error("An error occured while executing \"%s\": %s.", "level_init", lua_tostring(_state, -1));
|
|
|
|
lua_pop(_state, -1);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2019-06-05 22:58:36 +00:00
|
|
|
|
2019-06-20 14:09:35 +00:00
|
|
|
// Remove the error handler function from the stack
|
|
|
|
lua_pop(_state, 1);
|
|
|
|
|
2019-06-02 13:11:05 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-06-27 01:40:08 +00:00
|
|
|
void LuaScript::pushInt(int value) {
|
|
|
|
if (!_systemInit)
|
|
|
|
return;
|
|
|
|
lua_pushnumber(_state, (double)value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LuaScript::pushString(char *string) {
|
|
|
|
if (!_systemInit)
|
|
|
|
return;
|
|
|
|
lua_pushstring(_state, string);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LuaScript::pushFunction(char *func) {
|
2019-06-27 02:01:17 +00:00
|
|
|
int type;
|
|
|
|
|
2019-06-27 01:40:08 +00:00
|
|
|
if (!_systemInit)
|
|
|
|
return;
|
|
|
|
|
|
|
|
lua_getglobal(_state, func);
|
2019-06-27 02:01:17 +00:00
|
|
|
type = lua_type(_state, 1);
|
|
|
|
if (type != LUA_TFUNCTION && type != LUA_TNUMBER) {
|
|
|
|
warning("pushFunction: Function '%s' doesn't exists", func);
|
|
|
|
}
|
2019-06-27 01:40:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LuaScript::call(int args, int returns) {
|
|
|
|
if (!_systemInit)
|
|
|
|
return;
|
|
|
|
|
|
|
|
lua_call(_state, args, returns);
|
|
|
|
}
|
|
|
|
|
2019-06-17 22:44:45 +00:00
|
|
|
bool LuaScript::callFunction(const char *name, int returns) {
|
|
|
|
if (!_systemInit) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
lua_getglobal(_state, name);
|
|
|
|
|
2019-06-20 10:58:21 +00:00
|
|
|
if (lua_pcall(_state, 0, returns, -2)) {
|
2019-06-17 22:44:45 +00:00
|
|
|
error("An error occured while executing \"%s\": %s.", name, lua_tostring(_state, -1));
|
|
|
|
lua_pop(_state, -1);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-06-27 02:09:50 +00:00
|
|
|
void LuaScript::invokeLuaFunction(char *luaFunc, int x, int y, int value1, int value2) {
|
|
|
|
int type;
|
|
|
|
|
|
|
|
if (!_systemInit)
|
|
|
|
return;
|
|
|
|
|
|
|
|
lua_getglobal(_state, luaFunc);
|
|
|
|
type = lua_type(_state, 1);
|
|
|
|
if (type != LUA_TFUNCTION) {
|
|
|
|
warning("Function '%s' doesn't exist", luaFunc);
|
|
|
|
} else {
|
|
|
|
lua_pushnumber(_state, x);
|
|
|
|
lua_pushnumber(_state, y);
|
|
|
|
lua_pushnumber(_state, value1);
|
|
|
|
lua_pushnumber(_state, value2);
|
|
|
|
lua_call(_state, 4, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-06 13:21:53 +00:00
|
|
|
bool LuaScript::executeMPC(Common::SeekableReadStream *stream, const char *name, const char *scriptName, int32 length) {
|
2019-06-04 19:40:57 +00:00
|
|
|
|
|
|
|
if (!_systemInit) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-06 15:09:28 +00:00
|
|
|
char *chunk = new char[length + 1];
|
2019-06-04 19:40:57 +00:00
|
|
|
stream->read((void *)chunk, length);
|
2019-06-06 15:09:28 +00:00
|
|
|
chunk[length] = '\0'; // be on the safe side
|
2019-06-04 19:40:57 +00:00
|
|
|
|
2019-06-06 14:47:54 +00:00
|
|
|
stripComments(chunk);
|
2019-06-06 15:09:28 +00:00
|
|
|
|
2019-06-05 21:26:41 +00:00
|
|
|
/*
|
2019-06-06 13:21:53 +00:00
|
|
|
Remove C-style comments from the script
|
|
|
|
and update the upvalue syntax for Lua 5.1.3
|
2019-06-05 21:26:41 +00:00
|
|
|
*/
|
2019-06-06 15:09:28 +00:00
|
|
|
Common::String chunkString(chunk, length);
|
2019-06-06 13:21:53 +00:00
|
|
|
|
|
|
|
addPatches(chunkString, scriptName);
|
2019-06-04 21:36:21 +00:00
|
|
|
|
2019-06-06 15:09:28 +00:00
|
|
|
if (!executeChunk(chunkString, chunkString.size(), name)) {
|
2019-06-04 19:40:57 +00:00
|
|
|
delete[] chunk;
|
2019-06-05 22:58:36 +00:00
|
|
|
|
2019-06-04 19:40:57 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] chunk;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-06-05 08:45:22 +00:00
|
|
|
bool LuaScript::executeFile(const Common::String &filename) {
|
2019-06-05 22:58:36 +00:00
|
|
|
|
2019-06-02 13:33:34 +00:00
|
|
|
if (!_systemInit) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-02 13:11:05 +00:00
|
|
|
Common::File *file = new Common::File;
|
|
|
|
|
|
|
|
if (!file->open(filename)) {
|
|
|
|
error("Cannot find \"%s\"", filename.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
uint fileSize = file->size();
|
2019-06-06 15:09:28 +00:00
|
|
|
char *fileData = new char[fileSize + 1];
|
2019-06-02 13:11:05 +00:00
|
|
|
file->read((void *)fileData, fileSize);
|
2019-06-06 15:09:28 +00:00
|
|
|
fileData[fileSize] = '\0'; // be on the safe side
|
2019-06-02 13:11:05 +00:00
|
|
|
|
2019-06-06 14:47:54 +00:00
|
|
|
stripComments(fileData);
|
2019-06-05 23:36:54 +00:00
|
|
|
|
2019-06-06 13:21:53 +00:00
|
|
|
Common::String fileDataString(fileData);
|
|
|
|
|
|
|
|
addPatches(fileDataString, filename.c_str());
|
|
|
|
|
2019-06-06 15:09:28 +00:00
|
|
|
if (!executeChunk(fileDataString, fileDataString.size(), filename)) {
|
2019-06-02 13:11:05 +00:00
|
|
|
delete[] fileData;
|
|
|
|
delete file;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] fileData;
|
|
|
|
delete file;
|
|
|
|
|
|
|
|
return true;
|
2019-06-05 08:45:22 +00:00
|
|
|
}
|
2019-06-02 13:11:05 +00:00
|
|
|
|
2019-06-06 13:21:53 +00:00
|
|
|
bool LuaScript::executeChunk(Common::String &chunk, uint chunkSize, const Common::String &chunkName) const {
|
2019-06-05 22:58:13 +00:00
|
|
|
|
2019-06-02 13:33:34 +00:00
|
|
|
if (!_systemInit) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-06-05 22:58:13 +00:00
|
|
|
|
2019-06-02 13:11:05 +00:00
|
|
|
// Compile Chunk
|
2019-06-06 13:21:53 +00:00
|
|
|
if (luaL_loadbuffer(_state, chunk.c_str(), chunkSize, chunkName.c_str())) {
|
2019-06-02 13:11:05 +00:00
|
|
|
error("Couldn't compile \"%s\": %s", chunkName.c_str(), lua_tostring(_state, -1));
|
|
|
|
lua_pop(_state, -1);
|
2019-06-05 22:58:13 +00:00
|
|
|
|
2019-06-02 13:11:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-05 23:22:09 +00:00
|
|
|
// Error handling function to be executed after the function is put on the stack
|
|
|
|
lua_rawgeti(_state, LUA_REGISTRYINDEX, _pcallErrorhandlerRegistryIndex);
|
|
|
|
lua_insert(_state, -2);
|
|
|
|
|
2019-06-02 13:11:05 +00:00
|
|
|
// Execute Chunk
|
2019-06-05 23:25:30 +00:00
|
|
|
if (lua_pcall(_state, 0, 0, -2)) {
|
2019-06-02 13:11:05 +00:00
|
|
|
error("An error occured while executing \"%s\": %s.", chunkName.c_str(), lua_tostring(_state, -1));
|
|
|
|
lua_pop(_state, -1);
|
2019-06-05 22:58:36 +00:00
|
|
|
|
2019-06-02 13:11:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-20 14:09:35 +00:00
|
|
|
// Remove the error handler function from the stack
|
|
|
|
lua_pop(_state, 1);
|
|
|
|
|
2019-06-02 13:11:05 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-06-06 14:47:54 +00:00
|
|
|
void LuaScript::stripComments(char *chunk) {
|
2019-06-04 21:36:21 +00:00
|
|
|
uint32 offset = 0;
|
|
|
|
|
|
|
|
while (chunk[offset]) {
|
2019-06-05 21:26:41 +00:00
|
|
|
// Strip C-Style comments
|
2019-06-04 21:36:21 +00:00
|
|
|
if (chunk[offset] == '/' && chunk[offset + 1] == '/') {
|
|
|
|
while (chunk[offset] != 0x0d) {
|
|
|
|
chunk[offset++] = ' ';
|
|
|
|
}
|
2019-06-06 13:21:53 +00:00
|
|
|
}
|
2019-06-04 21:36:21 +00:00
|
|
|
offset++;
|
|
|
|
}
|
|
|
|
}
|
2019-06-06 13:21:53 +00:00
|
|
|
|
|
|
|
void LuaScript::addPatches(Common::String &chunk, const char* scriptName) {
|
|
|
|
ScriptPatch *patch = scriptPatches;
|
|
|
|
|
|
|
|
while (patch->scriptName) {
|
|
|
|
if (scriptName == patch->scriptName) {
|
|
|
|
Common::String searchString(patch->search);
|
|
|
|
Common::String replaceString(patch->replace);
|
|
|
|
Common::replace(chunk, searchString, replaceString);
|
|
|
|
}
|
|
|
|
patch++;
|
|
|
|
}
|
|
|
|
}
|
2019-06-18 10:42:45 +00:00
|
|
|
|
2019-06-18 14:15:44 +00:00
|
|
|
void LuaScript::checkParameters(const char *func, int params) {
|
2019-06-18 10:42:45 +00:00
|
|
|
int stackTop = lua_gettop(_state);
|
|
|
|
if (stackTop < params) {
|
|
|
|
warning("%s: Not Enough Parameters", func);
|
|
|
|
} else if (stackTop > params) {
|
|
|
|
warning("%s: Too Many Parameters", func);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-20 10:38:32 +00:00
|
|
|
void lua_printstack(lua_State *L) {
|
|
|
|
int n = lua_gettop(L);
|
|
|
|
for (int i = 1; i <= n; i++) {
|
|
|
|
debug(1, "STACK %d %s %s", i, lua_tostring(L, i), luaL_typename(L, i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-19 20:15:51 +00:00
|
|
|
const char *LuaScript::getStringOffStack() {
|
|
|
|
if (!_systemInit) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *string = lua_tostring(_state, 1);
|
|
|
|
lua_remove(_state, 1);
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
2019-06-04 21:36:21 +00:00
|
|
|
}
|