#include "Roster.h" #include "Appearance.h" #include #include #include #include namespace bs { namespace { std::string str(const nlohmann::json& j, const char* key, const std::string& def = {}) { auto it = j.find(key); return it != j.end() && it->is_string() ? it->get() : def; } float num(const nlohmann::json& j, const char* key, float def) { auto it = j.find(key); return it != j.end() && it->is_number() ? it->get() : def; } } // namespace bool Roster::load(const std::string& path, std::string* error) { std::ifstream f(path); if (!f) { if (error) *error = "cannot open " + path; return false; } try { nlohmann::json j = nlohmann::json::parse(f); species_.clear(); for (const auto& s : j.at("species")) { Species sp; sp.id = s.at("id").get(); sp.slug = str(s, "slug"); sp.name = str(s, "name", sp.slug); sp.domain = str(s, "domain"); sp.type = str(s, "type", "normal"); sp.type2 = str(s, "type2"); sp.body = str(s, "body"); std::string r = str(s, "rarity", "common"); sp.rarity = r == "legendary" ? Rarity::Legendary : r == "rare" ? Rarity::Rare : r == "uncommon" ? Rarity::Uncommon : Rarity::Common; std::string h = str(s, "habitat", "grass"); sp.habitat = h == "water" ? Habitat::Water : h == "both" ? Habitat::Both : Habitat::Grass; sp.catchRate = num(s, "catchRate", 0.5f); sp.fleeRate = num(s, "fleeRate", 0.1f); if (s.contains("colors") && s["colors"].is_object()) { sp.mainColor = parseHexColor(str(s["colors"], "main", "#888888")); sp.accentColor = parseHexColor(str(s["colors"], "accent", "#cccccc")); } sp.sprite = str(s, "sprite"); sp.anchorRow = int(num(s, "anchorRow", 63.0f)); sp.retired = s.contains("retired") && s["retired"].is_boolean() && s["retired"].get(); species_.push_back(sp); } // ids index the vector directly std::sort(species_.begin(), species_.end(), [](const Species& a, const Species& b) { return a.id < b.id; }); for (size_t i = 0; i < species_.size(); ++i) if (species_[i].id != i) { if (error) *error = path + ": species ids must be 0..N-1"; return false; } } catch (const std::exception& e) { if (error) *error = path + ": " + e.what(); return false; } if (species_.empty()) { if (error) *error = path + ": no species"; return false; } return true; } const char* rarityName(Rarity r) { switch (r) { case Rarity::Uncommon: return "Uncommon"; case Rarity::Rare: return "Rare"; case Rarity::Legendary: return "Legendary"; default: return "Common"; } } uint32_t typeColor(const std::string& type) { static const std::map colors = { {"normal", 0xa8a878}, {"fire", 0xf08030}, {"water", 0x6890f0}, {"grass", 0x78c850}, {"electric", 0xf8d030}, {"ice", 0x98d8d8}, {"fighting", 0xc03028}, {"poison", 0xa040a0}, {"ground", 0xe0c068}, {"flying", 0xa890f0}, {"psychic", 0xf85888}, {"bug", 0xa8b820}, {"rock", 0xb8a038}, {"ghost", 0x705898}, {"dragon", 0x7038f8}, }; auto it = colors.find(type); return it == colors.end() ? 0xa8a878 : it->second; } } // namespace bs