#include "lauxlib.h" #include "log.h" #include "lephisto.h" #include "rng.h" #include "land.h" #include "lluadef.h" #include "map.h" #include "llua_space.h" static int planetL_createmetatable(lua_State* L); static int systemL_createmetatable(lua_State* L); static int vectorL_createmetatable(lua_State* L); /* Space. */ static int planetL_get(lua_State* L); static int systemL_get(lua_State* L); static const luaL_reg space_methods[] = { { "getPlanet", planetL_get }, { "getSystem", systemL_get }, { 0, 0 } }; /* Planet metatable methods. */ static int planetL_eq(lua_State* L); static int planetL_name(lua_State* L); static int planetL_faction(lua_State* L); static int planetL_class(lua_State* L); static int planetL_services(lua_State* L); static int planetL_position(lua_State* L); static const luaL_reg planet_methods[] = { { "__eq", planetL_eq }, { "name", planetL_name }, { "faction", planetL_faction }, { "class", planetL_class }, { "services", planetL_services }, { "pos", planetL_position }, { 0, 0 } }; /* System metatable methods. */ static int systemL_eq(lua_State* L); static int systemL_name(lua_State* L); static int systemL_faction(lua_State* L); static int systemL_jumpdistance(lua_State* L); static const luaL_reg system_methods[] = { { "__eq", systemL_eq }, { "name", systemL_name }, { "faction", systemL_faction }, { "jumpDist", systemL_jumpdistance }, { 0, 0 } }; /* Vector metatable methods. */ static int vectorL_new(lua_State* L); static int vectorL_add(lua_State* L); static int vectorL_sub(lua_State* L); static int vectorL_mul(lua_State* L); static int vectorL_div(lua_State* L); static int vectorL_get(lua_State* L); static int vectorL_set(lua_State* L); static int vectorL_distance(lua_State* L); static const luaL_reg vector_methods[] = { { "new", vectorL_new }, { "__add", vectorL_add }, { "add", vectorL_add }, { "__sub", vectorL_sub }, { "sub", vectorL_sub }, { "__mul", vectorL_mul }, { "__div", vectorL_div }, { "get", vectorL_get }, { "set", vectorL_set }, { "dist", vectorL_distance }, { 0, 0 } }; /**< Vector metatable methods. */ /* Load the space library. */ int lua_loadSpace(lua_State* L, int readonly) { (void)readonly; /* Only read only atm. */ /* Register the functions. */ luaL_register(L, "space", space_methods); /* Register the metatables. */ planetL_createmetatable(L); systemL_createmetatable(L); lua_loadVector(L); return 0; } /** * @fn int lua_loadVector(lua_State* L) * * @brief Loads the vector metatable. * @param L State to load the vector metatable into. * @return 0 on success. */ int lua_loadVector(lua_State* L) { vectorL_createmetatable(L); return 0; } /* -- SPACE -- */ /* Create a planet metatable from a planet and put it on top of the stack. */ static int planetL_createmetatable(lua_State* L) { /* Create the metatable. */ luaL_newmetatable(L, PLANET_METATABLE); /* Create the access table. */ lua_pushvalue(L, -1); lua_setfield(L, -2,"__index"); /* Register the values. */ luaL_register(L, NULL, planet_methods); return 0; /* No error. */ } /* Register the system metatable. */ static int systemL_createmetatable(lua_State* L) { /* Create the metatable. */ luaL_newmetatable(L, SYSTEM_METATABLE); /* Create the access table. */ lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); /* Register the values. */ luaL_register(L, NULL, system_methods); return 0; /* No error. */ } /** * @fn static int vectorL_createmetatable(lua_State* L) * * @brief Registers the vector metatable. * @param L Lua state to register metatable in. * @return 0 on success. */ static int vectorL_createmetatable(lua_State* L) { /* Create the metatable. */ luaL_newmetatable(L, VECTOR_METATABLE); /* Create the access table. */ lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); /* Register the values. */ luaL_register(L, NULL, vector_methods); return 0; /* No error. */ } /* -- PLANET -- */ /* Get planet at index. */ LuaPlanet* lua_toplanet(lua_State* L, int ind) { if(lua_isuserdata(L, ind)) { return (LuaPlanet*) lua_touserdata(L, ind); } luaL_typerror(L, ind, PLANET_METATABLE); return NULL; } /* Push a planet on the stack. */ LuaPlanet* lua_pushplanet(lua_State* L, LuaPlanet planet) { LuaPlanet* p; p = (LuaPlanet*) lua_newuserdata(L, sizeof(LuaPlanet)); *p = planet; luaL_getmetatable(L, PLANET_METATABLE); lua_setmetatable(L, -2); return p; } /* Check see if ind is a planet. */ int lua_isplanet(lua_State* L, int ind) { int ret; if(lua_getmetatable(L, ind)==0) return 0; lua_getfield(L, LUA_REGISTRYINDEX, PLANET_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; } /* get a planet. */ static int planetL_get(lua_State* L) { int i; int* factions; int nfactions; char** planets; int nplanets; char* rndplanet; LuaPlanet planet; LuaSystem sys; rndplanet = NULL; nplanets = 0; /* Get the landed planet. */ if(lua_gettop(L) == 0) { if(land_planet != NULL) { planet.p = land_planet; lua_pushplanet(L, planet); sys.s = system_get(planet_getSystem(land_planet->name)); lua_pushsystem(L, sys); return 2; } return 0; /* Not landed. */ } /* Get a planet by faction */ else if(lua_isnumber(L, 1)) { i = lua_tonumber(L, 1); planets = space_getFactionPlanet(&nplanets, &i, 1); } /* Get a planet by name. */ else if(lua_isstring(L, 1)) { rndplanet = (char*) lua_tostring(L, 1); } /* Get a planet from faction list. */ 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 LLUA_INVALID_PARAMETER(); /* Bad parameter. */ /* No suitable planet found. */ if((rndplanet == NULL) && (nplanets == 0)) { free(planets); return 0; } /* Pick random planet. */ else if(rndplanet == NULL) { rndplanet = planets[RNG(0, nplanets-1)]; free(planets); } /* Push the planet. */ planet.p = planet_get(rndplanet); /* The real planet. */ lua_pushplanet(L, planet); sys.s = system_get(planet_getSystem(rndplanet)); lua_pushsystem(L, sys); return 2; } /* __eq (equality) metamethod for planets. */ static int planetL_eq(lua_State* L) { LuaPlanet* a, *b; a = lua_toplanet(L, 1); b = lua_toplanet(L, 2); if(a->p == b->p) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); return 1; } /* Get the planets name. */ static int planetL_name(lua_State* L) { LuaPlanet* p; p = lua_toplanet(L, 1); lua_pushstring(L, p->p->name); return 1; } /* Get the planets faction. */ static int planetL_faction(lua_State* L) { LuaPlanet* p; p = lua_toplanet(L, 1); lua_pushstring(L, faction_name(p->p->faction)); return 1; } /* Get the planets class. */ static int planetL_class(lua_State* L) { char buf[2]; LuaPlanet* p; p = lua_toplanet(L, 1); buf[0] = planet_getClass(p->p); buf[1] = '\0'; lua_pushstring(L, buf); return 1; } /* Get planet services. */ static int planetL_services(lua_State* L) { LuaPlanet* p; p = lua_toplanet(L, 1); lua_pushnumber(L, p->p->services); return 1; } /** * @fn static int planetL_position(lua_State* L) * @ingroup META_PLANET * * @brief Vec2 pos(nil) * * Get the position of the planet in the system. * @return The position of the planet in the system. */ static int planetL_position(lua_State* L) { LuaPlanet* p; LuaVector v; p = lua_toplanet(L, 1); vectcpy(&v.vec, &p->p->pos); lua_pushvector(L, v); return 1; } /* -- SYSTEM -- */ /* Get system at index. */ LuaSystem* lua_tosystem(lua_State* L, int ind) { if(lua_isuserdata(L, ind)) { return (LuaSystem*) lua_touserdata(L,ind); } luaL_typerror(L, ind, SYSTEM_METATABLE); return NULL; } /* Pushes a system on the stack. */ LuaSystem* lua_pushsystem(lua_State* L, LuaSystem sys) { LuaSystem* s; s = (LuaSystem*) lua_newuserdata(L, sizeof(LuaSystem)); *s = sys; luaL_getmetatable(L, SYSTEM_METATABLE); lua_setmetatable(L, -2); return s; } /* Check to see if ind is a planet. */ int lua_issystem(lua_State* L, int ind) { int ret; if(lua_getmetatable(L, ind)==0) return 0; lua_getfield(L, LUA_REGISTRYINDEX, SYSTEM_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; } /* Get a system. */ static int systemL_get(lua_State* L) { LuaSystem sys; LuaPlanet* p; /* Get the current system with no parameters. */ if(lua_gettop(L) == 0) { sys.s = cur_system; } /* Passing a string (systemname) */ else if(lua_isstring(L, 1)) { sys.s = system_get((char*)lua_tostring(L, 1)); } /* Passing a planet */ else if(lua_isplanet(L, 1)) { p = lua_toplanet(L, 1); sys.s = system_get(planet_getSystem(p->p->name)); } else LLUA_INVALID_PARAMETER(); /* Return the system. */ lua_pushsystem(L, sys); return 1; } /* Check system for equality. */ static int systemL_eq(lua_State* L) { LuaSystem* a, *b; a = lua_tosystem(L, 1); b = lua_tosystem(L, 2); if(a->s == b->s) lua_pushboolean(L, 1); else lua_pushboolean(L, 0); return 1; } /* Return the systems name. */ static int systemL_name(lua_State* L) { LuaSystem* sys; sys = lua_tosystem(L, 1); lua_pushstring(L, sys->s->name); return 1; } /* Get system factions. */ static int systemL_faction(lua_State* L) { int i; LuaSystem* sys; sys = lua_tosystem(L, 1); /* Return result in table. */ lua_newtable(L); for(i = 0; i < sys->s->nplanets; i++) { if(sys->s->planets[i]->faction > 0) { /* Faction must be valid. */ lua_pushboolean(L, 1); /* Value. */ lua_setfield(L, -2, faction_name(sys->s->planets[i]->faction)); /* Key. */ /* Allows syntax foo = space.faction("foo"); if foo["bar"] then ... end */ } } return 1; } /* Get jump distance for current system, or to another. */ static int systemL_jumpdistance(lua_State* L) { LLUA_MIN_ARGS(1); LuaSystem* sys; StarSystem** s; int jumps; char* start, *goal; sys = lua_tosystem(L, 1); start = sys->s->name; 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; } /** * @defgroup META_VECTOR Vector Metatable * * @brief Represents a 2d vector in Lua. * * To call members of the metatable always use: * @code * vector:function(param) * @endcode */ /** * @fn LuaVector* lua_tovector(lua_State* L, int ind) * * @brief Gets vector at index. * @param L Lua state to get vector from. * @param ind Index position of vector. * @return The LuaVector at ind. */ LuaVector* lua_tovector(lua_State* L, int ind) { if(lua_isuserdata(L, ind)) { return (LuaVector*)lua_touserdata(L, ind); } luaL_typerror(L, ind, VECTOR_METATABLE); return NULL; } /** * @fn LuaVector* lua_pushvector(lua_State* L, LuaVector vec) * * @brief Pushes a vector on the stack. * @param L Lua state to push vector onto. * @param sys Vector to push. * @return Vector just pushed. */ LuaVector* lua_pushvector(lua_State* L, LuaVector vec) { LuaVector* v; v = (LuaVector*) lua_newuserdata(L, sizeof(LuaVector)); *v = vec; luaL_getmetatable(L, VECTOR_METATABLE); lua_setmetatable(L, -2); return v; } /** * @fn int lua_isvector(lua_State* L, int ind) * * @brief Check to see if ind is a vector. * @param L lua state to check. * @param ind Index position to check. * @return 1 if there is a vector at index position. */ int lua_isvector(lua_State* L, int ind) { int ret; if(lua_getmetatable(L, ind)==0) return 0; lua_getfield(L, LUA_REGISTRYINDEX, VECTOR_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 vectorL_new(lua_State* L) * @ingroup META_VECTOR * * @brief */ static int vectorL_new(lua_State* L) { LuaVector v; double x, y; if((lua_gettop(L) > 1) && lua_isnumber(L,1) && lua_isnumber(L,2)) { x = lua_tonumber(L,1); y = lua_tonumber(L,2); } else { x = 0.; y = 0.; } vect_cset(&v.vec, x, y); lua_pushvector(L, v); return 1; } /** * @fn static int vectorL_add(lua_State* L) * @ingroup META_VECTOR * * @brief __add(Vec2 vector) * * __add(number x, number y) * * Adds two vectors or a vector and some cartesian coords. */ static int vectorL_add(lua_State* L) { LLUA_MIN_ARGS(2); LuaVector* v1, *v2; double x, y; /* Get self. */ v1 = lua_tovector(L, 1); /* Get rest of parameters. */ v2 = NULL; if(lua_isvector(L, 2)) { v2 = lua_tovector(L, 2); x = v2->vec.x; y = v2->vec.y; } else LLUA_INVALID_PARAMETER(); /* Actually add it. */ vect_cadd(&v1->vec, x, y); return 0; } /** * @fn static int vectorL_sub(lua_State* L) * @ingroup META_VECTOR * * @brief __sub(Vec2 vector) * * __sub(number x, number y) * * Subtracts two vectors or a vector and some cartesian coords. */ static int vectorL_sub(lua_State* L) { LLUA_MIN_ARGS(2); LuaVector* v1, *v2; double x, y; /* Get self. */ v1 = lua_tovector(L,1); /* Get rest of parameters. */ v2 = NULL; if(lua_isvector(L, 2)) { v2 = lua_tovector(L, 2); x = v2->vec.x; y = v2->vec.y; } else if((lua_gettop(L) > 2) && lua_isnumber(L, 2) && lua_isnumber(L, 3)) { x = lua_tonumber(L, 2); y = lua_tonumber(L, 3); } else LLUA_INVALID_PARAMETER(); /* Actually add it. */ vect_cadd(&v1->vec, -x, -y); return 0; } /** * @fn static int vectorL_mul(lua_State* L) * @ingroup META_VECTOR * * @brief __mul(number mod) * * Multiplies by a number. * @param mod Amount to multiply by. */ static int vectorL_mul(lua_State* L) { LLUA_MIN_ARGS(2); LuaVector* v1; double mod; /* Get self. */ v1 = lua_tovector(L,1); /* Get rest of parameters. */ if(lua_isnumber(L, 2)) mod = lua_tonumber(L, 2); else LLUA_INVALID_PARAMETER(); /* Actually add it. */ vect_cadd(&v1->vec, v1->vec.x * mod, v1->vec.x * mod); return 0; } /** * @fn static int vectorL_div(lua_State* L) * @ingroup META_VECTOR * * @brief __div(number mod) * * Divides a vector by a number. * @param mod Amount to divide by. */ static int vectorL_div(lua_State* L) { LLUA_MIN_ARGS(2); LuaVector* v1; double mod; /* Get self. */ v1 = lua_tovector(L,1); /* Get rest of parameters. */ if(lua_isnumber(L, 2)) mod = lua_tonumber(L, 2); else LLUA_INVALID_PARAMETER(); /* Actually add it. */ vect_cadd(&v1->vec, v1->vec.x / mod, v1->vec.x / mod); return 0; } /** * @fn static int vectorL_get(lua_State* L) * @ingroup META_VECTOR * * @brief number, number get(nil) * * Get the catesian positions of the vector. * @return X and Y position of the vector. */ static int vectorL_get(lua_State* L) { LLUA_MIN_ARGS(1); LuaVector* v1; /* Get self. */ v1 = lua_tovector(L,1); /* Push the vector. */ lua_pushnumber(L, v1->vec.x); lua_pushnumber(L, v1->vec.y); return 2; } /** * @fn static int vectorL_set(lua_State* L) * * @brief set(number x, number y) * * Set the vector by cartesian coordinates. * @param x X coordinate to set. * @param y Y coordinate to set. */ static int vectorL_set(lua_State* L) { LLUA_MIN_ARGS(3); LuaVector* v1; double x, y; /* Get self */ v1 = lua_tovector(L, 1); /* Get parameters. */ if(lua_isnumber(L,2)) x = lua_tonumber(L,2); else LLUA_INVALID_PARAMETER(); if(lua_isnumber(L, 3)) y = lua_tonumber(L, 3); else LLUA_INVALID_PARAMETER(); vect_cset(&v1->vec, x, y); return 0; } /** * @fn static int vectorL_distance(lua_State* L) * @ingroup META_VECTOR * * @brief number dist( [Vec2 vector] ) * * Get the distance from the Vec2. * @param vector Vector to get distance from, uses origin(0,0) if not set. * @return The distance calculated. */ static int vectorL_distance(lua_State* L) { LLUA_MIN_ARGS(1); LuaVector* v1, *v2; double dist; /* Get self. */ v1 = lua_tovector(L, 1); /* Get rest of parameters. */ v2 = NULL; if(lua_gettop(L) > 1) { if(lua_isvector(L,2)) v2 = lua_tovector(L, 2); else LLUA_INVALID_PARAMETER(); } /* Get distance. */ if(v2 == NULL) dist = vect_odist(&v1->vec); else dist = vect_dist(&v1->vec, &v2->vec); /* Return the distance. */ lua_pushnumber(L, dist); return 1; }