aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--files/dmtool.bash11
-rw-r--r--src/cmd/cmd.h1
-rw-r--r--src/cmd/cmd_manipulate.cc102
-rw-r--r--src/cmd/cmd_usage.cc4
-rw-r--r--src/dmtool.cc2
-rw-r--r--src/entry.cc4
-rw-r--r--src/entry.h2
-rw-r--r--src/item.cc4
-rw-r--r--src/item.h2
-rw-r--r--src/utils.cc8
-rw-r--r--src/utils.h4
11 files changed, 130 insertions, 14 deletions
diff --git a/files/dmtool.bash b/files/dmtool.bash
index 0d7116f..677eb03 100644
--- a/files/dmtool.bash
+++ b/files/dmtool.bash
@@ -86,7 +86,7 @@ _dmtool()
{
COMPREPLY=()
local cur="${COMP_WORDS[COMP_CWORD]}"
- local commands="ls cp mkdir mv rm attacks roll attack damage heal save reset set edit add del spellcasting help git"
+ local commands="ls cp mkdir mv rm attacks roll attack damage heal save reset set edit add del spellcasting create help git"
if [[ $COMP_CWORD -gt 1 ]]; then
local lastarg="${COMP_WORDS[$COMP_CWORD-1]}"
case "${COMP_WORDS[1]}" in
@@ -114,7 +114,7 @@ _dmtool()
_dmtool_complete_entries
fi
;;
- attacks|roll|attack|damage|heal|save|set|edit|del|spellcasting)
+ attacks|roll|attack|damage|heal|save|set|edit|del|create|spellcasting)
if [[ $COMP_CWORD -le 2 ]]; then
_dmtool_complete_entries
else
@@ -146,7 +146,7 @@ _dmtool()
set)
if [[ $COMP_CWORD -eq 3 ]]; then
_dmtool_complete_skills_abilities
- COMPREPLY+=($(compgen -W "proficiency name" -- ${cur}))
+ COMPREPLY+=($(compgen -W "proficiency name cost weight" -- ${cur}))
elif [[ $COMP_CWORD -eq 4 ]]; then
local skills="$(_dmtool_skills)"
if [[ "$skills" =~ "$lastarg" ]]; then
@@ -158,6 +158,11 @@ _dmtool()
#TODO: Add items and spells
_dmtool_complete_skills_abilities
;;
+ create)
+ if [[ $COMP_CWORD -eq 3 ]]; then
+ COMPREPLY+=($(compgen -W "item weapon armor spell feature feature_attack creature" -- ${cur}))
+ fi
+ ;;
spellcasting)
if [[ $COMP_CWORD -eq 3 ]]; then
COMPREPLY+=($(compgen -W "init ability level" -- ${cur}))
diff --git a/src/cmd/cmd.h b/src/cmd/cmd.h
index ff96b32..1763f95 100644
--- a/src/cmd/cmd.h
+++ b/src/cmd/cmd.h
@@ -29,6 +29,7 @@ namespace cmd {
std::string del(std::vector<std::string> args);
std::string edit(std::vector<std::string> args);
std::string spellcasting(std::vector<std::string> args);
+ std::string create(std::vector<std::string> args);
std::string git(std::vector<std::string> args);
//Queries
diff --git a/src/cmd/cmd_manipulate.cc b/src/cmd/cmd_manipulate.cc
index 904615b..f0d3fc4 100644
--- a/src/cmd/cmd_manipulate.cc
+++ b/src/cmd/cmd_manipulate.cc
@@ -44,7 +44,7 @@ namespace cmd {
} else {
c->applyDamage(amnt, dmgType, qualifiers);
}
- utils::saveJson(*c, p);
+ utils::saveJson(c->serialize(), p);
return formatHealingDamage(c, initHP, heal, amnt, dmgType, qualifiers);
}
@@ -159,7 +159,7 @@ namespace cmd {
if(flags.find("damage") != flags.end() and (halves or ! passed)) {
text << formatHealingDamage(c, initHP, false, damage, type, parseQualifiers(flags));
}
- utils::saveJson(*c, p);
+ utils::saveJson(c->serialize(), p);
}
return text.str();
}
@@ -169,7 +169,7 @@ namespace cmd {
fs::path p = getTruePath(s);
auto c = utils::instantiate<creature::Creature>(p);
c->longRest();
- utils::saveJson(*c, p);
+ utils::saveJson(c->serialize(), p);
}
return "";
}
@@ -180,13 +180,32 @@ namespace cmd {
}
fs::path p = getTruePath(args[0]);
args.erase(args.begin()); // remove path from args
- auto c = utils::instantiate<creature::Creature>(p);
if(args[0] == "name") {
args.erase(args.begin()); // remove "name" from args
- c->setGivenName(utils::join(args, " "));
+ auto newname = utils::join(args, " ");
+ auto e = utils::instantiate<entry::Entry>(p);
+ if(e->getEntryType() == "creatures") { // creature, we should do given name instead
+ auto c = utils::instantiate<creature::Creature>(p);
+ c->setGivenName(newname);
+ utils::saveJson(c->serialize(), p);
+ } else { // Standard entry, no given name so we set name
+ e->setName(newname);
+ utils::saveJson(e->serialize(), p);
+ }
} else if(args[0] == "proficiency") {
+ auto c = utils::instantiate<creature::Creature>(p);
c->setProficiency(utils::parseInt(args[1]));
+ utils::saveJson(c->serialize(), p);
+ } else if(args[0] == "cost") {
+ auto i = utils::instantiate<entry::Item>(p);
+ i->setCost(utils::parseInt(args[1]));
+ utils::saveJson(i->serialize(), p);
+ } else if(args[0] == "weight") {
+ auto i = utils::instantiate<entry::Item>(p);
+ i->setWeight(utils::parseDouble(args[1]));
+ utils::saveJson(i->serialize(), p);
} else {
+ auto c = utils::instantiate<creature::Creature>(p);
// Either an ability or a skill. If skill, then it could be multiple words long.
std::string toSet = args.back();
args.erase(--args.end());
@@ -209,8 +228,8 @@ namespace cmd {
} else {
throw std::runtime_error("Subcommand 'set' expected an ability, skill, proficiency, or name field to set, but was given " + abilityOrSkill);
}
+ utils::saveJson(c->serialize(), p);
}
- utils::saveJson(*c, p);
return "";
}
@@ -239,7 +258,7 @@ namespace cmd {
throw std::runtime_error("Could not add the " + ent->getType() + " " + ent->getName() + " to " + c->getGivenName() + " the " + c->getName() + ": Requires a weapon, armor, or spell, but received object of type " + ent->getType());
}
}
- utils::saveJson(*c, p);
+ utils::saveJson(c->serialize(), p);
text << "Added the " << ent->getType() << " " << ent->getName() << " to " << c->getGivenName() << " the " << c->getName() << std::endl;
return text.str();
}
@@ -278,7 +297,7 @@ namespace cmd {
}
}
}
- utils::saveJson(*c, p);
+ utils::saveJson(c->serialize(), p);
if(removed) {
text << "Successfully removed the " << removed->Entry::getType() << " " << removed->getName() << std::endl;
} else {
@@ -342,10 +361,75 @@ namespace cmd {
text << "Gave " << c->getName() << " " << slots << " " << utils::toOrdinal(level) << " level spell slots" << std::endl;
}
}
- utils::saveJson(*c, p);
+ utils::saveJson(c->serialize(), p);
return text.str();
}
+ std::string create(std::vector<std::string> args) {
+ auto p = getTruePath(args[0]);
+ args.erase(args.begin()); // remove path from args
+ auto name = args[1];
+ if(args[0] == "item") {
+ nlohmann::json j = entry::Entry("item", name, "item", "");
+ j["cost"] = 0;
+ j["weight"] = 0.0;
+ utils::saveJson(j, p);
+ } else if(args[0] == "weapon" or args[0] == "feature_attack") {
+ nlohmann::json j = entry::Entry((args[0] == "weapon")? "item" : "feature", name, "weapons", "");
+ j["cost"] = 0;
+ j["weight"] = 0.0;
+ j["damage"] = {{{"dmg_die_count", 1}, {"dmg_die_sides", 6}, {"dmg_type", "bludgeoning"}, {"is_or", false}}};
+ j["properties"] = std::vector<std::string>();
+ j["weapon_type"] = "";
+ j["range"] = {0, 0};
+ j["reach"] = 5;
+ j["toHitOverride"] = {}; // Set to null
+ j["dmgBonusOverride"] = {};
+ j["abilityOverride"] = {};
+ utils::saveJson(j, p);
+ } else if(args[0] == "armor") {
+ nlohmann::json j = entry::Entry("item", name, "armor", "");
+ j["cost"] = 0;
+ j["weight"] = 0.0;
+ j["ac"] = 10;
+ j["strength"] = 0;
+ j["disadvantage"] = false;
+ j["armor_type"] = "light";
+ utils::saveJson(j, p);
+ } else if(args[0] == "spell") {
+ nlohmann::json j = entry::Entry("spells", name, "UNKNOWN", "");
+ j["level"] = 0;
+ j["classes"] = std::vector<std::string>();
+ j["casting_time"] = "1 action";
+ j["range"] = "Touch";
+ j["components"] = "V, S, M";
+ j["duration"] = "Instantaneous";
+ utils::saveJson(j, p);
+ } else if(args[0] == "feature") {
+ nlohmann::json j = entry::Entry("feature", name, "feature", "");
+ utils::saveJson(j, p);
+ } else if(args[0] == "creature") {
+ nlohmann::json j = entry::Entry("creatures", name, "UNKNOWN", "");
+ j["givenName"] = "NAME";
+ j["hpMax"] = j["hp"] = -1;
+ j["inventory"] = j["saves"] = j["senses"] = j["d_resistances"] = j["d_vulnerabilities"] = j["d_immunities"] = j["c_immunities"] = j["features"] = std::vector<std::string>();
+ j["skills"] = std::map<std::string, std::string>();
+ j["stats"] = {{"str", 10}, {"dex", 10}, {"con", 10}, {"int", 10}, {"wis", 10}, {"cha", 10}};
+ j["prof"] = 2;
+ j["size"] = "Medium";
+ j["alignment"] = "any alignment";
+ j["hit_die_count"] = 1;
+ j["hit_die_sides"] = 8;
+ j["speed"] = "30 ft.";
+ j["langs"] = "any one language (usually Common)";
+ j["cr"] = 0.0;
+ j["observant"] = false;
+ j["natural_armor"] = {{"name", ""}, {"bonus", 0}};
+ utils::saveJson(j, p);
+ }
+ return "Successfully created " + args[0] + " " + args[1] + ".\n";
+ }
+
std::string git(std::vector<std::string> args) {
std::string root = getTruePath("").string();
std::system(("cd " + root + " && " + utils::join(args, " ")).c_str());
diff --git a/src/cmd/cmd_usage.cc b/src/cmd/cmd_usage.cc
index 44daca4..4f8d82f 100644
--- a/src/cmd/cmd_usage.cc
+++ b/src/cmd/cmd_usage.cc
@@ -40,6 +40,8 @@ namespace cmd {
text << indDesc << " skill (athletics, \"sleight of hand\", etc.); value is (none|proficient|expert)" << std::endl;
text << indDesc << " proficiency; value is new proficency bonus." << std::endl;
text << indDesc << " name; value is new given name." << std::endl;
+ text << indDesc << " cost; (for an item) value is cost in cp." << std::endl;
+ text << indDesc << " weight; (for an item) value is weight in lbs." << std::endl;
text << indOpt << "edit path" << std::endl;
text << indDesc << "Edit notes associated with creature." << std::endl;
text << indOpt << "add path entry" << std::endl;
@@ -51,6 +53,8 @@ namespace cmd {
text << indDesc << " init; adds spellcasting to a creature which currently does not have spellcasting" << std::endl;
text << indDesc << " ability value; sets the spellcasting ability, where value is the ability name" << std::endl;
text << indDesc << " level l slots; sets the number of slots at spell level l to slots" << std::endl;
+ text << indOpt << "create path type name" << std::endl;
+ text << indDesc << "Create a new entry at path location of type and name, where type is any of item, weapon, armor, spell, feature, feature_attack, creature." << std::endl;
text << indOpt << "git [command]" << std::endl;
text << indDesc << "Execute a git command within the dmtool folder." << std::endl;
text << indOpt << "help" << std::endl;
diff --git a/src/dmtool.cc b/src/dmtool.cc
index 3aec8b2..b94540c 100644
--- a/src/dmtool.cc
+++ b/src/dmtool.cc
@@ -13,6 +13,7 @@ const std::map<std::string, std::vector<int>> nargs({
{"damage", {2, 3}},
{"heal", {2}},
{"spellcasting", {2, 3, 4}},
+ {"create", {3}}
});
void checkArgs(std::string cmd, std::vector<std::string> args) {
@@ -87,6 +88,7 @@ int main(int argc, char *argv[]) {
else if(cmd == "del") std::cout << cmd::del(args);
else if(cmd == "edit") std::cout << cmd::edit(args);
else if(cmd == "spellcasting") std::cout << cmd::spellcasting(args);
+ else if(cmd == "create") std::cout << cmd::create(args);
else if(cmd == "git") std::cout << cmd::git(argsWithFlags);
else if(cmd == "help") std::cout << cmd::usage(exename);
else std::cout << cmd::list(argsOrig);
diff --git a/src/entry.cc b/src/entry.cc
index 9c9b3da..f958e17 100644
--- a/src/entry.cc
+++ b/src/entry.cc
@@ -7,7 +7,7 @@
#include <stdexcept>
namespace entry {
- // Returns either a feature, an item, a creature, or a spell
+ // Returns a feature, item, creature, or spell
std::shared_ptr<Entry> Entry::create(const nlohmann::json& data) {
if(data["entry"] == "feature") {
return Feature::create(data);
@@ -41,6 +41,8 @@ namespace entry {
}
std::string Entry::getName(void) const {return data->name;}
+ void Entry::setName(const std::string& name) {data->name = name;}
+ std::string Entry::getEntryType(void) const {return data->entry;}
std::string Entry::getType(void) const {return data->type;}
std::string Entry::getText(void) const {return data->text;}
std::string Entry::getText(const creature::Creature& c) const {
diff --git a/src/entry.h b/src/entry.h
index abfe831..9322fe7 100644
--- a/src/entry.h
+++ b/src/entry.h
@@ -19,6 +19,8 @@ namespace entry {
virtual ~Entry() {}
std::string getName(void) const;
+ void setName(const std::string& name);
+ std::string getEntryType(void) const;
std::string getType(void) const;
virtual std::string getText(void) const;
virtual std::string getText(const creature::Creature& c) const;
diff --git a/src/item.cc b/src/item.cc
index 24498db..cf55d4a 100644
--- a/src/item.cc
+++ b/src/item.cc
@@ -35,8 +35,12 @@ namespace entry {
int Item::getCost() const {return data->cost;}
+ void Item::setCost(int cost) {data->cost = cost;}
+
double Item::getWeight() const {return data->weight;}
+ void Item::setWeight(double weight) {data->weight = weight;}
+
string Item::getCostWeightText() const {
stringstream text;
if(getCost() >= 0) {
diff --git a/src/item.h b/src/item.h
index e8a40b9..33e6718 100644
--- a/src/item.h
+++ b/src/item.h
@@ -12,7 +12,9 @@ namespace entry {
static std::shared_ptr<Item> create(const nlohmann::json& data);
virtual ~Item() {}
virtual int getCost(void) const;
+ virtual void setCost(int cost);
virtual double getWeight(void) const;
+ virtual void setWeight(double weight);
virtual std::string getCostWeightText() const;
virtual std::string getText() const override;
virtual std::string getText(const creature::Creature& c) const override;
diff --git a/src/utils.cc b/src/utils.cc
index 75f13a3..94118ed 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -45,6 +45,14 @@ int utils::parseInt(const std::string& s) {
}
}
+double utils::parseDouble(const std::string& s) {
+ try {
+ return std::stod(s);
+ } catch(std::exception& e) {
+ throw std::runtime_error("A double was expected but " + s + " was given");
+ }
+}
+
void utils::saveJson(const nlohmann::json& data, const fs::path& path) {
std::ofstream f(path);
f << std::setw(4) << data << std::endl;
diff --git a/src/utils.h b/src/utils.h
index 9d22a66..ca4adee 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -81,6 +81,8 @@ namespace utils {
int parseInt(const std::string& s);
+ double parseDouble(const std::string& s);
+
template<typename S, typename D> std::shared_ptr<S> loadDFromJson(const nlohmann::json& data) {
nlohmann::json j = data;
try {
@@ -123,7 +125,7 @@ namespace utils {
const std::map<std::string, int> cpValue {
{"cp", 1},
{"sp", 10},
- {"ep", 50},
+ //{"ep", 50},
{"gp", 100},
{"pp", 1000}
};