#pragma once #include #include "entry.h" #include "defines.h" #include #include #include #include #include #include #include #include namespace nlohmann { template struct adl_serializer> { static void to_json(json& j, const std::shared_ptr& opt) { if(opt) { j = opt->serialize(); } else { j = nullptr; } } static void from_json(const json& j, std::shared_ptr& opt) { opt = std::shared_ptr(T::create(j)); } }; template struct adl_serializer> { static void to_json(json& j, const std::optional& opt) { if(opt) { j = *opt; } else { j = nullptr; } } static void from_json(const json& j, std::optional& opt) { if(j.is_null()) { opt = std::optional(); } else { opt = j.get(); } } }; } namespace utils { nlohmann::json loadJson(const std::filesystem::path& path); // Recursively loads all .json files under directory // If called multiple times with same directory, returns a cached result. std::vector loadAllJson(const std::string& directory); // looks up directory in settings. Returns element matching name. nlohmann::json loadJson(const std::string& type, const std::string& name); // goes through the available types and searches for the one matching name. nlohmann::json findByName(const std::string& name); void saveJson(const nlohmann::json& data, const std::filesystem::path& path); // converts in-place std::string lower(std::string& in); template std::shared_ptr instantiate(const std::filesystem::path& path) { std::shared_ptr ent; try { ent = entry::Entry::create(loadJson(path)); } catch(std::exception& e) { if(std::filesystem::directory_entry(path).exists()) { throw std::runtime_error("Invalid json: " + path.string() + ": " + e.what()); } else { throw std::runtime_error("No such file nor directory: " + path.string()); } } std::shared_ptr t = std::dynamic_pointer_cast(ent); if(! t) { throw std::runtime_error("Wrong instance type: " + ent->getType()); } return t; } int parseInt(const std::string& s); template std::shared_ptr loadDFromJson(const nlohmann::json& data) { nlohmann::json j = data; try { j = loadJson(data["type"], data["name"]); } catch(std::exception& e) { // Covers errors in building the creature or fs traversal. // Fall back on the data passed in. } D *d = new D(); from_json(j, *d); d->init(); return std::shared_ptr(d); } template std::vector> castPtrs(std::vector> from) { std::vector> Ts; for(std::shared_ptr f : from) { std::shared_ptr t = std::dynamic_pointer_cast(f); if(t) { Ts.push_back(t); } } return Ts; } template std::string join(Container parts, std::string joiner) { std::stringstream out; bool isFirst = true; for(auto p : parts) { if(! isFirst) { out << joiner; } isFirst = false; out << p; } return out.str(); } const std::map cpValue { {"cp", 1}, {"sp", 10}, {"ep", 50}, {"gp", 100}, {"pp", 1000} }; // Accepts coins formatted "X Yp" where X is an integer and Y is any of c, s, e, g, p. int coins2copper(const std::string& coins); // Greedily selects highest coin values to minimize total number of coins // Returns a vector of pairs mapping coin type to coint std::vector> copper2coins(int coppers); std::string getCostString(int coppers); std::string toOrdinal(std::size_t number); template std::vector json2vec(const nlohmann::json& data) { using std::begin; using std::end; return std::vector(begin(data), end(data)); } template std::vector> instantiateNames(const std::string& type, const std::vector& names) { std::vector> ret; for(auto name : names) { ret.push_back(loadDFromJson(utils::loadJson(type, name))); } return ret; } }