diff options
author | Your Name <you@example.com> | 2021-04-19 13:46:14 -0400 |
---|---|---|
committer | Your Name <you@example.com> | 2021-04-19 13:46:14 -0400 |
commit | 2cae1aa33f80ce0844fb54a84ce103146a7fe7ad (patch) | |
tree | 26945223a2672c5a80975a7b1998622da6edcc28 /src | |
parent | 4618763c0e3a723bf4bb43c7b9edbce87240e0af (diff) | |
download | dmtool-2cae1aa33f80ce0844fb54a84ce103146a7fe7ad.tar.gz dmtool-2cae1aa33f80ce0844fb54a84ce103146a7fe7ad.tar.bz2 dmtool-2cae1aa33f80ce0844fb54a84ce103146a7fe7ad.zip |
Started earnest work on cli
Diffstat (limited to 'src')
-rw-r--r-- | src/creature.cc | 118 | ||||
-rw-r--r-- | src/creature.h | 10 | ||||
-rw-r--r-- | src/dmtool.cc | 72 | ||||
-rw-r--r-- | src/rules.h | 88 | ||||
-rw-r--r-- | src/settings.cc | 41 | ||||
-rw-r--r-- | src/settings.h | 7 | ||||
-rw-r--r-- | src/test.cc | 53 | ||||
-rw-r--r-- | src/utils.cc | 2 | ||||
-rw-r--r-- | src/utils.h | 1 |
9 files changed, 254 insertions, 138 deletions
diff --git a/src/creature.cc b/src/creature.cc index 13b54d3..53a4994 100644 --- a/src/creature.cc +++ b/src/creature.cc @@ -7,13 +7,15 @@ #include "armor.h" #include <algorithm> #include <iostream> +#include <sstream> +#include <iomanip> typedef nlohmann::json json; using namespace std; namespace creature { Creature::Creature(const json& data) - : inventory(json2ptrvec<entry::Item>(data["inventory"])), creatureName(data["name"]), size(data["size"]), type(data["type"]), alignment(data["alignment"]), hdCount(data["hit_die_count"]), hdSides(data["hit_die_sides"]), speed(data["speed"]), stats(data["stats"]), skills(data["skills"]), saves(data["saves"]), langs(data["langs"]), cr(data["cr"]), proficiency(data["prof"]), dmgImmunities(json2vec<dmgType>(data["d_immunities"])), dmgResistances(json2vec<dmgType>(data["d_resistances"])), dmgVulnerabilities(json2vec<dmgType>(data["d_vulnerabilities"])), condImmunities(json2vec<dmgType>(data["c_immunities"])), features(json2ptrvec<entry::Feature>(data["features"])) + : inventory(json2ptrvec<entry::Item>(data["inventory"])), stats(data["stats"]), skills(data["skills"]), creatureName(data["name"]), size(data["size"]), type(data["type"]), alignment(data["alignment"]), hdCount(data["hit_die_count"]), hdSides(data["hit_die_sides"]), speed(data["speed"]), saves(data["saves"]), langs(data["langs"]), cr(data["cr"]), proficiency(data["prof"]), dmgImmunities(json2vec<dmgType>(data["d_immunities"])), dmgResistances(json2vec<dmgType>(data["d_resistances"])), dmgVulnerabilities(json2vec<dmgType>(data["d_vulnerabilities"])), condImmunities(json2vec<dmgType>(data["c_immunities"])), features(json2ptrvec<entry::Feature>(data["features"])) { // Initialize names and hp if(((map<string, json>) data).contains("givenName")) { @@ -37,32 +39,32 @@ namespace creature { } return ret; } - + nlohmann::json Creature::toJson() const { return nlohmann::json({ - {"name", creatureName}, - {"size", size}, - {"type", type}, - {"alignment", alignment}, - {"hit_die_count", hdCount}, - {"hit_die_sides", hdSides}, - {"speed", speed}, - {"stats", stats}, - {"skills", skills}, - {"saves", saves}, - {"langs", langs}, - {"cr", cr}, - {"prof", proficiency}, - {"d_immunities", dmgImmunities}, - {"d_resistances", dmgResistances}, - {"d_vulnerabilities", dmgVulnerabilities}, - {"c_immunities", condImmunities}, - {"givenName", givenName}, - {"hpMax", hpMax}, - {"hp", hp}, - {"inventory", getJsonVectP(inventory)}, - {"features", getJsonVectP(features)} - }); + {"name", creatureName}, + {"size", size}, + {"type", type}, + {"alignment", alignment}, + {"hit_die_count", hdCount}, + {"hit_die_sides", hdSides}, + {"speed", speed}, + {"stats", stats}, + {"skills", skills}, + {"saves", saves}, + {"langs", langs}, + {"cr", cr}, + {"prof", proficiency}, + {"d_immunities", dmgImmunities}, + {"d_resistances", dmgResistances}, + {"d_vulnerabilities", dmgVulnerabilities}, + {"c_immunities", condImmunities}, + {"givenName", givenName}, + {"hpMax", hpMax}, + {"hp", hp}, + {"inventory", getJsonVectP(inventory)}, + {"features", getJsonVectP(features)} + }); } // True if type without matching qualifiers is in subdata @@ -94,7 +96,7 @@ namespace creature { } int Creature::getSkillBonus(const string& skill) const { - int bonus = this->getBonus(skill2ability[skill]); + int bonus = this->getBonus(rules::skill2ability[skill]); if(skills.contains(skill)) { bonus += skills.at(skill) * getProficiency(); } @@ -138,6 +140,14 @@ namespace creature { return s; } + void Creature::setScore(const string& ability, int score) { + stats[ability] = score; + } + + void Creature::setProfLevel(const string& skill, int level) { + skills[skill] = level; + } + const int getAC(const Creature& c) { int baseBonus = 10 + c.getBonus("dex"); int miscBonus = 0; @@ -159,4 +169,60 @@ namespace creature { } return baseBonus + miscBonus; } + + template<typename T> vector<string> mapItems(const vector<shared_ptr<T>>& items) { + vector<string> out; + for(auto i : items) { + out.push_back(i->getName()); + } + return out; + } + + string genText(const Creature& c) { + stringstream text; + text << c.getGivenName() << " (" << c.getCreatureName() << "): " << c.getHP() << "/" << c.getHPMax() << " hp, " << getAC(c) << " ac"; + string armor = utils::join(mapItems(creature::getItems<entry::Armor>(c)), ", "); + if(! armor.empty()) { + text << " (" << armor << ")"; + } + text << ", speed " << c.getSpeed() << "\n"; + text << "A cr " << c.getCR() << " " << c.getAlignment() << " " << c.getSize() << " " << c.getType() << ".\n"; + text << "Stats:\n"; + //text << setiosflags(ios::fixed) << setw(6); + for(auto ability : rules::abilities) { + text << " " << setw(6) << std::left << ability; + } + text << "\n"; + for(auto ability : rules::abilities) { + text << setw(7) << std::left << (to_string(c.getScore(ability)) + "(" + to_string(c.getBonus(ability)) + ")"); + } + text << "\n"; + text << "Senses: "; + if(! c.getSenses().empty()) { + text << utils::join(c.getSenses(), ", ") << ". "; + } + text << "Passive Perception " << 10 + c.getBonus("wis") << "\n"; + if(! c.getLanguages().empty()) { + text << "Languages: " << c.getLanguages() << "\n"; + } + + text << "\nSkills:\n"; + for(auto skill : c.getSkills()) { + text << skill.first << " (+" << skill.second << ")\n"; + } + text << "\nSaves:\n"; + for(auto save : c.getSaves()) { + text << save.first << " (+" << save.second << ")\n"; + } + text << "\nFeatures:\n"; + for(auto f: c.getFeatures()) { + text << f->getText(c) << "\n"; + } + text << "\nInventory:\n"; + for(auto i : c.getInventory()) { + text << i->getText(c) << "\n"; + } + + return text.str(); + } } diff --git a/src/creature.h b/src/creature.h index fee7c35..7327de9 100644 --- a/src/creature.h +++ b/src/creature.h @@ -61,7 +61,8 @@ namespace creature { // Setters (mutators) void setGivenName(std::string name) {givenName = name;} void applyDamage(int amount, const std::string& type, const std::vector<std::string>& qualifiers); - //void setScore(const std::string& ability, int score); + void setScore(const std::string& ability, int score); + void setProfLevel(const std::string& skill, int level); void addInventoryItem(std::shared_ptr<entry::Item> item); void removeInventoryItem(const std::string& itemName); @@ -73,6 +74,8 @@ namespace creature { int hpMax; int hp; std::vector<std::shared_ptr<entry::Item>> inventory; + std::map<std::string, int> stats; + std::map<std::string, int> skills; //Immutable variables const std::string creatureName; @@ -82,8 +85,6 @@ namespace creature { const int hdCount; const int hdSides; const std::string speed; - const std::map<std::string, int> stats; - const std::map<std::string, int> skills; const std::vector<std::string> saves; const std::vector<std::string> senses; const std::string langs; @@ -111,4 +112,7 @@ namespace creature { // Convenience function to calculate AC const int getAC(const Creature& c); + + // Convenience function to spit out everything about it + std::string genText(const Creature& c); } diff --git a/src/dmtool.cc b/src/dmtool.cc index 5c322e3..7f2c72c 100644 --- a/src/dmtool.cc +++ b/src/dmtool.cc @@ -1,23 +1,26 @@ #include "creature.h" -#include "feature.h" +#include "settings.h" #include <iostream> +#include <vector> +#include <string> +#include <filesystem> using namespace std; +namespace fs = std::filesystem; + void usage(string exename) { cout << "Usage:\n"; string indOpt = " " + exename + " "; string indDesc = " "; cout << indOpt << "[ls] [subfolder]\n"; cout << indDesc << "List creatures and objects.\n"; - cout << indOpt << "[print] path\n"; - cout << indDesc << "Print existing creature or object.\n"; cout << indOpt << "cp old-path new-path\n"; cout << indDesc << "Copy old-path to new-path.\n"; - cout << indOpt << "rm [--recursive,-r] path\n"; + cout << indOpt << "rm path\n"; cout << indDesc << "Remove existing creature, object, or directory.\n"; - cout << indOpt << "roll [--advantage,-a] path name\n"; - cout << indDesc << "Roll, optionally with advantage, a skill check, save, or attack.\n"; + cout << indOpt << "roll path name\n"; + cout << indDesc << "Roll a skill check, save, or attack.\n"; cout << indOpt << "damage path amount [type]\n"; cout << indDesc << "Damage creature by amount. Type defaults to \"force\".\n"; cout << indOpt << "set path field value\n"; @@ -31,3 +34,60 @@ void usage(string exename) { cout << indOpt << "help\n"; cout << indDesc << "Show this help.\n"; } + +void list(vector<string> args) { + string baseDir = settings::getString("savedir"); + vector<string> listPaths; + if(args.empty()) { + listPaths.push_back(baseDir); + } else { + for(auto dir : args) { + listPaths.push_back(baseDir + "/" + dir); + } + } + for(auto listPath : listPaths) { + if(fs::is_regular_file(fs::status(listPath))) { + // Try loading and printing stuff about it + creature::Creature c(utils::loadJson(listPath)); + cout << genText(c); + } + else if(fs::is_directory(fs::status(listPath))) { + for(fs::directory_entry path : filesystem::directory_iterator(listPath)) { + cout << path.path().filename().string(); + if(path.is_directory()) { + cout << "/"; + } + cout << "\n"; + } + } + } +} + +void cp(vector<string> args) {} +void rm(vector<string> args) {} +void roll(vector<string> args) {} +void damage(vector<string> args) {} +void set(vector<string> args) {} +void add(vector<string> args) {} + +int main(int argc, char *argv[]) { + string exename = argv[0]; + vector<string> args(&argv[1], &argv[argc]); + if(args.empty()) { + list(args); + return 0; + } + string cmd = args[0]; + vector<string> argsOrig(args); + args.erase(args.begin()); + if(cmd == "ls") list(args); + else if(cmd == "cp") cp(args); + else if(cmd == "rm") rm(args); + else if(cmd == "roll") roll(args); + else if(cmd == "damage") damage(args); + else if(cmd == "set") set(args); + else if(cmd == "add") add(args); + else if(cmd == "help") usage(exename); + else list(argsOrig); + return 0; +} diff --git a/src/rules.h b/src/rules.h index d61b176..c1cc6e1 100644 --- a/src/rules.h +++ b/src/rules.h @@ -4,50 +4,54 @@ using namespace std; -static vector<string> abilities {"str", "dex", "con", "int", "wis", "cha"}; +namespace rules { -static map<string, string> skill2ability { + static vector<string> abilities {"str", "dex", "con", "int", "wis", "cha"}; + + static map<string, string> skill2ability { {"Athletics", "str"}, - {"Acrobatics", "dex"}, - {"Sleight of Hand", "dex"}, - {"Stealth", "dex"}, - {"Arcana", "int"}, - {"History", "int"}, - {"Investigation", "int"}, - {"Nature", "int"}, - {"Religion", "int"}, - {"Animal Handling", "wis"}, - {"Insight", "wis"}, - {"Medicine", "wis"}, - {"Perception", "wis"}, - {"Survival", "wis"}, - {"Deception", "cha"}, - {"Intimidation", "cha"}, - {"Performance", "cha"}, - {"Persuasion", "cha"} -}; + {"Acrobatics", "dex"}, + {"Sleight of Hand", "dex"}, + {"Stealth", "dex"}, + {"Arcana", "int"}, + {"History", "int"}, + {"Investigation", "int"}, + {"Nature", "int"}, + {"Religion", "int"}, + {"Animal Handling", "wis"}, + {"Insight", "wis"}, + {"Medicine", "wis"}, + {"Perception", "wis"}, + {"Survival", "wis"}, + {"Deception", "cha"}, + {"Intimidation", "cha"}, + {"Performance", "cha"}, + {"Persuasion", "cha"} + }; -static map<string, map<string, int>> armor { + static map<string, map<string, int>> armor { {"light", { - {"padded", 11}, - {"leather", 11}, - {"studded leather", 12} - }}, - {"medium", { - {"hide", 12}, - {"chain shirt", 13}, - {"scale mail", 14}, - {"breastplate", 14}, - {"half plate", 15} - }}, - {"heavy", { - {"ring mail", 14}, - {"chain mail", 16}, - {"splint", 17}, - {"plate", 18} + {"padded", 11}, + {"leather", 11}, + {"studded leather", 12} }}, - {"misc", { - {"shield", 2}, - {"ring of protection", 1} - }} -}; + {"medium", { + {"hide", 12}, + {"chain shirt", 13}, + {"scale mail", 14}, + {"breastplate", 14}, + {"half plate", 15} + }}, + {"heavy", { + {"ring mail", 14}, + {"chain mail", 16}, + {"splint", 17}, + {"plate", 18} + }}, + {"misc", { + {"shield", 2}, + {"ring of protection", 1} + }} + }; + +} diff --git a/src/settings.cc b/src/settings.cc new file mode 100644 index 0000000..e9a6165 --- /dev/null +++ b/src/settings.cc @@ -0,0 +1,41 @@ +#include "settings.h" +#include <map> +#include <cstdlib> +#include <regex> + +namespace settings { + const std::map<std::string, std::string> dummySettings { + {"weapon", "parser/items/weapons/"}, + {"armor", "parser/items/armor/"}, + {"spellcasting", "parser/spells/"}, + {"savedir", "~/.dmtool/"} + }; + + + // Update the input string. + // Obtained from https://stackoverflow.com/a/23442780 + void autoExpandEnvironmentVariables(std::string& text) { + std::size_t tilde; + while((tilde = text.find("~")) != std::string::npos) { + text.replace(tilde, tilde+1, "${HOME}"); + } + static std::regex env("\\$(?:\\{([^}]+)\\}|([^/]+))"); + std::smatch match; + while(std::regex_search(text, match, env)) { + std::string matchStr = match[1].str().empty()? match[2].str() : match[1].str(); + auto s = getenv(matchStr.c_str()); + const std::string var(s == NULL? "" : s); + text.replace(match[0].first, match[0].second, var); + } + } + + // Returns the setting, or an empty string in the case of an error + std::string getString(const std::string& key) { + if(! dummySettings.contains(key)) { + return ""; + } + std::string ret = dummySettings.at(key); + autoExpandEnvironmentVariables(ret); + return ret; + } +} diff --git a/src/settings.h b/src/settings.h index 43eeb07..a2312df 100644 --- a/src/settings.h +++ b/src/settings.h @@ -1,11 +1,6 @@ #pragma once #include <string> -#include <map> namespace settings { - const std::map<std::string, std::string> dummySettings { - {"weapon", "parser/items/weapons/"}, - {"armor", "parser/items/armor/"}, - {"spellcasting", "parser/spells"} - }; + std::string getString(const std::string& key); } diff --git a/src/test.cc b/src/test.cc deleted file mode 100644 index 3c47537..0000000 --- a/src/test.cc +++ /dev/null @@ -1,53 +0,0 @@ -#include "creature.h" -#include "feature.h" -#include <iostream> -#include <sstream> -#include "rules.h" -#include "utils.h" -#include "item.h" -#include "armor.h" -#include "weapon.h" -#include "spellcasting.h" - -using namespace std; - -template<typename T> vector<string> mapItems(const vector<shared_ptr<T>>& items) { - vector<string> out; - for(auto i : items) { - out.push_back(i->getName()); - } - return out; -} - -int main(int argc, char *argv[]) { - creature::Creature c(utils::loadJson(argv[argc-1])); - cout << c.getCreatureName() << " " << c.getGivenName() << ", a cr " << c.getCR() << " " << c.getAlignment() << " " << c.getSize() << " " << c.getType() << ", has " << c.getHP() << " hp, ac " << creature::getAC(c) << " (" << utils::join(mapItems(creature::getItems<entry::Armor>(c)), ", ") << "), speaks " << c.getLanguages() << ", has " << utils::join(c.getSenses(), ", ") << ", speed " << c.getSpeed() << ", and wields " << utils::join(mapItems(creature::getItems<entry::Weapon>(c)), ", ") << ".\n Stats:\n"; - for(auto ability : abilities) { - cout << ability << ": " << c.getScore(ability) << " (" << c.getBonus(ability) << ")\n"; - } - cout << "\nSkills:\n"; - for(auto skill : c.getSkills()) { - cout << skill.first << " (+" << skill.second << ")\n"; - } - cout << "\nSaves:\n"; - for(auto save : c.getSaves()) { - cout << save.first << " (+" << save.second << ")\n"; - } - cout << "\nFeatures:\n"; - for(auto f: c.getFeatures()) { - cout << f->getText(c) << "\n"; - } - cout << "\nInventory:\n"; - for(auto i : c.getInventory()) { - cout << i->getText(c) << "\n"; - } - - cout << "\nWe strike him with mace, dealing 5 fire damage!\n"; - c.applyDamage(5, "fire", vector<string>()); - cout << "Now he has " << c.getHP() << " out of " << c.getHPMax() << " hp.\n"; - - //cout << "Increasing str by 4...\n"; - //c.setScore("str", c.getScore("str") + 4); - cout << "Saving to out.json...\n"; - utils::saveJson(c.toJson(), "out.json"); -} diff --git a/src/utils.cc b/src/utils.cc index 1df3308..d071fe6 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -17,7 +17,7 @@ nlohmann::json utils::loadJson(const std::string& path) { } nlohmann::json utils::loadJson(const std::string& type, const std::string& name) { - for(auto data : utils::loadAllJson(settings::dummySettings.at(type))) { + for(auto data : utils::loadAllJson(settings::getString(type))) { if(data["name"] == name) { return data; } diff --git a/src/utils.h b/src/utils.h index 9f4cf5c..156c88b 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,6 +1,5 @@ #pragma once #include "json.hpp" -#include "settings.h" #include <string> #include <vector> #include <map> |