Added Enigma game
This commit is contained in:
928
project/jni/application/enigma/src/lua.cpp
Normal file
928
project/jni/application/enigma/src/lua.cpp
Normal file
@@ -0,0 +1,928 @@
|
||||
/*
|
||||
* Copyright (C) 2002,2003,2004 Daniel Heck
|
||||
*
|
||||
* 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 "lua.hh"
|
||||
#include "errors.hh"
|
||||
#include "main.hh"
|
||||
#include "world.hh"
|
||||
#include "config.h"
|
||||
#include "video.hh"
|
||||
#include "server.hh"
|
||||
#include "sound.hh"
|
||||
#include "options.hh"
|
||||
#include "lev/Index.hh"
|
||||
#include "lev/Proxy.hh"
|
||||
|
||||
#ifndef CXXLUA
|
||||
extern "C" {
|
||||
#include "lualib.h"
|
||||
#include "tolua++.h"
|
||||
}
|
||||
#else
|
||||
#include "lualib.h"
|
||||
#include "tolua++.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "lua-display.hh"
|
||||
#include "lua-enigma.hh"
|
||||
#include "lua-ecl.hh"
|
||||
|
||||
#include "ecl.hh"
|
||||
#include <cassert>
|
||||
|
||||
#include "nls.hh"
|
||||
|
||||
using namespace std;
|
||||
using namespace enigma;
|
||||
using namespace lua;
|
||||
|
||||
using ecl::round_down;
|
||||
using ecl::strf;
|
||||
|
||||
using enigma::GridPos;
|
||||
using world::Object;
|
||||
using world::GridObject;
|
||||
using world::ForceField;
|
||||
|
||||
namespace lua
|
||||
{
|
||||
int EmitSound (lua_State *L);
|
||||
int EmitSoundGlobal (lua_State *L);
|
||||
int MakeObject (lua_State *L);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
lua_State *level_state = 0; // level-local state
|
||||
lua_State *global_state = 0; // global Lua state
|
||||
|
||||
lua::Error _lua_err_code (int i)
|
||||
{
|
||||
switch (i) {
|
||||
case 0: return NO_LUAERROR;
|
||||
case LUA_ERRRUN: return ERRRUN;
|
||||
case LUA_ERRFILE: return ERRFILE;
|
||||
case LUA_ERRSYNTAX: return ERRSYNTAX;
|
||||
case LUA_ERRMEM: return ERRMEM;
|
||||
case LUA_ERRERR: return ERRERR;
|
||||
}
|
||||
assert (!"Should never get there!");
|
||||
}
|
||||
|
||||
void throwLuaError(lua_State * L, const char * message) {
|
||||
std::string backtrace = message;
|
||||
backtrace += "\nBacktrace:\n";
|
||||
lua_Debug dbgInfo;
|
||||
int frame = 0;
|
||||
while (lua_getstack(L, frame, &dbgInfo)) {
|
||||
lua_getinfo(L, "Sl", &dbgInfo);
|
||||
if (dbgInfo.source[0] == '@')
|
||||
// lua code loaded from file
|
||||
backtrace += ecl::strf("#%d %s: %d\n", frame, dbgInfo.source,
|
||||
dbgInfo.currentline);
|
||||
else if (dbgInfo.source[0] == '-' && dbgInfo.source[1] == '-' &&
|
||||
dbgInfo.source[2] == '@') {
|
||||
// lua code loaded from string
|
||||
std::string code = dbgInfo.source;
|
||||
std::string::size_type slashPosFilenameEnd = code.find('\n');
|
||||
std::string::size_type slashPosLineStart;
|
||||
std::string::size_type slashPosLineEnd = slashPosFilenameEnd;
|
||||
for (int i = 1; i < dbgInfo.currentline; i++) {
|
||||
slashPosLineStart = slashPosLineEnd;
|
||||
slashPosLineEnd = code.find('\n', slashPosLineStart + 1);
|
||||
}
|
||||
backtrace += ecl::strf("#%d %s: %d\n (%s)\n", frame,
|
||||
code.substr(2, slashPosFilenameEnd - 2).c_str(),
|
||||
dbgInfo.currentline - 1,
|
||||
code.substr(slashPosLineStart + 1, slashPosLineEnd -
|
||||
slashPosLineStart - 1).c_str());
|
||||
}
|
||||
frame++;
|
||||
}
|
||||
luaL_error(L, backtrace.c_str());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------- Helper routines -------------------- */
|
||||
|
||||
using enigma::Value;
|
||||
|
||||
void lua::SetTableVar (lua_State *L,
|
||||
const char *tablename,
|
||||
const char *name,
|
||||
double value)
|
||||
{
|
||||
lua_getglobal (L, tablename);
|
||||
lua_pushstring (L, name);
|
||||
lua_pushnumber (L, value);
|
||||
lua_rawset (L, -3);
|
||||
lua_pop (L, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
push_value(lua_State *L, const Value &val)
|
||||
{
|
||||
switch (val.get_type()) {
|
||||
case Value::NIL: lua_pushnil(L); break;
|
||||
case Value::DOUBLE: lua_pushnumber(L, to_double(val)); break;
|
||||
case Value::STRING: lua_pushstring(L, to_string(val)); break;
|
||||
}
|
||||
}
|
||||
|
||||
static Value
|
||||
to_value(lua_State *L, int idx)
|
||||
{
|
||||
switch (lua_type(L, idx)) {
|
||||
case LUA_TNIL: return Value();
|
||||
case LUA_TNUMBER: return Value(lua_tonumber(L,idx));
|
||||
case LUA_TSTRING: return Value(lua_tostring(L,idx));
|
||||
case LUA_TBOOLEAN: return (lua_toboolean(L,idx)) ? Value(1) : Value();
|
||||
default: throwLuaError(L,"Cannot convert type to Value.");
|
||||
}
|
||||
return Value();
|
||||
}
|
||||
|
||||
static bool
|
||||
is_object(lua_State *L, int idx)
|
||||
{
|
||||
return lua_isuserdata(L,idx) && luaL_checkudata(L,idx,"_ENIGMAOBJECT");
|
||||
}
|
||||
|
||||
static Object *
|
||||
to_object(lua_State *L, int idx)
|
||||
{
|
||||
if (lua_isnil(L,idx))
|
||||
return 0;
|
||||
|
||||
if (!is_object(L,idx)) {
|
||||
throwLuaError(L, "Cannot convert type to an Object");
|
||||
return 0;
|
||||
}
|
||||
return static_cast<Object*>(*(static_cast<void**>(lua_touserdata(L,idx))));
|
||||
}
|
||||
|
||||
static void
|
||||
pushobject (lua_State *L, Object *obj)
|
||||
{
|
||||
Object **udata;
|
||||
/* Lua does not allow NULL pointers in userdata variables, so
|
||||
convert them manually to `nil' values. */
|
||||
if (obj == 0)
|
||||
lua_pushnil(L);
|
||||
else
|
||||
{
|
||||
udata=(Object**)lua_newuserdata(L,sizeof(int));
|
||||
*udata=obj;
|
||||
luaL_getmetatable(L, "_ENIGMAOBJECT");
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------- Interface routines -------------------- */
|
||||
|
||||
int lua::MakeObject (lua_State *L)
|
||||
{
|
||||
const char *name = lua_tostring(L, 1);
|
||||
if (!name) {
|
||||
throwLuaError(L, "MakeObject: string expected as argument");
|
||||
}
|
||||
Object *obj = world::MakeObject(name);
|
||||
if (obj == NULL)
|
||||
throwLuaError(L, ecl::strf("MakeObject: unknown object name '%s'", name).c_str());
|
||||
pushobject(L, obj);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
en_get_object_template(lua_State *L)
|
||||
{
|
||||
Object *obj = world::GetObjectTemplate(lua_tostring(L, 1));
|
||||
pushobject(L, obj);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
en_set_attrib(lua_State *L)
|
||||
{
|
||||
Object *obj = to_object(L,1);
|
||||
const char *key = lua_tostring(L,2);
|
||||
if (obj && key)
|
||||
obj->set_attrib(key, to_value(L, 3));
|
||||
else
|
||||
throwLuaError(L, strf("SetAttrib: invalid object or attribute name '%s'", key).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
en_get_attrib(lua_State *L)
|
||||
{
|
||||
Object *obj = to_object(L,1);
|
||||
const char *key = lua_tostring(L,2);
|
||||
|
||||
if (!obj) {
|
||||
throwLuaError(L, "GetAttrib: invalid object");
|
||||
return 0;
|
||||
}
|
||||
if (!key) {
|
||||
throwLuaError(L, "GetAttrib: invalid key");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (0 == strcmp(key, "kind")) {
|
||||
throwLuaError(L, "GetAttrib: illegal attribute, use GetKind()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Value *v = obj->get_attrib(key);
|
||||
if (!v) {
|
||||
// unknown attribute
|
||||
lua_pushnil(L);
|
||||
}
|
||||
else
|
||||
push_value(L, *v);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
en_get_kind(lua_State *L)
|
||||
{
|
||||
Object *obj = to_object(L,1);
|
||||
|
||||
if (!obj) {
|
||||
throwLuaError(L, "GetKind: invalid object");
|
||||
return 0;
|
||||
}
|
||||
|
||||
push_value(L, Value(obj->get_kind()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
en_is_same_object(lua_State *L)
|
||||
{
|
||||
Object *obj1 = to_object(L,1);
|
||||
Object *obj2 = to_object(L,2);
|
||||
|
||||
lua_pushboolean(L, obj1 == obj2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
en_set_floor(lua_State *L)
|
||||
{
|
||||
int x = round_down<int>(lua_tonumber(L, 1));
|
||||
int y = round_down<int>(lua_tonumber(L, 2));
|
||||
Floor *fl=0;
|
||||
|
||||
if (lua_isnil(L, 3))
|
||||
fl = 0;
|
||||
else if (is_object(L,3)) {
|
||||
fl = static_cast<Floor*>(*(static_cast<void**> (lua_touserdata(L,3))));
|
||||
if( ! fl)
|
||||
throwLuaError(L, "object is no valid floor");
|
||||
} else
|
||||
throwLuaError(L, "argument 3 must be an Object or nil");
|
||||
world::SetFloor(GridPos(x,y), fl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
en_set_item(lua_State *L)
|
||||
{
|
||||
int x = round_down<int>(lua_tonumber(L, 1));
|
||||
int y = round_down<int>(lua_tonumber(L, 2));
|
||||
Item *it = dynamic_cast<Item*>(to_object(L, 3));
|
||||
if( ! it) {
|
||||
throwLuaError(L, "object is no valid item");
|
||||
}
|
||||
world::SetItem(GridPos(x,y), it);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
en_set_stone(lua_State *L)
|
||||
{
|
||||
int x = round_down<int>(lua_tonumber(L, 1));
|
||||
int y = round_down<int>(lua_tonumber(L, 2));
|
||||
Stone *st = dynamic_cast<Stone*>(to_object(L, 3));
|
||||
if( ! st)
|
||||
throwLuaError(L, "object is no valid stone");
|
||||
world::SetStone(GridPos(x,y), st);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int en_kill_stone(lua_State *L)
|
||||
{
|
||||
int x = round_down<int>(lua_tonumber(L, 1));
|
||||
int y = round_down<int>(lua_tonumber(L, 2));
|
||||
world::KillStone(GridPos(x,y));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int en_kill_item(lua_State *L)
|
||||
{
|
||||
int x = round_down<int>(lua_tonumber(L, 1));
|
||||
int y = round_down<int>(lua_tonumber(L, 2));
|
||||
world::KillItem(GridPos(x,y));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
en_set_actor(lua_State *L)
|
||||
{
|
||||
double x = lua_tonumber(L,1);
|
||||
double y = lua_tonumber(L,2);
|
||||
Actor *ac = dynamic_cast<Actor*>(to_object(L, 3));
|
||||
if( ! ac)
|
||||
throwLuaError(L, "object is no valid actor");
|
||||
if (world::IsInsideLevel(GridPos(round_down<int>(x), round_down<int>(y))))
|
||||
world::AddActor(x, y, ac);
|
||||
else
|
||||
throwLuaError(L, "position is outside of world");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
en_send_message(lua_State *L)
|
||||
{
|
||||
Object *obj = to_object(L, 1);
|
||||
const char *msg = lua_tostring(L, 2);
|
||||
Value v;
|
||||
if (!msg)
|
||||
throwLuaError(L,"Illegal message");
|
||||
else if (obj) {
|
||||
try {
|
||||
v = world::SendMessage (obj, msg, to_value(L, 3));
|
||||
}
|
||||
catch (const XLevelRuntime &e) {
|
||||
throwLuaError (L, e.what());
|
||||
}
|
||||
catch (...) {
|
||||
throwLuaError (L, "uncaught exception");
|
||||
}
|
||||
}
|
||||
push_value(L, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua::EmitSound (lua_State *L)
|
||||
{
|
||||
Object *obj = to_object(L, 1);
|
||||
const char *soundname = lua_tostring(L, 2);
|
||||
double vol = 1.0;
|
||||
|
||||
if (lua_isnumber(L, 3))
|
||||
vol = lua_tonumber(L, 3);
|
||||
if (!soundname)
|
||||
throwLuaError(L,"Illegal sound");
|
||||
else if (obj) {
|
||||
GridObject *gobj = dynamic_cast<GridObject*>(obj);
|
||||
if (gobj) {
|
||||
if (!gobj->sound_event (soundname, vol)) {
|
||||
//throwLuaError(L, strf("Can't find sound '%s'", soundname).c_str());
|
||||
// Don't throw an error when no sound file was found.
|
||||
// Remember that user sound sets might be incomplete, and
|
||||
// absolutely correct levels could throw an error here.
|
||||
// Instead, write the "silence string" to the command line:
|
||||
sound::WriteSilenceString(soundname);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
throwLuaError(L, "EmitSound: invalid object");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua::EmitSoundGlobal (lua_State *L)
|
||||
{
|
||||
const char *soundname = lua_tostring(L, 1);
|
||||
double vol = 1.0;
|
||||
|
||||
if (lua_isnumber(L, 3))
|
||||
vol = lua_tonumber(L, 3);
|
||||
if (!soundname)
|
||||
throwLuaError(L,"Illegal sound");
|
||||
else
|
||||
sound::EmitSoundEventGlobal(soundname, vol);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
en_name_object(lua_State *L)
|
||||
{
|
||||
Object *obj = to_object(L, 1);
|
||||
const char *name = lua_tostring(L, 2);
|
||||
|
||||
if (!obj)
|
||||
throwLuaError(L, "NameObject: Illegal object");
|
||||
else if (!name)
|
||||
throwLuaError(L, "NameObject: Illegal name");
|
||||
else
|
||||
world::NameObject(obj, name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
en_get_named_object(lua_State *L)
|
||||
{
|
||||
Object *o = world::GetNamedObject(lua_tostring(L,1));
|
||||
pushobject(L, o);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
en_get_floor(lua_State *L)
|
||||
{
|
||||
int x = round_down<int>(lua_tonumber(L, 1));
|
||||
int y = round_down<int>(lua_tonumber(L, 2));
|
||||
Object *o = world::GetFloor(GridPos(x, y));
|
||||
pushobject(L, o);
|
||||
return 1;
|
||||
}
|
||||
static int
|
||||
en_get_item(lua_State *L)
|
||||
{
|
||||
int x = round_down<int>(lua_tonumber(L, 1));
|
||||
int y = round_down<int>(lua_tonumber(L, 2));
|
||||
Object *o = world::GetItem(GridPos(x, y));
|
||||
pushobject(L, o);
|
||||
return 1;
|
||||
}
|
||||
static int
|
||||
en_get_stone(lua_State *L)
|
||||
{
|
||||
int x = round_down<int>(lua_tonumber(L, 1));
|
||||
int y = round_down<int>(lua_tonumber(L, 2));
|
||||
Object *o = world::GetStone(GridPos(x, y));
|
||||
pushobject(L, o);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
en_get_pos(lua_State *L)
|
||||
{
|
||||
Object *obj = to_object(L, 1);
|
||||
GridPos p;
|
||||
|
||||
if (!obj) {
|
||||
throwLuaError(L, "GetPos: Illegal object");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (GridObject *gobj = dynamic_cast<GridObject*>(obj))
|
||||
p = gobj->get_pos();
|
||||
else if (Actor *a = dynamic_cast<Actor*>(obj)) {
|
||||
p = GridPos(a->get_pos());
|
||||
}
|
||||
else
|
||||
p = GridPos(-1, -1);
|
||||
|
||||
lua_pushnumber(L, double(p.x));
|
||||
lua_pushnumber(L, double(p.y));
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int en_add_constant_force(lua_State *L) {
|
||||
ecl::V2 v;
|
||||
v[0] = lua_tonumber(L, 1);
|
||||
v[1] = lua_tonumber(L, 2);
|
||||
world::SetConstantForce (v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
en_add_rubber_band (lua_State *L)
|
||||
{
|
||||
Actor *a1 = dynamic_cast<Actor*> (to_object(L, 1));
|
||||
Object *o2 = to_object(L, 2);
|
||||
Actor *a2 = dynamic_cast<Actor*>(o2);
|
||||
Stone *st = dynamic_cast<Stone*>(o2);
|
||||
world::RubberBandData d;
|
||||
d.strength = lua_tonumber (L, 3);
|
||||
d.length = lua_tonumber (L, 4);
|
||||
d.minlength = lua_tonumber (L, 5);
|
||||
|
||||
if (!a1)
|
||||
throwLuaError(L, "AddRubberBand: First argument must be an actor\n");
|
||||
else {
|
||||
if (a2)
|
||||
world::AddRubberBand (a1, a2, d);
|
||||
else if (st)
|
||||
world::AddRubberBand (a1, st, d);
|
||||
else
|
||||
throwLuaError(L, "AddRubberBand: Second argument must be actor or stone\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
en_get_ticks(lua_State *L)
|
||||
{
|
||||
lua_pushnumber(L, SDL_GetTicks());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
en_is_solved(lua_State *L)
|
||||
{
|
||||
// Function depreceated
|
||||
// - filename is no longer a useful reference for levels
|
||||
// - levels should not depend on external data for reasons of
|
||||
// network compatibility and level journaling
|
||||
throwLuaError(L, "Usage of depreceated function \"IsSolved()\"");
|
||||
|
||||
// const char *levelname = lua_tostring(L,1);
|
||||
// int solved = 0;
|
||||
//
|
||||
// levels::Level level (0, 0);
|
||||
// if (levels::FindLevel (levelname, level)) {
|
||||
// solved = level.is_solved(options::GetInt("Difficulty"));
|
||||
// } else
|
||||
// if (solved)
|
||||
// lua_pushnumber(L, solved);
|
||||
// else
|
||||
// lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
en_add_scramble(lua_State *L)
|
||||
{
|
||||
int x = round_down<int>(lua_tonumber(L, 1));
|
||||
int y = round_down<int>(lua_tonumber(L, 2));
|
||||
const char *dir = lua_tostring(L,3);
|
||||
const char *allowed = "wsen";
|
||||
const char *found = strchr(allowed, dir[0]);
|
||||
|
||||
if (found && found[0])
|
||||
world::AddScramble(GridPos(x,y), enigma::Direction(found-allowed));
|
||||
else
|
||||
throwLuaError(L, "AddScramble: Third argument must be one character of \"wsen\"");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
en_set_scramble_intensity(lua_State *L)
|
||||
{
|
||||
world::SetScrambleIntensity(int(lua_tonumber(L, 1)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
en_add_signal (lua_State *L) {
|
||||
const char *sourcestr = lua_tostring (L, 1);
|
||||
const char *targetstr = lua_tostring (L, 2);
|
||||
const char *msg = lua_tostring (L, 3);
|
||||
|
||||
using namespace enigma;
|
||||
GridLoc source, target;
|
||||
|
||||
if (sourcestr == 0 || !to_gridloc(sourcestr, source))
|
||||
throwLuaError (L, "AddSignal: invalid source descriptor");
|
||||
if (targetstr == 0 || !to_gridloc(targetstr, target))
|
||||
throwLuaError (L, "AddSignal: invalid target descriptor");
|
||||
if (msg == 0)
|
||||
msg = "signal";
|
||||
|
||||
world::AddSignal (source, target, msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int loadLib(lua_State *L)
|
||||
{
|
||||
const char *id = lua_tostring(L, 1);
|
||||
lev::Proxy * curProxy = lev::Index::getCurrentProxy();
|
||||
try {
|
||||
curProxy->loadDependency(id);
|
||||
} catch (XLevelLoading &err) {
|
||||
throwLuaError(L, err.what());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static CFunction globalfuncs[] = {
|
||||
{FindDataFile, "FindDataFile"},
|
||||
// {lua::PlaySoundGlobal, "PlaySoundGlobal"},
|
||||
// {lua::PlaySound, "PlaySound"},
|
||||
{en_get_ticks, "GetTicks"},
|
||||
{0,0}
|
||||
};
|
||||
|
||||
static CFunction levelfuncs[] = {
|
||||
|
||||
// internal functions
|
||||
|
||||
{FindDataFile, "FindDataFile"},
|
||||
{loadLib, "LoadLib"},
|
||||
{en_get_object_template,"GetObjectTemplate"},
|
||||
{lua::MakeObject, "MakeObject"},
|
||||
{en_set_actor, "SetActor"},
|
||||
|
||||
// finding objects
|
||||
|
||||
{en_get_named_object, "GetNamedObject"},
|
||||
|
||||
{en_get_floor, "GetFloor"},
|
||||
{en_get_item, "GetItem"},
|
||||
{en_get_stone, "GetStone"},
|
||||
|
||||
// information from objects
|
||||
|
||||
{en_get_pos, "GetPos"},
|
||||
{en_get_attrib, "GetAttrib"},
|
||||
{en_get_kind, "GetKind"},
|
||||
{en_is_same_object, "IsSameObject"},
|
||||
|
||||
// manipulating objects
|
||||
|
||||
{en_set_attrib, "SetAttrib"},
|
||||
{en_send_message, "SendMessage"},
|
||||
{en_name_object, "NameObject"},
|
||||
|
||||
// sound effects
|
||||
|
||||
{lua::EmitSound, "EmitSound"},
|
||||
|
||||
// manipulating level
|
||||
|
||||
{en_set_floor, "SetFloor"},
|
||||
{en_set_item, "SetItem"},
|
||||
{en_set_stone, "SetStone"},
|
||||
|
||||
{en_kill_stone, "KillStone"},
|
||||
{en_kill_item, "KillItem"},
|
||||
|
||||
|
||||
// signals
|
||||
{en_add_signal, "AddSignal"},
|
||||
|
||||
// access/modify global data
|
||||
|
||||
{en_get_ticks, "GetTicks"},
|
||||
{en_is_solved, "IsSolved"},
|
||||
|
||||
{en_add_constant_force, "AddConstantForce"},
|
||||
{en_add_rubber_band, "AddRubberBand"},
|
||||
{en_add_scramble, "AddScramble"},
|
||||
{en_set_scramble_intensity, "SetScrambleIntensity"},
|
||||
|
||||
|
||||
{0,0}
|
||||
};
|
||||
|
||||
|
||||
/* -------------------- lua:: functions -------------------- */
|
||||
|
||||
int lua::FindDataFile (lua_State *L)
|
||||
{
|
||||
const char *filename = lua_tostring(L, 1);
|
||||
string absfile;
|
||||
if (app.resourceFS->findFile(filename, absfile))
|
||||
lua_pushstring(L, absfile.c_str());
|
||||
else
|
||||
lua_pushnil (L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void lua::RegisterFuncs(lua_State *L, CFunction *funcs)
|
||||
{
|
||||
lua_getglobal(L, "enigma");
|
||||
for (unsigned i=0; funcs[i].func; ++i) {
|
||||
lua_pushstring(L, funcs[i].name);
|
||||
lua_pushcfunction(L, funcs[i].func);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
Error lua::CallFunc(lua_State *L, const char *funcname, const Value& arg, world::Object *obj) {
|
||||
int retval;
|
||||
lua_getglobal(L, funcname);
|
||||
push_value(L, arg);
|
||||
pushobject(L, obj);
|
||||
retval=lua_pcall(L,2,0,0);
|
||||
if (retval!=0) // error
|
||||
{
|
||||
lua_setglobal (L, "_LASTERROR") ; //Set _LASTERROR to returned error message
|
||||
}
|
||||
return _lua_err_code(retval);
|
||||
}
|
||||
|
||||
Error lua::CallFunc(lua_State *L, const char *funcname, const ByteVec& arg) {
|
||||
int retval;
|
||||
lua_getglobal(L, funcname);
|
||||
lua_pushlstring (L, &arg[0], arg.size());
|
||||
retval=lua_pcall(L,1,0,0);
|
||||
if (retval!=0) // error
|
||||
{
|
||||
lua_setglobal (L, "_LASTERROR") ; //Set _LASTERROR to returned error message
|
||||
}
|
||||
return _lua_err_code(retval);
|
||||
}
|
||||
|
||||
Error lua::DoAbsoluteFile(lua_State *L, const string &filename)
|
||||
{
|
||||
int oldtop = lua_gettop(L);
|
||||
int retval = luaL_loadfile(L, filename.c_str());
|
||||
if (retval!=0) // error
|
||||
{
|
||||
lua_setglobal (L, "_LASTERROR") ; //Set _LASTERROR to returned error message
|
||||
}
|
||||
else
|
||||
{
|
||||
retval= lua_pcall(L, 0, 0, 0);
|
||||
if (retval!=0) // error
|
||||
{
|
||||
lua_setglobal (L, "_LASTERROR") ; //Set _LASTERROR to returned error message
|
||||
}
|
||||
}
|
||||
lua_settop(L, oldtop);
|
||||
return _lua_err_code(retval);
|
||||
}
|
||||
|
||||
Error lua::DoGeneralFile(lua_State *L, GameFS * fs, const string &filename)
|
||||
{
|
||||
string completefn;
|
||||
if (fs->findFile(filename, completefn)) {
|
||||
return lua::DoAbsoluteFile(L, completefn);
|
||||
}
|
||||
else {
|
||||
return _lua_err_code(LUA_ERRFILE);
|
||||
}
|
||||
}
|
||||
|
||||
Error lua::Dofile(lua_State *L, const string &filename)
|
||||
{
|
||||
return lua::DoGeneralFile(L, app.resourceFS, filename);
|
||||
}
|
||||
|
||||
Error lua::DoSysFile(lua_State *L, const string &filename)
|
||||
{
|
||||
return lua::DoGeneralFile(L, app.systemFS, filename);
|
||||
}
|
||||
|
||||
void lua::CheckedDoFile (lua_State *L, GameFS * fs, std::string const& fname)
|
||||
{
|
||||
string completefn;
|
||||
if (!fs->findFile(fname, completefn))
|
||||
{
|
||||
fprintf(stderr, _("Cannot find '%s'.\n"), fname.c_str());
|
||||
fprintf(stderr, _("Your installation may be incomplete or invalid.\n"));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
lua::Error status = lua::DoAbsoluteFile(L, completefn);
|
||||
if (status != lua::NO_LUAERROR) {
|
||||
fprintf(stderr, _("There was an error loading '%s'.\n"), completefn.c_str());
|
||||
fprintf(stderr, _("Your installation may be incomplete or invalid.\n"));
|
||||
fprintf(stderr, _("Error: '%s'\n"), lua::LastError(L).c_str());
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Error lua::Dobuffer (lua_State *L, const ByteVec &luacode) {
|
||||
int retval;
|
||||
const char *buffer = reinterpret_cast<const char *>(&luacode[0]);
|
||||
|
||||
retval=luaL_loadbuffer(L, buffer, luacode.size(), "buffer");
|
||||
if (retval!=0) // error
|
||||
{
|
||||
lua_setglobal (L, "_LASTERROR") ; //Set _LASTERROR to returned error message
|
||||
}
|
||||
else
|
||||
{
|
||||
retval= lua_pcall(L, 0, 0, 0);
|
||||
if (retval!=0) // error
|
||||
{
|
||||
lua_setglobal (L, "_LASTERROR") ; //Set _LASTERROR to returned error message
|
||||
}
|
||||
}
|
||||
return _lua_err_code(retval);
|
||||
}
|
||||
|
||||
string lua::LastError (lua_State *L)
|
||||
{
|
||||
lua_getglobal (L, "_LASTERROR");
|
||||
if (lua_isstring(L,-1)){
|
||||
return string (lua_tostring (L, -1));
|
||||
}
|
||||
else {
|
||||
return "Lua Error. No error message available.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Error lua::DoSubfolderfile(lua_State *L, const string &basefolder, const string &filename) {
|
||||
std::list <string> fnames = app.resourceFS->findSubfolderFiles(basefolder, filename);
|
||||
int retval = 0;
|
||||
while (fnames.size() > 0) {
|
||||
int oldtop = lua_gettop(L);
|
||||
string fname = fnames.front();
|
||||
retval = luaL_loadfile(L, fname.c_str());
|
||||
if (retval!=0) // error
|
||||
{
|
||||
lua_setglobal (L, "_LASTERROR") ; //Set _LASTERROR to returned error message
|
||||
}
|
||||
else
|
||||
{
|
||||
retval= lua_pcall(L, 0, 0, 0);
|
||||
if (retval!=0) // error
|
||||
{
|
||||
lua_setglobal (L, "_LASTERROR") ; //Set _LASTERROR to returned error message
|
||||
}
|
||||
}
|
||||
fnames.pop_front();
|
||||
lua_settop(L, oldtop);
|
||||
}
|
||||
return _lua_err_code(retval);
|
||||
}
|
||||
|
||||
lua_State *lua::GlobalState()
|
||||
{
|
||||
if (global_state == 0) {
|
||||
lua_State *L = global_state = lua_open();
|
||||
|
||||
luaL_openlibs(L);
|
||||
CheckedDoFile(L, app.systemFS, "compat.lua");
|
||||
|
||||
tolua_open(L);
|
||||
tolua_enigma_open(L);
|
||||
|
||||
RegisterFuncs(L, globalfuncs);
|
||||
}
|
||||
return global_state;
|
||||
}
|
||||
|
||||
void lua::ShutdownGlobal()
|
||||
{
|
||||
assert (global_state);
|
||||
lua_close(global_state);
|
||||
global_state = 0;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
lua_State *lua::InitLevel()
|
||||
{
|
||||
char buffer[255];
|
||||
|
||||
lua_State *L = level_state = lua_open();
|
||||
luaL_dostring (L, "options={}");
|
||||
snprintf (buffer, sizeof(buffer), "options.Difficulty = %d",
|
||||
server::GetDifficulty());
|
||||
luaL_dostring (L, buffer);
|
||||
|
||||
luaL_openlibs(L);
|
||||
|
||||
tolua_open(L);
|
||||
tolua_enigma_open(L);
|
||||
tolua_px_open(L);
|
||||
tolua_display_open(L);
|
||||
|
||||
RegisterFuncs(L, levelfuncs);
|
||||
|
||||
// Create a new metatable for world::Object objects
|
||||
luaL_newmetatable(L,"_ENIGMAOBJECT");
|
||||
return L;
|
||||
}
|
||||
|
||||
lua_State *lua::LevelState ()
|
||||
{
|
||||
return level_state;
|
||||
}
|
||||
|
||||
void lua::ShutdownLevel() {
|
||||
if (level_state) {
|
||||
lua_close(level_state);
|
||||
level_state = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user