void ShipType::Init() { static bool isInitted = false; if (isInitted) return; isInitted = true; lua_State *l = luaL_newstate(); LUA_DEBUG_START(l); luaL_requiref(l, "_G", &luaopen_base, 1); luaL_requiref(l, LUA_DBLIBNAME, &luaopen_debug, 1); luaL_requiref(l, LUA_MATHLIBNAME, &luaopen_math, 1); lua_pop(l, 3); LuaConstants::Register(l); LuaVector::Register(l); LUA_DEBUG_CHECK(l, 0); // provide shortcut vector constructor: v = vector.new lua_getglobal(l, LuaVector::LibName); lua_getfield(l, -1, "new"); assert(lua_iscfunction(l, -1)); lua_setglobal(l, "v"); lua_pop(l, 1); // pop the vector library table LUA_DEBUG_CHECK(l, 0); // register ship definition functions lua_register(l, "define_ship", define_ship); lua_register(l, "define_static_ship", define_static_ship); lua_register(l, "define_missile", define_missile); LUA_DEBUG_CHECK(l, 0); // load all ship definitions namespace fs = FileSystem; for (fs::FileEnumerator files(fs::gameDataFiles, "ships", fs::FileEnumerator::Recurse); !files.Finished(); files.Next()) { const fs::FileInfo &info = files.Current(); if (ends_with(info.GetPath(), ".lua")) { const std::string name = info.GetName(); s_currentShipFile = name.substr(0, name.size()-4); pi_lua_dofile(l, info.GetPath()); s_currentShipFile.clear(); } } LUA_DEBUG_END(l, 0); lua_close(l); if (ShipType::player_ships.empty()) Error("No playable ships have been defined! The game cannot run."); //collect ships that can fit atmospheric shields for (std::vector<ShipType::Type>::const_iterator it = ShipType::player_ships.begin(); it != ShipType::player_ships.end(); ++it) { const ShipType &ship = ShipType::types[*it]; if (ship.equipSlotCapacity[Equip::SLOT_ATMOSHIELD] != 0) ShipType::playable_atmospheric_ships.push_back(*it); } if (ShipType::playable_atmospheric_ships.empty()) Error("No ships can fit atmospheric shields! The game cannot run."); }
int _define_ship(lua_State *L, ShipType::Tag tag, std::vector<ShipType::Id> *list) { if (s_currentShipFile.empty()) return luaL_error(L, "ship file contains multiple ship definitions"); Json::Value data; ShipType s; s.tag = tag; s.id = s_currentShipFile; LUA_DEBUG_START(L); LuaTable t(L, -1); s.name = t.Get("name", ""); s.shipClass = t.Get("ship_class", "unknown"); s.manufacturer = t.Get("manufacturer", "unknown"); s.modelName = t.Get("model", ""); data["name"] = s.name; data["ship_class"] = s.shipClass; data["manufacturer"] = s.manufacturer; data["model"] = s.modelName; s.cockpitName = t.Get("cockpit", ""); s.linThrust[ShipType::THRUSTER_REVERSE] = t.Get("reverse_thrust", 0.0f); s.linThrust[ShipType::THRUSTER_FORWARD] = t.Get("forward_thrust", 0.0f); s.linThrust[ShipType::THRUSTER_UP] = t.Get("up_thrust", 0.0f); s.linThrust[ShipType::THRUSTER_DOWN] = t.Get("down_thrust", 0.0f); s.linThrust[ShipType::THRUSTER_LEFT] = t.Get("left_thrust", 0.0f); s.linThrust[ShipType::THRUSTER_RIGHT] = t.Get("right_thrust", 0.0f); s.angThrust = t.Get("angular_thrust", 0.0f); data["cockpit"] = s.cockpitName; data["reverse_thrust"] = s.linThrust[ShipType::THRUSTER_REVERSE]; data["forward_thrust"] = s.linThrust[ShipType::THRUSTER_FORWARD]; data["up_thrust"] = s.linThrust[ShipType::THRUSTER_UP]; data["down_thrust"] = s.linThrust[ShipType::THRUSTER_DOWN]; data["left_thrust"] = s.linThrust[ShipType::THRUSTER_LEFT]; data["right_thrust"] = s.linThrust[ShipType::THRUSTER_RIGHT]; data["angular_thrust"] = s.angThrust; // invert values where necessary s.linThrust[ShipType::THRUSTER_FORWARD] *= -1.f; s.linThrust[ShipType::THRUSTER_LEFT] *= -1.f; s.linThrust[ShipType::THRUSTER_DOWN] *= -1.f; // angthrust fudge (XXX: why?) s.angThrust = s.angThrust / 2; s.capacity = t.Get("capacity", 0); s.hullMass = t.Get("hull_mass", 100); s.fuelTankMass = t.Get("fuel_tank_mass", 5); data["capacity"] = s.capacity; data["hull_mass"] = s.hullMass; data["fuel_tank_mass"] = s.fuelTankMass; LuaTable slot_table = t.Sub("slots"); if (slot_table.GetLua()) { s.slots = slot_table.GetMap<std::string, int>(); } lua_pop(L, 1); { const auto it = s.slots.find("engine"); if (it != s.slots.end()) { it->second = Clamp(it->second, 0, 1); } } for( auto slot : s.slots ) { data["slots"][slot.first] = slot.second; } // fuel_use_rate can be given in two ways float thruster_fuel_use = 0; s.effectiveExhaustVelocity = t.Get("effective_exhaust_velocity", -1.0f); thruster_fuel_use = t.Get("thruster_fuel_use", -1.0f); data["effective_exhaust_velocity"] = s.effectiveExhaustVelocity; data["thruster_fuel_use"] = thruster_fuel_use; if(s.effectiveExhaustVelocity < 0 && thruster_fuel_use < 0) { // default value of v_c is used s.effectiveExhaustVelocity = 55000000; } else if(s.effectiveExhaustVelocity < 0 && thruster_fuel_use >= 0) { // v_c undefined and thruster fuel use defined -- use it! s.effectiveExhaustVelocity = GetEffectiveExhaustVelocity(s.fuelTankMass, thruster_fuel_use, s.linThrust[ShipType::THRUSTER_FORWARD]); } else { if(thruster_fuel_use >= 0) Output("Warning: Both thruster_fuel_use and effective_exhaust_velocity defined for %s, using effective_exhaust_velocity.\n", s.modelName.c_str()); } s.baseprice = t.Get("price", 0.0); s.minCrew = t.Get("min_crew", 1); s.maxCrew = t.Get("max_crew", 1); s.hyperdriveClass = t.Get("hyperdrive_class", 1); data["price"] = s.baseprice; data["min_crew"] = s.minCrew; data["max_crew"] = s.maxCrew; data["hyperdrive_class"] = s.hyperdriveClass; Json::StyledWriter writer; const std::string saveMe = writer.write( data ); const std::string path("ships/" + s_currentShipFile + ".json"); FileSystem::FileSourceFS newFS(FileSystem::GetDataDir()); FILE *f = newFS.OpenWriteStream(path); if (!f) { Output("couldn't open file for writing '%s'\n", path.c_str()); abort(); } fwrite(saveMe.data(), saveMe.length(), 1, f); fclose(f); lua_pop(L, 1); LUA_DEBUG_END(L, 0); //sanity check if (s.name.empty()) return luaL_error(L, "Ship has no name"); if (s.modelName.empty()) return luaL_error(L, "Missing model name in ship"); if (s.minCrew < 1 || s.maxCrew < 1 || s.minCrew > s.maxCrew) return luaL_error(L, "Invalid values for min_crew and max_crew"); const std::string& id = s_currentShipFile; typedef std::map<std::string, const ShipType>::iterator iter; std::pair<iter, bool> result = ShipType::types.insert(std::make_pair(id, s)); if (result.second) list->push_back(s_currentShipFile); else return luaL_error(L, "Ship '%s' was already defined by a different file", id.c_str()); s_currentShipFile.clear(); return 0; }
void ShipType::Init() { static bool isInitted = false; if (isInitted) return; isInitted = true; // load all ship definitions namespace fs = FileSystem; for (fs::FileEnumerator files(fs::gameDataFiles, "ships", fs::FileEnumerator::Recurse); !files.Finished(); files.Next()) { const fs::FileInfo &info = files.Current(); if (ends_with_ci(info.GetPath(), ".json")) { const std::string id(info.GetName().substr(0, info.GetName().size()-5)); try { ShipType st = ShipType(id, info.GetPath()); types.insert(std::make_pair(st.id, st)); // assign the names to the various lists switch( st.tag ) { case TAG_SHIP: player_ships.push_back(id); break; case TAG_STATIC_SHIP: static_ships.push_back(id); break; case TAG_MISSILE: missile_ships.push_back(id); break; break; case TAG_NONE: default: break; } } catch (ShipTypeLoadError) { // TODO: Actual error handling would be nice. Error("Error while loading Ship data (check stdout/output.txt).\n"); } } } #if ALLOW_LUA_SHIP_DEF lua_State *l = luaL_newstate(); LUA_DEBUG_START(l); luaL_requiref(l, "_G", &luaopen_base, 1); luaL_requiref(l, LUA_DBLIBNAME, &luaopen_debug, 1); luaL_requiref(l, LUA_MATHLIBNAME, &luaopen_math, 1); lua_pop(l, 3); LuaConstants::Register(l); LuaVector::Register(l); LUA_DEBUG_CHECK(l, 0); // provide shortcut vector constructor: v = vector.new lua_getglobal(l, LuaVector::LibName); lua_getfield(l, -1, "new"); assert(lua_iscfunction(l, -1)); lua_setglobal(l, "v"); lua_pop(l, 1); // pop the vector library table LUA_DEBUG_CHECK(l, 0); // register ship definition functions lua_register(l, "define_ship", define_ship); lua_register(l, "define_static_ship", define_static_ship); lua_register(l, "define_missile", define_missile); LUA_DEBUG_CHECK(l, 0); // load all ship definitions namespace fs = FileSystem; for (fs::FileEnumerator files(fs::gameDataFiles, "ships", fs::FileEnumerator::Recurse); !files.Finished(); files.Next()) { const fs::FileInfo &info = files.Current(); if (ends_with_ci(info.GetPath(), ".lua")) { const std::string name = info.GetName(); s_currentShipFile = name.substr(0, name.size() - 4); if (ShipType::types.find(s_currentShipFile) == ShipType::types.end()) { pi_lua_dofile(l, info.GetPath()); s_currentShipFile.clear(); } } } LUA_DEBUG_END(l, 0); lua_close(l); #endif //remove unbuyable ships from player ship list ShipType::player_ships.erase( std::remove_if(ShipType::player_ships.begin(), ShipType::player_ships.end(), ShipIsUnbuyable), ShipType::player_ships.end()); if (ShipType::player_ships.empty()) Error("No playable ships have been defined! The game cannot run."); }
const char *LuaSerializer::unpickle(lua_State *l, const char *pos) { LUA_DEBUG_START(l); char type = *pos++; switch (type) { case 'f': { char *end; double f = strtod(pos, &end); if (pos == end) throw SavedGameCorruptException(); lua_pushnumber(l, f); pos = end+1; // skip newline break; } case 'b': { if (*pos != '0' && *pos != '1') throw SavedGameCorruptException(); bool b = (*pos == '0') ? false : true; lua_pushboolean(l, b); pos++; break; } case 's': { char *end; int len = strtod(pos, &end); if (pos == end) throw SavedGameCorruptException(); end++; // skip newline lua_pushlstring(l, end, len); pos = end + len; break; } case 't': { lua_newtable(l); while (*pos != 'n') { pos = unpickle(l, pos); pos = unpickle(l, pos); lua_rawset(l, -3); } pos++; break; } case 'u': { const char *end = strchr(pos, '\n'); if (!end) throw SavedGameCorruptException(); int len = end - pos; end++; // skip newline if (len == 10 && strncmp(pos, "SystemPath", 10) == 0) { pos = end; Sint32 sectorX = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Sint32 sectorY = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Sint32 sectorZ = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Sint32 systemNum = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Sint32 sbodyId = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline SystemPath *sbp = new SystemPath(sectorX, sectorY, sectorZ, systemNum, sbodyId); LuaSystemPath::PushToLuaGC(sbp); break; } if (len == 4 && strncmp(pos, "Body", 4) == 0) { pos = end; int n = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Body *body = Serializer::LookupBody(n); if (pos == end) throw SavedGameCorruptException(); switch (body->GetType()) { case Object::BODY: LuaBody::PushToLua(body); break; case Object::SHIP: LuaShip::PushToLua(dynamic_cast<Ship*>(body)); break; case Object::SPACESTATION: LuaSpaceStation::PushToLua(dynamic_cast<SpaceStation*>(body)); break; case Object::PLANET: LuaPlanet::PushToLua(dynamic_cast<Planet*>(body)); break; case Object::STAR: LuaStar::PushToLua(dynamic_cast<Star*>(body)); break; case Object::PLAYER: LuaPlayer::PushToLua(dynamic_cast<Player*>(body)); break; default: throw SavedGameCorruptException(); } break; } throw SavedGameCorruptException(); } default: throw SavedGameCorruptException(); } LUA_DEBUG_END(l, 1); return pos; }
void LuaConstants::Register(lua_State *l) { LUA_DEBUG_START(l); /* * Constants: BodyType * * Describe different kinds of system bodies such as stars, planets and * space stations. * * GRAVPOINT - a pseudo-type for a gravitational point that multiple * bodies may orbit * BROWN_DWARF - brown dwarf sub-stellar object * STAR_M - type 'M' red star * STAR_K - type 'K' orange star * STAR_G - type 'G' yellow star * STAR_F - type 'F' white star * STAR_A - type 'A' hot white star * STAR_B - type 'B' blue star * STAR_O - type 'O' hot blue star * WHITE_DWARF - white dwarf stellar remnant * STAR_M_GIANT - red giant star * STAR_K_GIANT - orange giant star * STAR_G_GIANT - yellow giant star * STAR_F_GIANT - white giant star * STAR_A_GIANT - hot white giant star * STAR_B_GIANT - blue giant star * STAR_O_GIANT - hot blue giant star * STAR_M_SUPER_GIANT - red supergiant star * STAR_K_SUPER_GIANT - orange supergiant star * STAR_G_SUPER_GIANT - yellow supergiant star * STAR_F_SUPER_GIANT - white supergiant star * STAR_A_SUPER_GIANT - hot white supergiant star * STAR_B_SUPER_GIANT - blue supergiant star * STAR_O_SUPER_GIANT - hot blue supergiant star * STAR_M_HYPER_GIANT - red hypergiant star * STAR_K_HYPER_GIANT - orange hypergiant star * STAR_G_HYPER_GIANT - yellow hypergiant star * STAR_F_HYPER_GIANT - white hypergiant star * STAR_A_HYPER_GIANT - hot white hypergiant star * STAR_B_HYPER_GIANT - blue hypergiant star * STAR_O_HYPER_GIANT - hot blue hypergiant star * STAR_M_WF - Wolf-Rayet star (unstable) * STAR_B_WF - Wolf-Rayet star (risk of collapse) * STAR_O_WF - Wolf-Rayet star (imminent collapse) * STAR_S_BH - stellar black hole * STAR_IM_BH - intermediate-mass black hole * STAR_SM_BH - supermassive black hole * PLANET_GAS_GIANT - gas giant * PLANET_ASTEROID - asteroid * PLANET_TERRESTRIAL - terrestrial planet * STARPORT_ORBITAL - orbital starport (space station) * STARPORT_SURFACE - surface starport * * Availability: * * alpha 10 * * Status: * * stable */ _create_constant_table_nonconsecutive(l, "BodyType", ENUM_BodyType); /* * Constants: BodySuperType * * Describe general categories of system bodies. * * NONE - uncategorised * STAR - star * ROCKY_PLANET - a solid planet (terrestrial or asteroid) * GAS_GIANT - gas giant * STARPORT - surface or orbital starport * * Availability: * * alpha 10 * * Status: * * stable */ _create_constant_table_nonconsecutive(l, "BodySuperType", ENUM_BodySuperType); /* * Constants: PolitCrime * * Crimes * * TRADING_ILLEGAL_GOODS - . * WEAPON_DISCHARGE - . * PIRACY - . * MURDER - . * * Availability: * * alpha 10 * * Status: * * experimental */ _create_constant_table_nonconsecutive(l, "PolitCrime", ENUM_PolitCrime); /* * Constants: PolitEcon * * Economy type * * NONE - . * VERY_CAPITALIST - . * CAPITALIST - . * MIXED - . * PLANNED - . * * Availability: * * alpha 10 * * Status: * * experimental */ _create_constant_table_nonconsecutive(l, "PolitEcon", ENUM_PolitEcon); /* * Constants: PolitGovType * * Government type * * NONE - . * EARTHCOLONIAL - . * EARTHDEMOC - . * EMPIRERULE - . * CISLIBDEM - . * CISSOCDEM - . * LIBDEM - . * CORPORATE - . * SOCDEM - . * EARTHMILDICT - . * MILDICT1 - . * MILDICT2 - . * EMPIREMILDICT - . * COMMUNIST - . * PLUTOCRATIC - . * DISORDER - . * * Availability: * * alpha 10 * * Status: * * experimental */ _create_constant_table_nonconsecutive(l, "PolitGovType", ENUM_PolitGovType); /* * Constants: EquipSlot * * Equipment slots. Every equipment or cargo type has a corresponding * "slot" that it fits in to. Each slot has an independent capacity. * * CARGO - any cargo (commodity) item * ENGINE - hyperdrives and military drives * LASER - lasers and plasma accelerators * MISSILE - missile * ECM - ECM system * SCANNER - scanner * RADARMAPPER - radar mapper * HYPERCLOUD - hyperspace cloud analyser * HULLAUTOREPAIR - hull auto-repair system * ENERGYBOOSTER - shield energy booster unit * ATMOSHIELD - atmospheric shielding * CABIN - cabin * SHIELD - shield * FUELSCOOP - fuel scoop * CARGOSCOOP - cargo scoop * LASERCOOLER - laser cooling booster * CARGOLIFESUPPORT - cargo bay life support * AUTOPILOT - autopilot * * Availability: * * alpha 10 * * Status: * * experimental */ _create_constant_table_nonconsecutive(l, "EquipSlot", ENUM_EquipSlot); /* * Constants: EquipType * * Equipment and cargo types. Because of the slot arrangement described * under <EquipType> means that cargo is treated as a special type of * equipment. * * NONE - no equipment. Usually used to indicate the absence of equipment * HYDROGEN - hydrogen (CARGO) * LIQUID_OXYGEN - liquid oxygen (CARGO) * METAL_ORE - metal ore (CARGO) * CARBON_ORE - carbon ore (CARGO) * METAL_ALLOYS - metal alloys (CARGO) * PLASTICS - plastics (CARGO) * FRUIT_AND_VEG - fruit and vegetables (CARGO) * ANIMAL_MEAT - animal meat (CARGO) * LIVE_ANIMALS - live animals (CARGO) * LIQUOR - liquor (CARGO) * GRAIN - grain (CARGO) * TEXTILES - textiles (CARGO) * FERTILIZER - fertilizer (CARGO) * WATER - water (CARGO) * MEDICINES - medicines (CARGO) * CONSUMER_GOODS - consumer goods (CARGO) * COMPUTERS - computers (CARGO) * ROBOTS - robots (CARGO) * PRECIOUS_METALS - precious metals (CARGO) * INDUSTRIAL_MACHINERY - industrial machinery (CARGO) * FARM_MACHINERY - farm machinery (CARGO) * MINING_MACHINERY - mining machinery (CARGO * AIR_PROCESSORS - air processors (CARGO) * SLAVES - slaves (CARGO) * HAND_WEAPONS - hand weapons (CARGO) * BATTLE_WEAPONS - battle weapons (CARGO) * NERVE_GAS - nerve gas (CARGO) * NARCOTICS - narcotics (CARGO) * MILITARY_FUEL - military fuel (CARGO) * RUBBISH - rubbish (CARGO) * RADIOACTIVES - radioactives (CARGO) * MISSILE_UNGUIDED - unguided rocket (MISSILE) * MISSILE_GUIDED - guided missile (MISSILE) * MISSILE_SMART - smart missile (MISSILE) * MISSILE_NAVAL - naval missile (MISSILE) * ATMOSPHERIC_SHIELDING - atmospheric shielding (ATMOSHIELD) * ECM_BASIC - basic ECM system (ECM) * SCANNER - scanner (SCANNER) * ECM_ADVANCED - advanced ECM system (ECM) * UNOCCUPIED_CABIN - unoccupied passenger cabin (CABIN) * PASSENGER_CABIN - occupied passenger cabin (CABIN) * SHIELD_GENERATOR - shield generator (SHIELD) * LASER_COOLING_BOOSTER - laser cooling booster (LASERCOOLER) * CARGO_LIFE_SUPPORT - cargo bay life support (CARGOLIFESUPPORT) * AUTOPILOT - autopilot (AUTOPILOT) * RADAR_MAPPER - radar mapper (RADARMAPPER) * FUEL_SCOOP - fuel scoop (FUELSCOOP) * CARGO_SCOOP - cargo scoop (CARGOSCOOP) * HYPERCLOUD_ANALYZER - hyperspace cloud analyser (HYPERCLOUD) * HULL_AUTOREPAIR - hull auto-repair system (HULLAUTOREPAIR) * SHIELD_ENERGY_BOOSTER - shield energy booster unit (ENERGYBOOSTER) * DRIVE_CLASS1 - class 1 hyperdrive (ENGINE) * DRIVE_CLASS2 - class 2 hyperdrive (ENGINE) * DRIVE_CLASS3 - class 3 hyperdrive (ENGINE) * DRIVE_CLASS4 - class 4 hyperdrive (ENGINE) * DRIVE_CLASS5 - class 5 hyperdrive (ENGINE) * DRIVE_CLASS6 - class 6 hyperdrive (ENGINE) * DRIVE_CLASS7 - class 7 hyperdrive (ENGINE) * DRIVE_CLASS8 - class 8 hyperdrive (ENGINE) * DRIVE_CLASS9 - class 9 hyperdrive (ENGINE) * DRIVE_MIL1 - class 1 military drive (ENGINE) * DRIVE_MIL2 - class 2 military drive (ENGINE) * DRIVE_MIL3 - class 3 military drive (ENGINE) * DRIVE_MIL4 - class 4 military drive (ENGINE) * PULSECANNON_1MW - 1MW pulse cannon (LASER) * PULSECANNON_DUAL_1MW - 1MW dual-fire pulse cannon (LASER) * PULSECANNON_2MW - 2MW pulse cannon (LASER) * PULSECANNON_RAPID_2MW - 2MW rapid-fire pulse cannon (LASER) * PULSECANNON_4MW - 4MW pulse cannon (LASER) * PULSECANNON_10MW - 10MW pulse cannon (LASER) * PULSECANNON_20MW - 20MW pulse cannon (LASER) * MININGCANNON_17MW - 17MW blast-mining cannon (LASER) * SMALL_PLASMA_ACCEL - small plasma accelerator (LASER) * LARGE_PLASMA_ACCEL - large plasma accelerator (LASER) * * Availability: * * alpha 10 * * Status: * * experimental */ _create_constant_table_nonconsecutive(l, "EquipType", ENUM_EquipType); /* * Constants: DualLaserOrientation * * The orientation of dual laser mountings. * * HORIZONTAL - Lasers are mounted left and right * VERTICAL - Lasers are mounted top and bottom * * Availability: * * alpha 27 * * Status: * * experimental */ _create_constant_table_nonconsecutive(l, "DualLaserOrientation", ENUM_DualLaserOrientation); /* * Constants: ShipTypeTag * * Ship tags mark whether a ship is suitable for a particular use. Used * with <ShipType.GetShipTypes> to select which set of ships to search. * * NONE - no tags * SHIP - standard ships. These are the ones available to the player and * used for regular game functions (trade, combat, etc) * STATIC_SHIP - static ships. These are not available to the player and * are used for mission specific functions (large supply * ships, warships, etc) * MISSILE - missiles. Correspond directly to the <EquipType> constants of * the same name. * * Availability: * * alpha 10 * * Status: * * stable */ _create_constant_table_nonconsecutive(l, "ShipTypeTag", ENUM_ShipTypeTag); /* * Constants: ShipTypeThruster * * Thruster types. Used by <ShipType.GetLinearThrust>. The name * corresponds to the direction the ship moves when the thruster is fired. * * REVERSE - front (fore) thruster * FORWARD - main/rear (aft) thruster * UP - bottom/underbelly (ventral) thruster * DOWN - top/back (dorsal) thruster * LEFT - right-side (starboard) thruster * RIGHT - left-side (port) thruster * * Availability: * * alpha 10 * * Status: * * stable */ _create_constant_table_nonconsecutive(l, "ShipTypeThruster", ENUM_ShipTypeThruster); /* * Constants: ShipJumpStatus * * Reasons that that a hyperspace jump might succeed or fail. Returned by * <Ship.HyperspaceTo>, <Ship.CheckHyperspaceTo> and <Ship.GetHyperspaceDetails>. * * OK - jump successful * CURRENT_SYSTEM - ship is already in the target system * NO_DRIVE - ship has no drive * DRIVE_ACTIVE - ship is already in hyperspace * OUT_OF_RANGE - target system is out of range * INSUFFICIENT_FUEL - target system is in range but the ship doesn't have * enough fuel * SAFETY_LOCKOUT - drive locked out for safety reasons * (currently this happens if landed, docked or docking) * * Availability: * * alpha 10 * * Status: * * stable */ _create_constant_table_nonconsecutive(l, "ShipJumpStatus", ENUM_ShipJumpStatus); /* * Constants: ShipAlertStatus * * Current alert status. Based on proximity and actions of nearby ships. * * NONE - no alert. All is well (green) * SHIP_NEARBY - ship within 100km (yellow) * SHIP_FIRING - ship within 100km is firing lasers (though not * necessarily at us) (red) * * Availability: * * alpha 10 * * Status: * * experimental */ _create_constant_table_nonconsecutive(l, "ShipAlertStatus", ENUM_ShipAlertStatus); /* * Constants: ShipFuelStatus * * Current fuel status. * * OK - more than 5% fuel remaining * WARNING - less than 5% fuel remaining * EMPTY - no fuel remaining * * Availability: * * alpha 20 * * Status: * * experimental */ _create_constant_table_nonconsecutive(l, "ShipFuelStatus", ENUM_ShipFuelStatus); /* * Constants: ShipFlightState * * Ship flight state (used by LMR) * * FLYING - open flight (includes autopilot) * DOCKING - in docking animation * DOCKED - docked with station * LANDED - rough landed (not docked) * HYPERSPACE - in hyperspace * * Availability: * * alpha 16 * * Status: * * experimental */ _create_constant_table_nonconsecutive(l, "ShipFlightState", ENUM_ShipFlightState); /* * Constants: ShipAIError * * AI command error/result code passed to Event.onAICompleted * * NONE - AI completed successfully * GRAV_TOO_HIGH - AI can not compensate for gravity * REFUSED_PERM - AI was refused docking permission * ORBIT_IMPOSSIBLE - AI was asked to enter an impossible orbit (orbit is * outside target's frame) * * Availability: * * alpha 17 * * Status: * * experimental */ _create_constant_table_nonconsecutive(l, "ShipAIError", ENUM_ShipAIError); /* * Constants: ShipAnimation * * Animation code used by LMR. Pass one of these constants to * get_animation_stage() or get_animation_position() in a model script. * * WHEEL_STATE - animation state unused; position gives position of undercarriage * * Availability: * * alpha 16 * * Status: * * experimental */ _create_constant_table_nonconsecutive(l, "ShipAnimation", ENUM_ShipAnimation); /* * Constants: SpaceStationAnimation * * Animation code used by LMR. Pass one of these constants to * get_animation_stage() or get_animation_position() in a model script. * * WHEEL_STATE - animation state unused; position gives position of undercarriage * * Availability: * * alpha 16 * * Status: * * experimental */ _create_constant_table_nonconsecutive(l, "SpaceStationAnimation", ENUM_SpaceStationAnimation); /* * Constants: MissionStatus * * Status of a mission. * * ACTIVE - mission in progress * COMPLETED - mission completed * FAILED - mission failed * * Availability: * * alpha 10 * * Status: * * stable */ _create_constant_table_nonconsecutive(l, "MissionStatus", ENUM_MissionStatus); /* * Constants: FileSystemRoot * * Specifier of filesystem base. * * USER - directory containing Pioneer's config, savefiles, mods and other * user-specific data * DATA - directory containing Pioneer's data files * * Availability: * * alpha 25 * * Status: * * experimental */ _create_constant_table_nonconsecutive(l, "FileSystemRoot", ENUM_FileSystemRoot); // XXX document these _create_constant_table_nonconsecutive(l, "UIAlignDirection", ENUM_UIAlignDirection); _create_constant_table_nonconsecutive(l, "UIMarginDirection", ENUM_UIMarginDirection); _create_constant_table_nonconsecutive(l, "UIFont", ENUM_UIFont); _create_constant_table_nonconsecutive(l, "UISizeControl", ENUM_UISizeControl); _create_constant_table_nonconsecutive(l, "UIEventType", ENUM_UIEventType); _create_constant_table_nonconsecutive(l, "UIGradientDirection", ENUM_UIGradientDirection); _create_constant_table_nonconsecutive(l, "UIExpandDirection", ENUM_UIExpandDirection); _create_constant_table_nonconsecutive(l, "UIKeyboardAction", ENUM_UIKeyboardAction); _create_constant_table_nonconsecutive(l, "UIMouseButtonAction", ENUM_UIMouseButtonAction); _create_constant_table_nonconsecutive(l, "UIMouseButtonType", ENUM_UIMouseButtonType); _create_constant_table_nonconsecutive(l, "UIMouseWheelDirection", ENUM_UIMouseWheelDirection); _create_constant_table_nonconsecutive(l, "GameUIFaceFlags", ENUM_GameUIFaceFlags); LUA_DEBUG_END(l, 0); }
void LuaEngine::Register() { lua_State *l = Lua::manager->GetLuaState(); LUA_DEBUG_START(l); static const luaL_Reg l_methods[] = { { "Quit", l_engine_quit }, { "GetVideoModeList", l_engine_get_video_mode_list }, { "GetVideoResolution", l_engine_get_video_resolution }, { "SetVideoResolution", l_engine_set_video_resolution }, { "GetFullscreen", l_engine_get_fullscreen }, { "SetFullscreen", l_engine_set_fullscreen }, { "GetVSyncEnabled", l_engine_get_vsync_enabled }, { "SetVSyncEnabled", l_engine_set_vsync_enabled }, { "GetTextureCompressionEnabled", l_engine_get_texture_compression_enabled }, { "SetTextureCompressionEnabled", l_engine_set_texture_compression_enabled }, { "GetMultisampling", l_engine_get_multisampling }, { "SetMultisampling", l_engine_set_multisampling }, { "GetPlanetDetailLevel", l_engine_get_planet_detail_level }, { "SetPlanetDetailLevel", l_engine_set_planet_detail_level }, { "GetCityDetailLevel", l_engine_get_city_detail_level }, { "SetCityDetailLevel", l_engine_set_city_detail_level }, { "GetFractalDetailLevel", l_engine_get_fractal_detail_level }, { "SetFractalDetailLevel", l_engine_set_fractal_detail_level }, { "GetPlanetFractalColourEnabled", l_engine_get_planet_fractal_colour_enabled }, { "SetPlanetFractalColourEnabled", l_engine_set_planet_fractal_colour_enabled }, { "GetDisplayNavTunnels", l_engine_get_display_nav_tunnels }, { "SetDisplayNavTunnels", l_engine_set_display_nav_tunnels }, { "GetDisplaySpeedLines", l_engine_get_display_speed_lines }, { "SetDisplaySpeedLines", l_engine_set_display_speed_lines }, { "GetCockpitEnabled", l_engine_get_cockpit_enabled }, { "SetCockpitEnabled", l_engine_set_cockpit_enabled }, { "GetDisplayHudTrails", l_engine_get_display_hud_trails }, { "SetDisplayHudTrails", l_engine_set_display_hud_trails }, { "GetCompactScanner", l_engine_get_compact_scanner }, { "SetCompactScanner", l_engine_set_compact_scanner }, { "GetConfirmQuit", l_engine_get_confirm_quit }, { "SetConfirmQuit", l_engine_set_confirm_quit }, { "GetMasterMuted", l_engine_get_master_muted }, { "SetMasterMuted", l_engine_set_master_muted }, { "GetMasterVolume", l_engine_get_master_volume }, { "SetMasterVolume", l_engine_set_master_volume }, { "GetEffectsMuted", l_engine_get_effects_muted }, { "SetEffectsMuted", l_engine_set_effects_muted }, { "GetEffectsVolume", l_engine_get_effects_volume }, { "SetEffectsVolume", l_engine_set_effects_volume }, { "GetMusicMuted", l_engine_get_music_muted }, { "SetMusicMuted", l_engine_set_music_muted }, { "GetMusicVolume", l_engine_get_music_volume }, { "SetMusicVolume", l_engine_set_music_volume }, { "GetKeyBindings", l_engine_get_key_bindings }, { "SetKeyBinding", l_engine_set_key_binding }, { "GetMouseYInverted", l_engine_get_mouse_y_inverted }, { "SetMouseYInverted", l_engine_set_mouse_y_inverted }, { "GetJoystickEnabled", l_engine_get_joystick_enabled }, { "SetJoystickEnabled", l_engine_set_joystick_enabled }, { "GetModel", l_engine_get_model }, { 0, 0 } }; static const luaL_Reg l_attrs[] = { { "rand", l_engine_attr_rand }, { "ticks", l_engine_attr_ticks }, { "ui", l_engine_attr_ui }, { "version", l_engine_attr_version }, { 0, 0 } }; lua_getfield(l, LUA_REGISTRYINDEX, "CoreImports"); LuaObjectBase::CreateObject(l_methods, l_attrs, 0); lua_setfield(l, -2, "Engine"); lua_pop(l, 1); LUA_DEBUG_END(l, 0); }
/* * Method: GetNearbySystems * * Get a list of nearby <StarSystems> that match some criteria * * > systems = system:GetNearbySystems(range, filter) * * Parameters: * * range - distance from this system to search, in light years * * filter - an optional function. If specified the function will be called * once for each candidate system with the <StarSystem> object * passed as the only parameter. If the filter function returns * true then the system will be included in the array returned by * <GetNearbySystems>, otherwise it will be omitted. If no filter * function is specified then all systems in range are returned. * * Return: * * systems - an array of systems in range that matched the filter * * Availability: * * alpha 10 * * Status: * * experimental */ static int l_starsystem_get_nearby_systems(lua_State *l) { LUA_DEBUG_START(l); StarSystem *s = LuaStarSystem::CheckFromLua(1); double dist_ly = luaL_checknumber(l, 2); bool filter = false; if (lua_gettop(l) >= 3) { luaL_checktype(l, 3, LUA_TFUNCTION); // any type of function filter = true; } lua_newtable(l); SystemPath here = s->GetPath(); int here_x = here.sectorX; int here_y = here.sectorY; int here_z = here.sectorZ; Uint32 here_idx = here.systemIndex; Sector here_sec(here_x, here_y, here_z); int diff_sec = int(ceil(dist_ly/Sector::SIZE)); for (int x = here_x-diff_sec; x <= here_x+diff_sec; x++) { for (int y = here_y-diff_sec; y <= here_y+diff_sec; y++) { for (int z = here_z-diff_sec; z <= here_z+diff_sec; z++) { Sector sec(x, y, z); for (unsigned int idx = 0; idx < sec.m_systems.size(); idx++) { if (x == here_x && y == here_y && z == here_z && idx == here_idx) continue; if (Sector::DistanceBetween(&here_sec, here_idx, &sec, idx) > dist_ly) continue; RefCountedPtr<StarSystem> sys = StarSystem::GetCached(SystemPath(x, y, z, idx)); if (filter) { lua_pushvalue(l, 3); LuaStarSystem::PushToLua(sys.Get()); lua_call(l, 1, 1); if (!lua_toboolean(l, -1)) { lua_pop(l, 1); continue; } lua_pop(l, 1); } lua_pushinteger(l, lua_rawlen(l, -1)+1); LuaStarSystem::PushToLua(sys.Get()); lua_rawset(l, -3); } } } } LUA_DEBUG_END(l, 1); return 1; }
const char *LuaSerializer::unpickle(lua_State *l, const char *pos) { LUA_DEBUG_START(l); // tables are also unpickled recursively, so we can run out of Lua stack space if we're not careful // start by ensuring we have enough (this grows the stack if necessary) // (20 is somewhat arbitrary) if (!lua_checkstack(l, 20)) luaL_error(l, "The Lua stack couldn't be extended (not enough memory?)"); char type = *pos++; switch (type) { case 'f': { char *end; double f = strtod(pos, &end); if (pos == end) throw SavedGameCorruptException(); lua_pushnumber(l, f); pos = end+1; // skip newline break; } case 'b': { if (*pos != '0' && *pos != '1') throw SavedGameCorruptException(); bool b = (*pos == '0') ? false : true; lua_pushboolean(l, b); pos++; break; } case 's': { char *end; int len = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); end++; // skip newline lua_pushlstring(l, end, len); pos = end + len; break; } case 't': { lua_newtable(l); lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); pos = unpickle(l, pos); lua_pushvalue(l, -3); lua_rawset(l, -3); lua_pop(l, 1); while (*pos != 'n') { pos = unpickle(l, pos); pos = unpickle(l, pos); lua_rawset(l, -3); } pos++; break; } case 'r': { pos = unpickle(l, pos); lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); lua_pushvalue(l, -2); lua_rawget(l, -2); if (lua_isnil(l, -1)) throw SavedGameCorruptException(); lua_insert(l, -3); lua_pop(l, 2); break; } case 'u': { const char *end; if (!LuaObjectBase::Deserialize(pos, &end)) throw SavedGameCorruptException(); pos = end; break; } case 'o': { const char *end = strchr(pos, '\n'); if (!end) throw SavedGameCorruptException(); int len = end - pos; end++; // skip newline const char *cl = pos; // unpickle the object, and insert it beneath the method table value pos = unpickle(l, end); // If it is a reference, don't run the unserializer. It has either // already been run, or the data is still building (cyclic // references will do that to you.) if (*end != 'r') { // get PiSerializerClasses[typename] lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerClasses"); lua_pushlstring(l, cl, len); lua_gettable(l, -2); lua_remove(l, -2); if (lua_isnil(l, -1)) { lua_pop(l, 2); break; } lua_getfield(l, -1, "Unserialize"); if (lua_isnil(l, -1)) { lua_pushlstring(l, cl, len); luaL_error(l, "No Unserialize method found for class '%s'\n", lua_tostring(l, -1)); } lua_insert(l, -3); lua_pop(l, 1); pi_lua_protected_call(l, 1, 1); } break; } default: throw SavedGameCorruptException(); } LUA_DEBUG_END(l, 1); return pos; }
void LuaSerializer::pickle(lua_State *l, int to_serialize, std::string &out, std::string key) { static char buf[256]; LUA_DEBUG_START(l); // tables are pickled recursively, so we can run out of Lua stack space if we're not careful // start by ensuring we have enough (this grows the stack if necessary) // (20 is somewhat arbitrary) if (!lua_checkstack(l, 20)) luaL_error(l, "The Lua stack couldn't be extended (out of memory?)"); to_serialize = lua_absindex(l, to_serialize); int idx = to_serialize; if (lua_getmetatable(l, idx)) { lua_getfield(l, -1, "class"); if (lua_isnil(l, -1)) lua_pop(l, 2); else { const char *cl = lua_tostring(l, -1); snprintf(buf, sizeof(buf), "o%s\n", cl); lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerClasses"); lua_getfield(l, -1, cl); if (lua_isnil(l, -1)) luaL_error(l, "No Serialize method found for class '%s'\n", cl); lua_getfield(l, -1, "Serialize"); if (lua_isnil(l, -1)) luaL_error(l, "No Serialize method found for class '%s'\n", cl); lua_pushvalue(l, idx); pi_lua_protected_call(l, 1, 1); idx = lua_gettop(l); if (lua_isnil(l, idx)) { lua_pop(l, 5); LUA_DEBUG_END(l, 0); return; } out += buf; } } switch (lua_type(l, idx)) { case LUA_TNIL: break; case LUA_TNUMBER: { snprintf(buf, sizeof(buf), "f%f\n", lua_tonumber(l, idx)); out += buf; break; } case LUA_TBOOLEAN: { snprintf(buf, sizeof(buf), "b%d", lua_toboolean(l, idx) ? 1 : 0); out += buf; break; } case LUA_TSTRING: { lua_pushvalue(l, idx); size_t len; const char *str = lua_tolstring(l, -1, &len); snprintf(buf, sizeof(buf), "s" SIZET_FMT "\n", len); out += buf; out.append(str, len); lua_pop(l, 1); break; } case LUA_TTABLE: { lua_pushinteger(l, lua_Integer(lua_topointer(l, to_serialize))); // ptr lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); // ptr reftable lua_pushvalue(l, -2); // ptr reftable ptr lua_rawget(l, -2); // ptr reftable ??? if (!lua_isnil(l, -1)) { out += "r"; pickle(l, -3, out, key); lua_pop(l, 3); // [empty] } else { out += "t"; lua_pushvalue(l, -3); // ptr reftable nil ptr lua_pushvalue(l, to_serialize); // ptr reftable nil ptr table lua_rawset(l, -4); // ptr reftable nil pickle(l, -3, out, key); lua_pop(l, 3); // [empty] lua_pushvalue(l, idx); lua_pushnil(l); while (lua_next(l, -2)) { lua_pushvalue(l, -2); const char *k = lua_tostring(l, -1); std::string new_key = key + "." + (k? std::string(k) : "<" + std::string(lua_typename(l, lua_type(l, -1))) + ">"); lua_pop(l, 1); // Copy the values to pickle, as they might be mutated by the pickling process. pickle(l, -2, out, new_key); pickle(l, -1, out, new_key); lua_pop(l, 1); } lua_pop(l, 1); out += "n"; } break; } case LUA_TUSERDATA: { out += "u"; LuaObjectBase *lo = static_cast<LuaObjectBase*>(lua_touserdata(l, idx)); void *o = lo->GetObject(); if (!o) Error("Lua serializer '%s' tried to serialize an invalid '%s' object", key.c_str(), lo->GetType()); out += lo->Serialize(); break; } default: Error("Lua serializer '%s' tried to serialize %s value", key.c_str(), lua_typename(l, lua_type(l, idx))); break; } if (idx != lua_absindex(l, to_serialize)) // It means we called a transformation function on the data, so we clean it up. lua_pop(l, 5); LUA_DEBUG_END(l, 0); }
int _define_ship(lua_State *L, ShipType::Tag tag, std::vector<ShipType::Id> *list) { if (s_currentShipFile.empty()) return luaL_error(L, "ship file contains multiple ship definitions"); ShipType s; s.tag = tag; s.id = s_currentShipFile; LUA_DEBUG_START(L); LuaTable t(L, -1); s.name = t.Get("name", ""); s.modelName = t.Get("model", ""); s.linThrust[ShipType::THRUSTER_REVERSE] = t.Get("reverse_thrust", 0.0f); s.linThrust[ShipType::THRUSTER_FORWARD] = t.Get("forward_thrust", 0.0f); s.linThrust[ShipType::THRUSTER_UP] = t.Get("up_thrust", 0.0f); s.linThrust[ShipType::THRUSTER_DOWN] = t.Get("down_thrust", 0.0f); s.linThrust[ShipType::THRUSTER_LEFT] = t.Get("left_thrust", 0.0f); s.linThrust[ShipType::THRUSTER_RIGHT] = t.Get("right_thrust", 0.0f); s.angThrust = t.Get("angular_thrust", 0.0f); // invert values where necessary s.linThrust[ShipType::THRUSTER_FORWARD] *= -1.f; s.linThrust[ShipType::THRUSTER_LEFT] *= -1.f; s.linThrust[ShipType::THRUSTER_DOWN] *= -1.f; // angthrust fudge (XXX: why?) s.angThrust = s.angThrust / 2; lua_pushstring(L, "camera_offset"); lua_gettable(L, -2); if (!lua_isnil(L, -1)) fprintf(stderr, "ship definition for '%s' has deprecated 'camera_offset' field\n", s.id.c_str()); lua_pop(L, 1); s.cameraOffset = t.Get("camera_offset", vector3d(0.0)); for (int i=0; i<Equip::SLOT_MAX; i++) s.equipSlotCapacity[i] = 0; s.equipSlotCapacity[Equip::SLOT_CARGO] = t.Get("max_cargo", 0); s.equipSlotCapacity[Equip::SLOT_ENGINE] = t.Get("max_engine", 1); s.equipSlotCapacity[Equip::SLOT_LASER] = t.Get("max_laser", 1); s.equipSlotCapacity[Equip::SLOT_MISSILE] = t.Get("max_missile", 0); s.equipSlotCapacity[Equip::SLOT_ECM] = t.Get("max_ecm", 1); s.equipSlotCapacity[Equip::SLOT_SCANNER] = t.Get("max_scanner", 1); s.equipSlotCapacity[Equip::SLOT_RADARMAPPER] = t.Get("max_radarmapper", 1); s.equipSlotCapacity[Equip::SLOT_HYPERCLOUD] = t.Get("max_hypercloud", 1); s.equipSlotCapacity[Equip::SLOT_HULLAUTOREPAIR] = t.Get("max_hullautorepair", 1); s.equipSlotCapacity[Equip::SLOT_ENERGYBOOSTER] = t.Get("max_energybooster", 1); s.equipSlotCapacity[Equip::SLOT_ATMOSHIELD] = t.Get("max_atmoshield", 1); s.equipSlotCapacity[Equip::SLOT_CABIN] = t.Get("max_cabin", 50); s.equipSlotCapacity[Equip::SLOT_SHIELD] = t.Get("max_shield", 9999); s.equipSlotCapacity[Equip::SLOT_FUELSCOOP] = t.Get("max_fuelscoop", 1); s.equipSlotCapacity[Equip::SLOT_CARGOSCOOP] = t.Get("max_cargoscoop", 1); s.equipSlotCapacity[Equip::SLOT_LASERCOOLER] = t.Get("max_lasercooler", 1); s.equipSlotCapacity[Equip::SLOT_CARGOLIFESUPPORT] = t.Get("max_cargolifesupport", 1); s.equipSlotCapacity[Equip::SLOT_AUTOPILOT] = t.Get("max_autopilot", 1); s.capacity = t.Get("capacity", 0); s.hullMass = t.Get("hull_mass", 100); s.fuelTankMass = t.Get("fuel_tank_mass", 5); // fuel_use_rate can be given in two ways float thruster_fuel_use = 0; s.effectiveExhaustVelocity = t.Get("effective_exhaust_velocity", -1.0f); thruster_fuel_use = t.Get("thruster_fuel_use", -1.0f); if(s.effectiveExhaustVelocity < 0 && thruster_fuel_use < 0) { // default value of v_c is used s.effectiveExhaustVelocity = 55000000; } else if(s.effectiveExhaustVelocity < 0 && thruster_fuel_use >= 0) { // v_c undefined and thruster fuel use defined -- use it! s.effectiveExhaustVelocity = GetEffectiveExhaustVelocity(s.fuelTankMass, thruster_fuel_use, s.linThrust[ShipType::THRUSTER_FORWARD]); } else { if(thruster_fuel_use >= 0) printf("Warning: Both thruster_fuel_use and effective_exhaust_velocity defined for %s, using effective_exhaust_velocity.\n", s.modelName.c_str()); } s.baseprice = t.Get("price", 0); s.baseprice *= 100; // in hundredths of credits s.minCrew = t.Get("min_crew", 1); s.maxCrew = t.Get("max_crew", 1); s.equipSlotCapacity[Equip::SLOT_ENGINE] = Clamp(s.equipSlotCapacity[Equip::SLOT_ENGINE], 0, 1); { int hyperclass; hyperclass = t.Get("hyperdrive_class", 1); if (!hyperclass) { s.hyperdrive = Equip::NONE; } else { s.hyperdrive = Equip::Type(Equip::DRIVE_CLASS1+hyperclass-1); } } for (int i = 0; i < ShipType::GUNMOUNT_MAX; i++) { s.gunMount[i].pos = vector3f(0,0,0); s.gunMount[i].dir = vector3f(0,0,1); s.gunMount[i].sep = 5; s.gunMount[i].orient = ShipType::DUAL_LASERS_HORIZONTAL; } lua_pushstring(L, "gun_mounts"); lua_gettable(L, -2); if (lua_istable(L, -1)) { fprintf(stderr, "ship definition for '%s' has deprecated 'gun_mounts' field\n", s.id.c_str()); for (unsigned int i=0; i<lua_rawlen(L,-1); i++) { lua_pushinteger(L, i+1); lua_gettable(L, -2); if (lua_istable(L, -1) && lua_rawlen(L,-1) == 4) { lua_pushinteger(L, 1); lua_gettable(L, -2); s.gunMount[i].pos = LuaVector::CheckFromLuaF(L, -1); lua_pop(L, 1); lua_pushinteger(L, 2); lua_gettable(L, -2); s.gunMount[i].dir = LuaVector::CheckFromLuaF(L, -1); lua_pop(L, 1); lua_pushinteger(L, 3); lua_gettable(L, -2); s.gunMount[i].sep = lua_tonumber(L,-1); lua_pop(L, 1); lua_pushinteger(L, 4); lua_gettable(L, -2); s.gunMount[i].orient = static_cast<ShipType::DualLaserOrientation>( LuaConstants::GetConstantFromArg(L, "DualLaserOrientation", -1)); lua_pop(L, 1); } lua_pop(L, 1); } } lua_pop(L, 1); LUA_DEBUG_END(L, 0); //sanity check if (s.name.empty()) return luaL_error(L, "Ship has no name"); if (s.modelName.empty()) return luaL_error(L, "Missing model name in ship"); if (s.minCrew < 1 || s.maxCrew < 1 || s.minCrew > s.maxCrew) return luaL_error(L, "Invalid values for min_crew and max_crew"); const std::string& id = s_currentShipFile; typedef std::map<ShipType::Id, ShipType>::iterator iter; std::pair<iter, bool> result = ShipType::types.insert(std::make_pair(id, s)); if (result.second) list->push_back(s_currentShipFile); else return luaL_error(L, "Ship '%s' was already defined by a different file", id.c_str()); s_currentShipFile.clear(); return 0; }
void pi_lua_dofile_recursive(lua_State *l, const std::string &basepath) { DIR *dir; struct dirent *entry; std::string path; struct stat info; // putting directory contents into sorted order so order of // model definition is consistent std::set<std::string> entries; LUA_DEBUG_START(l); // XXX CurrentDirectory stuff has to go lua_getglobal(l, "CurrentDirectory"); std::string save_dir = luaL_checkstring(l, -1); lua_pop(l, 1); lua_pushstring(l, basepath.c_str()); lua_setglobal(l, "CurrentDirectory"); if ((dir = opendir(basepath.c_str())) == NULL) { fprintf(stderr, "opendir: couldn't open directory '%s': %s\n", basepath.c_str(), strerror(errno)); return; } while ((entry = readdir(dir)) != NULL) { if (entry->d_name[0] != '.') { entries.insert(entry->d_name); } } closedir(dir); for (std::set<std::string>::iterator i = entries.begin(); i!=entries.end(); ++i) { const std::string &name = *i; path = basepath + "/" + name; if (stat(path.c_str(), &info) != 0) { fprintf(stderr, "stat: couldn't get info for '%s': %s\n", path.c_str(), strerror(errno)); continue; } if (S_ISDIR(info.st_mode)) { pi_lua_dofile_recursive(l, path.c_str()); continue; } if ( name.size() >= 4 && name.find(".lua") == name.size() - 4 ) { // XXX panic stuff can be removed once the global lua is used everywhere lua_pushcfunction(l, pi_lua_panic); if (luaL_loadfile(l, path.c_str())) { pi_lua_panic(l); } else { lua_pcall(l, 0, 0, -2); } lua_pop(l, 1); } } lua_pushstring(l, save_dir.c_str()); lua_setglobal(l, "CurrentDirectory"); LUA_DEBUG_END(l, 0); }
/* * Function: SpawnShipLandedNear * * Create a ship and place it on the surface near the given <Body>. * * > ship = Space.SpawnShipLandedNear(type, body, min, max) * * Parameters: * * type - the name of the ship * * body - the <Body> near which the ship should be spawned. It must be on the ground or close to it, * i.e. it must be in the rotating frame of the planetary body. * * min - minimum distance from the surface point below the body to place the ship, in Km * * max - maximum distance to place the ship * * Return: * * ship - a <Ship> object for the new ship * * Example: * * > -- spawn a ship 10km from the player * > local ship = Ship.SpawnShipLandedNear("viper_police", Game.player, 10, 10) * * Availability: * * July 2013 * * Status: * * experimental */ static int l_space_spawn_ship_landed_near(lua_State *l) { if (!Pi::game) luaL_error(l, "Game is not started"); LUA_DEBUG_START(l); const char *type = luaL_checkstring(l, 1); if (! ShipType::Get(type)) luaL_error(l, "Unknown ship type '%s'", type); Body *nearbody = LuaObject<Body>::CheckFromLua(2); const float min_dist = luaL_checknumber(l, 3); const float max_dist = luaL_checknumber(l, 4); if (min_dist > max_dist) luaL_error(l, "min_dist must not be larger than max_dist"); Ship *ship = new Ship(type); assert(ship); // XXX protect against spawning inside the body Frame * newframe = nearbody->GetFrame()->GetRotFrame(); if (!newframe->IsRotFrame()) luaL_error(l, "Body must be in rotating frame"); SystemBody *sbody = newframe->GetSystemBody(); if (sbody->GetSuperType() != SystemBody::SUPERTYPE_ROCKY_PLANET) luaL_error(l, "Body is not on a rocky planet"); if (max_dist > sbody->GetRadius()) luaL_error(l, "max_dist too large for planet radius"); // We assume that max_dist is much smaller than the planet radius, i.e. that our area is reasonably flat // So, we const vector3d up = nearbody->GetPosition().Normalized(); vector3d x; vector3d y; // Calculate a orthonormal basis for a horizontal plane. For numerical reasons we do that determining the smallest // coordinate and take the cross product with (1,0,0), (0,1,0) or (0,0,1) respectively to calculate the first vector. // The second vector is just the cross product of the up-vector and out first vector. if (up.x <= up.y && up.x <= up.z) { x = vector3d(0.0, up.z, -up.y).Normalized(); y = vector3d(-up.y*up.y - up.z*up.z, up.x*up.y, up.x*up.z).Normalized(); } else if (up.y <= up.x && up.y <= up.z) { x = vector3d(-up.z, 0.0, up.x).Normalized(); y = vector3d(up.x*up.y, -up.x*up.x - up.z*up.z, up.y*up.z).Normalized(); } else { x = vector3d(up.y, -up.x, 0.0).Normalized(); y = vector3d(up.x*up.z, up.y*up.z, -up.x*up.x - up.y*up.y).Normalized(); } Planet *planet = static_cast<Planet*>(newframe->GetBody()); const double radius = planet->GetSystemBody()->GetRadius(); const vector3d planar = MathUtil::RandomPointInCircle(min_dist * 1000.0, max_dist * 1000.0); vector3d pos = (radius * up + x * planar.x + y * planar.y).Normalized(); float latitude = atan2(pos.y, sqrt(pos.x*pos.x + pos.z * pos.z)); float longitude = atan2(pos.x, pos.z); Pi::game->GetSpace()->AddBody(ship); ship->SetLandedOn(planet, latitude, longitude); LuaObject<Ship>::PushToLua(ship); LUA_DEBUG_END(l, 1); return 1; }
int ShipType::define_ship(lua_State *L, const char *model_name) { ShipType s; s.lmrModelName = model_name; LUA_DEBUG_START(L) _get_string_attrib(L, "name", s.name, model_name); _get_float_attrib(L, "reverse_thrust", s.linThrust[THRUSTER_REVERSE], 0.0f); _get_float_attrib(L, "forward_thrust", s.linThrust[THRUSTER_FORWARD], 0.0f); _get_float_attrib(L, "up_thrust", s.linThrust[THRUSTER_UP], 0.0f); _get_float_attrib(L, "down_thrust", s.linThrust[THRUSTER_DOWN], 0.0f); _get_float_attrib(L, "left_thrust", s.linThrust[THRUSTER_LEFT], 0.0f); _get_float_attrib(L, "right_thrust", s.linThrust[THRUSTER_RIGHT], 0.0f); _get_float_attrib(L, "angular_thrust", s.angThrust, 0.0f); for (int i=0; i<(int)Equip::SLOT_MAX; i++) s.equipSlotCapacity[i] = 0; _get_int_attrib(L, "max_cargo", s.equipSlotCapacity[Equip::SLOT_CARGO], 0); _get_int_attrib(L, "max_engine", s.equipSlotCapacity[Equip::SLOT_ENGINE], 1); _get_int_attrib(L, "max_laser", s.equipSlotCapacity[Equip::SLOT_LASER], 1); _get_int_attrib(L, "max_missile", s.equipSlotCapacity[Equip::SLOT_MISSILE], 0); _get_int_attrib(L, "max_ecm", s.equipSlotCapacity[Equip::SLOT_ECM], 1); _get_int_attrib(L, "max_scanner", s.equipSlotCapacity[Equip::SLOT_SCANNER], 1); _get_int_attrib(L, "max_radarmapper", s.equipSlotCapacity[Equip::SLOT_RADARMAPPER], 1); _get_int_attrib(L, "max_hypercloud", s.equipSlotCapacity[Equip::SLOT_HYPERCLOUD], 1); _get_int_attrib(L, "max_hullautorepair", s.equipSlotCapacity[Equip::SLOT_HULLAUTOREPAIR], 1); _get_int_attrib(L, "max_energybooster", s.equipSlotCapacity[Equip::SLOT_ENERGYBOOSTER], 1); _get_int_attrib(L, "max_atmoshield", s.equipSlotCapacity[Equip::SLOT_ATMOSHIELD], 1); _get_int_attrib(L, "max_fuelscoop", s.equipSlotCapacity[Equip::SLOT_FUELSCOOP], 1); _get_int_attrib(L, "max_lasercooler", s.equipSlotCapacity[Equip::SLOT_LASERCOOLER], 1); _get_int_attrib(L, "max_cargolifesupport", s.equipSlotCapacity[Equip::SLOT_CARGOLIFESUPPORT], 1); _get_int_attrib(L, "max_autopilot", s.equipSlotCapacity[Equip::SLOT_AUTOPILOT], 1); _get_int_attrib(L, "capacity", s.capacity, 0); _get_int_attrib(L, "hull_mass", s.hullMass, 100); _get_int_attrib(L, "price", s.baseprice, 0); s.baseprice *= 100; // in hundredths of credits { int hyperclass; _get_int_attrib(L, "hyperdrive_class", hyperclass, 1); if (!hyperclass) { s.hyperdrive = Equip::NONE; } else { s.hyperdrive = (Equip::Type)((int)Equip::DRIVE_CLASS1+hyperclass-1); } } lua_pushstring(L, "gun_mounts"); lua_gettable(L, -2); if (lua_istable(L, -1)) { for (unsigned int i=0; i<lua_objlen(L,-1); i++) { lua_pushinteger(L, i+1); lua_gettable(L, -2); if (lua_istable(L, -1) && lua_objlen(L,-2) == 2) { lua_pushinteger(L, 1); lua_gettable(L, -2); s.gunMount[i].pos = *MyLuaVec::checkVec(L, -1); lua_pop(L, 1); lua_pushinteger(L, 2); lua_gettable(L, -2); s.gunMount[i].dir = *MyLuaVec::checkVec(L, -1); lua_pop(L, 1); } lua_pop(L, 1); } } lua_pop(L, 1); LUA_DEBUG_END(L, 0) types[s.name] = s; return 0; }
void LuaSerializer::pickle(lua_State *l, int idx, std::string &out, const char *key = NULL) { static char buf[256]; LUA_DEBUG_START(l); switch (lua_type(l, idx)) { case LUA_TNIL: break; case LUA_TNUMBER: { snprintf(buf, sizeof(buf), "f%f\n", lua_tonumber(l, idx)); out += buf; break; } case LUA_TBOOLEAN: { snprintf(buf, sizeof(buf), "b%d", lua_toboolean(l, idx) ? 1 : 0); out += buf; break; } case LUA_TSTRING: { lua_pushvalue(l, idx); const char *str = lua_tostring(l, -1); snprintf(buf, sizeof(buf), "s%lu\n", strlen(str)); out += buf; out += str; lua_pop(l, 1); break; } case LUA_TTABLE: { out += "t"; lua_pushvalue(l, idx); lua_pushnil(l); while (lua_next(l, -2)) { if (key) { pickle(l, -2, out, key); pickle(l, -1, out, key); } else { lua_pushvalue(l, -2); const char *k = lua_tostring(l, -1); pickle(l, -3, out, k); pickle(l, -2, out, k); lua_pop(l, 1); } lua_pop(l, 1); } lua_pop(l, 1); out += "n"; break; } case LUA_TUSERDATA: { out += "u"; lid *idp = static_cast<lid*>(lua_touserdata(l, idx)); LuaObjectBase *lo = LuaObjectBase::Lookup(*idp); if (!lo) Error("Lua serializer '%s' tried to serialize object with id 0x%08x, but it no longer exists", key, *idp); // XXX object wrappers should really have Serialize/Unserialize // methods to deal with this if (lo->Isa("SystemPath")) { SystemPath *sbp = dynamic_cast<SystemPath*>(lo->m_object); snprintf(buf, sizeof(buf), "SystemPath\n%d\n%d\n%d\n%d\n%d\n", sbp->sectorX, sbp->sectorY, sbp->sectorZ, sbp->systemIndex, sbp->bodyIndex); out += buf; break; } if (lo->Isa("Body")) { Body *b = dynamic_cast<Body*>(lo->m_object); snprintf(buf, sizeof(buf), "Body\n%d\n", Serializer::LookupBody(b)); out += buf; break; } Error("Lua serializer '%s' tried to serialize unsupported userdata value", key); break; } default: Error("Lua serializer '%s' tried to serialize %s value", key, lua_typename(l, lua_type(l, idx))); break; } LUA_DEBUG_END(l, 0); }
int _define_ship(lua_State *L, ShipType::Tag tag, std::vector<ShipType::Type> *list) { if (s_currentShipFile.empty()) return luaL_error(L, "ship file contains multiple ship definitions"); ShipType s; s.tag = tag; LUA_DEBUG_START(L); _get_string_attrib(L, "name", s.name, ""); _get_string_attrib(L, "model", s.lmrModelName, ""); _get_float_attrib(L, "reverse_thrust", s.linThrust[ShipType::THRUSTER_REVERSE], 0.0f); _get_float_attrib(L, "forward_thrust", s.linThrust[ShipType::THRUSTER_FORWARD], 0.0f); _get_float_attrib(L, "up_thrust", s.linThrust[ShipType::THRUSTER_UP], 0.0f); _get_float_attrib(L, "down_thrust", s.linThrust[ShipType::THRUSTER_DOWN], 0.0f); _get_float_attrib(L, "left_thrust", s.linThrust[ShipType::THRUSTER_LEFT], 0.0f); _get_float_attrib(L, "right_thrust", s.linThrust[ShipType::THRUSTER_RIGHT], 0.0f); _get_float_attrib(L, "angular_thrust", s.angThrust, 0.0f); // invert values where necessary s.linThrust[ShipType::THRUSTER_FORWARD] *= -1.f; s.linThrust[ShipType::THRUSTER_LEFT] *= -1.f; s.linThrust[ShipType::THRUSTER_DOWN] *= -1.f; // angthrust fudge (XXX: why?) s.angThrust = s.angThrust / 2; _get_vec_attrib(L, "camera_offset", s.cameraOffset, vector3d(0.0)); for (int i=0; i<Equip::SLOT_MAX; i++) s.equipSlotCapacity[i] = 0; _get_int_attrib(L, "max_cargo", s.equipSlotCapacity[Equip::SLOT_CARGO], 0); _get_int_attrib(L, "max_engine", s.equipSlotCapacity[Equip::SLOT_ENGINE], 1); _get_int_attrib(L, "max_laser", s.equipSlotCapacity[Equip::SLOT_LASER], 1); _get_int_attrib(L, "max_missile", s.equipSlotCapacity[Equip::SLOT_MISSILE], 0); _get_int_attrib(L, "max_ecm", s.equipSlotCapacity[Equip::SLOT_ECM], 1); _get_int_attrib(L, "max_scanner", s.equipSlotCapacity[Equip::SLOT_SCANNER], 1); _get_int_attrib(L, "max_radarmapper", s.equipSlotCapacity[Equip::SLOT_RADARMAPPER], 1); _get_int_attrib(L, "max_hypercloud", s.equipSlotCapacity[Equip::SLOT_HYPERCLOUD], 1); _get_int_attrib(L, "max_hullautorepair", s.equipSlotCapacity[Equip::SLOT_HULLAUTOREPAIR], 1); _get_int_attrib(L, "max_energybooster", s.equipSlotCapacity[Equip::SLOT_ENERGYBOOSTER], 1); _get_int_attrib(L, "max_atmoshield", s.equipSlotCapacity[Equip::SLOT_ATMOSHIELD], 1); _get_int_attrib(L, "max_cabin", s.equipSlotCapacity[Equip::SLOT_CABIN], 50); _get_int_attrib(L, "max_shield", s.equipSlotCapacity[Equip::SLOT_SHIELD], 9999); _get_int_attrib(L, "max_fuelscoop", s.equipSlotCapacity[Equip::SLOT_FUELSCOOP], 1); _get_int_attrib(L, "max_cargoscoop", s.equipSlotCapacity[Equip::SLOT_CARGOSCOOP], 1); _get_int_attrib(L, "max_lasercooler", s.equipSlotCapacity[Equip::SLOT_LASERCOOLER], 1); _get_int_attrib(L, "max_cargolifesupport", s.equipSlotCapacity[Equip::SLOT_CARGOLIFESUPPORT], 1); _get_int_attrib(L, "max_autopilot", s.equipSlotCapacity[Equip::SLOT_AUTOPILOT], 1); _get_int_attrib(L, "capacity", s.capacity, 0); _get_int_attrib(L, "hull_mass", s.hullMass, 100); _get_int_attrib(L, "fuel_tank_mass", s.fuelTankMass, 5); _get_float_attrib(L, "thruster_fuel_use", s.thrusterFuelUse, 1.f); _get_int_attrib(L, "price", s.baseprice, 0); s.baseprice *= 100; // in hundredths of credits s.equipSlotCapacity[Equip::SLOT_ENGINE] = Clamp(s.equipSlotCapacity[Equip::SLOT_ENGINE], 0, 1); { int hyperclass; _get_int_attrib(L, "hyperdrive_class", hyperclass, 1); if (!hyperclass) { s.hyperdrive = Equip::NONE; } else { s.hyperdrive = Equip::Type(Equip::DRIVE_CLASS1+hyperclass-1); } } lua_pushstring(L, "gun_mounts"); lua_gettable(L, -2); if (lua_istable(L, -1)) { for (unsigned int i=0; i<lua_rawlen(L,-1); i++) { lua_pushinteger(L, i+1); lua_gettable(L, -2); if (lua_istable(L, -1) && lua_rawlen(L,-1) == 4) { lua_pushinteger(L, 1); lua_gettable(L, -2); s.gunMount[i].pos = LuaVector::CheckFromLuaF(L, -1); lua_pop(L, 1); lua_pushinteger(L, 2); lua_gettable(L, -2); s.gunMount[i].dir = LuaVector::CheckFromLuaF(L, -1); lua_pop(L, 1); lua_pushinteger(L, 3); lua_gettable(L, -2); s.gunMount[i].sep = lua_tonumber(L,-1); lua_pop(L, 1); lua_pushinteger(L, 4); lua_gettable(L, -2); s.gunMount[i].orient = static_cast<ShipType::DualLaserOrientation>( LuaConstants::GetConstantFromArg(L, "DualLaserOrientation", -1)); lua_pop(L, 1); } lua_pop(L, 1); } } lua_pop(L, 1); LUA_DEBUG_END(L, 0); //sanity check if (s.name.empty()) return luaL_error(L, "Ship has no name"); if (s.lmrModelName.empty()) return luaL_error(L, "Missing model name in ship"); //this shouldn't necessarily be a fatal problem, could just warn+mark ship unusable //or replace with proxy geometry try { LmrLookupModelByName(s.lmrModelName.c_str()); } catch (LmrModelNotFoundException &) { return luaL_error(L, "Model %s is not defined", s.lmrModelName.c_str()); } const std::string& id = s_currentShipFile; typedef std::map<ShipType::Type, ShipType>::iterator iter; std::pair<iter, bool> result = ShipType::types.insert(std::make_pair(id, s)); if (result.second) list->push_back(s_currentShipFile); else return luaL_error(L, "Ship '%s' was already defined by a different file", id.c_str()); s_currentShipFile.clear(); return 0; }
const char *LuaSerializer::unpickle(lua_State *l, const char *pos) { LUA_DEBUG_START(l); char type = *pos++; switch (type) { case 'f': { char *end; double f = strtod(pos, &end); if (pos == end) throw SavedGameCorruptException(); lua_pushnumber(l, f); pos = end+1; // skip newline break; } case 'b': { if (*pos != '0' && *pos != '1') throw SavedGameCorruptException(); bool b = (*pos == '0') ? false : true; lua_pushboolean(l, b); pos++; break; } case 's': { char *end; int len = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); end++; // skip newline lua_pushlstring(l, end, len); pos = end + len; break; } case 't': { lua_newtable(l); lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); pos = unpickle(l, pos); lua_pushvalue(l, -3); lua_rawset(l, -3); lua_pop(l, 1); while (*pos != 'n') { pos = unpickle(l, pos); pos = unpickle(l, pos); lua_rawset(l, -3); } pos++; break; } case 'r': { pos = unpickle(l, pos); lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); lua_pushvalue(l, -2); lua_rawget(l, -2); if (lua_isnil(l, -1)) throw SavedGameCorruptException(); lua_insert(l, -3); lua_pop(l, 2); break; } case 'u': { const char *end = strchr(pos, '\n'); if (!end) throw SavedGameCorruptException(); int len = end - pos; end++; // skip newline if (len == 10 && strncmp(pos, "SystemPath", 10) == 0) { pos = end; Sint32 sectorX = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Sint32 sectorY = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Sint32 sectorZ = strtol(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Uint32 systemNum = strtoul(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Uint32 sbodyId = strtoul(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline SystemPath *sbp = new SystemPath(sectorX, sectorY, sectorZ, systemNum, sbodyId); LuaSystemPath::PushToLuaGC(sbp); break; } if (len == 4 && strncmp(pos, "Body", 4) == 0) { pos = end; Uint32 n = strtoul(pos, const_cast<char**>(&end), 0); if (pos == end) throw SavedGameCorruptException(); pos = end+1; // skip newline Body *body = Pi::game->GetSpace()->GetBodyByIndex(n); if (pos == end) throw SavedGameCorruptException(); switch (body->GetType()) { case Object::BODY: LuaBody::PushToLua(body); break; case Object::SHIP: LuaShip::PushToLua(dynamic_cast<Ship*>(body)); break; case Object::SPACESTATION: LuaSpaceStation::PushToLua(dynamic_cast<SpaceStation*>(body)); break; case Object::PLANET: LuaPlanet::PushToLua(dynamic_cast<Planet*>(body)); break; case Object::STAR: LuaStar::PushToLua(dynamic_cast<Star*>(body)); break; case Object::PLAYER: LuaPlayer::PushToLua(dynamic_cast<Player*>(body)); break; default: throw SavedGameCorruptException(); } break; } throw SavedGameCorruptException(); } case 'o': { const char *end = strchr(pos, '\n'); if (!end) throw SavedGameCorruptException(); int len = end - pos; end++; // skip newline const char *cl = pos; // unpickle the object, and insert it beneath the method table value pos = unpickle(l, end); // get _G[typename] lua_rawgeti(l, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); lua_pushlstring(l, cl, len); lua_gettable(l, -2); lua_remove(l, -2); if (lua_isnil(l, -1)) { lua_pop(l, 2); break; } lua_getfield(l, -1, "Unserialize"); if (lua_isnil(l, -1)) { lua_pushlstring(l, cl, len); luaL_error(l, "No Unserialize method found for class '%s'\n", lua_tostring(l, -1)); } lua_insert(l, -3); lua_pop(l, 1); pi_lua_protected_call(l, 1, 1); break; } default: throw SavedGameCorruptException(); } LUA_DEBUG_END(l, 1); return pos; }
static void push_bindings(lua_State *l, const KeyBindings::BindingPrototype *protos) { LUA_DEBUG_START(l); lua_newtable(l); // [-1] bindings lua_pushnil(l); // [-2] bindings, [-1] group (no current group) assert(!protos[0].function); // first entry should be a group header int group_idx = 1; int binding_idx = 1; for (const KeyBindings::BindingPrototype *proto = protos; proto->label; ++proto) { if (! proto->function) { // start a new named binding group // [-2] bindings, [-1] group lua_pop(l, 1); // [-1] bindings lua_newtable(l); lua_pushstring(l, proto->label); lua_setfield(l, -2, "label"); // [-2] bindings, [-1] group lua_pushvalue(l, -1); // [-3] bindings, [-2] group, [-1] group copy lua_rawseti(l, -3, group_idx); ++group_idx; binding_idx = 1; } else { // key or axis binding prototype // [-2] bindings, [-1] group lua_createtable(l, 0, 5); // [-3] bindings, [-2] group, [-1] binding // fields are: type ('KEY' or 'AXIS'), id ('BindIncreaseSpeed'), label ('Increase Speed'), binding ('Key13'), bindingDescription ('') lua_pushstring(l, (proto->kb ? "KEY" : "AXIS")); lua_setfield(l, -2, "type"); lua_pushstring(l, proto->function); lua_setfield(l, -2, "id"); lua_pushstring(l, proto->label); lua_setfield(l, -2, "label"); if (proto->kb) { const KeyBindings::KeyBinding kb1 = proto->kb->binding1; if (kb1.Enabled()) { lua_pushstring(l, kb1.ToString().c_str()); lua_setfield(l, -2, "binding1"); lua_pushstring(l, kb1.Description().c_str()); lua_setfield(l, -2, "bindingDescription1"); } const KeyBindings::KeyBinding kb2 = proto->kb->binding2; if (kb2.Enabled()) { lua_pushstring(l, kb2.ToString().c_str()); lua_setfield(l, -2, "binding2"); lua_pushstring(l, kb2.Description().c_str()); lua_setfield(l, -2, "bindingDescription2"); } } else if (proto->ab) { const KeyBindings::AxisBinding &ab = *proto->ab; lua_pushstring(l, ab.ToString().c_str()); lua_setfield(l, -2, "binding1"); lua_pushstring(l, ab.Description().c_str()); lua_setfield(l, -2, "bindingDescription1"); } else { assert(0); // invalid prototype binding } // [-3] bindings, [-2] group, [-1] binding lua_rawseti(l, -2, binding_idx); ++binding_idx; } LUA_DEBUG_CHECK(l, 2); // [-2] bindings, [-1] group } // pop the group table (which should already have been put in the bindings table) lua_pop(l, 1); LUA_DEBUG_END(l, 1); }
void LuaSerializer::pickle(lua_State *l, int idx, std::string &out, const char *key = NULL) { static char buf[256]; LUA_DEBUG_START(l); idx = lua_absindex(l, idx); if (lua_getmetatable(l, idx)) { lua_getfield(l, -1, "class"); if (lua_isnil(l, -1)) lua_pop(l, 2); else { const char *cl = lua_tostring(l, -1); snprintf(buf, sizeof(buf), "o%s\n", cl); lua_getglobal(l, cl); if (lua_isnil(l, -1)) luaL_error(l, "No Serialize method found for class '%s'\n", cl); lua_getfield(l, -1, "Serialize"); if (lua_isnil(l, -1)) luaL_error(l, "No Serialize method found for class '%s'\n", cl); lua_pushvalue(l, idx); pi_lua_protected_call(l, 1, 1); lua_remove(l, idx); lua_insert(l, idx); lua_pop(l, 3); if (lua_isnil(l, idx)) { LUA_DEBUG_END(l, 0); return; } out += buf; } } switch (lua_type(l, idx)) { case LUA_TNIL: break; case LUA_TNUMBER: { snprintf(buf, sizeof(buf), "f%f\n", lua_tonumber(l, idx)); out += buf; break; } case LUA_TBOOLEAN: { snprintf(buf, sizeof(buf), "b%d", lua_toboolean(l, idx) ? 1 : 0); out += buf; break; } case LUA_TSTRING: { lua_pushvalue(l, idx); const char *str = lua_tostring(l, -1); snprintf(buf, sizeof(buf), "s" SIZET_FMT "\n", strlen(str)); out += buf; out += str; lua_pop(l, 1); break; } case LUA_TTABLE: { lua_pushinteger(l, lua_Integer(lua_topointer(l, idx))); // ptr lua_getfield(l, LUA_REGISTRYINDEX, "PiSerializerTableRefs"); // ptr reftable lua_pushvalue(l, -2); // ptr reftable ptr lua_rawget(l, -2); // ptr reftable ??? if (!lua_isnil(l, -1)) { out += "r"; pickle(l, -3, out, key); lua_pop(l, 3); // [empty] } else { out += "t"; lua_pushvalue(l, -3); // ptr reftable nil ptr lua_pushvalue(l, idx); // ptr reftable nil ptr table lua_rawset(l, -4); // ptr reftable nil pickle(l, -3, out, key); lua_pop(l, 3); // [empty] lua_pushvalue(l, idx); lua_pushnil(l); while (lua_next(l, -2)) { if (key) { pickle(l, -2, out, key); pickle(l, -1, out, key); } else { lua_pushvalue(l, -2); const char *k = lua_tostring(l, -1); pickle(l, -3, out, k); pickle(l, -2, out, k); lua_pop(l, 1); } lua_pop(l, 1); } lua_pop(l, 1); out += "n"; } break; } case LUA_TUSERDATA: { out += "u"; lid *idp = static_cast<lid*>(lua_touserdata(l, idx)); LuaObjectBase *lo = LuaObjectBase::Lookup(*idp); if (!lo) Error("Lua serializer '%s' tried to serialize object with id 0x%08x, but it no longer exists", key, *idp); // XXX object wrappers should really have Serialize/Unserialize // methods to deal with this if (lo->Isa("SystemPath")) { SystemPath *sbp = dynamic_cast<SystemPath*>(lo->m_object); snprintf(buf, sizeof(buf), "SystemPath\n%d\n%d\n%d\n%u\n%u\n", sbp->sectorX, sbp->sectorY, sbp->sectorZ, sbp->systemIndex, sbp->bodyIndex); out += buf; break; } if (lo->Isa("Body")) { Body *b = dynamic_cast<Body*>(lo->m_object); snprintf(buf, sizeof(buf), "Body\n%u\n", Pi::game->GetSpace()->GetIndexForBody(b)); out += buf; break; } Error("Lua serializer '%s' tried to serialize unsupported userdata value", key); break; } default: Error("Lua serializer '%s' tried to serialize %s value", key, lua_typename(l, lua_type(l, idx))); break; } LUA_DEBUG_END(l, 0); }
void LuaConstants::Register(lua_State *l) { LUA_DEBUG_START(l); for (const EnumTable *table = ENUM_TABLES_PUBLIC; table->name; table++) _create_constant_table(l, table->name, table->first); /* * Constants: BodyType * * Describe different kinds of system bodies such as stars, planets and * space stations. * * GRAVPOINT - a pseudo-type for a gravitational point that multiple * bodies may orbit * BROWN_DWARF - brown dwarf sub-stellar object * STAR_M - type 'M' red star * STAR_K - type 'K' orange star * STAR_G - type 'G' yellow star * STAR_F - type 'F' white star * STAR_A - type 'A' hot white star * STAR_B - type 'B' blue star * STAR_O - type 'O' hot blue star * WHITE_DWARF - white dwarf stellar remnant * STAR_M_GIANT - red giant star * STAR_K_GIANT - orange giant star * STAR_G_GIANT - yellow giant star * STAR_F_GIANT - white giant star * STAR_A_GIANT - hot white giant star * STAR_B_GIANT - blue giant star * STAR_O_GIANT - hot blue giant star * STAR_M_SUPER_GIANT - red supergiant star * STAR_K_SUPER_GIANT - orange supergiant star * STAR_G_SUPER_GIANT - yellow supergiant star * STAR_F_SUPER_GIANT - white supergiant star * STAR_A_SUPER_GIANT - hot white supergiant star * STAR_B_SUPER_GIANT - blue supergiant star * STAR_O_SUPER_GIANT - hot blue supergiant star * STAR_M_HYPER_GIANT - red hypergiant star * STAR_K_HYPER_GIANT - orange hypergiant star * STAR_G_HYPER_GIANT - yellow hypergiant star * STAR_F_HYPER_GIANT - white hypergiant star * STAR_A_HYPER_GIANT - hot white hypergiant star * STAR_B_HYPER_GIANT - blue hypergiant star * STAR_O_HYPER_GIANT - hot blue hypergiant star * STAR_M_WF - Wolf-Rayet star (unstable) * STAR_B_WF - Wolf-Rayet star (risk of collapse) * STAR_O_WF - Wolf-Rayet star (imminent collapse) * STAR_S_BH - stellar black hole * STAR_IM_BH - intermediate-mass black hole * STAR_SM_BH - supermassive black hole * PLANET_GAS_GIANT - gas giant * PLANET_ASTEROID - asteroid * PLANET_TERRESTRIAL - terrestrial planet * STARPORT_ORBITAL - orbital starport (space station) * STARPORT_SURFACE - surface starport * * Availability: * * alpha 10 * * Status: * * stable */ /* * Constants: BodySuperType * * Describe general categories of system bodies. * * NONE - uncategorised * STAR - star * ROCKY_PLANET - a solid planet (terrestrial or asteroid) * GAS_GIANT - gas giant * STARPORT - surface or orbital starport * * Availability: * * alpha 10 * * Status: * * stable */ /* * Constants: PhysicsObjectType * * General physical objects * * BODY - . * MODELBODY - . * SHIP - . * PLAYER - . * SPACESTATION - . * PLANET - . * STAR - . * CARGOBODY - . * MISSILE - . * * Availability: * * 2014 April * * Status: * * experimental */ /* * Constants: PolitEcon * * Economy type * * NONE - . * VERY_CAPITALIST - . * CAPITALIST - . * MIXED - . * PLANNED - . * * Availability: * * alpha 10 * * Status: * * experimental */ /* * Constants: PolitGovType * * Government type * * NONE - . * EARTHCOLONIAL - . * EARTHDEMOC - . * EMPIRERULE - . * CISLIBDEM - . * CISSOCDEM - . * LIBDEM - . * CORPORATE - . * SOCDEM - . * EARTHMILDICT - . * MILDICT1 - . * MILDICT2 - . * EMPIREMILDICT - . * COMMUNIST - . * PLUTOCRATIC - . * DISORDER - . * * Availability: * * alpha 10 * * Status: * * experimental */ /* * Constants: CommodityType * * Cargo/commodity types. * * HYDROGEN - hydrogen * LIQUID_OXYGEN - liquid oxygen * METAL_ORE - metal ore * CARBON_ORE - carbon ore * METAL_ALLOYS - metal alloys * PLASTICS - plastics * FRUIT_AND_VEG - fruit and vegetables * ANIMAL_MEAT - animal meat * LIVE_ANIMALS - live animals * LIQUOR - liquor * GRAIN - grain * TEXTILES - textiles * FERTILIZER - fertilizer * WATER - water * MEDICINES - medicines * CONSUMER_GOODS - consumer goods * COMPUTERS - computers * ROBOTS - robots * PRECIOUS_METALS - precious metals * INDUSTRIAL_MACHINERY - industrial machinery * FARM_MACHINERY - farm machinery * MINING_MACHINERY - mining machinery (CARGO * AIR_PROCESSORS - air processors * SLAVES - slaves * HAND_WEAPONS - hand weapons * BATTLE_WEAPONS - battle weapons * NERVE_GAS - nerve gas * NARCOTICS - narcotics * MILITARY_FUEL - military fuel * RUBBISH - rubbish * RADIOACTIVES - radioactives * * Availability: * * alpha 10 * * Status: * * experimental */ /* * Constants: DualLaserOrientation * * The orientation of dual laser mountings. * * HORIZONTAL - Lasers are mounted left and right * VERTICAL - Lasers are mounted top and bottom * * Availability: * * alpha 27 * * Status: * * experimental */ /* * Constants: ShipTypeTag * * Ship tags mark whether a ship is suitable for a particular use. Used * with <ShipType.GetShipTypes> to select which set of ships to search. * * NONE - no tags * SHIP - standard ships. These are the ones available to the player and * used for regular game functions (trade, combat, etc) * STATIC_SHIP - static ships. These are not available to the player and * are used for mission specific functions (large supply * ships, warships, etc) * MISSILE - missiles. * * Availability: * * alpha 10 * * Status: * * stable */ /* * Constants: ShipTypeThruster * * Thruster types. Used by <ShipType.GetLinearThrust>. The name * corresponds to the direction the ship moves when the thruster is fired. * * REVERSE - front (fore) thruster * FORWARD - main/rear (aft) thruster * UP - bottom/underbelly (ventral) thruster * DOWN - top/back (dorsal) thruster * LEFT - right-side (starboard) thruster * RIGHT - left-side (port) thruster * * Availability: * * alpha 10 * * Status: * * stable */ /* * Constants: ShipJumpStatus * * Reasons that that a hyperspace jump might succeed or fail. Returned by * <Ship.HyperspaceTo>, <Ship.CheckHyperspaceTo> and <Ship.GetHyperspaceDetails>. * * OK - jump successful * CURRENT_SYSTEM - ship is already in the target system * NO_DRIVE - ship has no drive * DRIVE_ACTIVE - ship is already in hyperspace * OUT_OF_RANGE - target system is out of range * INSUFFICIENT_FUEL - target system is in range but the ship doesn't have * enough fuel * SAFETY_LOCKOUT - drive locked out for safety reasons * (currently this happens if landed, docked or docking) * * Availability: * * alpha 10 * * Status: * * stable */ /* * Constants: ShipAlertStatus * * Current alert status. Based on proximity and actions of nearby ships. * * NONE - no alert. All is well (green) * SHIP_NEARBY - ship within 100km (yellow) * SHIP_FIRING - ship within 100km is firing lasers (though not * necessarily at us) (red) * * Availability: * * alpha 10 * * Status: * * experimental */ /* * Constants: ShipFuelStatus * * Current fuel status. * * OK - more than 5% fuel remaining * WARNING - less than 5% fuel remaining * EMPTY - no fuel remaining * * Availability: * * alpha 20 * * Status: * * experimental */ /* * Constants: ShipFlightState * * Ship flight state * * FLYING - open flight (includes autopilot) * DOCKING - in docking animation * UNDOCKING - in docking animation * DOCKED - docked with station * LANDED - rough landed (not docked) * JUMPING - just initiating hyperjump (as of February 2014) * HYPERSPACE - in hyperspace * * Availability: * * alpha 16 * * Status: * * experimental */ /* * Constants: ShipAIError * * AI command error/result code passed to Event.onAICompleted * * NONE - AI completed successfully * GRAV_TOO_HIGH - AI can not compensate for gravity * REFUSED_PERM - AI was refused docking permission * ORBIT_IMPOSSIBLE - AI was asked to enter an impossible orbit (orbit is * outside target's frame) * * Availability: * * alpha 17 * * Status: * * experimental */ /* * Constants: FileSystemRoot * * Specifier of filesystem base. * * USER - directory containing Pioneer's config, savefiles, mods and other * user-specific data * DATA - directory containing Pioneer's data files * * Availability: * * alpha 25 * * Status: * * experimental */ // XXX document UI tables LUA_DEBUG_END(l, 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); }
static int l_lang_get_resource(lua_State *l) { LUA_DEBUG_START(l); const std::string resourceName(luaL_checkstring(l, 1)); const std::string langCode(lua_isnoneornil(l, 2) ? Lang::GetCore().GetLangCode() : lua_tostring(l, 2)); const std::string key = resourceName + "_" + langCode; lua_getfield(l, LUA_REGISTRYINDEX, "LangCache"); if (lua_isnil(l, -1)) { lua_pop(l, 1); lua_newtable(l); lua_pushvalue(l, -1); lua_setfield(l, LUA_REGISTRYINDEX, "LangCache"); } // find it in the cache lua_getfield(l, -1, key.c_str()); if (!lua_isnil(l, -1)) { lua_remove(l, -2); return 1; } lua_pop(l, 1); Lang::Resource res(resourceName, langCode); if (!res.Load()) { lua_pushnil(l); return 1; } lua_newtable(l); lua_pushstring(l, "langCode"); lua_pushstring(l, langCode.c_str()); lua_settable(l, -3); lua_pushstring(l, "resourceName"); lua_pushstring(l, resourceName.c_str()); lua_settable(l, -3); for (auto i : res.GetStrings()) { const std::string token(i.first); const std::string text(i.second.empty() ? token : i.second); lua_pushlstring(l, token.c_str(), token.size()); lua_pushlstring(l, text.c_str(), text.size()); lua_rawset(l, -3); } lua_pushstring(l, "get"); lua_pushcfunction(l, _get); lua_rawset(l, -3); lua_newtable(l); lua_pushstring(l, "__index"); lua_pushcfunction(l, _resource_index); lua_rawset(l, -3); lua_pushstring(l, "__newindex"); lua_pushcfunction(l, _resource_newindex); lua_rawset(l, -3); lua_setmetatable(l, -2); // insert into cache lua_pushvalue(l, -1); lua_setfield(l, -3, key.c_str()); lua_remove(l, -2); 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); }