define ship roles via added modules and allow multiple weapons

This commit is contained in:
2026-06-01 22:57:53 +02:00
parent f363f7a67c
commit 9d0a60a93b
31 changed files with 873 additions and 407 deletions

View File

@@ -7,8 +7,13 @@
#include <utility>
#include <vector>
#include <QPoint>
#include "toml.hpp"
#include "Rotation.h"
#include "ShipLayout.h"
namespace
{
@@ -207,6 +212,42 @@ toml::table parseFile(const std::string& path, const std::string& file)
}
}
Rotation parseRotationString(const std::string& s)
{
if (s == "east") { return Rotation::East; }
if (s == "south") { return Rotation::South; }
if (s == "west") { return Rotation::West; }
return Rotation::North;
}
std::vector<PlacedModule> parsePlacedModules(const toml::array& arr,
const std::string& file,
const std::string& path)
{
std::vector<PlacedModule> result;
result.reserve(arr.size());
for (std::size_t i = 0; i < arr.size(); ++i)
{
const std::string elemPath = path + "[" + std::to_string(i) + "]";
const toml::table* t = arr[i].as_table();
if (t == nullptr) { continue; }
toml::table& mt = const_cast<toml::table&>(*t);
const std::optional<std::string> type = mt["type"].value<std::string>();
const std::optional<int64_t> x = mt["x"].value<int64_t>();
const std::optional<int64_t> y = mt["y"].value<int64_t>();
const std::optional<std::string> rot = mt["rotation"].value<std::string>();
if (!type || !x || !y || !rot) { continue; }
PlacedModule pm;
pm.moduleId = *type;
pm.position = QPoint(static_cast<int>(*x), static_cast<int>(*y));
pm.rotation = parseRotationString(*rot);
result.push_back(std::move(pm));
}
return result;
}
} // namespace
@@ -418,43 +459,13 @@ ShipsConfig ConfigLoader::loadShips(const std::string& path)
def.loot.scrapDrop = static_cast<int>(requireInt(lMt["scrap_drop"], file, lPath + ".scrap_drop"));
}
// Optional: combat
if (mt.contains("combat"))
// Optional: default_modules (REQ-WAV-DEFAULT-MODULES)
if (mt.contains("default_modules"))
{
const std::string cPath = elemPath + ".combat";
const toml::table& cTable = requireTable(mt["combat"], file, cPath);
toml::table& cMt = const_cast<toml::table&>(cTable);
ShipCombat combat {
requireFormula(cMt["damage_formula"], file, cPath + ".damage_formula"),
requireFormula(cMt["attack_range_formula"], file, cPath + ".attack_range_formula"),
requireFormula(cMt["attack_rate_formula"], file, cPath + ".attack_rate_formula"),
};
def.combat = std::move(combat);
}
// Optional: salvage
if (mt.contains("salvage"))
{
const std::string sPath = elemPath + ".salvage";
const toml::table& sTable = requireTable(mt["salvage"], file, sPath);
toml::table& sMt = const_cast<toml::table&>(sTable);
ShipSalvage salvage;
salvage.collectionRange = requireDouble(sMt["collection_range"], file, sPath + ".collection_range");
salvage.cargoCapacity = static_cast<int>(requireInt(sMt["cargo_capacity"], file, sPath + ".cargo_capacity"));
def.salvage = salvage;
}
// Optional: repair
if (mt.contains("repair"))
{
const std::string rPath = elemPath + ".repair";
const toml::table& rTable = requireTable(mt["repair"], file, rPath);
toml::table& rMt = const_cast<toml::table&>(rTable);
ShipRepair repair {
requireFormula(rMt["repair_rate_formula"], file, rPath + ".repair_rate_formula"),
requireFormula(rMt["repair_range_formula"], file, rPath + ".repair_range_formula"),
};
def.repair = std::move(repair);
const toml::array& modArr = requireArray(mt["default_modules"], file,
elemPath + ".default_modules");
def.defaultModules = parsePlacedModules(modArr, file,
elemPath + ".default_modules");
}
cfg.ships.push_back(std::move(def));
@@ -514,9 +525,11 @@ static const StatEntry kKnownStats[] = {
{"health", "hp"},
{"movement", "speed"},
{"sensor", "sensor_range"},
{"combat", "damage"},
{"combat", "attack_range"},
{"combat", "attack_rate"},
{"weapon", "damage"},
{"weapon", "attack_range"},
{"weapon", "attack_rate"},
{"salvage", "collection_range"},
{"salvage", "cargo_capacity"},
{"repair", "repair_rate"},
{"repair", "repair_range"},
};
@@ -597,6 +610,60 @@ ModulesConfig ConfigLoader::loadModules(const std::string& path)
}
}
// Weapon capability section: [module.weapon] with base stat formulas
if (mt.contains("weapon"))
{
const std::string wPath = elemPath + ".weapon";
const toml::table& wTable = requireTable(mt["weapon"], file, wPath);
toml::table& wMt = const_cast<toml::table&>(wTable);
if (wMt.contains("damage_formula") || wMt.contains("attack_range_formula")
|| wMt.contains("attack_rate_formula"))
{
ModuleWeaponCapability cap;
cap.damageFormula = requireFormula(wMt["damage_formula"],
file, wPath + ".damage_formula");
cap.attackRangeFormula = requireFormula(wMt["attack_range_formula"],
file, wPath + ".attack_range_formula");
cap.attackRateFormula = requireFormula(wMt["attack_rate_formula"],
file, wPath + ".attack_rate_formula");
def.weaponCapability = std::move(cap);
}
}
// Salvage capability section: [module.salvage] with base stat formulas
if (mt.contains("salvage"))
{
const std::string sPath = elemPath + ".salvage";
const toml::table& sTable = requireTable(mt["salvage"], file, sPath);
toml::table& sMt = const_cast<toml::table&>(sTable);
if (sMt.contains("collection_range_formula") || sMt.contains("cargo_capacity_formula"))
{
ModuleSalvageCapability cap;
cap.collectionRangeFormula = requireFormula(sMt["collection_range_formula"],
file, sPath + ".collection_range_formula");
cap.cargoCapacityFormula = requireFormula(sMt["cargo_capacity_formula"],
file, sPath + ".cargo_capacity_formula");
def.salvageCapability = std::move(cap);
}
}
// Repair capability section: [module.repair] with base stat formulas
if (mt.contains("repair"))
{
const std::string rPath = elemPath + ".repair";
const toml::table& rTable = requireTable(mt["repair"], file, rPath);
toml::table& rMt = const_cast<toml::table&>(rTable);
if (rMt.contains("repair_rate_formula") || rMt.contains("repair_range_formula"))
{
ModuleRepairCapability cap;
cap.repairRateFormula = requireFormula(rMt["repair_rate_formula"],
file, rPath + ".repair_rate_formula");
cap.repairRangeFormula = requireFormula(rMt["repair_range_formula"],
file, rPath + ".repair_range_formula");
def.repairCapability = std::move(cap);
}
}
cfg.modules.push_back(std::move(def));
}