aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYour Name <you@example.com>2023-11-22 15:28:00 -0500
committerYour Name <you@example.com>2023-11-22 15:28:00 -0500
commitae68e84557a7e56fd7210c1009aa1313dcc78adf (patch)
tree60616c822927847dd078f014c514a65f764607f3
parent0d32e0d3342ef2455014c8e1164977c816763317 (diff)
downloaddmtool-ae68e84557a7e56fd7210c1009aa1313dcc78adf.tar.gz
dmtool-ae68e84557a7e56fd7210c1009aa1313dcc78adf.tar.bz2
dmtool-ae68e84557a7e56fd7210c1009aa1313dcc78adf.zip
Increased capacity for creating items from command line
-rw-r--r--src/cmd/cmd_manipulate.cc41
-rw-r--r--src/creature.cc86
-rw-r--r--src/creature.h10
-rw-r--r--src/entry.cc5
-rw-r--r--src/item.cc5
5 files changed, 108 insertions, 39 deletions
diff --git a/src/cmd/cmd_manipulate.cc b/src/cmd/cmd_manipulate.cc
index f0d3fc4..e29fd34 100644
--- a/src/cmd/cmd_manipulate.cc
+++ b/src/cmd/cmd_manipulate.cc
@@ -224,7 +224,9 @@ namespace cmd {
}
c->setProfLevel(skill, level);
} else if(ability) {
- c->setScore(ability, utils::parseInt(toSet));
+ if(toSet == "proficient") c->setProficientSave(ability);
+ else if(toSet == "none") c->removeProficientSave(ability);
+ else c->setScore(ability, utils::parseInt(toSet));
} else {
throw std::runtime_error("Subcommand 'set' expected an ability, skill, proficiency, or name field to set, but was given " + abilityOrSkill);
}
@@ -246,17 +248,8 @@ namespace cmd {
} else {
ent = entry::Entry::create(utils::findByName(addName));
}
- // Determine if it is an item or a spell
- auto i = std::dynamic_pointer_cast<entry::Item>(ent);
- if(i) {
- c->addInventoryItem(i);
- } else {
- auto s = std::dynamic_pointer_cast<entry::Spell>(ent);
- if(s) {
- c->addSpell(s);
- } else {
- 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());
- }
+ if(! creature::addEntry(ent, *c)) {
+ 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->serialize(), p);
text << "Added the " << ent->getType() << " " << ent->getName() << " to " << c->getGivenName() << " the " << c->getName() << std::endl;
@@ -276,32 +269,12 @@ namespace cmd {
itemName = i->getName();
}
} catch(std::exception& e) {} // eat.
- utils::lower(itemName);
- // Loop through all of c's stuff, searching for itemName
- std::shared_ptr<entry::Entry> removed;
- for(auto item : c->getInventory()) {
- std::string name = item->getName();
- if(utils::lower(name) == itemName) {
- c->removeInventoryItem(item);
- removed = item;
- break;
- }
- }
- if(! removed) {
- for(auto spell : c->getSpellcasting()->getSpells()) {
- std::string name = spell->getName();
- if(utils::lower(name) == itemName) {
- c->removeSpell(spell);
- removed = spell;
- break;
- }
- }
- }
+ auto removed = creature::removeEntry(itemName, *c);
utils::saveJson(c->serialize(), p);
if(removed) {
text << "Successfully removed the " << removed->Entry::getType() << " " << removed->getName() << std::endl;
} else {
- text << "Could not find any inventory item nor spell by that name" << std::endl;
+ text << "Could not find any entry by that name" << std::endl;
}
return text.str();
}
diff --git a/src/creature.cc b/src/creature.cc
index 4343b6d..955da4d 100644
--- a/src/creature.cc
+++ b/src/creature.cc
@@ -152,6 +152,19 @@ namespace creature {
return bonus;
}
+ void Creature::setProficientSave(const rules::Ability& ability) {
+ if(find(data->saves.begin(), data->saves.end(), ability) == data->saves.end()) {
+ data->saves.push_back(ability);
+ }
+ }
+
+ void Creature::removeProficientSave(const rules::Ability& ability) {
+ for(auto it = data->saves.begin(); it != data->saves.end();) {
+ if(*it == ability) it = data->saves.erase(it);
+ else ++it;
+ }
+ }
+
void Creature::addInventoryItem(std::shared_ptr<entry::Item> item) {
data->inventory.push_back(item);
}
@@ -209,6 +222,19 @@ namespace creature {
}
}
+ void Creature::addFeature(std::shared_ptr<entry::Feature> feature) {
+ data->features.push_back(feature);
+ }
+
+ void Creature::removeFeature(std::shared_ptr<entry::Feature> feature) {
+ for(auto it = data->features.begin(); it != data->features.end(); it++) {
+ if(*it == feature) {
+ data->features.erase(it);
+ break;
+ }
+ }
+ }
+
std::map<rules::Skill, int> Creature::getSkills() const {
std::map<rules::Skill, int> s;
for(auto skill : data->skills) {
@@ -309,6 +335,46 @@ namespace creature {
return out;
}
+ bool addEntry(std::shared_ptr<entry::Entry> entry, Creature& c) {
+ auto i = std::dynamic_pointer_cast<entry::Item>(entry);
+ if(i) {
+ c.addInventoryItem(i);
+ return true;
+ }
+ auto s = std::dynamic_pointer_cast<entry::Spell>(entry);
+ if(s) {
+ c.addSpell(s);
+ return true;
+ }
+ auto f = std::dynamic_pointer_cast<entry::Feature>(entry);
+ if(f) {
+ c.addFeature(f);
+ return true;
+ }
+ return false;
+ }
+
+ template<typename F, typename E> std::shared_ptr<entry::Entry> tryRemove(std::string entryName, F remover, std::vector<E> entries) {
+ for(auto e : entries) {
+ std::string name = e->getName();
+ if(utils::lower(name) == entryName) {
+ remover(e);
+ return e;
+ }
+ }
+ return std::shared_ptr<entry::Entry>();
+ }
+
+ std::shared_ptr<entry::Entry> removeEntry(std::string entryName, Creature& c) {
+ entryName = utils::lower(entryName);
+ if(auto e = tryRemove(entryName, [c](auto e) mutable {c.removeInventoryItem(e);}, c.getInventory())) return e;
+ if(auto e = tryRemove(entryName, [c](auto e) mutable {c.removeFeature(e);}, c.getFeatures())) return e;
+ if(c.getSpellcasting()) {
+ if(auto e = tryRemove(entryName, [c](auto e) mutable {c.removeSpell(e);}, c.getSpellcasting()->getSpells())) return e;
+ }
+ return std::shared_ptr<entry::Entry>();
+ }
+
std::vector<std::string> dmgTypes2text(std::vector<dmgType> dmg) {
std::vector<std::string> ret;
for(dmgType t : dmg) {
@@ -361,7 +427,9 @@ namespace creature {
if(! getSkills().empty()) {
text << std::endl << "Skills:" << std::endl;
for(auto skill : getSkills()) {
- text << " * " << skill.first.getName() << " (+" << skill.second << ")" << std::endl;
+ text << " * " << skill.first.getName();
+ if(data->skills.at(skill.first) == 2) text << " Expert";
+ text << " (+" << skill.second << ")" << std::endl;
}
}
if(! getSaves().empty()) {
@@ -389,9 +457,21 @@ namespace creature {
}
}
if(! getInventory().empty()) {
- text << std::endl << "Inventory:" << std::endl;
+ std::map<std::string, int> inventoryText;
+ double totalWeight = 0;
+ int totalCost = 0;
for(auto i : getInventory()) {
- text << " * " << i->getText(*this) << std::endl;
+ totalWeight += i->getWeight();
+ totalCost += i->getCost();
+ auto t = i->getText(*this);
+ if(inventoryText.contains(t)) inventoryText[t]++;
+ else inventoryText.insert({t, 1});
+ }
+ text << std::endl << "Inventory (" << totalWeight << " lbs, value " << utils::getCostString(totalCost) << "):" << std::endl;
+ for(auto const& [t, count] : inventoryText) {
+ text << " * ";
+ if(count > 1) text << count << "x ";
+ text << t << std::endl;
}
}
if(! Entry::getText().empty()) {
diff --git a/src/creature.h b/src/creature.h
index de93b0e..621b397 100644
--- a/src/creature.h
+++ b/src/creature.h
@@ -80,11 +80,15 @@ namespace creature {
void setScore(const rules::Ability& ability, int score);
void setProfLevel(const rules::Skill& skill, int level);
void setProficiency(int p);
+ void setProficientSave(const rules::Ability& ability);
+ void removeProficientSave(const rules::Ability& ability);
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);
+ void addFeature(std::shared_ptr<entry::Feature> feature);
+ void removeFeature(std::shared_ptr<entry::Feature> feature);
// Events
void longRest(void);
@@ -107,4 +111,10 @@ namespace creature {
// Helper function to get the best ability for this creature (chooses arbitrarily in case of ties)
rules::Ability getBestAbility(const std::vector<rules::Ability>& abilities, const Creature& c);
+
+ // Helper function to smartly add an entry. Returns true on success.
+ bool addEntry(std::shared_ptr<entry::Entry> entry, Creature& c);
+
+ // Helper function to smartly remove an entry. Returns the removed entry on success, else a null shared_ptr
+ std::shared_ptr<entry::Entry> removeEntry(std::string entryName, Creature& c);
}
diff --git a/src/entry.cc b/src/entry.cc
index f958e17..249382f 100644
--- a/src/entry.cc
+++ b/src/entry.cc
@@ -44,7 +44,10 @@ namespace entry {
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(void) const {
+ if(!data->text.empty() and data->text.back() == '\n') return data->text.substr(0, data->text.length()-1); // Strip final newline
+ return data->text;
+ }
std::string Entry::getText(const creature::Creature& c) const {
return getName() + " (" + getType() + "): " + getText();
}
diff --git a/src/item.cc b/src/item.cc
index cf55d4a..8d5d9a3 100644
--- a/src/item.cc
+++ b/src/item.cc
@@ -59,7 +59,10 @@ namespace entry {
}
string Item::getText() const {
- return Entry::getText() + " " + getCostWeightText();
+ stringstream text;
+ text << getName() << " (" << getType() << "): ";
+ text << Entry::getText() << " " << getCostWeightText();
+ return text.str();
}
string Item::getText(const creature::Creature& c) const {