#include "stock_designs.h" #include #include #include "game/data/common.h" #include "json_min.h" using namespace game::design; using json_min::Value; namespace { std::vector strings(const Value& v) { std::vector out; for (const Value& x : v.items) if (x.is_string()) out.push_back(x.str()); return out; } } // namespace bool load_stock_designs(const std::string& path, std::vector& out, std::string& err) { std::ifstream in(path, std::ios::binary); if (!in) { err = "cannot read " + path; return false; } std::ostringstream ss; ss << in.rdbuf(); Value root; if (!json_min::parse(ss.str(), root, err)) return false; if (!root.is_array()) { err = "expected a list of players"; return false; } int pi = 0; for (const Value& player : root.items) { int di = 0; for (const Value& d : player["designs"].items) { StockDesign sd; sd.player_index = pi; sd.design_index = di++; sd.save = player["save"].str(); sd.player = player["player"].str(); sd.npc = player["npc"].as_bool(); sd.race_text = d["race"].str(); sd.list = d["list"].str(); Design& des = sd.design; des.name = d["name"].str(); des.hidden = d["hidden"].as_bool(); des.designer_made = d["faiDes"].as_bool(); des.default_weapons = d["dWep"].as_int(); des.race = game::data::parse_species(sd.race_text); if (!d["known_techs"].is_null()) des.known_techs = strings(d["known_techs"]); // Three entries: command, mission, engine. Fixtures generated // before the reference reader stopped sweeping the design's Dtc and // Dwgv tail into the section list carry five, the last two empty; // both are accepted so an old fixture still loads. const Value& raw = d["raw_slots"]; if (!raw.is_array() || raw.items.size() < 3 || raw.items.size() > static_cast(kSlotCount)) { err = des.name + ": raw_slots must have 3 to " + std::to_string(kSlotCount) + " entries"; return false; } const int slots = static_cast(raw.items.size()); for (int i = 0; i < slots; ++i) { const Value& r = raw.items[static_cast(i)]; SectionUse& u = des.slots[static_cast(i)]; int species = r["species"].as_int(); u.section_id = r["section_id"].as_int(); if (species == 0 && u.section_id == 0) continue; // empty slot u.species = static_cast(species); const Value& weapons = r["weapons"]; const Value& riders = r["rider_design_ids"]; for (std::size_t w = 0; w < weapons.items.size(); ++w) { const Value& x = weapons.items[w]; WeaponRef ref; if (x.is_number()) ref = WeaponRef::by_id(x.as_int()); else if (x.is_string()) ref = WeaponRef::by_file(x.str()); if (w < riders.items.size()) ref.rider_design_id = riders.items[w].as_int(); u.weapons.push_back(ref); } u.options = strings(r["options"]); if (i < 3) { sd.dopts[static_cast(i)] = u.options; sd.bank_count[static_cast(i)] = r["bank_count"].as_int(); } } for (std::size_t i = 0; i < 3; ++i) { const Value& view = d[slot_name(kUsedSlots[i])]; if (view.is_null()) continue; sd.expect_stem[i] = view["section"].str(); sd.expect_options[i] = strings(view["options"]); } out.push_back(std::move(sd)); } ++pi; } return true; }