diff --git a/src/llua_pilot.c b/src/llua_pilot.c new file mode 100644 index 0000000..4260f67 --- /dev/null +++ b/src/llua_pilot.c @@ -0,0 +1,417 @@ +/** + * @file llua_space.c + * + * @brief Handle the Lua space bindings. + * + * These bindings control the planets and systems. + */ + +#include "lauxlib.h" +#include "lephisto.h" +#include "llua_space.h" +#include "lluadef.h" +#include "rng.h" +#include "pilot.h" +#include "pilot.h" +#include "llua_pilot.h" + +static int pilotL_createmetatable(lua_State* L); +/* Pilots. */ +static int pilot_addFleet(lua_State* L); +static int pilot_clear(lua_State* L); +static int pilot_toggleSpawn(lua_State* L); +static const luaL_reg pilot_methods[] = { + { "add", pilot_addFleet }, + { "clear", pilot_clear }, + { "clear", pilot_toggleSpawn }, + { 0, 0 } +}; /**< Pilot lua methods. */ + +static int pilotL_eq(lua_State* L); +static int pilotL_name(lua_State* L); +static int pilotL_rename(lua_State* L); +static int pilotL_position(lua_State* L); +static int pilotL_warp(lua_State* L); +static const luaL_reg pilotL_methods[] = { + { "__eq", pilotL_eq }, + { "name", pilotL_name }, + { "rename", pilotL_rename }, + { "pos", pilotL_position }, + { "warp", pilotL_warp }, + { 0, 0 } +}; /**< Pilot metatable methods. */ + +/** + * @fn int lua_loadPilot(lua_State* L, int readonly) + * + * @brief Load the space library. + * @param L State to load space library into. + * @return 0 on success. + */ +int lua_loadPilot(lua_State* L, int readonly) { + if(readonly) /* Nothing is read only. */ + return 0; + + /* Register the functions. */ + luaL_register(L, "pilot", pilot_methods); + + /* Register the metatables. */ + pilotL_createmetatable(L); + + return 0; +} + +/** + * @fn static int pilotL_createmetatable(lua_State* L) + * + * @brief Registers the pilot metatable. + * @param L Lua state to register metatable in. + * @return 0 on success. + */ +static int pilotL_createmetatable(lua_State* L) { + /* Create the metatable. */ + luaL_newmetatable(L, PILOT_METATABLE); + + /* Create the access table. */ + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + + /* Register the values. */ + luaL_register(L, NULL, pilotL_methods); + + return 0; +} + +/** + * @defgroup PILOT Pilot Lua bindings. + * + * @brief Lua bindings to interact with pilots. + * + * Functions should be called like: + * + * @code + * pilot.function(parameters) + * @endcode + */ +/** + * @defgroup META_PILOT Pilot Metatable + * + * @brief Represents a pilot in Lua. + * + * To call members of the metatable always use: + * + * @code + * pilot:function(param) + * @endcode + */ + +/** + * @fn LuaPilot* lua_topilot(lua_State* L, int ind) + * + * @brief Get pilot at index. + * @param L Lua state to get pilot from. + * @param ind Index position to find the pilot. + * @return Pilot found at the index in the state. + */ +LuaPilot* lua_topilot(lua_State* L, int ind) { + if(lua_isuserdata(L, ind)) { + return (LuaPilot*)lua_touserdata(L, ind); + } + luaL_typerror(L, ind, PILOT_METATABLE); + return NULL; +} + +/** + * @fn LuaPilot* lua_pushpilot(lua_State* L, LuaPilot pilot) + * + * @brief Push a pilot on the stack. + * @param L Lua state to push pilot into. + * @param pilot Pilot to push. + * @return Newly pushed pilot. + */ +LuaPilot* lua_pushpilot(lua_State* L, LuaPilot pilot) { + LuaPilot* p; + p = (LuaPilot*)lua_newuserdata(L, sizeof(LuaPilot)); + *p = pilot; + luaL_getmetatable(L, PILOT_METATABLE); + lua_setmetatable(L, -2); + return p; +} + +/** + * @fn int lua_ispilot(lua_State* L, int ind) + * + * @brief Check to see if ind is a pilot. + * @param L Lua state to check. + * @param ind Index position to check. + * @return 1 if ind is a pilot. + */ +int lua_ispilot(lua_State* L, int ind) { + int ret; + + if(lua_getmetatable(L, ind)==0) + return 0; + lua_getfield(L, LUA_REGISTRYINDEX, PILOT_METATABLE); + + ret = 0; + if(lua_rawequal(L, -1, -2)) /* Does it have the correct mt?*/ + ret = 1; + + lua_pop(L, 2); /* Remove both metatables. */ + return ret; +} + +/** + * @fn static int pilot_addFleet(lua_State* L) + * @ingroup PILOT + * + * @brief table add(string fleetname [, string ai ]) + * + * Adds a fleet to the system. + * @param fleetname Name of the fleet to add. + * @param ai If set will override the standard fleet AI. + * @return Table populated with all the identifiers of the pilots created. + */ +static int pilot_addFleet(lua_State* L) { + LLUA_MIN_ARGS(1); + Fleet* flt; + char* fltname, *fltai; + int i, j; + unsigned int p; + double a; + Vec2 vv, vp, vn; + FleetPilot* plt; + LuaPilot lp; + + + /* Parse first argument - Fleet name */ + if(lua_isstring(L, 1)) fltname = (char*) lua_tostring(L, 1); + else LLUA_INVALID_PARAMETER(); + + /* Parse second argument - Fleet IA override. */ + if((lua_gettop(L) > 1) && lua_isstring(L, 2)) + fltai = (char*)lua_tostring(L, 2); + else fltai = NULL; + + /* Pull the fleet. */ + flt = fleet_get(fltname); + if(flt == NULL) { + LLUA_DEBUG("Fleet not found!"); + return 0; + } + + /* This should probably be done better. */ + vect_pset(&vp, RNG(MIN_HYPERSPACE_DIST, MIN_HYPERSPACE_DIST*1.5), + RNG(0,360)*M_PI/180.); + vectnull(&vn); + + j = 0; + lua_newtable(L); + for(i = 0; i < flt->npilots; i++) { + plt = &flt->pilots[i]; + + if(RNG(0, 100) <= plt->chance) { + /* Fleet displacement. */ + vect_cadd(&vp, RNG(75, 150) * (RNG(0,1) ? 1 : -1), + RNG(75, 150) * (RNG(0,1) ? 1 : -1)); + + a = vect_angle(&vp, &vn); + vectnull(&vv); + p = pilot_create(plt->ship, + plt->name, + flt->faction, + (fltai != NULL) ? /* Lua AI override. */ + ai_getProfile(fltai) : + (plt->ai != NULL) ? /* Pilot AI override */ + plt->ai : flt->ai, + a, + &vp, + &vv, + 0); + + /* We push each pilot created into a table and return it. */ + lua_pushnumber(L, ++j); /* Index, starts with 1. */ + lp.pilot = p; + lua_pushpilot(L, lp); /* value = LuaPilot */ + lua_rawset(L, -3); /* Store the value in the table. */ + } + } + + return 1; + +} + +/** + * @fn static int pilot_clear(lua_State* L) + * @ingroup PILOT + * + * @brief clear(nil) + * + * Clears the current system of pilots. Used for epic battles and such. + */ +static int pilot_clear(lua_State* L) { + (void) L; + pilots_clean(); + return 0; +} + +/** + * @fn static int pilot_toggleSpawn(lua_State* L) + * @ingroup PILOT + * + * @brief bool togglespawn( [bool enable] ) + * + * Disable or enable pilot spawning in the current system. If player jumps + * the spawn is enabled again automatically. + * @param enable true enables spawn, false disables it. + * @return The current spawn state. + */ +static int pilot_toggleSpawn(lua_State* L) { + /* Setting it directly. */ + if((lua_gettop(L) > 0) && lua_isboolean(L, 1)) + space_spawn = lua_toboolean(L, 1); + /* Toggling. */ + else + space_spawn = !space_spawn; + + lua_pushboolean(L, space_spawn); + return 1; +} + +/** + * @fn static int pilotL_eq(lua_State* L) + * + * @brief bool __eq(Pilot p) + * + * Check to see if pilot and p are the same. + * @param p Pilot to compare against. + * @return true if they are the same. + */ +static int pilotL_eq(lua_State* L) { + LLUA_MIN_ARGS(2); + LuaPilot* p1, *p2; + + /* Get parameters. */ + p1 = lua_topilot(L, 1); + if(lua_ispilot(L, 2)) + p2 = lua_topilot(L, 2); + else LLUA_INVALID_PARAMETER(); + + /* Push result. */ + lua_pushboolean(L, p1->pilot == p2->pilot); + return 1; +} + +/** + * @fn static int pilotL_name(lua_State* L) + * @ingroup META_PILOT + * + * @brief string name(nil) + * + * Get the pilots current name. + * @return The current name of the pilot. + */ +static int pilotL_name(lua_State* L) { + LLUA_MIN_ARGS(1); + LuaPilot* p1; + Pilot* p; + + /* Parse parameters. */ + p1 = lua_topilot(L, 1); + p = pilot_get(p1->pilot); + + /* Pilot must exist. */ + if(p == NULL) return 0; + + /* Get name. */ + lua_pushstring(L, p->name); + return 1; +} + +/** + * @fn static int pilotL_rename(lua_State* L) + * + * @brief rename(string name) + * + * Changes the pilots name. + * @param name Name to change to. + */ +static int pilotL_rename(lua_State* L) { + LLUA_MIN_ARGS(2); + LuaPilot* p1; + char* name; + Pilot* p; + + /* Parse parameters. */ + p1 = lua_topilot(L, 1); + p = pilot_get(p1->pilot); + if(lua_isstring(L, 2)) + name = (char*)lua_tostring(L, 2); + else LLUA_INVALID_PARAMETER(); + + /* Pilot must exist. */ + if(p == NULL) return 0; + + /* Change name. */ + if(p->name != NULL) + free(p->name); + p->name = strdup(name); + + return 0; +} + +/** + * @fn static int pilotL_position(lua_State* L) + * + * @brief Vec2 position( nil ) + * + * Get the pilots position. + * @return The pilots current position. + */ +static int pilotL_position(lua_State* L) { + LLUA_MIN_ARGS(1); + LuaPilot* p1; + Pilot* p; + LuaVector v; + + /* Parse parameters */ + p1 = lua_topilot(L, 1); + p = pilot_get(p1->pilot); + + /* Pilot must exist. */ + if(p == NULL) return 0; + + /* Push position. */ + vectcpy(&v.vec, &p->solid->pos); + lua_pushvector(L, v); + return 1; +} + +/** + * @fn static int pilotL_warp(lua_State* L) + * @ingroup META_PILOT + * + * @brief Vec2 position. + * @return The pilots current position. + */ +static int pilotL_warp(lua_State* L) { + LLUA_MIN_ARGS(2); + LuaPilot* p1; + Pilot* p; + LuaVector* v; + + /* Parse parameters. */ + p1 = lua_topilot(L, 1); + p = pilot_get(p1->pilot); + if(lua_isvector(L,2)) + v = lua_tovector(L, 2); + else LLUA_INVALID_PARAMETER(); + + /* Pilot must exist. */ + if(p == NULL) return 0; + + /* Warp pilot to new position. */ + vectcpy(&p->solid->pos, &v->vec); + return 0; +} + diff --git a/src/llua_pilot.h b/src/llua_pilot.h new file mode 100644 index 0000000..6b8d762 --- /dev/null +++ b/src/llua_pilot.h @@ -0,0 +1,18 @@ +#pragma once +#include "lua.h" +#include "pilot.h" + +#define PILOT_METATABLE "Pilot" + +/* Lua wrappers. */ +typedef struct LuaPilot_s { + unsigned int pilot; +} LuaPilot; + +/* Library loading. */ +int lua_loadPilot(lua_State* L, int readonly); + +LuaPilot* lua_topilot(lua_State* L, int ind); +LuaPilot* lua_pushpilot(lua_State* L, LuaPilot pilot); +int lua_ispilot(lua_State* L, int ind); + diff --git a/src/misn_lua.c b/src/misn_lua.c index abd629f..22d7a8e 100644 --- a/src/misn_lua.c +++ b/src/misn_lua.c @@ -8,6 +8,7 @@ #include "llua.h" #include "llua_space.h" +#include "llua_pilot.h" #include "lluadef.h" #include "hook.h" #include "mission.h" @@ -146,20 +147,6 @@ static const luaL_reg hook_methods[] = { { 0, 0 } }; -/* Pilots. */ -static int pilot_addFleet(lua_State* L); -static int pilot_rename(lua_State* L); -static int pilot_clear(lua_State* L); -static int pilot_toggleSpawn(lua_State* L); -static const luaL_reg pilot_methods[] = { - { "add", pilot_addFleet }, - { "rename", pilot_rename }, - { "clear", pilot_clear }, - { "togglespawn", pilot_toggleSpawn }, - { "clear", pilot_toggleSpawn }, - { 0, 0 } -}; - /* Register all the libaries. */ int misn_loadLibs(lua_State* L) { lua_loadLephisto(L); @@ -171,7 +158,7 @@ int misn_loadLibs(lua_State* L) { lua_loadRnd(L); lua_loadTk(L); lua_loadHook(L); - lua_loadPilot(L); + lua_loadPilot(L, 0); return 0; } @@ -210,11 +197,6 @@ int lua_loadHook(lua_State* L) { return 0; } -int lua_loadPilot(lua_State* L) { - luaL_register(L, "pilot", pilot_methods); - return 0; -} - /* * Run a mission function. * -1 on error, 1 on misn.finish() call and 0 normally. @@ -773,7 +755,7 @@ static int hook_enter(lua_State* L) { * @fn static int hook_pilot(lua_State* L) * @ingroup HOOK * - * @brief number pilot(number pilot, string type, string func) + * @brief number pilot(Pilot pilot, string type, string func) * * Hooks the function to a specific pilot. * @@ -790,12 +772,13 @@ static int hook_enter(lua_State* L) { */ static int hook_pilot(lua_State* L) { LLUA_MIN_ARGS(2); - unsigned int h, p; + unsigned int h; + LuaPilot* p; int type; char* hook_type; /* First parameter - pilot to hook. */ - if(lua_isnumber(L, 1)) p = (unsigned int)lua_tonumber(L, 1); + if(lua_ispilot(L, 1)) p = lua_topilot(L, 1); else LLUA_INVALID_PARAMETER(); /* Second parameer - Hook name. */ @@ -815,122 +798,8 @@ static int hook_pilot(lua_State* L) { /* Actually add the hook. */ h = hook_generic(L, hook_type); - pilot_addHook(pilot_get(p), type, h); + pilot_addHook(pilot_get(p->pilot), type, h); return 0; } -/* -- Pilot. -- */ -static int pilot_addFleet(lua_State* L) { - LLUA_MIN_ARGS(1); - Fleet* flt; - char* fltname, *fltai;; - int i, j; - unsigned int p; - double a; - Vec2 vv, vp, vn; - FleetPilot* plt; - - /* Parse first argument - Fleet name. */ - if(lua_isstring(L, 1)) fltname = (char*) lua_tostring(L, 1); - else LLUA_INVALID_PARAMETER(); - - /* Parse second arguement - Fleet AI override. */ - if(lua_isstring(L, 2)) fltai = (char*) lua_tostring(L, 2); - else fltai = NULL; - - /* Pull the fleet. */ - flt = fleet_get(fltname); - if(flt == NULL) { - LLUA_DEBUG("Fleet not found!"); - return 0; - } - - /* This should probably be done better.. */ - vect_pset(&vp, RNG(MIN_HYPERSPACE_DIST, MIN_HYPERSPACE_DIST*1.5), - RNG(0, 360)*M_PI/180.); - vectnull(&vn); - - /* Now we start adding pilots and toss ids into the table we return. */ - j = 0; - for(i = 0; i < flt->npilots; i++) { - plt = &flt->pilots[i]; - if(RNG(0, 100) <= plt->chance) { - /* Fleet displacement. */ - vect_cadd(&vp, RNG(75, 150) & (RNG(0, 1) ? 1: -1), - RNG(75, 150) * (RNG(0, 1) ? 1 : -1)); - - a = vect_angle(&vp, &vn); - vectnull(&vv); - p = pilot_create(plt->ship, - plt->name, - flt->faction, - (fltai != NULL) ? /* Lua AI override */ - ai_getProfile(fltai) : - (plt->ai != NULL) ? /* Pilot AI override. */ - plt->ai : flt->ai, - a, - &vp, - &vv, - 0); - - /* We push each pilot created into a table and return it. */ - lua_pushnumber(L, ++j); /* Index start with 1. */ - lua_pushnumber(L, p); /* value = pilot id. */ - lua_rawset(L, -3); /* Store the value in the table. */ - } - } - return 1; -} - -static int pilot_rename(lua_State* L) { - LLUA_MIN_ARGS(2); - char* name; - unsigned int id; - Pilot* p; - - if(lua_isnumber(L, 1)) id = (unsigned int) lua_tonumber(L, 1); - else LLUA_INVALID_PARAMETER(); - if(lua_isstring(L, 2)) name = (char*) lua_tostring(L, 2); - else LLUA_INVALID_PARAMETER(); - - p = pilot_get(id); - free(p->name); - p->name = strdup(name); - return 0; -} - -/** - * @fn static int pilot_clear(lua_State* L) - * - * @brief clear(nil) - * - * Clears the current system of pilots. Used for epic battles etc. - */ -static int pilot_clear(lua_State* L) { - (void) L; - pilots_clean(); - return 0; -} - -/** - * @fn static int pilot_toggleSpawn(lua_State* L) - * - * @brief bool togglespawn( [bool enable] ) - * - * Disable or enable pilot spawning in the current system. If player jumps - * the spawn is enabled again automagically. - * @param enable true Enables spawn, false disables it. - * @return The current spawn state. - */ -static int pilot_toggleSpawn(lua_State* L) { - if((lua_gettop(L) > 0) && lua_isboolean(L, 1)) - space_spawn = lua_toboolean(L, 1); - /* Toggling. */ - else - space_spawn = !space_spawn; - - lua_pushboolean(L, space_spawn); - return 1; -} - diff --git a/src/misn_lua.h b/src/misn_lua.h index ee6ab64..f0756c1 100644 --- a/src/misn_lua.h +++ b/src/misn_lua.h @@ -15,5 +15,4 @@ int lua_loadMisn(lua_State* L); int lua_loadVar(lua_State* L, int readonly); int lua_loadPlayer(lua_State* L, int readonly); int lua_loadHook(lua_State* L); -int lua_loadPilot(lua_State* L);