aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYour Name <you@example.com>2021-04-19 13:46:14 -0400
committerYour Name <you@example.com>2021-04-19 13:46:14 -0400
commit2cae1aa33f80ce0844fb54a84ce103146a7fe7ad (patch)
tree26945223a2672c5a80975a7b1998622da6edcc28 /src
parent4618763c0e3a723bf4bb43c7b9edbce87240e0af (diff)
downloaddmtool-2cae1aa33f80ce0844fb54a84ce103146a7fe7ad.tar.gz
dmtool-2cae1aa33f80ce0844fb54a84ce103146a7fe7ad.tar.bz2
dmtool-2cae1aa33f80ce0844fb54a84ce103146a7fe7ad.zip
Started earnest work on cli
Diffstat (limited to 'src')
-rw-r--r--src/creature.cc118
-rw-r--r--src/creature.h10
-rw-r--r--src/dmtool.cc72
-rw-r--r--src/rules.h88
-rw-r--r--src/settings.cc41
-rw-r--r--src/settings.h7
-rw-r--r--src/test.cc53
-rw-r--r--src/utils.cc2
-rw-r--r--src/utils.h1
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>