Lephisto/src/llua.c
2014-06-04 21:06:29 +01:00

295 lines
6.3 KiB
C

/**
* @file llua.c
*
* @brief Contains some standard Lua binding libraries.
*
* Namely:
* -- lephisto : General game stuff.
* -- time : For manipulating time.
* -- rnd : For access to the random number generator.
* -- tk : Access to the toolkit.
*/
#include "lauxlib.h"
#include "log.h"
#include "lephisto.h"
#include "rng.h"
#include "ltime.h"
#include "dialogue.h"
#include "space.h"
#include "land.h"
#include "map.h"
#include "ldata.h"
#include "lluadef.h"
#include "llua.h"
static int llua_packfileLoader(lua_State* L);
/* -- Libraries. -- */
/* Lephisto. */
static int lephisto_lang(lua_State* L);
static const luaL_reg lephisto_methods[] = {
{ "lang", lephisto_lang },
{ 0, 0 }
};
/* Time. */
static int time_get(lua_State* L);
static int time_str(lua_State* L);
static int time_units(lua_State* L);
static const luaL_reg time_methods[] = {
{ "get", time_get },
{ "str", time_str },
{ "units", time_units },
{0, 0}
};
/* RND. */
static int rnd_int(lua_State*L);
static const luaL_reg rnd_methods[] = {
{ "int", rnd_int },
{ 0, 0 }
};
/* Toolkit. */
static int tk_msg(lua_State* L);
static int tk_yesno(lua_State* L);
static int tk_input(lua_State* L);
static const luaL_reg tk_methods[] = {
{ "msg", tk_msg },
{ "yesno", tk_yesno },
{ "input", tk_input },
{ 0, 0 }
};
/* Wrapper around luaL_newstate. */
lua_State* llua_newState(void) {
lua_State* L;
/* Try to create the new state. */
L = luaL_newstate();
if(L == NULL) {
WARN("Failed to create new lua state.");
return NULL;
}
return L;
}
/* Open a lua library. */
int llua_load(lua_State* L, lua_CFunction f) {
lua_pushcfunction(L, f);
if(lua_pcall(L, 0, 0, 0))
WARN("llua include error: %s", lua_tostring(L, 1));
return 0;
}
/**
* @brief Load specially modified basic stuff.
* @param L Lua state to load the basic stuff into.
* @return 0 on success.
*/
int llua_loadBasic(lua_State* L) {
int i;
/* Unsafe functions. */
const char* override[] = {
"collectgarbage",
"dofile",
"getfenv",
"getmetatable",
"load",
"loadfile",
"loadstring",
"rawequal",
"rawget",
"rawset",
"setfenv",
"setmetatable",
"END"
};
llua_load(L, luaopen_base); /* Open base. */
/* Replace non-safe functions. */
for(i = 0; strcmp(override[i], "END") != 0; i++) {
lua_pushnil(L);
lua_setglobal(L, override[i]);
}
llua_load(L, luaopen_math); /* Open math. */
llua_load(L, luaopen_table); /* Open table. */
/* Add our own. */
lua_register(L, "include", llua_packfileLoader);
return 0;
}
/**
* @brief include(string module)
*
* Loads a module into the current Lua state from inside the data file.
* @param module Name of the module to load.
* @return An error string on error.
*/
static int llua_packfileLoader(lua_State* L) {
char* buf, *filename;
uint32_t bufsize;
LLUA_MIN_ARGS(1);
if(!lua_isstring(L, 1)) {
LLUA_INVALID_PARAMETER();
return 0;
}
filename = (char*) lua_tostring(L, 1);
/* Try to locate the data. */
buf = ldata_read(filename, &bufsize);
if(buf == NULL) {
lua_pushfstring(L, "%s not found in ldata.", filename);
return 1;
}
/* Run the buffer. */
if(luaL_dobuffer(L, buf, bufsize, filename) != 0) {
/* Will push the current error from the dobuffer. */
return 1;
}
/* Cleanup. */
free(buf);
return 0;
}
/* Individual libraries. */
int lua_loadLephisto(lua_State* L) {
luaL_register(L, "lephisto", lephisto_methods);
return 0;
}
int lua_loadTime(lua_State* L, int readonly) {
(void)readonly;
luaL_register(L, "time", time_methods);
return 0;
}
int lua_loadRnd(lua_State* L) {
luaL_register(L, "rnd", rnd_methods);
return 0;
}
int lua_loadTk(lua_State* L) {
luaL_register(L, "tk", tk_methods);
return 0;
}
/* -- Lephisto. -- */
static int lephisto_lang(lua_State* L) {
/* @todo Multilanguage stuff. */
lua_pushstring(L, "en");
return 1;
}
/* -- Time. -- */
static int time_get(lua_State* L) {
lua_pushnumber(L, ltime_get());
return 1;
}
static int time_str(lua_State* L) {
char* lt;
if((lua_gettop(L) > 0) && (lua_isnumber(L, 1)))
lt = ltime_pretty((unsigned int) lua_tonumber(L, 1));
else
lt = ltime_pretty(ltime_get());
lua_pushstring(L, lt);
free(lt);
return 1;
}
static int time_units(lua_State* L) {
if((lua_gettop(L) > 0) && (lua_isnumber(L, 1)))
lua_pushnumber(L, (unsigned int) lua_tonumber(L, 1) * LTIME_UNIT_LENGTH);
else
lua_pushnumber(L, LTIME_UNIT_LENGTH);
return 1;
}
/* -- RND. -- */
static int rnd_int(lua_State* L) {
int o;
o = lua_gettop(L);
if(o == 0) lua_pushnumber(L, RNGF()); /* Random double o <= x <= 1. */
else if(o == 1) {
/* Random int 0 <= x <= param. */
if(lua_isnumber(L, 1))
lua_pushnumber(L, RNG(0, (int)lua_tonumber(L, 1)));
else return 0;
}
else if(o >= 2) {
/* Random int param 1 <= x <= param 2. */
if(lua_isnumber(L, 1) && lua_isnumber(L, 2))
lua_pushnumber(L, RNG((int)lua_tonumber(L, 1), (int)lua_tonumber(L, 2)));
else return 0;
}
else LLUA_INVALID_PARAMETER();
/* Unless it's returned 0 already it'll always return param. */
return 1;
}
/* -- Toolkit. -- */
static int tk_msg(lua_State* L) {
char* title, *str;
LLUA_MIN_ARGS(2);
if(lua_isstring(L, 1)) title = (char*) lua_tostring(L, 1);
else LLUA_INVALID_PARAMETER();
if(lua_isstring(L, 2)) str = (char*) lua_tostring(L, 2);
else LLUA_INVALID_PARAMETER();
dialogue_msg(title, str);
return 0;
}
static int tk_yesno(lua_State* L) {
int ret;
char* title, *str;
LLUA_MIN_ARGS(2);
if(lua_isstring(L, 1)) title = (char*) lua_tostring(L, 1);
else LLUA_INVALID_PARAMETER();
if(lua_isstring(L, 2)) str = (char*) lua_tostring(L, 2);
else LLUA_INVALID_PARAMETER();
ret = dialogue_YesNo(title, str);
lua_pushboolean(L, ret);
return 1;
}
static int tk_input(lua_State* L) {
char* title, *str;
int min, max;
LLUA_MIN_ARGS(4);
if(lua_isstring(L, 1)) title = (char*) lua_tostring(L, 1);
else LLUA_INVALID_PARAMETER();
if(lua_isnumber(L, 2)) min = (int) lua_tonumber(L, 2);
else LLUA_INVALID_PARAMETER();
if(lua_isnumber(L, 3)) max = (int) lua_tonumber(L, 3);
else LLUA_INVALID_PARAMETER();
if(lua_isstring(L, 4)) str = (char*) lua_tostring(L, 4);
else LLUA_INVALID_PARAMETER();
dialogue_input(title, min, max, str);
return 0;
}