2018-01-01 12:22:12 -08:00
|
|
|
// Copyright © 2008-2018 Pioneer Developers. See AUTHORS.txt for details
|
2012-09-15 17:59:15 -07:00
|
|
|
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
|
2012-09-12 04:38:30 -07:00
|
|
|
|
2015-11-29 04:12:50 -08:00
|
|
|
#define ALLOW_LUA_SHIP_DEF 0
|
2014-11-22 07:55:55 -08:00
|
|
|
|
2008-06-24 03:17:31 -07:00
|
|
|
#include "ShipType.h"
|
2014-11-22 07:55:55 -08:00
|
|
|
#if ALLOW_LUA_SHIP_DEF
|
2012-05-04 20:04:20 -07:00
|
|
|
#include "LuaVector.h"
|
2011-03-28 03:56:42 -07:00
|
|
|
#include "LuaUtils.h"
|
2013-04-15 11:35:34 -07:00
|
|
|
#include "LuaTable.h"
|
2012-10-02 15:34:08 -07:00
|
|
|
#include "LuaConstants.h"
|
2014-11-20 14:43:49 -08:00
|
|
|
#endif
|
2012-08-18 07:29:48 -07:00
|
|
|
#include "FileSystem.h"
|
2010-03-30 05:44:20 -07:00
|
|
|
#include "utils.h"
|
2011-07-27 03:46:56 -07:00
|
|
|
#include "Lang.h"
|
2014-11-20 14:43:49 -08:00
|
|
|
#include "json/json.h"
|
2013-07-07 14:12:28 -07:00
|
|
|
#include <algorithm>
|
2008-06-24 03:17:31 -07:00
|
|
|
|
2011-03-13 15:55:32 -07:00
|
|
|
|
2014-11-20 14:43:49 -08:00
|
|
|
std::map<ShipType::Id, const ShipType> ShipType::types;
|
2014-11-22 09:03:48 -08:00
|
|
|
std::vector<ShipType::Id> ShipType::player_ships;
|
|
|
|
std::vector<ShipType::Id> ShipType::static_ships;
|
|
|
|
std::vector<ShipType::Id> ShipType::missile_ships;
|
2011-03-13 15:55:32 -07:00
|
|
|
|
2014-11-20 14:43:49 -08:00
|
|
|
const std::string ShipType::POLICE = "kanara";
|
|
|
|
const std::string ShipType::MISSILE_GUIDED = "missile_guided";
|
|
|
|
const std::string ShipType::MISSILE_NAVAL = "missile_naval";
|
|
|
|
const std::string ShipType::MISSILE_SMART = "missile_smart";
|
|
|
|
const std::string ShipType::MISSILE_UNGUIDED = "missile_unguided";
|
2010-03-30 05:44:20 -07:00
|
|
|
|
2013-10-15 04:17:14 -07:00
|
|
|
float ShipType::GetFuelUseRate() const
|
|
|
|
{
|
|
|
|
const float denominator = fuelTankMass * effectiveExhaustVelocity * 10;
|
|
|
|
return denominator > 0 ? -linThrust[THRUSTER_FORWARD]/denominator : 1e9;
|
|
|
|
}
|
|
|
|
|
2012-11-05 08:57:01 -08:00
|
|
|
// returns velocity of engine exhausts in m/s
|
2013-01-15 11:28:27 -08:00
|
|
|
static double GetEffectiveExhaustVelocity(double fuelTankMass, double thrusterFuelUse, double forwardThrust) {
|
2013-01-06 06:25:59 -08:00
|
|
|
double denominator = fuelTankMass * thrusterFuelUse * 10;
|
2012-11-05 08:57:01 -08:00
|
|
|
return fabs(denominator > 0 ? forwardThrust/denominator : 1e9);
|
|
|
|
}
|
|
|
|
|
2014-11-20 14:43:49 -08:00
|
|
|
static bool ShipIsUnbuyable(const std::string &id)
|
2013-07-07 14:12:28 -07:00
|
|
|
{
|
|
|
|
const ShipType &t = ShipType::types[id];
|
2014-08-15 11:16:19 -07:00
|
|
|
return is_zero_exact(t.baseprice);
|
2013-07-07 14:12:28 -07:00
|
|
|
}
|
|
|
|
|
2017-01-06 10:22:40 -08:00
|
|
|
ShipType::ShipType(const Id &_id, const std::string &path)
|
2014-11-20 14:43:49 -08:00
|
|
|
{
|
|
|
|
Json::Reader reader;
|
|
|
|
Json::Value data;
|
|
|
|
|
2017-03-13 01:17:28 -07:00
|
|
|
isGlobalColorDefined = false;
|
|
|
|
|
2014-11-20 14:43:49 -08:00
|
|
|
auto fd = FileSystem::gameDataFiles.ReadFile(path);
|
|
|
|
if (!fd) {
|
|
|
|
Output("couldn't open ship def '%s'\n", path.c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!reader.parse(fd->GetData(), fd->GetData()+fd->GetSize(), data)) {
|
|
|
|
Output("couldn't read ship def '%s': %s\n", path.c_str(), reader.getFormattedErrorMessages().c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// determine what kind (tag) of ship this is.
|
|
|
|
const std::string tagStr = data.get("tag", "").asString();
|
|
|
|
if( tagStr.empty() || strcasecmp(tagStr.c_str(), "ship")==0 ) {
|
|
|
|
tag = TAG_SHIP;
|
|
|
|
} else if( strcasecmp(tagStr.c_str(), "static")==0 ) {
|
|
|
|
tag = TAG_STATIC_SHIP;
|
|
|
|
} else if( strcasecmp(tagStr.c_str(), "missile")==0 ) {
|
|
|
|
tag = TAG_MISSILE;
|
|
|
|
}
|
|
|
|
|
|
|
|
id = _id;
|
|
|
|
name = data.get("name", "").asString();
|
|
|
|
shipClass = data.get("ship_class", "").asString();
|
|
|
|
manufacturer = data.get("manufacturer", "").asString();
|
|
|
|
modelName = data.get("model", "").asString();
|
2015-11-29 04:11:38 -08:00
|
|
|
cockpitName = data.get("cockpit", "").asString();
|
2014-11-20 14:43:49 -08:00
|
|
|
|
|
|
|
linThrust[THRUSTER_REVERSE] = data.get("reverse_thrust", 0.0f).asFloat();
|
|
|
|
linThrust[THRUSTER_FORWARD] = data.get("forward_thrust", 0.0f).asFloat();
|
|
|
|
linThrust[THRUSTER_UP] = data.get("up_thrust", 0.0f).asFloat();
|
|
|
|
linThrust[THRUSTER_DOWN] = data.get("down_thrust", 0.0f).asFloat();
|
|
|
|
linThrust[THRUSTER_LEFT] = data.get("left_thrust", 0.0f).asFloat();
|
|
|
|
linThrust[THRUSTER_RIGHT] = data.get("right_thrust", 0.0f).asFloat();
|
|
|
|
angThrust = data.get("angular_thrust", 0.0f).asFloat();
|
|
|
|
|
2017-03-13 01:17:28 -07:00
|
|
|
// Parse global thrusters color
|
|
|
|
bool error = false;
|
|
|
|
int parse = 0;
|
|
|
|
for( Json::Value::iterator thruster_color = data["thruster_global_color"].begin() ; thruster_color != data["thruster_global_color"].end() ; ++thruster_color ) {
|
|
|
|
const std::string colorchannel = thruster_color.key().asString();
|
|
|
|
if (colorchannel.length()!=1) {
|
|
|
|
error = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (colorchannel.at(0) == 'r') {
|
|
|
|
globalThrusterColor.r = data["thruster_global_color"].get(colorchannel, 0).asInt();
|
|
|
|
parse++;
|
|
|
|
continue;
|
|
|
|
} else if (colorchannel.at(0) == 'g') {
|
|
|
|
globalThrusterColor.g = data["thruster_global_color"].get(colorchannel, 0).asInt();
|
|
|
|
parse++;
|
|
|
|
continue;
|
|
|
|
} else if (colorchannel.at(0) == 'b') {
|
|
|
|
globalThrusterColor.b = data["thruster_global_color"].get(colorchannel, 0).asInt();
|
|
|
|
parse++;
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
// No 'r', no 'g', no 'b', no good :/
|
|
|
|
error = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (error==true) {
|
|
|
|
Output("In file \"%s.json\" global thrusters custom color must be \"r\",\"g\" and \"b\"\n", modelName.c_str());
|
2017-04-13 14:40:11 -07:00
|
|
|
} else if (parse>0 && parse<3) {
|
2017-04-12 14:57:37 -07:00
|
|
|
Output("In file \"%s.json\" global thrusters custom color is malformed\n", modelName.c_str());
|
|
|
|
} else if (parse==3) {
|
2017-03-13 01:17:28 -07:00
|
|
|
globalThrusterColor.a = 255;
|
|
|
|
isGlobalColorDefined = true;
|
|
|
|
}
|
|
|
|
// Parse direction thrusters color
|
|
|
|
for (int i=0; i<THRUSTER_MAX; i++) isDirectionColorDefined[i]=false;
|
|
|
|
error = false;
|
|
|
|
for( Json::Value::iterator thruster_color = data["thruster_direction_color"].begin() ; thruster_color != data["thruster_direction_color"].end() ; ++thruster_color ) {
|
|
|
|
const std::string th_color_dir = thruster_color.key().asString();
|
|
|
|
Json::Value dir_color = data["thruster_direction_color"].get(th_color_dir, 0);
|
|
|
|
Color color;
|
|
|
|
if (!dir_color.isMember("r")||!dir_color.isMember("g")||!dir_color.isMember("b")) {
|
|
|
|
error = true;
|
|
|
|
continue /* for */;
|
|
|
|
} else {
|
|
|
|
color.r = dir_color["r"].asInt();
|
|
|
|
color.g = dir_color["g"].asInt();
|
|
|
|
color.b = dir_color["b"].asInt();
|
|
|
|
color.a = 255;
|
|
|
|
}
|
|
|
|
if (th_color_dir.find("forward")!=std::string::npos) {
|
|
|
|
isDirectionColorDefined[THRUSTER_FORWARD]=true;
|
|
|
|
directionThrusterColor[THRUSTER_FORWARD]= color;
|
|
|
|
}
|
|
|
|
if (th_color_dir.find("retro")!=std::string::npos) {
|
|
|
|
isDirectionColorDefined[THRUSTER_REVERSE]=true;
|
|
|
|
directionThrusterColor[THRUSTER_REVERSE]= color;
|
|
|
|
}
|
|
|
|
if (th_color_dir.find("left")!=std::string::npos) {
|
|
|
|
isDirectionColorDefined[THRUSTER_LEFT]=true;
|
|
|
|
directionThrusterColor[THRUSTER_LEFT]= color;
|
|
|
|
}
|
|
|
|
if (th_color_dir.find("right")!=std::string::npos) {
|
|
|
|
isDirectionColorDefined[THRUSTER_RIGHT]=true;
|
|
|
|
directionThrusterColor[THRUSTER_RIGHT]= color;
|
|
|
|
}
|
|
|
|
if (th_color_dir.find("up")!=std::string::npos) {
|
|
|
|
isDirectionColorDefined[THRUSTER_UP]=true;
|
|
|
|
directionThrusterColor[THRUSTER_UP]= color;
|
|
|
|
}
|
|
|
|
if (th_color_dir.find("down")!=std::string::npos) {
|
|
|
|
isDirectionColorDefined[THRUSTER_DOWN]=true;
|
|
|
|
directionThrusterColor[THRUSTER_DOWN]= color;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (error==true) {
|
|
|
|
for (int i=0; i<THRUSTER_MAX; i++) isDirectionColorDefined[i]=false;
|
|
|
|
Output("In file \"%s.json\" directional thrusters custom color must be \"r\",\"g\" and \"b\"\n", modelName.c_str());
|
|
|
|
}
|
2014-11-20 14:43:49 -08:00
|
|
|
// invert values where necessary
|
|
|
|
linThrust[THRUSTER_FORWARD] *= -1.f;
|
|
|
|
linThrust[THRUSTER_LEFT] *= -1.f;
|
|
|
|
linThrust[THRUSTER_DOWN] *= -1.f;
|
|
|
|
// angthrust fudge (XXX: why?)
|
|
|
|
angThrust = angThrust * 0.5f;
|
|
|
|
|
|
|
|
hullMass = data.get("hull_mass", 100).asInt();
|
|
|
|
capacity = data.get("capacity", 0).asInt();
|
|
|
|
fuelTankMass = data.get("fuel_tank_mass", 5).asInt();
|
|
|
|
|
2015-04-23 13:05:54 -07:00
|
|
|
for( Json::Value::iterator slot = data["slots"].begin() ; slot != data["slots"].end() ; ++slot ) {
|
2014-11-20 14:43:49 -08:00
|
|
|
const std::string slotname = slot.key().asString();
|
|
|
|
slots[slotname] = data["slots"].get(slotname, 0).asInt();
|
|
|
|
}
|
|
|
|
|
2017-01-09 11:32:39 -08:00
|
|
|
for( Json::Value::iterator role = data["roles"].begin(); role != data["roles"].end(); ++role ) {
|
|
|
|
const std::string rolename = role.key().asString();
|
|
|
|
roles[rolename] = data["roles"].get(rolename, 0).asBool();
|
|
|
|
}
|
|
|
|
|
2016-10-09 03:41:37 -07:00
|
|
|
for(int it=0;it<4;it++) thrusterUpgrades[it] = 1.0 + (double(it)/10.0);
|
|
|
|
for( Json::Value::iterator slot = data["thrust_upgrades"].begin() ; slot != data["thrust_upgrades"].end() ; ++slot ) {
|
|
|
|
const std::string slotname = slot.key().asString();
|
|
|
|
const int index = Clamp(atoi(&slotname.c_str()[9]), 1, 3);
|
|
|
|
thrusterUpgrades[index] = data["thrust_upgrades"].get(slotname, 0).asDouble();
|
|
|
|
}
|
|
|
|
|
2017-05-05 13:13:22 -07:00
|
|
|
atmosphericPressureLimit = data.get("atmospheric_pressure_limit", 10.0).asDouble(); // 10 atmosphere is about 90 metres underwater (on Earth)
|
2017-05-01 12:50:03 -07:00
|
|
|
|
2014-11-20 14:43:49 -08:00
|
|
|
{
|
|
|
|
const auto it = slots.find("engine");
|
2017-01-06 10:22:40 -08:00
|
|
|
if (it != slots.end())
|
|
|
|
{
|
|
|
|
it->second = Clamp(it->second, 0, 1);
|
2014-11-20 14:43:49 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
effectiveExhaustVelocity = data.get("effective_exhaust_velocity", -1.0f).asFloat();
|
|
|
|
const float thruster_fuel_use = data.get("thruster_fuel_use", -1.0f).asFloat();
|
|
|
|
|
|
|
|
if(effectiveExhaustVelocity < 0 && thruster_fuel_use < 0) {
|
|
|
|
// default value of v_c is used
|
|
|
|
effectiveExhaustVelocity = 55000000;
|
|
|
|
} else if(effectiveExhaustVelocity < 0 && thruster_fuel_use >= 0) {
|
|
|
|
// v_c undefined and thruster fuel use defined -- use it!
|
2017-01-06 10:22:40 -08:00
|
|
|
effectiveExhaustVelocity = GetEffectiveExhaustVelocity(fuelTankMass, thruster_fuel_use, linThrust[Thruster::THRUSTER_FORWARD]);
|
2014-11-20 14:43:49 -08:00
|
|
|
} else {
|
|
|
|
if(thruster_fuel_use >= 0) {
|
|
|
|
Output("Warning: Both thruster_fuel_use and effective_exhaust_velocity defined for %s, using effective_exhaust_velocity.\n", modelName.c_str());
|
|
|
|
}
|
|
|
|
}
|
2017-01-06 10:22:40 -08:00
|
|
|
|
2014-11-20 14:43:49 -08:00
|
|
|
baseprice = data.get("price", 0.0).asDouble();
|
|
|
|
minCrew = data.get("min_crew", 1).asInt();
|
|
|
|
maxCrew = data.get("max_crew", 1).asInt();
|
|
|
|
hyperdriveClass = data.get("hyperdrive_class", 1).asInt();
|
|
|
|
}
|
2012-08-18 07:29:48 -07:00
|
|
|
|
2014-11-22 07:55:55 -08:00
|
|
|
#if ALLOW_LUA_SHIP_DEF
|
2014-11-20 14:43:49 -08:00
|
|
|
static std::string s_currentShipFile;
|
2014-11-22 09:03:48 -08:00
|
|
|
int _define_ship(lua_State *L, ShipType::Tag tag, std::vector<ShipType::Id> *list)
|
2012-02-29 06:21:37 -08:00
|
|
|
{
|
2012-08-18 07:29:48 -07:00
|
|
|
if (s_currentShipFile.empty())
|
|
|
|
return luaL_error(L, "ship file contains multiple ship definitions");
|
|
|
|
|
2014-11-20 14:43:49 -08:00
|
|
|
Json::Value data;
|
|
|
|
|
2012-02-29 06:21:37 -08:00
|
|
|
ShipType s;
|
|
|
|
s.tag = tag;
|
2012-10-30 21:26:42 -07:00
|
|
|
s.id = s_currentShipFile;
|
2012-02-29 06:21:37 -08:00
|
|
|
|
|
|
|
LUA_DEBUG_START(L);
|
2013-04-15 11:35:34 -07:00
|
|
|
LuaTable t(L, -1);
|
2013-09-17 04:28:13 -07:00
|
|
|
|
2013-04-15 11:35:34 -07:00
|
|
|
s.name = t.Get("name", "");
|
2014-01-04 15:07:45 -08:00
|
|
|
s.shipClass = t.Get("ship_class", "unknown");
|
|
|
|
s.manufacturer = t.Get("manufacturer", "unknown");
|
2013-04-15 11:35:34 -07:00
|
|
|
s.modelName = t.Get("model", "");
|
2013-09-20 00:31:02 -07:00
|
|
|
|
2014-11-20 14:43:49 -08:00
|
|
|
data["name"] = s.name;
|
|
|
|
data["ship_class"] = s.shipClass;
|
|
|
|
data["manufacturer"] = s.manufacturer;
|
|
|
|
data["model"] = s.modelName;
|
|
|
|
|
2013-12-14 15:12:18 -08:00
|
|
|
s.cockpitName = t.Get("cockpit", "");
|
2013-04-15 11:35:34 -07:00
|
|
|
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);
|
2014-11-20 14:43:49 -08:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2012-09-23 10:50:37 -07:00
|
|
|
// 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;
|
2012-10-16 13:37:01 -07:00
|
|
|
|
2013-04-15 11:35:34 -07:00
|
|
|
s.capacity = t.Get("capacity", 0);
|
|
|
|
s.hullMass = t.Get("hull_mass", 100);
|
|
|
|
s.fuelTankMass = t.Get("fuel_tank_mass", 5);
|
2012-11-05 08:57:01 -08:00
|
|
|
|
2014-11-20 14:43:49 -08:00
|
|
|
data["capacity"] = s.capacity;
|
|
|
|
data["hull_mass"] = s.hullMass;
|
|
|
|
data["fuel_tank_mass"] = s.fuelTankMass;
|
|
|
|
|
2012-10-22 14:53:06 -07:00
|
|
|
LuaTable slot_table = t.Sub("slots");
|
|
|
|
if (slot_table.GetLua()) {
|
|
|
|
s.slots = slot_table.GetMap<std::string, int>();
|
|
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
2014-07-15 18:39:50 -07:00
|
|
|
{
|
|
|
|
const auto it = s.slots.find("engine");
|
|
|
|
if (it != s.slots.end()) { it->second = Clamp(it->second, 0, 1); }
|
|
|
|
}
|
|
|
|
|
2014-11-20 14:43:49 -08:00
|
|
|
for( auto slot : s.slots ) {
|
|
|
|
data["slots"][slot.first] = slot.second;
|
|
|
|
}
|
|
|
|
|
2012-11-05 08:57:01 -08:00
|
|
|
// fuel_use_rate can be given in two ways
|
2013-01-06 06:25:59 -08:00
|
|
|
float thruster_fuel_use = 0;
|
2013-04-15 11:35:34 -07:00
|
|
|
s.effectiveExhaustVelocity = t.Get("effective_exhaust_velocity", -1.0f);
|
|
|
|
thruster_fuel_use = t.Get("thruster_fuel_use", -1.0f);
|
2014-11-20 14:43:49 -08:00
|
|
|
|
|
|
|
data["effective_exhaust_velocity"] = s.effectiveExhaustVelocity;
|
|
|
|
data["thruster_fuel_use"] = thruster_fuel_use;
|
|
|
|
|
2013-01-06 06:25:59 -08:00
|
|
|
if(s.effectiveExhaustVelocity < 0 && thruster_fuel_use < 0) {
|
2012-11-05 08:57:01 -08:00
|
|
|
// default value of v_c is used
|
2013-01-06 06:25:59 -08:00
|
|
|
s.effectiveExhaustVelocity = 55000000;
|
|
|
|
} else if(s.effectiveExhaustVelocity < 0 && thruster_fuel_use >= 0) {
|
2012-11-05 08:57:01 -08:00
|
|
|
// v_c undefined and thruster fuel use defined -- use it!
|
2013-01-06 06:25:59 -08:00
|
|
|
s.effectiveExhaustVelocity = GetEffectiveExhaustVelocity(s.fuelTankMass, thruster_fuel_use, s.linThrust[ShipType::THRUSTER_FORWARD]);
|
2012-11-05 08:57:01 -08:00
|
|
|
} else {
|
2013-01-06 06:25:59 -08:00
|
|
|
if(thruster_fuel_use >= 0)
|
2014-01-28 01:40:09 -08:00
|
|
|
Output("Warning: Both thruster_fuel_use and effective_exhaust_velocity defined for %s, using effective_exhaust_velocity.\n", s.modelName.c_str());
|
2012-11-05 08:57:01 -08:00
|
|
|
}
|
|
|
|
|
2014-08-15 11:16:19 -07:00
|
|
|
s.baseprice = t.Get("price", 0.0);
|
2012-02-29 06:21:37 -08:00
|
|
|
|
2013-04-15 11:35:34 -07:00
|
|
|
s.minCrew = t.Get("min_crew", 1);
|
|
|
|
s.maxCrew = t.Get("max_crew", 1);
|
2012-12-29 16:05:39 -08:00
|
|
|
|
2014-04-11 09:46:49 -07:00
|
|
|
s.hyperdriveClass = t.Get("hyperdrive_class", 1);
|
2017-01-06 10:22:40 -08:00
|
|
|
|
2014-11-20 14:43:49 -08:00
|
|
|
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 );
|
|
|
|
|
2014-11-22 07:55:55 -08:00
|
|
|
const std::string path("ships/" + s_currentShipFile + ".json");
|
2014-11-20 14:43:49 -08:00
|
|
|
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();
|
2013-09-17 04:23:00 -07:00
|
|
|
}
|
2014-12-31 04:00:14 -08:00
|
|
|
fwrite(saveMe.data(), saveMe.length(), 1, f);
|
2014-11-20 14:43:49 -08:00
|
|
|
fclose(f);
|
2013-09-17 04:23:00 -07:00
|
|
|
|
2012-02-29 06:21:37 -08:00
|
|
|
lua_pop(L, 1);
|
|
|
|
LUA_DEBUG_END(L, 0);
|
|
|
|
|
2012-03-05 07:25:03 -08:00
|
|
|
//sanity check
|
|
|
|
if (s.name.empty())
|
|
|
|
return luaL_error(L, "Ship has no name");
|
|
|
|
|
2013-02-02 07:31:00 -08:00
|
|
|
if (s.modelName.empty())
|
2012-03-05 07:25:03 -08:00
|
|
|
return luaL_error(L, "Missing model name in ship");
|
|
|
|
|
2012-12-29 16:05:39 -08:00
|
|
|
if (s.minCrew < 1 || s.maxCrew < 1 || s.minCrew > s.maxCrew)
|
|
|
|
return luaL_error(L, "Invalid values for min_crew and max_crew");
|
|
|
|
|
2012-08-18 07:29:48 -07:00
|
|
|
const std::string& id = s_currentShipFile;
|
2014-11-20 14:43:49 -08:00
|
|
|
typedef std::map<std::string, const ShipType>::iterator iter;
|
2012-08-18 07:29:48 -07:00
|
|
|
std::pair<iter, bool> result = ShipType::types.insert(std::make_pair(id, s));
|
|
|
|
if (result.second)
|
2014-11-22 09:03:48 -08:00
|
|
|
list->push_back(s_currentShipFile);
|
2012-08-18 07:29:48 -07:00
|
|
|
else
|
|
|
|
return luaL_error(L, "Ship '%s' was already defined by a different file", id.c_str());
|
|
|
|
s_currentShipFile.clear();
|
|
|
|
|
2012-02-29 06:21:37 -08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int define_ship(lua_State *L)
|
|
|
|
{
|
2014-11-22 09:03:48 -08:00
|
|
|
return _define_ship(L, ShipType::TAG_SHIP, &ShipType::player_ships);
|
2012-02-29 06:21:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
int define_static_ship(lua_State *L)
|
|
|
|
{
|
2014-11-22 09:03:48 -08:00
|
|
|
return _define_ship(L, ShipType::TAG_STATIC_SHIP, &ShipType::static_ships);
|
2012-02-29 06:21:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
int define_missile(lua_State *L)
|
|
|
|
{
|
2014-11-22 09:03:48 -08:00
|
|
|
return _define_ship(L, ShipType::TAG_MISSILE, &ShipType::missile_ships);
|
2012-02-29 06:21:37 -08:00
|
|
|
}
|
2014-11-20 14:43:49 -08:00
|
|
|
#endif
|
2012-02-29 06:21:37 -08:00
|
|
|
|
2011-03-13 15:55:32 -07:00
|
|
|
void ShipType::Init()
|
|
|
|
{
|
|
|
|
static bool isInitted = false;
|
2017-01-06 10:22:40 -08:00
|
|
|
if (isInitted)
|
2014-11-20 14:43:49 -08:00
|
|
|
return;
|
2011-03-13 15:55:32 -07:00
|
|
|
isInitted = true;
|
|
|
|
|
2014-11-22 07:55:55 -08:00
|
|
|
// 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));
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if ALLOW_LUA_SHIP_DEF
|
2012-05-04 20:04:20 -07:00
|
|
|
lua_State *l = luaL_newstate();
|
2012-02-29 06:21:37 -08:00
|
|
|
|
|
|
|
LUA_DEBUG_START(l);
|
|
|
|
|
2012-05-06 14:42:43 -07:00
|
|
|
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);
|
2012-05-04 20:04:20 -07:00
|
|
|
|
2012-10-02 15:34:08 -07:00
|
|
|
LuaConstants::Register(l);
|
2012-05-04 20:04:20 -07:00
|
|
|
LuaVector::Register(l);
|
2012-05-05 08:58:48 -07:00
|
|
|
LUA_DEBUG_CHECK(l, 0);
|
|
|
|
|
2012-05-05 10:55:06 -07:00
|
|
|
// provide shortcut vector constructor: v = vector.new
|
|
|
|
lua_getglobal(l, LuaVector::LibName);
|
|
|
|
lua_getfield(l, -1, "new");
|
2012-05-04 20:04:20 -07:00
|
|
|
assert(lua_iscfunction(l, -1));
|
|
|
|
lua_setglobal(l, "v");
|
2012-05-05 10:55:06 -07:00
|
|
|
lua_pop(l, 1); // pop the vector library table
|
2012-05-04 20:04:20 -07:00
|
|
|
|
|
|
|
LUA_DEBUG_CHECK(l, 0);
|
|
|
|
|
|
|
|
// register ship definition functions
|
2012-02-29 06:21:37 -08:00
|
|
|
lua_register(l, "define_ship", define_ship);
|
|
|
|
lua_register(l, "define_static_ship", define_static_ship);
|
|
|
|
lua_register(l, "define_missile", define_missile);
|
|
|
|
|
2012-05-04 20:04:20 -07:00
|
|
|
LUA_DEBUG_CHECK(l, 0);
|
|
|
|
|
|
|
|
// load all ship definitions
|
2012-08-18 07:29:48 -07:00
|
|
|
namespace fs = FileSystem;
|
2014-11-22 07:55:55 -08:00
|
|
|
for (fs::FileEnumerator files(fs::gameDataFiles, "ships", fs::FileEnumerator::Recurse); !files.Finished(); files.Next()) {
|
2012-08-18 07:29:48 -07:00
|
|
|
const fs::FileInfo &info = files.Current();
|
2013-12-05 13:18:31 -08:00
|
|
|
if (ends_with_ci(info.GetPath(), ".lua")) {
|
2012-08-18 07:29:48 -07:00
|
|
|
const std::string name = info.GetName();
|
2014-11-22 07:55:55 -08:00
|
|
|
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();
|
|
|
|
}
|
2012-08-18 07:29:48 -07:00
|
|
|
}
|
|
|
|
}
|
2012-02-29 06:21:37 -08:00
|
|
|
|
|
|
|
LUA_DEBUG_END(l, 0);
|
|
|
|
|
|
|
|
lua_close(l);
|
2014-11-20 14:43:49 -08:00
|
|
|
#endif
|
|
|
|
|
2013-07-07 14:12:28 -07:00
|
|
|
//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());
|
|
|
|
|
2012-03-06 12:00:01 -08:00
|
|
|
if (ShipType::player_ships.empty())
|
2012-05-26 16:30:55 -07:00
|
|
|
Error("No playable ships have been defined! The game cannot run.");
|
2010-03-30 05:44:20 -07:00
|
|
|
}
|
|
|
|
|