#pragma once #include "jsonable.h" #include "utils.h" #include #include #include #include #include #include namespace rules { class Ability : public Jsonable { public: std::string getFull() const {return abilities.at(getAbbrev());} std::string getAbbrev() const {return abbrev;} operator std::string() const {return getAbbrev();} virtual nlohmann::json toJson(void) const { return getAbbrev(); } bool operator<(const Ability& rhs) const {return getAbbrev() < rhs.getAbbrev();} bool operator==(const Ability& rhs) const {return getAbbrev() == rhs.getAbbrev();} operator bool() const {return ! getAbbrev().empty();} Ability() {} explicit Ability(const nlohmann::json& data) : abbrev(data) { if(! abilities.contains(abbrev)) { throw std::invalid_argument("No such ability: " + abbrev); } } virtual ~Ability() {} static Ability Str() {return Ability("str");} static Ability Dex() {return Ability("dex");} static Ability Con() {return Ability("con");} static Ability Int() {return Ability("int");} static Ability Wis() {return Ability("wis");} static Ability Cha() {return Ability("cha");} static Ability fromString(std::string s) { utils::lower(s); for(auto [abbrev, full] : abilities) { utils::lower(full); if(s == abbrev || s == full) { return Ability(abbrev); } } throw std::invalid_argument("Cannot find an ability for input: \"" + s + "\""); } private: const std::string abbrev; static const std::map abilities; }; class Skill : public Jsonable { public: std::string getName() const {return name;} Ability getAbility() const {return Ability(skill2ability.at(getName()));} operator std::string() const {return getName();} virtual nlohmann::json toJson(void) const { return getName(); } bool operator<(const Skill& rhs) const {return getName() < rhs.getName();} bool operator==(const Skill& rhs) const {return getName() == rhs.getName();} operator bool() const {return ! getName().empty();} virtual ~Skill() {} static Skill Athletics() {return Skill("Athletics");} static Skill Acrobatics() {return Skill("Acrobatics");} static Skill SleightOfHand() {return Skill("Sleight of Hand");} static Skill Stealth() {return Skill("Stealth");} static Skill Arcana() {return Skill("Arcana");} static Skill History() {return Skill("History");} static Skill Investigation() {return Skill("Investigation");} static Skill Nature() {return Skill("Nature");} static Skill Religion() {return Skill("Religion");} static Skill AnimalHandling() {return Skill("Animal Handling");} static Skill Insight() {return Skill("Insight");} static Skill Medicine() {return Skill("Medicine");} static Skill Perception() {return Skill("Perception");} static Skill Survival() {return Skill("Survival");} static Skill Deception() {return Skill("Deception");} static Skill Intimidation() {return Skill("Intimidation");} static Skill Performance() {return Skill("Performance");} static Skill Persuasion() {return Skill("Persuasion");} Skill() {}; explicit Skill(const nlohmann::json& data) : name(data) { if(! skill2ability.contains(name)) { throw std::invalid_argument("No such skill: " + name); } } static Skill fromString(std::string s) { utils::lower(s); for(auto& [name, _] : skill2ability) { std::string n = name; utils::lower(n); if(s == n) { return Skill(name); } } throw std::invalid_argument("Cannot find a skill for input: \"" + s + "\""); } private: const std::string name; static const std::map skill2ability; }; class Qualifier : public Jsonable { public: Qualifier() {} Qualifier(const nlohmann::json& data) : negative(data) { if(! negative2positive.contains(negative)) { throw std::invalid_argument("No such qualifier: " + negative); } } std::string getNegative() const {return negative;} std::string getPositive() const {return negative2positive.at(getNegative());} operator std::string() const {return getNegative();} virtual nlohmann::json toJson(void) const { return getNegative(); } virtual ~Qualifier() {} bool operator==(const Qualifier& rhs) const {return getNegative() == rhs.getNegative();} static Qualifier Magical() {return Qualifier("nonmagical");} static Qualifier Silvered() {return Qualifier("non-silvered");} static Qualifier Adamantine() {return Qualifier("non-adamantine");} private: const std::string negative; static const std::map negative2positive; }; std::ostream& operator<<(std::ostream& os, const Ability& a); std::ostream& operator<<(std::ostream& os, const Skill& s); std::ostream& operator<<(std::ostream& os, const Qualifier& q); template T tryGetAbilityOrSkill(std::string src) { try { return T::fromString(src); } catch(std::exception& e) {} // eat. return T(); } }