// game::data -- ShipSectionDef: one `Species//sections/*.shipsection`. // // shipsection { // model PATH requires TECH... section_type command|mission|engine // section_class destroyer|cruiser|dreadnought // health mass cost cpoints crew socket_fore/socket_aft NODE // option TECH -- one-member option group // option { option A option B } -- mutually exclusive option group // optiondef { option ... } -- shield-level group (shield sections) // bank { turretclass C turretsize S [weapon FILE] mount { node N min/max_azimuth min/max_inclination } ... } // ftlspeed nodespeed engine_techera netforcelimits { force_* torque_* speed rotspeed } // thruster { node effect idle_effect } // } // // `options` is the normalised view of every `option` entry in file order: // a scalar `option T` becomes a one-member group, a block keeps its members. // `section_type` / `section_class` are case-mixed in the data; the enums are // derived case-insensitively and the text is kept as written. #pragma once #include #include #include #include #include #include "game/data/block.h" #include "game/data/common.h" #include "mars/parse/blocks.h" namespace game::data { enum class SectionType { None, Command, Mission, Engine, Other }; enum class SectionClass { None, Destroyer, Cruiser, Dreadnought, Other }; std::string_view section_type_name(SectionType t); std::string_view section_class_name(SectionClass c); SectionType parse_section_type(std::string_view s); SectionClass parse_section_class(std::string_view s); struct OptionGroup { std::vector members; // tech names, file order bool scalar = false; // written as `option T` (one member) int line = 0; }; struct MountDef { std::string node; std::optional min_azimuth, max_azimuth, min_inclination, max_inclination; std::optional home_azimuth, home_inclination; int line = 0; }; struct BankDef { std::string turret_class; // last value if the key repeats std::string turret_size; std::string weapon; // fixed weapon file (NPC banks); "" when the design chooses std::optional show_turrets, invincible; std::vector mounts; bool repeated_turret_spec = false; // turretsize/turretclass written more than once int line = 0; }; struct NetForceLimits { std::optional force_forward, force_right, force_up; std::optional torque_yaw, torque_pitch, torque_roll; std::optional speed, rotspeed; }; struct ThrusterDef { std::string node, effect, idle_effect; }; struct ShipSectionDef { // identity (filled by the catalog) std::string race; // directory name under Species/ Species species = Species::Unknown; std::string stem; std::string file; std::optional id; // from the race's _shipsections.txt std::optional display_name, description; std::vector unlocked_by; // techs whose ship{section} lists this stem // body std::string model, dam_model; std::vector requires_tech; // AND; may name GRP_ std::string section_type_text; SectionType section_type = SectionType::None; std::string section_class_text; SectionClass section_class = SectionClass::None; std::string design_class, entity_class; std::optional health, mass; std::optional cost, cpoints, crew; std::optional command_cost, maintenance_cost, command_quota; std::string socket_fore, socket_aft, dam_socket_fore, dam_socket_aft; std::vector options; std::optional optiondef; std::vector banks; std::optional ftlspeed, nodespeed, range, scanrange, tactical_sensor_range; std::string engine_techera; std::optional netforcelimits; std::vector thrusters; std::vector exclude; std::string explicit_command_section, explicit_engine_section; std::optional explicit_section, autonomous, nodesign; Block raw; bool has_sockets() const { return !socket_fore.empty() || !socket_aft.empty(); } }; Loaded load_shipsection(const mars::parse::Document& doc, std::string file = {}); Loaded parse_shipsection(std::string_view text, std::string file = {}); } // namespace game::data