mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
434 lines
11 KiB
C++
434 lines
11 KiB
C++
/* Residual - A 3D game interpreter
|
|
*
|
|
* Residual 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 library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*
|
|
*/
|
|
|
|
#include "common/endian.h"
|
|
#include "common/system.h"
|
|
|
|
#include "math/matrix3.h"
|
|
|
|
#include "engines/grim/debug.h"
|
|
#include "engines/grim/lua.h"
|
|
#include "engines/grim/actor.h"
|
|
#include "engines/grim/lipsync.h"
|
|
#include "engines/grim/costume.h"
|
|
#include "engines/grim/registry.h"
|
|
#include "engines/grim/localize.h"
|
|
#include "engines/grim/colormap.h"
|
|
#include "engines/grim/grim.h"
|
|
#include "engines/grim/savegame.h"
|
|
#include "engines/grim/resource.h"
|
|
#include "engines/grim/bitmap.h"
|
|
#include "engines/grim/font.h"
|
|
#include "engines/grim/set.h"
|
|
#include "engines/grim/gfx_base.h"
|
|
#include "engines/grim/model.h"
|
|
#include "engines/grim/primitives.h"
|
|
|
|
#include "engines/grim/lua/lauxlib.h"
|
|
#include "engines/grim/lua/luadebug.h"
|
|
#include "engines/grim/lua/lualib.h"
|
|
|
|
namespace Grim {
|
|
|
|
int refSystemTable;
|
|
int refTypeOverride;
|
|
int refOldConcatFallback;
|
|
int refTextObjectX;
|
|
int refTextObjectY;
|
|
int refTextObjectFont;
|
|
int refTextObjectWidth;
|
|
int refTextObjectHeight;
|
|
int refTextObjectFGColor;
|
|
int refTextObjectBGColor;
|
|
int refTextObjectFXColor;
|
|
int refTextObjectHIColor;
|
|
int refTextObjectDuration;
|
|
int refTextObjectCenter;
|
|
int refTextObjectLJustify;
|
|
int refTextObjectRJustify;
|
|
int refTextObjectVolume;
|
|
int refTextObjectBackground;
|
|
int refTextObjectPan;
|
|
|
|
LuaBase *LuaBase::s_instance = NULL;
|
|
|
|
LuaBase::LuaBase() :
|
|
_translationMode(0) {
|
|
s_instance = this;
|
|
|
|
lua_iolibopen();
|
|
lua_strlibopen();
|
|
lua_mathlibopen();
|
|
}
|
|
|
|
LuaBase::~LuaBase() {
|
|
s_instance = NULL;
|
|
|
|
lua_removelibslists();
|
|
lua_close();
|
|
lua_iolibclose();
|
|
}
|
|
|
|
// Entries in the system table
|
|
static struct {
|
|
const char *name;
|
|
int key;
|
|
} system_defaults[] = {
|
|
{ "frameTime", 0 },
|
|
{ "movieTime", 0 }
|
|
};
|
|
|
|
void LuaBase::registerLua() {
|
|
// Register system table
|
|
lua_Object system_table = lua_createtable();
|
|
lua_pushobject(system_table);
|
|
lua_setglobal("system");
|
|
|
|
lua_pushobject(system_table);
|
|
refSystemTable = lua_ref(1);
|
|
|
|
for (unsigned i = 0; i < ARRAYSIZE(system_defaults); i++) {
|
|
lua_pushobject(lua_getref(refSystemTable));
|
|
lua_pushstring(system_defaults[i].name);
|
|
lua_pushnumber(system_defaults[i].key);
|
|
lua_settable();
|
|
}
|
|
|
|
// Create and populate system.controls table
|
|
lua_Object controls_table = lua_createtable();
|
|
lua_pushobject(lua_getref(refSystemTable));
|
|
lua_pushstring("controls");
|
|
lua_pushobject(controls_table);
|
|
lua_settable();
|
|
|
|
for (int i = 0; controls[i].name; i++) {
|
|
lua_pushobject(controls_table);
|
|
lua_pushstring(controls[i].name);
|
|
lua_pushnumber(controls[i].key);
|
|
lua_settable();
|
|
}
|
|
|
|
lua_pushobject(lua_getref(refSystemTable));
|
|
lua_pushstring("camChangeHandler");
|
|
lua_pushcfunction(LUA_OPCODE(LuaBase, dummyHandler));
|
|
lua_settable();
|
|
|
|
lua_pushobject(lua_getref(refSystemTable));
|
|
lua_pushstring("axisHandler");
|
|
lua_pushcfunction(LUA_OPCODE(LuaBase, dummyHandler));
|
|
lua_settable();
|
|
|
|
lua_pushobject(lua_getref(refSystemTable));
|
|
lua_pushstring("buttonHandler");
|
|
lua_pushcfunction(LUA_OPCODE(LuaBase, dummyHandler));
|
|
lua_settable();
|
|
|
|
lua_pushobject(lua_getglobal("type"));
|
|
refTypeOverride = lua_ref(true);
|
|
lua_pushCclosure(LUA_OPCODE(LuaBase, typeOverride), 0);
|
|
lua_setglobal("type");
|
|
|
|
// Register constants for box types
|
|
lua_pushnumber(Sector::NoneType);
|
|
lua_setglobal("NONE");
|
|
lua_pushnumber(Sector::WalkType);
|
|
lua_setglobal("WALK");
|
|
lua_pushnumber(Sector::CameraType);
|
|
lua_setglobal("CAMERA");
|
|
lua_pushnumber(Sector::SpecialType);
|
|
lua_setglobal("SPECIAL");
|
|
lua_pushnumber(Sector::HotType);
|
|
lua_setglobal("HOT");
|
|
|
|
lua_pushobject(lua_setfallback("concat", LUA_OPCODE(LuaBase, concatFallback)));
|
|
refOldConcatFallback = lua_ref(1);
|
|
|
|
// initialize Text globals
|
|
lua_pushstring("x");
|
|
refTextObjectX = lua_ref(true);
|
|
lua_pushstring("y");
|
|
refTextObjectY = lua_ref(true);
|
|
lua_pushstring("font");
|
|
refTextObjectFont = lua_ref(true);
|
|
lua_pushstring("width");
|
|
refTextObjectWidth = lua_ref(true);
|
|
lua_pushstring("height");
|
|
refTextObjectHeight = lua_ref(true);
|
|
lua_pushstring("fgcolor");
|
|
refTextObjectFGColor = lua_ref(true);
|
|
lua_pushstring("bgcolor");
|
|
refTextObjectBGColor = lua_ref(true);
|
|
lua_pushstring("fxcolor");
|
|
refTextObjectFXColor = lua_ref(true);
|
|
lua_pushstring("hicolor");
|
|
refTextObjectHIColor = lua_ref(true);
|
|
lua_pushstring("duration");
|
|
refTextObjectDuration = lua_ref(true);
|
|
lua_pushstring("center");
|
|
refTextObjectCenter = lua_ref(true);
|
|
lua_pushstring("ljustify");
|
|
refTextObjectLJustify = lua_ref(true);
|
|
lua_pushstring("rjustify");
|
|
refTextObjectRJustify = lua_ref(true);
|
|
lua_pushstring("volume");
|
|
refTextObjectVolume = lua_ref(true);
|
|
lua_pushstring("pan");
|
|
refTextObjectPan = lua_ref(true);
|
|
lua_pushstring("background");
|
|
refTextObjectBackground = lua_ref(true);
|
|
}
|
|
|
|
struct luaL_reg baseOpcodes[] = {
|
|
{ " concatfallback", LUA_OPCODE(LuaBase, concatFallback) },
|
|
{ " typeoverride", LUA_OPCODE(LuaBase, typeOverride) },
|
|
{ " dfltcamera", LUA_OPCODE(LuaBase, dummyHandler) },
|
|
{ " dfltcontrol", LUA_OPCODE(LuaBase, dummyHandler) },
|
|
};
|
|
|
|
void LuaBase::registerOpcodes() {
|
|
luaL_openlib(baseOpcodes, ARRAYSIZE(baseOpcodes));
|
|
}
|
|
|
|
void LuaBase::boot() {
|
|
lua_pushnil(); // resumeSave
|
|
lua_pushnil(); // bootParam - not used in scripts
|
|
lua_call("BOOT");
|
|
}
|
|
|
|
void LuaBase::setFrameTime(float frameTime) {
|
|
lua_pushobject(lua_getref(refSystemTable));
|
|
lua_pushstring("frameTime");
|
|
lua_pushnumber(frameTime);
|
|
lua_settable();
|
|
}
|
|
|
|
void LuaBase::setMovieTime(float movieTime) {
|
|
lua_pushobject(lua_getref(refSystemTable));
|
|
lua_pushstring("movieTime");
|
|
lua_pushnumber(movieTime);
|
|
lua_settable();
|
|
}
|
|
|
|
bool LuaBase::getbool(int num) {
|
|
return !lua_isnil(lua_getparam(num));
|
|
}
|
|
|
|
void LuaBase::pushbool(bool val) {
|
|
if (val)
|
|
lua_pushnumber(1);
|
|
else
|
|
lua_pushnil();
|
|
}
|
|
|
|
void LuaBase::pushobject(PoolObjectBase *o) {
|
|
lua_pushusertag(o->getId(), o->getTag());
|
|
}
|
|
|
|
Actor *LuaBase::getactor(lua_Object obj) {
|
|
return Actor::getPool()->getObject(lua_getuserdata(obj));
|
|
}
|
|
|
|
TextObject *LuaBase::gettextobject(lua_Object obj) {
|
|
return TextObject::getPool()->getObject(lua_getuserdata(obj));
|
|
}
|
|
|
|
Font *LuaBase::getfont(lua_Object obj) {
|
|
return Font::getPool()->getObject(lua_getuserdata(obj));
|
|
}
|
|
|
|
PoolColor *LuaBase::getcolor(lua_Object obj) {
|
|
return PoolColor::getPool()->getObject(lua_getuserdata(obj));
|
|
}
|
|
|
|
PrimitiveObject *LuaBase::getprimitive(lua_Object obj) {
|
|
return PrimitiveObject::getPool()->getObject(lua_getuserdata(obj));
|
|
}
|
|
|
|
ObjectState *LuaBase::getobjectstate(lua_Object obj) {
|
|
return ObjectState::getPool()->getObject(lua_getuserdata(obj));
|
|
}
|
|
|
|
void LuaBase::dummyHandler() {
|
|
}
|
|
|
|
bool LuaBase::findCostume(lua_Object costumeObj, Actor *actor, Costume **costume) {
|
|
*costume = actor->getCurrentCostume(); // should be root of list I think
|
|
if (lua_isnil(costumeObj))
|
|
return true;
|
|
if (lua_isnumber(costumeObj)) {
|
|
/* int num = (int)lua_getnumber(costumeObj);*/
|
|
error("findCostume: search by Id not implemented");
|
|
// TODO get costume by ID ?
|
|
}
|
|
if (lua_isstring(costumeObj)) {
|
|
*costume = actor->findCostume(lua_getstring(costumeObj));
|
|
return *costume != 0;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Common::String LuaBase::parseMsgText(const char *msg, char *msgId) {
|
|
Common::String translation = g_localizer->localize(msg);
|
|
const char *secondSlash = NULL;
|
|
|
|
if (msg[0] == '/' && msgId) {
|
|
secondSlash = strchr(msg + 1, '/');
|
|
if (secondSlash) {
|
|
strncpy(msgId, msg + 1, secondSlash - msg - 1);
|
|
msgId[secondSlash - msg - 1] = 0;
|
|
} else {
|
|
msgId[0] = 0;
|
|
}
|
|
}
|
|
|
|
if (_translationMode == 1)
|
|
return secondSlash;
|
|
|
|
if (_translationMode == 2)
|
|
return msg;
|
|
|
|
return translation;
|
|
}
|
|
|
|
void LuaBase::parseSayLineTable(lua_Object paramObj, bool *background, int *vol, int *pan, int *x, int *y) {
|
|
lua_Object tableObj;
|
|
|
|
lua_pushobject(paramObj);
|
|
lua_pushobject(lua_getref(refTextObjectX));
|
|
tableObj = lua_gettable();
|
|
if (lua_isnumber(tableObj)) {
|
|
if (*x)
|
|
*x = (int)lua_getnumber(tableObj);
|
|
}
|
|
|
|
lua_pushobject(paramObj);
|
|
lua_pushobject(lua_getref(refTextObjectY));
|
|
tableObj = lua_gettable();
|
|
if (lua_isnumber(tableObj)) {
|
|
if (*y)
|
|
*y = (int)lua_getnumber(tableObj);
|
|
}
|
|
|
|
lua_pushobject(paramObj);
|
|
lua_pushobject(lua_getref(refTextObjectBackground));
|
|
tableObj = lua_gettable();
|
|
if (tableObj) {
|
|
if (*background)
|
|
*background = (int)lua_getnumber(tableObj);
|
|
}
|
|
|
|
lua_pushobject(paramObj);
|
|
lua_pushobject(lua_getref(refTextObjectVolume));
|
|
tableObj = lua_gettable();
|
|
if (lua_isnumber(tableObj)) {
|
|
if (*vol)
|
|
*vol = (int)lua_getnumber(tableObj);
|
|
}
|
|
|
|
lua_pushobject(paramObj);
|
|
lua_pushobject(lua_getref(refTextObjectPan));
|
|
tableObj = lua_gettable();
|
|
if (lua_isnumber(tableObj)) {
|
|
if (*pan)
|
|
*pan = (int)lua_getnumber(tableObj);
|
|
}
|
|
}
|
|
|
|
void LuaBase::typeOverride() {
|
|
lua_Object data = lua_getparam(1);
|
|
|
|
if (lua_isuserdata(data)) {
|
|
switch (lua_tag(data)) {
|
|
case MKTAG('A','C','T','R'):
|
|
lua_pushstring("actor");
|
|
lua_pushnumber(lua_tag(data));
|
|
return;
|
|
case MKTAG('C','O','S','T'):
|
|
lua_pushstring("costume");
|
|
lua_pushnumber(lua_tag(data));
|
|
return;
|
|
case MKTAG('S','E','T',' '):
|
|
lua_pushstring("set");
|
|
lua_pushnumber(lua_tag(data));
|
|
return;
|
|
case MKTAG('K','E','Y','F'):
|
|
lua_pushstring("keyframe");
|
|
lua_pushnumber(lua_tag(data));
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
lua_pushobject(data);
|
|
lua_callfunction(lua_getref(refTypeOverride));
|
|
lua_Object param1 = lua_getresult(1);
|
|
lua_Object param2 = lua_getresult(2);
|
|
lua_pushobject(param1);
|
|
lua_pushobject(param2);
|
|
}
|
|
|
|
void LuaBase::concatFallback() {
|
|
lua_Object params[2];
|
|
char result[200];
|
|
char *strPtr;
|
|
|
|
params[0] = lua_getparam(1);
|
|
params[1] = lua_getparam(2);
|
|
result[0] = 0;
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
if (!lua_isnil(params[i]) && !lua_isuserdata(params[i]) && !lua_isstring(params[i])) {
|
|
lua_pushobject(params[0]);
|
|
lua_pushobject(params[1]);
|
|
lua_callfunction(lua_getref(refOldConcatFallback));
|
|
lua_pushobject(lua_getresult(1));
|
|
return;
|
|
}
|
|
|
|
int pos = strlen(result);
|
|
strPtr = &result[pos];
|
|
|
|
if (lua_isnil(params[i]))
|
|
sprintf(strPtr, "(nil)");
|
|
else if (lua_isstring(params[i]))
|
|
sprintf(strPtr, "%s", lua_getstring(params[i]));
|
|
else if (lua_tag(params[i]) == MKTAG('A','C','T','R')) {
|
|
Actor *a = getactor(params[i]);
|
|
sprintf(strPtr, "(actor%p:%s)", (void *)a,
|
|
(a->getCurrentCostume() && a->getCurrentCostume()->getModelNodes()) ?
|
|
a->getCurrentCostume()->getModelNodes()->_name : "");
|
|
} else {
|
|
lua_pushobject(params[0]);
|
|
lua_pushobject(params[1]);
|
|
lua_callfunction(lua_getref(refOldConcatFallback));
|
|
lua_pushobject(lua_getresult(1));
|
|
return;
|
|
}
|
|
}
|
|
|
|
lua_pushstring(result);
|
|
}
|
|
|
|
}
|