#include "lua.h" #include "lualib.h" #include "lauxlib.h" #include "hook.h" #include "mission.h" #include "log.h" #include "lephisto.h" #include "rng.h" #include "space.h" #include "toolkit.h" #include "land.h" #include "misn_lua.h" // FUCK LUA!!! //#define luaL_register(L,n,l) (luaL_openlib(L, (n),(l), 0)) #define MIN_ARGS(n) if(lua_gettop(L) < n) return 0 static Mission* cur_mission = NULL; static int misn_delete = 0; // If 1 delete current mission. // -- Libraries. -- // Mission. static int misn_setTitle(lua_State* L); static int misn_setDesc(lua_State* L); static int misn_setReward(lua_State* L); static int misn_factions(lua_State* L); static int misn_accept(lua_State* L); static int misn_finish(lua_State* L); static const luaL_Reg misn_methods[] = { { "setTitle", misn_setTitle }, { "setDesc", misn_setDesc }, { "setReward", misn_setReward }, { "factions", misn_factions }, { "accept", misn_accept }, { "finish", misn_finish }, { 0, 0 } }; // Space. static int space_getPlanet(lua_State* L); static int space_landName(lua_State* L); static const luaL_Reg space_methods[] = { { "getPlanet", space_getPlanet }, { "landName", space_landName }, { 0, 0 } }; // Player. static int player_freeSpace(lua_State* L); static int player_addCargo(lua_State* L); static int player_rmCargo(lua_State* L); static int player_pay(lua_State* L); static const luaL_Reg player_methods[] = { { "freeCargo", player_freeSpace }, { "addCargo", player_addCargo }, { "rmCargo", player_rmCargo }, { "pay", player_pay }, { 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 } }; static int hook_land(lua_State* L); static const luaL_Reg hook_methods[] = { { "land", hook_land }, { 0, 0 } }; // Register all the libaries. int misn_loadLibs(lua_State* L) { luaL_register(L, "misn", misn_methods); luaL_register(L, "space", space_methods); luaL_register(L, "player", player_methods); luaL_register(L, "rnd", rnd_methods); luaL_register(L, "hook", hook_methods); luaL_register(L, "tk", tk_methods); return 0; } // Run a mission function. int misn_run(Mission* misn, char* func) { int i, ret; char* err; cur_mission = misn; lua_getglobal(misn->L, func); if((ret = lua_pcall(misn->L, 0, 0, 0))) { // Did an oops. err = (lua_isstring(misn->L, -1)) ? (char*) lua_tostring(misn->L, -1) : NULL; if(strcmp(err, "Mission Finished")) WARN("Mission '%s' -> '%s' : %s", cur_mission->data->name, func, (err) ? err : "Unknown Error"); else ret = 0; } // Mission is finished. if(misn_delete) { mission_cleanup(cur_mission); for(i = 0; i < MISSION_MAX; i++) if(cur_mission == &player_missions[i]) { memmove(&player_missions[i], &player_missions[i+1], sizeof(Mission) * (MISSION_MAX-i-1)); break; } } cur_mission = NULL; return ret; } // -- Mission. -- static int misn_setTitle(lua_State* L) { MIN_ARGS(1); if(lua_isstring(L, -1)) { if(cur_mission->title) // Cleanup the old title. free(cur_mission->title); cur_mission->title = strdup((char*)lua_tostring(L, -1)); } return 0; } static int misn_setDesc(lua_State* L) { MIN_ARGS(1); if(lua_isstring(L, -1)) { if(cur_mission->desc) // Cleanup the old description. free(cur_mission->desc); cur_mission->desc = strdup((char*)lua_tostring(L, -1)); } return 0; } static int misn_setReward(lua_State* L) { MIN_ARGS(1); if(lua_isstring(L, -1)) { if(cur_mission->reward) // Cleanup the old reward. free(cur_mission->reward); cur_mission->reward = strdup((char*)lua_tostring(L, -1)); } return 0; } static int misn_factions(lua_State* L) { int i; MissionData* dat; dat = cur_mission->data; lua_newtable(L); for(i = 0; i < dat->avail.nfactions; i++) { lua_pushnumber(L, i+1); // Index, starts with 1. lua_pushnumber(L, dat->avail.factions[i]); // Value. lua_rawset(L, -3); // Store the value in the table. } return 1; } static int misn_accept(lua_State* L) { int i, ret; ret = 0; // Find the last mission. for(i = 0; i < MISSION_MAX; i++) if(player_missions[i].data == NULL) break; // No missions left. if(i >= MISSION_MAX) ret = 1; else { memcpy(&player_missions[i], cur_mission, sizeof(Mission)); memset(cur_mission, 0, sizeof(Mission)); cur_mission = &player_missions[i]; } lua_pushboolean(L, !ret); // We'll convert C style return to lua. return 1; } static int misn_finish(lua_State* L) { misn_delete = 1; lua_pushstring(L, "Mission Finished"); lua_error(L); // Should not return.. return 0; } 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_landName(lua_State* L) { if(landed) { lua_pushstring(L, land_planet->name); return 1; } return 0; } // -- Player. -- static int player_freeSpace(lua_State* L) { lua_pushnumber(L, pilot_freeCargo(player)); return 1; } static int player_addCargo(lua_State* L) { Commodity* cargo; int quantity, ret; MIN_ARGS(2); if(lua_isstring(L, -2)) cargo = commodity_get((char*) lua_tostring(L, -2)); else return 0; if(lua_isnumber(L, -1)) quantity = (int)lua_tonumber(L, -1); else return 0; ret = pilot_addMissionCargo(player, cargo, quantity); lua_pushnumber(L, ret); return 1; } static int player_rmCargo(lua_State* L) { int ret; unsigned int id; MIN_ARGS(1); if(lua_isnumber(L, -1)) id = (unsigned int) lua_tonumber(L, -1); else return 0; ret = pilot_rmMissionCargo(player, id); lua_pushboolean(L, !ret); return 0; } static int player_pay(lua_State* L) { int money; MIN_ARGS(1); if(lua_isnumber(L, -1)) money = (int) lua_tonumber(L, -1); else return 0; player->credits += money; return 0; } // -- 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, -2), (int)lua_tonumber(L,-1))); else return 0; } else return 0; // Unless it's returned 0 already it'll always return param. return 1; } // -- Toolkit. -- static int tk_msg(lua_State* L) { char* title, *str; MIN_ARGS(2); if(lua_isstring(L, -2)) title = (char*) lua_tostring(L, -2); else return 0; if(lua_isstring(L, -1)) str = (char*) lua_tostring(L, -1); else return 0; dialogue_msg(title, str); return 0; } static int tk_yesno(lua_State* L) { int ret; char* title, *str; MIN_ARGS(2); if(lua_isstring(L, -2)) title = (char*) lua_tostring(L, -2); else return 0; if(lua_isstring(L, -1)) str = (char*) lua_tostring(L, -1); else return 0; ret = dialogue_YesNo(title, str); lua_pushboolean(L, ret); return 1; } static int tk_input(lua_State* L) { char* title, *str; int min, max; MIN_ARGS(4); if(lua_isstring(L, -4)) title = (char*) lua_tostring(L, -4); else return 0; if(lua_isnumber(L, -3)) min = (int) lua_tonumber(L, -3); else return 0; if(lua_isnumber(L, -2)) max = (int) lua_tonumber(L, -2); else return 0; if(lua_isstring(L, -1)) str = (char*) lua_tostring(L, -1); else return 0; dialogue_input(title, min, max, str); return 0; } // -- HOOK -- static int hook_land(lua_State* L) { char* func; MIN_ARGS(1); if(lua_isstring(L, -1)) func = (char*)lua_tostring(L, -1); else { WARN("Mission '%s': trying to push non-valid function hook", cur_mission->data->name); return 0; } hook_add(cur_mission, func, "land"); return 0; }