static void _mission_to_table(lua_State *l, const Mission &m) { LUA_DEBUG_START(l); lua_newtable(l); pi_lua_table_ro(l); pi_lua_settable(l, "ref", m.ref); pi_lua_settable(l, "due", m.due); pi_lua_settable(l, "reward", double(m.reward) * 0.01); lua_pushstring(l, "type"); lua_pushstring(l, m.type.c_str()); lua_rawset(l, -3); lua_pushstring(l, "client"); lua_pushstring(l, m.client.c_str()); lua_rawset(l, -3); lua_pushstring(l, "location"); LuaSystemPath::PushToLuaGC(new SystemPath(m.location)); lua_rawset(l, -3); lua_pushstring(l, "status"); lua_pushstring(l, LuaConstants::GetConstantString(l, "MissionStatus", m.status)); lua_rawset(l, -3); LUA_DEBUG_END(l, 1); }
/* * Method: CallEvery * * Request that a function be called over at over at a regular interval. * * > Timer:CallEvery(interval, function) * * Since the <Timer> system is locked to the game time, time acceleration may * cause the function to be called more frequently than the corresponding * number of real-time seconds. Even under time acceleration, the function * will never called more than once per real-time second. * * If the called function returns a false value (as is the default for Lua * when no return value is specified), the timer will continue to be triggered * after each interval. To request that no further timer events be fired, the * function should explicitly return a true value. * * Parameters: * * time - the interval between calls to the function, in seconds * * function - the function to call. Returns false to continue receiving * calls after the next interval, or true to cancel the timer. * * Example: * * > -- dump fuel every two seconds until none left * > Timer:CallEvery(2, function () * > local did_dump = Game.player:Jettison(Equip.Type.HYDROGEN) * > return not did_dump * > end) * * Availability: * * alpha 10 * * Status: * * stable */ static int l_timer_call_every(lua_State *l) { if (!Pi::game) { luaL_error(l, "Game is not started"); return 0; } double every = luaL_checknumber(l, 2); luaL_checktype(l, 3, LUA_TFUNCTION); // any type of function if (every <= 0) luaL_error(l, "Specified interval must be greater than zero"); LUA_DEBUG_START(l); lua_newtable(l); pi_lua_settable(l, "every", every); pi_lua_settable(l, "at", Pi::game->GetTime() + every); _finish_timer_create(l); LUA_DEBUG_END(l, 0); return 0; }
void Color4f::ToLuaTable(lua_State *l) { lua_newtable(l); pi_lua_settable(l, "r", r); pi_lua_settable(l, "g", g); pi_lua_settable(l, "b", b); pi_lua_settable(l, "a", a); }
void Color4ub::ToLuaTable(lua_State *l) { lua_newtable(l); pi_lua_settable(l, "r", 255.0/r); pi_lua_settable(l, "g", 255.0/g); pi_lua_settable(l, "b", 255.0/b); pi_lua_settable(l, "a", 255.0/a); }
void JoystickAxisMotionEvent::ToLuaTable(lua_State *l) const { lua_newtable(l); pi_lua_settable(l, "type", EnumStrings::GetString("UIEventType", type)); pi_lua_settable(l, "joystick", joystick); pi_lua_settable(l, "value", value); pi_lua_settable(l, "axis", axis); }
void JoystickHatMotionEvent::ToLuaTable(lua_State *l) const { lua_newtable(l); pi_lua_settable(l, "type", EnumStrings::GetString("UIEventType", type)); pi_lua_settable(l, "joystick", joystick); pi_lua_settable(l, "direction", EnumStrings::GetString("UIJoystickHatDirection", direction)); pi_lua_settable(l, "hat", hat); }
void JoystickButtonEvent::ToLuaTable(lua_State *l) const { lua_newtable(l); pi_lua_settable(l, "type", EnumStrings::GetString("UIEventType", type)); pi_lua_settable(l, "joystick", joystick); pi_lua_settable(l, "action", EnumStrings::GetString("UIJoystickButtonAction", action)); pi_lua_settable(l, "button", button); }
/* * Attribute: flavour * * Various attributes that describe variations in the way the ship model is * rendered. * * flavour is a table with the following keys: * * id - the id (name) of the ship definition * * regId - the registration ID that will be displayed on the side of the * ship. Usually the same as the ship's label * * price - trade price for the ship * * primaryColour - a table describing the ship's primary colour. Contains * three tables "diffuse", "specular" and "emissive", each * containing values "r", "g", "b" and "a" for the colour, * and a fourth value "shininess". These form a typical * OpenGL material * * secondaryColour - a table describing the ship's secondary colour. The * structure is the same as primaryColour * * Availability: * * alpha 27 * * Status: * * experimental */ static inline void _colour_to_table(lua_State *l, const char *name, const float rgba[4]) { lua_newtable(l); pi_lua_settable(l, "r", rgba[0]); pi_lua_settable(l, "g", rgba[1]); pi_lua_settable(l, "b", rgba[2]); pi_lua_settable(l, "a", rgba[3]); lua_setfield(l, -2, name); }
void KeyboardEvent::ToLuaTable(lua_State *l) const { lua_newtable(l); pi_lua_settable(l, "type", EnumStrings::GetString("UIEventType", type)); pi_lua_settable(l, "action", EnumStrings::GetString("UIKeyboardAction", action)); pi_lua_settable(l, "repeat", repeat); // XXX expose sym and mod constants }
void MouseWheelEvent::ToLuaTable(lua_State *l) const { lua_newtable(l); pi_lua_settable(l, "type", EnumStrings::GetString("UIEventType", type)); _settable(l, "pos", pos); pi_lua_settable(l, "direction", EnumStrings::GetString("UIMouseWheelDirection", direction)); }
/* * Method: GetPosition * * Get the ships position * * > ship:GetPosition() * * Availability: * * April 2016 * * Status: * * experimental */ static int l_ship_get_position(lua_State *l) { Ship *s = LuaObject<Ship>::CheckFromLua(1); vector3d v = s->GetPosition(); lua_newtable(l); pi_lua_settable(l, "x", v.x); pi_lua_settable(l, "y", v.y); pi_lua_settable(l, "z", v.z); return 1; }
void MouseButtonEvent::ToLuaTable(lua_State *l) const { lua_newtable(l); pi_lua_settable(l, "type", EnumStrings::GetString("UIEventType", type)); _settable(l, "pos", pos); pi_lua_settable(l, "action", EnumStrings::GetString("UIMouseButtonAction", action)); pi_lua_settable(l, "button", EnumStrings::GetString("UIMouseButtonType", button)); }
static void _settable(lua_State *l, const char *key, const Point &value) { lua_pushstring(l, key); lua_newtable(l); pi_lua_settable(l, "x", value.x); pi_lua_settable(l, "y", value.y); lua_rawset(l, -3); }
static int l_ship_attr_flavour(lua_State *l) { Ship *s = LuaObject<Ship>::CheckFromLua(1); ShipFlavour f = *(s->GetFlavour()); lua_newtable(l); pi_lua_settable(l, "id", f.id.c_str()); pi_lua_settable(l, "regId", f.regid.c_str()); pi_lua_settable(l, "price", double(f.price)*0.01); return 1; }
void MouseMotionEvent::ToLuaTable(lua_State *l) const { lua_newtable(l); pi_lua_settable(l, "type", EnumStrings::GetString("UIEventType", type)); _settable(l, "pos", pos); _settable(l, "rel", rel); }
void TextInputEvent::ToLuaTable(lua_State *l) const { lua_newtable(l); pi_lua_settable(l, "type", EnumStrings::GetString("UIEventType", type)); lua_pushvalue(l, unicode); lua_setfield(l, -2, "unicode"); }
void LuaTimer::Tick() { assert(Pi::game); lua_State *l = Pi::luaManager->GetLuaState(); LUA_DEBUG_START(l); lua_getfield(l, LUA_REGISTRYINDEX, "PiTimerCallbacks"); if (lua_isnil(l, -1)) { lua_pop(l, 1); LUA_DEBUG_END(l, 0); return; } assert(lua_istable(l, -1)); double now = Pi::game->GetTime(); lua_pushnil(l); while (lua_next(l, -2)) { assert(lua_istable(l, -1)); lua_getfield(l, -1, "at"); double at = lua_tonumber(l, -1); lua_pop(l, 1); if (at <= now) { lua_getfield(l, -1, "callback"); pi_lua_protected_call(l, 0, 1); bool cancel = lua_toboolean(l, -1); lua_pop(l, 1); lua_getfield(l, -1, "every"); if (lua_isnil(l, -1) || cancel) { lua_pop(l, 1); lua_pushvalue(l, -2); lua_pushnil(l); lua_settable(l, -5); } else { double every = lua_tonumber(l, -1); lua_pop(l, 1); pi_lua_settable(l, "at", Pi::game->GetTime() + every); } } lua_pop(l, 1); } lua_pop(l, 1); LUA_DEBUG_END(l, 0); }
/* * Method: CallEvery * * Request that a function be called over at over at a regular interval. * * > Timer:CallEvery(interval, function) * * Since the <Timer> system is locked to the game time, time acceleration may * cause the function to be called more frequently than the corresponding * number of real-time seconds. Even under time acceleration, the function * will never called more than once per real-time second. * * If the called function returns a false value (as is the default for Lua * when no return value is specified), the timer will continue to be triggered * after each interval. To request that no further timer events be fired, the * function should explicitly return a true value. * * Parameters: * * time - the interval between calls to the function, in seconds * * function - the function to call. Returns false to continue receiving * calls after the next interval, or true to cancel the timer. * * Example: * * > -- dump fuel every two seconds until none left * > Timer:CallEvery(2, function () * > local did_dump = Game.player:Jettison(Equip.Type.HYDROGEN) * > return not did_dump * > end) * * Availability: * * alpha 10 * * Status: * * stable */ static int l_timer_call_every(lua_State *l) { double every = luaL_checknumber(l, 2); if (!lua_isfunction(l, 3)) luaL_typerror(l, 3, lua_typename(l, LUA_TFUNCTION)); if (every <= 0) luaL_error(l, "Specified interval must be greater than zero"); LUA_DEBUG_START(l); lua_newtable(l); pi_lua_settable(l, "every", every); pi_lua_settable(l, "at", Pi::GetGameTime() + every); _finish_timer_create(l); LUA_DEBUG_END(l, 0); return 0; }
static void push_date_time(lua_State *l, const Time::DateTime &dt) { int year, month, day, hour, minute, second; dt.GetDateParts(&year, &month, &day); dt.GetTimeParts(&hour, &minute, &second); lua_newtable(l); pi_lua_settable(l, "year", year); pi_lua_settable(l, "month", month); pi_lua_settable(l, "day", day); pi_lua_settable(l, "hour", hour); pi_lua_settable(l, "minute", minute); pi_lua_settable(l, "second", second); pi_lua_settable(l, "timestamp", dt.ToGameTime()); }
/* * Method: CallAt * * Request that a function be called at a specific game time. * * > Timer:CallAt(time, function) * * Time acceleration may cause the function to be called long after the desired * time has passed. * * Parameters: * * time - the absolute game time to call the function at. This will usually * be created by adding some small amount to <Game.time>. * * function - the function to call. Takes no parameters and returns nothing. * * Example: * * > Timer:CallAt(Game.time+30, function () * > UI.Message("Special offer expired, sorry.") * > end) * * Availability: * * alpha 10 * * Status: * * stable */ static int l_timer_call_at(lua_State *l) { double at = luaL_checknumber(l, 2); if (!lua_isfunction(l, 3)) luaL_typerror(l, 3, lua_typename(l, LUA_TFUNCTION)); if (at <= Pi::GetGameTime()) luaL_error(l, "Specified time is in the past"); LUA_DEBUG_START(l); lua_newtable(l); pi_lua_settable(l, "at", at); _finish_timer_create(l); LUA_DEBUG_END(l, 0); return 0; }
/* * Method: CallAt * * Request that a function be called at a specific game time. * * > Timer:CallAt(time, function) * * Time acceleration may cause the function to be called long after the desired * time has passed. * * Parameters: * * time - the absolute game time to call the function at. This will usually * be created by adding some small amount to <Game.time>. * * function - the function to call. Takes no parameters and returns nothing. * * Example: * * > Timer:CallAt(Game.time+30, function () * > Comms.Message("Special offer expired, sorry.") * > end) * * Availability: * * alpha 10 * * Status: * * stable */ static int l_timer_call_at(lua_State *l) { if (!Pi::game) luaL_error(l, "Game is not started"); double at = luaL_checknumber(l, 2); luaL_checktype(l, 3, LUA_TFUNCTION); // any type of function if (at <= Pi::game->GetTime()) luaL_error(l, "Specified time is in the past"); LUA_DEBUG_START(l); lua_newtable(l); pi_lua_settable(l, "at", at); _finish_timer_create(l); LUA_DEBUG_END(l, 0); return 0; }
static void _create_constant_table(lua_State *l, const char *ns, const EnumItem *c, bool consecutive) { LUA_DEBUG_START(l); lua_getglobal(l, "Constants"); if (lua_isnil(l, -1)) { lua_pop(l, 1); lua_newtable(l); // publish a read-only proxy wrapper lua_rawgeti(l, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); lua_pushstring(l, "Constants"); pi_lua_readonly_table_proxy(l, -3); lua_rawset(l, -3); lua_pop(l, 1); } else { pi_lua_readonly_table_original(l, -1); lua_remove(l, -2); } assert(lua_istable(l, -1)); lua_newtable(l); // 'Constants' table, enum table int enum_table_idx = lua_gettop(l); // publish a read-only proxy to the enum table lua_pushstring(l, ns); pi_lua_readonly_table_proxy(l, enum_table_idx); lua_rawset(l, -4); lua_getfield(l, LUA_REGISTRYINDEX, "PiConstants"); if (lua_isnil(l, -1)) { lua_pop(l, 1); lua_newtable(l); lua_pushstring(l, "PiConstants"); lua_pushvalue(l, -2); lua_rawset(l, LUA_REGISTRYINDEX); } assert(lua_istable(l, -1)); lua_newtable(l); // 'Constants' table, enum table, 'PiConstants' table, mapping table lua_pushstring(l, ns); lua_pushvalue(l, -2); lua_rawset(l, -4); int value = 0; int index = 1; for (; c->name; c++) { if (! consecutive) value = c->value; pi_lua_settable(l, c->name, value); pi_lua_settable(l, value, c->name); ++value; lua_pushinteger(l, index); lua_pushstring(l, c->name); lua_rawset(l, enum_table_idx); ++index; } lua_pop(l, 4); LUA_DEBUG_END(l, 0); }
void LuaShipDef::Register() { lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); lua_newtable(l); for (std::map<ShipType::Id,ShipType>::const_iterator i = ShipType::types.begin(); i != ShipType::types.end(); ++i) { const ShipType &st = (*i).second; lua_newtable(l); pi_lua_settable(l, "id", (*i).first.c_str()); pi_lua_settable(l, "name", st.name.c_str()); pi_lua_settable(l, "shipClass", st.shipClass.c_str()); pi_lua_settable(l, "manufacturer", st.manufacturer.c_str()); pi_lua_settable(l, "modelName", st.modelName.c_str()); pi_lua_settable(l, "cockpitName", st.cockpitName.c_str()); pi_lua_settable(l, "tag", EnumStrings::GetString("ShipTypeTag", st.tag)); pi_lua_settable(l, "angularThrust", st.angThrust); pi_lua_settable(l, "capacity", st.capacity); pi_lua_settable(l, "hullMass", st.hullMass); pi_lua_settable(l, "fuelTankMass", st.fuelTankMass); pi_lua_settable(l, "basePrice", double(st.baseprice)*0.01); pi_lua_settable(l, "minCrew", st.minCrew); pi_lua_settable(l, "maxCrew", st.maxCrew); pi_lua_settable(l, "defaultHyperdrive", EnumStrings::GetString("EquipType", st.hyperdrive)); pi_lua_settable(l, "effectiveExhaustVelocity", st.effectiveExhaustVelocity); pi_lua_settable(l, "thrusterFuelUse", st.GetFuelUseRate()); lua_newtable(l); for (int t = ShipType::THRUSTER_REVERSE; t < ShipType::THRUSTER_MAX; t++) pi_lua_settable(l, EnumStrings::GetString("ShipTypeThruster", t), st.linThrust[t]); pi_lua_readonly_table_proxy(l, -1); lua_setfield(l, -3, "linearThrust"); lua_pop(l, 1); lua_newtable(l); for (int slot = Equip::SLOT_CARGO; slot < Equip::SLOT_MAX; slot++) pi_lua_settable(l, EnumStrings::GetString("EquipSlot", slot), st.equipSlotCapacity[slot]); pi_lua_readonly_table_proxy(l, -1); lua_setfield(l, -3, "equipSlotCapacity"); lua_pop(l, 1); pi_lua_readonly_table_proxy(l, -1); lua_setfield(l, -3, (*i).first.c_str()); lua_pop(l, 1); } lua_getfield(l, LUA_REGISTRYINDEX, "CoreImports"); pi_lua_readonly_table_proxy(l, -2); lua_setfield(l, -2, "ShipDef"); lua_pop(l, 2); LUA_DEBUG_END(l, 0); }
/* * Function: ReadDirectory * * > local files, dirs = FileSystem.ReadDirectory(root, path) * * Return a list of files and dirs in the specified directory. * * Parameters: * * root - a <FileSystemRoot> constant for the root of the dir to read from * path - optional. a directory under the root * * Returns: * * files - a list of files as full paths from the root * dirs - a list of dirs as full paths from the root * * Availability: * * alpha 26 * * Status: * * experimental */ static int l_filesystem_read_dir(lua_State *l) { LuaFileSystem::Root root = static_cast<LuaFileSystem::Root>(LuaConstants::GetConstantFromArg(l, "FileSystemRoot", 1)); std::string path; if (lua_gettop(l) > 1) path = luaL_checkstring(l, 2); FileSystem::FileSource *fs = nullptr; switch (root) { case LuaFileSystem::ROOT_USER: fs = &FileSystem::userFiles; break; case LuaFileSystem::ROOT_DATA: fs = &FileSystem::gameDataFiles; break; default: assert(0); // can't happen return 0; } assert(fs); { try { const FileSystem::FileInfo &info = fs->Lookup(path); if (!info.IsDir()) { luaL_error(l, "'%s' is not a directory", path.c_str()); return 0; } } catch (std::invalid_argument) { luaL_error(l, "'%s' is not a valid path", path.c_str()); return 0; } } FileSystem::FileEnumerator files(*fs, FileSystem::FileEnumerator::IncludeDirs); files.AddSearchRoot(path); lua_newtable(l); int filesTable = lua_gettop(l); lua_newtable(l); int dirsTable = lua_gettop(l); for (; !files.Finished(); files.Next()) { const FileSystem::FileInfo &info = files.Current(); lua_newtable(l); pi_lua_settable(l, "name", info.GetName().c_str()); push_date_time(l, info.GetModificationTime()); lua_setfield(l, -2, "mtime"); if (info.IsDir()) lua_rawseti(l, dirsTable, lua_rawlen(l, dirsTable)+1); else lua_rawseti(l, filesTable, lua_rawlen(l, filesTable)+1); } return 2; }
/* * Method: GetStats * * Returns statistics for the ship * * > stats = ship:GetStats() * * Returns: * * stats - a table with the following fields * * maxCapacity - maximum space for cargo and equipment (t) * usedCapacity - amount of space used (t) * usedCargo - amount of cargo space used (t) * freeCapacity - total space remaining (t) * totalMass - total mass of the ship (cargo, equipment & hull) (t) * hullMassLeft - remaining hull mass. when this reaches 0, the ship is destroyed (t) * shieldMass - total mass equivalent of all shields (t) * shieldMassLeft - remaining shield mass. when this reaches 0, the shields are depleted and the hull is exposed (t) * hyperspaceRange - distance of furthest possible jump based on current contents (ly) * maxHyperspaceRange - distance furthest possible jump under ideal conditions (ly) * maxFuelTankMass - mass of internal (thruster) fuel tank, when full (t) * fuelMassLeft - current mass of the internal fuel tank (t) * fuelUse - thruster fuel use, scaled for the strongest thrusters at full thrust (percentage points per second, e.g. 0.0003) * * Example: * * > local stats = ship:GetStats() * > if stats.shieldMass == stats.shieldMassLeft then * > print("shields at full strength") * > end * * Availability: * * alpha 10 * * Status: * * experimental */ static int l_ship_get_stats(lua_State *l) { LUA_DEBUG_START(l); Ship *s = LuaObject<Ship>::CheckFromLua(1); const shipstats_t &stats = s->GetStats(); lua_newtable(l); pi_lua_settable(l, "maxCapacity", stats.max_capacity); pi_lua_settable(l, "usedCapacity", stats.used_capacity); pi_lua_settable(l, "usedCargo", stats.used_cargo); pi_lua_settable(l, "freeCapacity", stats.free_capacity); pi_lua_settable(l, "totalMass", stats.total_mass); pi_lua_settable(l, "hullMassLeft", stats.hull_mass_left); pi_lua_settable(l, "hyperspaceRange", stats.hyperspace_range); pi_lua_settable(l, "maxHyperspaceRange", stats.hyperspace_range_max); pi_lua_settable(l, "shieldMass", stats.shield_mass); pi_lua_settable(l, "shieldMassLeft", stats.shield_mass_left); pi_lua_settable(l, "maxFuelTankMass", stats.fuel_tank_mass); pi_lua_settable(l, "fuelUse", stats.fuel_use); pi_lua_settable(l, "fuelMassLeft", stats.fuel_tank_mass_left); LUA_DEBUG_END(l, 1); return 1; }
void LuaShipDef::Register() { lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); lua_newtable(l); for (auto iter : ShipType::types) { const ShipType &st = iter.second; lua_newtable(l); pi_lua_settable(l, "id", iter.first.c_str()); pi_lua_settable(l, "name", st.name.c_str()); pi_lua_settable(l, "shipClass", st.shipClass.c_str()); pi_lua_settable(l, "manufacturer", st.manufacturer.c_str()); pi_lua_settable(l, "modelName", st.modelName.c_str()); pi_lua_settable(l, "cockpitName", st.cockpitName.c_str()); pi_lua_settable(l, "tag", EnumStrings::GetString("ShipTypeTag", st.tag)); pi_lua_settable(l, "angularThrust", st.angThrust); pi_lua_settable(l, "capacity", st.capacity); pi_lua_settable(l, "hullMass", st.hullMass); pi_lua_settable(l, "fuelTankMass", st.fuelTankMass); pi_lua_settable(l, "basePrice", st.baseprice); pi_lua_settable(l, "minCrew", st.minCrew); pi_lua_settable(l, "maxCrew", st.maxCrew); pi_lua_settable(l, "hyperdriveClass", st.hyperdriveClass); pi_lua_settable(l, "effectiveExhaustVelocity", st.effectiveExhaustVelocity); pi_lua_settable(l, "thrusterFuelUse", st.GetFuelUseRate()); lua_newtable(l); for (int t = Thruster::THRUSTER_REVERSE; t < Thruster::THRUSTER_MAX; t++) pi_lua_settable(l, EnumStrings::GetString("ShipTypeThruster", t), st.linThrust[t]); pi_lua_readonly_table_proxy(l, -1); lua_setfield(l, -3, "linearThrust"); lua_pop(l, 1); lua_newtable(l); for (auto it = st.slots.cbegin(); it != st.slots.cend(); ++it) { pi_lua_settable(l, it->first.c_str(), it->second); } pi_lua_readonly_table_proxy(l, -1); luaL_getmetafield(l, -1, "__index"); if (!lua_getmetatable(l, -1)) { lua_newtable(l); } pi_lua_import(l, "EquipSet"); luaL_getsubtable(l, -1, "default"); lua_setfield(l, -3, "__index"); lua_pop(l, 1); lua_setmetatable(l, -2); lua_pop(l, 1); lua_setfield(l, -3, "equipSlotCapacity"); lua_pop(l, 1); lua_newtable(l); for (auto it = st.roles.cbegin(); it != st.roles.cend(); ++it) { pi_lua_settable(l, it->first.c_str(), it->second); } pi_lua_readonly_table_proxy(l, -1); lua_setfield(l, -3, "roles"); lua_pop(l, 1); pi_lua_readonly_table_proxy(l, -1); lua_setfield(l, -3, iter.first.c_str()); lua_pop(l, 1); } lua_getfield(l, LUA_REGISTRYINDEX, "CoreImports"); pi_lua_readonly_table_proxy(l, -2); lua_setfield(l, -2, "ShipDef"); lua_pop(l, 2); LUA_DEBUG_END(l, 0); }