416 lines
9.0 KiB
C
416 lines
9.0 KiB
C
#include "lauxlib.h"
|
|
|
|
#include "log.h"
|
|
#include "lephisto.h"
|
|
#include "rng.h"
|
|
#include "ltime.h"
|
|
#include "toolkit.h"
|
|
#include "space.h"
|
|
#include "land.h"
|
|
#include "map.h"
|
|
#include "pack.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 }
|
|
};
|
|
|
|
/* Space. */
|
|
static int space_getPlanet(lua_State* L);
|
|
static int space_getSystem(lua_State* L);
|
|
static int space_landName(lua_State* L);
|
|
static int space_systemName(lua_State* L);
|
|
static int space_jumpDist(lua_State* L);
|
|
static int space_faction(lua_State* L);
|
|
static const luaL_reg space_methods[] = {
|
|
{ "getPlanet", space_getPlanet },
|
|
{ "getSystem", space_getSystem },
|
|
{ "landName", space_landName },
|
|
{ "system", space_systemName },
|
|
{ "jumpDist", space_jumpDist },
|
|
{ "spaceFaction", space_faction },
|
|
{ 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;
|
|
}
|
|
|
|
/* Load specially modified basic stuff. */
|
|
int llua_loadBasic(lua_State* L) {
|
|
int i;
|
|
/* Unsafe functions. */
|
|
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]);
|
|
}
|
|
|
|
/* Add our own. */
|
|
lua_register(L, "include", llua_packfileLoader);
|
|
|
|
return 0;
|
|
}
|
|
|
|
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 = pack_readfile(DATA, filename, &bufsize);
|
|
if(buf == NULL) {
|
|
lua_pushfstring(L, "%s not found in packfile %s", filename, DATA);
|
|
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_loadSpace(lua_State* L, int readonly) {
|
|
(void)readonly;
|
|
luaL_register(L, "space", space_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;
|
|
}
|
|
|
|
/* -- Space. -- */
|
|
static int space_getPlanet(lua_State* L) {
|
|
int i;
|
|
int *factions;
|
|
int nfactions;
|
|
char** planets;
|
|
int nplanets;
|
|
char* rndplanet;
|
|
|
|
if(lua_gettop(L) == 0) {
|
|
/* Get random planet. */
|
|
lua_pushstring(L, space_getRndPlanet());
|
|
return 1;
|
|
}
|
|
else if(lua_isnumber(L, 1)) {
|
|
i = lua_tonumber(L, 1);
|
|
planets = space_getFactionPlanet(&nplanets, &i, 1);
|
|
}
|
|
else if(lua_isstring(L, 1)) {
|
|
i = faction_get((char*) lua_tostring(L, 1));
|
|
planets = space_getFactionPlanet(&nplanets, &i, 1);
|
|
}
|
|
else if(lua_istable(L, 1)) {
|
|
/* Load up the table. */
|
|
lua_pushnil(L);
|
|
nfactions = (int) lua_gettop(L);
|
|
factions = malloc(sizeof(int) * nfactions);
|
|
i = 0;
|
|
while(lua_next(L, -2) != 0) {
|
|
factions[i++] = (int) lua_tonumber(L, -1);
|
|
lua_pop(L, 1);
|
|
}
|
|
/* Get the planets. */
|
|
planets = space_getFactionPlanet(&nplanets, factions, nfactions);
|
|
free(factions);
|
|
}
|
|
else return 0; /* Nothing useful. */
|
|
|
|
/* Choose random planet. */
|
|
if(nplanets == 0) {
|
|
/* No suitable planet. */
|
|
free(planets);
|
|
return 0;
|
|
}
|
|
|
|
rndplanet = planets[RNG(0, nplanets-1)];
|
|
free(planets);
|
|
|
|
lua_pushstring(L, rndplanet);
|
|
return 1;
|
|
}
|
|
|
|
static int space_getSystem(lua_State* L) {
|
|
LLUA_MIN_ARGS(1);
|
|
char* planetname, *sysname;
|
|
|
|
if(lua_isstring(L, 1)) planetname = (char*) lua_tostring(L, 1);
|
|
else return 0;
|
|
|
|
sysname = planet_getSystem(planetname);
|
|
lua_pushstring(L, sysname);
|
|
return 1;
|
|
}
|
|
|
|
static int space_landName(lua_State* L) {
|
|
if(landed) {
|
|
lua_pushstring(L, land_planet->name);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int space_systemName(lua_State* L) {
|
|
lua_pushstring(L, cur_system->name);
|
|
return 1;
|
|
}
|
|
|
|
static int space_jumpDist(lua_State* L) {
|
|
LLUA_MIN_ARGS(1);
|
|
StarSystem** s;
|
|
int jumps;
|
|
char* start, *goal;
|
|
|
|
if(lua_isstring(L, 1))
|
|
start = (char*)lua_tostring(L, 1);
|
|
else LLUA_INVALID_PARAMETER();
|
|
|
|
if((lua_gettop(L) > 1) && lua_isstring(L, 2))
|
|
goal = (char*) lua_tostring(L, 2);
|
|
else
|
|
goal = cur_system->name;
|
|
|
|
s = map_getJumpPath(&jumps, start, goal, 1);
|
|
free(s);
|
|
|
|
lua_pushnumber(L, jumps);
|
|
return 1;
|
|
}
|
|
|
|
static int space_faction(lua_State* L) {
|
|
int i;
|
|
StarSystem* s;
|
|
|
|
/* Get the system. */
|
|
if(lua_isstring(L, 2))
|
|
s = system_get(lua_tostring(L, 1));
|
|
else s = cur_system;
|
|
|
|
/* Check if valid. */
|
|
if(s == NULL) {
|
|
LLUA_DEBUG("Invalid system!");
|
|
return 0;
|
|
}
|
|
|
|
/* Return the result in table. */
|
|
lua_newtable(L);
|
|
for(i = 0; i < s->nplanets; i++) {
|
|
lua_pushboolean(L, 1); /* Value. */
|
|
lua_setfield(L, -2, faction_name(s->planets[i].faction)); /* Key. */
|
|
/* Allows syntax foo = space.faction("foo"); if foo["bar"] then ... end */
|
|
}
|
|
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;
|
|
}
|
|
|