#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; }