aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYour Name <you@example.com>2021-05-18 16:26:49 -0400
committerYour Name <you@example.com>2021-05-18 16:26:49 -0400
commit38e33d8756a5b652965be8ada478b5c4238b857c (patch)
treed4e3b166103c4c0cc8d3a4ed963333a2982bb366
parente044fc4255aa64ef1dbc3d20ed87ed6e2f61a6bd (diff)
downloaddmtool-38e33d8756a5b652965be8ada478b5c4238b857c.tar.gz
dmtool-38e33d8756a5b652965be8ada478b5c4238b857c.tar.bz2
dmtool-38e33d8756a5b652965be8ada478b5c4238b857c.zip
Added spellcasting command
-rw-r--r--files/dmtool.bash12
-rw-r--r--src/cmd.h1
-rw-r--r--src/cmd_manipulate.cc42
-rw-r--r--src/cmd_usage.cc5
-rw-r--r--src/creature.cc8
-rw-r--r--src/creature.h1
-rw-r--r--src/dmtool.cc2
-rw-r--r--src/entry.h3
-rw-r--r--src/feature.h2
-rw-r--r--src/spellcasting.h2
10 files changed, 76 insertions, 2 deletions
diff --git a/files/dmtool.bash b/files/dmtool.bash
index ffc75f7..f683e05 100644
--- a/files/dmtool.bash
+++ b/files/dmtool.bash
@@ -81,7 +81,7 @@ _dmtool()
{
COMPREPLY=()
local cur="${COMP_WORDS[COMP_CWORD]}"
- local commands="ls cp mkdir mv rm attacks roll damage heal reset set edit add del help"
+ local commands="ls cp mkdir mv rm attacks roll damage heal reset set edit add del spellcasting help"
if [[ $COMP_CWORD -gt 1 ]]; then
local lastarg="${COMP_WORDS[$COMP_CWORD-1]}"
case "${COMP_WORDS[1]}" in
@@ -93,7 +93,7 @@ _dmtool()
_dmtool_complete_entries
fi
;;
- attacks|roll|damage|heal|set|edit|del)
+ attacks|roll|damage|heal|set|edit|del|spellcasting)
if [[ $COMP_CWORD -le 2 ]]; then
_dmtool_complete_entries
else
@@ -126,6 +126,14 @@ _dmtool()
#TODO: Add items and spells
_dmtool_complete_skills_abilities
;;
+ spellcasting)
+ if [[ $COMP_CWORD -eq 3 ]]; then
+ COMPREPLY+=($(compgen -W "init ability level" -- ${cur}))
+ elif [[ "$lastarg" == "ability" ]]; then
+ local IFS=$'\n'
+ COMPREPLY+=($(compgen -W "$(_dmtool_abilities)" -- ${cur}))
+ fi
+ ;;
esac
fi
;;
diff --git a/src/cmd.h b/src/cmd.h
index 92a3cc3..69c258b 100644
--- a/src/cmd.h
+++ b/src/cmd.h
@@ -24,6 +24,7 @@ namespace cmd {
std::string add(std::vector<std::string> args);
std::string del(std::vector<std::string> args);
std::string edit(std::vector<std::string> args);
+ std::string spellcasting(std::vector<std::string> args);
//Queries
std::string attacks(std::vector<std::string> args);
diff --git a/src/cmd_manipulate.cc b/src/cmd_manipulate.cc
index 1300008..9fc019e 100644
--- a/src/cmd_manipulate.cc
+++ b/src/cmd_manipulate.cc
@@ -204,4 +204,46 @@ namespace cmd {
utils::saveJson(*e, p);
return "";
}
+
+ std::string spellcasting(std::vector<std::string> args) {
+ std::stringstream text;
+ auto p = getTruePath(args[0]);
+ auto c = utils::instantiate<creature::Creature>(p);
+ auto subcommand = args[1];
+ if(subcommand != "init" && subcommand != "ability" && subcommand != "level") {
+ throw std::runtime_error("Unknown option \"" + subcommand + "\"");
+ }
+ if(subcommand == "init") {
+ c->addSpellcasting();
+ } else {
+ auto sc = c->getSpellcasting();
+ if(! sc) {
+ throw std::runtime_error("Creature " + c->getName() + " has no spellcasting");
+ }
+ text << "Added spellcasting to " << c->getName() << std::endl;
+ if(subcommand == "ability") {
+ if(args.size() != 3) {
+ throw std::runtime_error("Subcommand \"spellcasting ability\" requires an additional parameter, but none was given");
+ }
+ sc->setAbility(args[2]);
+ text << "Set " << c->getName() << " spellcasting ability to " << args[2] << std::endl;
+ } else { // subcommand == "level"
+ if(args.size() != 4) {
+ throw std::runtime_error("Subcommand \"spellcasting level\" requires more parameters");
+ }
+ int level = utils::parseInt(args[2]);
+ int slots = utils::parseInt(args[3]);
+ if(level <= 0 || slots < 0) {
+ throw std::runtime_error("Spellcasting target out of range");
+ }
+ while(sc->getSlotLevels().size() <= (std::size_t) level) {
+ sc->addSlotLevel();
+ }
+ sc->getSlotLevels()[level]->numSlots = slots;
+ text << "Gave " << c->getName() << " " << slots << " " << utils::toOrdinal(level) << " level spell slots" << std::endl;
+ }
+ }
+ utils::saveJson(*c, p);
+ return text.str();
+ }
}
diff --git a/src/cmd_usage.cc b/src/cmd_usage.cc
index 03dae56..53e9d01 100644
--- a/src/cmd_usage.cc
+++ b/src/cmd_usage.cc
@@ -40,6 +40,11 @@ namespace cmd {
text << indDesc << "Add entry to creature, where entry is an item or spell." << std::endl;
text << indOpt << "del path entry" << std::endl;
text << indDesc << "Delete entry from creature, where entry is an item or spell." << std::endl;
+ text << indOpt << "spellcasting path SUBCOMMAND" << std::endl;
+ text << indDesc << "Manipulate creature's spellcasting feature, where subcommand is any of:" << std::endl;
+ 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 << "help" << std::endl;
text << indDesc << "Show this help." << std::endl;
return text.str();
diff --git a/src/creature.cc b/src/creature.cc
index 9366bac..7060c10 100644
--- a/src/creature.cc
+++ b/src/creature.cc
@@ -80,6 +80,14 @@ namespace creature {
inventory.push_back(item);
}
+ void Creature::addSpellcasting() {
+ if(getSpellcasting()) {
+ throw runtime_error("Creature " + getName() + " already has spellcasting");
+ }
+ std::shared_ptr<entry::Feature> sc(new entry::Spellcasting());
+ features.push_back(sc);
+ }
+
shared_ptr<entry::Spellcasting> Creature::getSpellcasting() const {
for(auto f : getFeatures()) {
if(f->getType() == "spells") {
diff --git a/src/creature.h b/src/creature.h
index c6697ce..b2a01e6 100644
--- a/src/creature.h
+++ b/src/creature.h
@@ -85,6 +85,7 @@ namespace creature {
void setProfLevel(const rules::Skill& skill, int level);
void setProficiency(int p) {prof = p;}
void addInventoryItem(std::shared_ptr<entry::Item> item);
+ void addSpellcasting(void);
void addSpell(std::shared_ptr<entry::Spell> spell);
void removeSpell(std::shared_ptr<entry::Spell> spell);
void removeInventoryItem(std::shared_ptr<entry::Item> item);
diff --git a/src/dmtool.cc b/src/dmtool.cc
index 3c5d3a1..f4fe19c 100644
--- a/src/dmtool.cc
+++ b/src/dmtool.cc
@@ -11,6 +11,7 @@ const std::map<std::string, std::vector<int>> nargs({
{"attacks", {1}},
{"damage", {2, 3}},
{"heal", {2}},
+ {"spellcasting", {2, 3, 4}},
});
void checkArgs(std::string cmd, std::vector<std::string> args) {
@@ -69,6 +70,7 @@ int main(int argc, char *argv[]) {
else if(cmd == "add") std::cout << cmd::add(args);
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 == "help") std::cout << cmd::usage(exename);
else std::cout << cmd::list(argsOrig);
} catch(std::exception& e) {
diff --git a/src/entry.h b/src/entry.h
index 56fc884..9e00798 100644
--- a/src/entry.h
+++ b/src/entry.h
@@ -10,6 +10,9 @@ namespace creature {
namespace entry {
class Entry {
public:
+ Entry() {}
+ // Also can be created programmatically
+ Entry(const std::string& entry, const std::string& name, const std::string& type, const std::string& text) : entry(entry), name(name), type(type), text(text) {}
static std::shared_ptr<Entry> create(const nlohmann::json& data);
virtual ~Entry() {}
diff --git a/src/feature.h b/src/feature.h
index 294cf1d..e3c8bdf 100644
--- a/src/feature.h
+++ b/src/feature.h
@@ -6,6 +6,8 @@
namespace entry {
class Feature : public Entry {
public:
+ Feature() {}
+ Feature(const std::string& name, const std::string& type, const std::string& text) : Entry("feature", name, type, text) {}
static std::shared_ptr<Feature> create(const nlohmann::json& data);
virtual ~Feature() {}
};
diff --git a/src/spellcasting.h b/src/spellcasting.h
index f5cebcb..aa3b3e8 100644
--- a/src/spellcasting.h
+++ b/src/spellcasting.h
@@ -28,8 +28,10 @@ namespace entry {
class Spellcasting : public Feature {
public:
+ Spellcasting() : Feature("spellcasting", "spells", ""), innate(false), spellcasting_ability("int") {}
bool isInnate(void) const {return innate;}
rules::Ability getAbility(void) const {return spellcasting_ability;}
+ void setAbility(const rules::Ability& ability) {spellcasting_ability = ability;}
const std::vector<std::shared_ptr<SlotLevel>>& getSlotLevels(void) const {return levels;}
void addSlotLevel(void) {levels.push_back(std::shared_ptr<SlotLevel>(new SlotLevel()));}
std::vector<std::shared_ptr<Spell>> getSpells(void) const;