From 0d32e0d3342ef2455014c8e1164977c816763317 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 21 Nov 2023 16:26:34 -0500 Subject: Added rudimentary item creation --- files/dmtool.bash | 11 +++-- src/cmd/cmd.h | 1 + src/cmd/cmd_manipulate.cc | 102 ++++++++++++++++++++++++++++++++++++++++++---- src/cmd/cmd_usage.cc | 4 ++ src/dmtool.cc | 2 + src/entry.cc | 4 +- src/entry.h | 2 + src/item.cc | 4 ++ src/item.h | 2 + src/utils.cc | 8 ++++ src/utils.h | 4 +- 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 args); std::string edit(std::vector args); std::string spellcasting(std::vector args); + std::string create(std::vector args); std::string git(std::vector 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(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(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(p); + if(e->getEntryType() == "creatures") { // creature, we should do given name instead + auto c = utils::instantiate(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(p); c->setProficiency(utils::parseInt(args[1])); + utils::saveJson(c->serialize(), p); + } else if(args[0] == "cost") { + auto i = utils::instantiate(p); + i->setCost(utils::parseInt(args[1])); + utils::saveJson(i->serialize(), p); + } else if(args[0] == "weight") { + auto i = utils::instantiate(p); + i->setWeight(utils::parseDouble(args[1])); + utils::saveJson(i->serialize(), p); } else { + auto c = utils::instantiate(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 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(); + 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(); + 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(); + j["skills"] = std::map(); + 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 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> nargs({ {"damage", {2, 3}}, {"heal", {2}}, {"spellcasting", {2, 3, 4}}, + {"create", {3}} }); void checkArgs(std::string cmd, std::vector 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 namespace entry { - // Returns either a feature, an item, a creature, or a spell + // Returns a feature, item, creature, or spell std::shared_ptr 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 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 std::shared_ptr loadDFromJson(const nlohmann::json& data) { nlohmann::json j = data; try { @@ -123,7 +125,7 @@ namespace utils { const std::map cpValue { {"cp", 1}, {"sp", 10}, - {"ep", 50}, + //{"ep", 50}, {"gp", 100}, {"pp", 1000} }; -- cgit v1.2.3