aboutsummaryrefslogtreecommitdiff
path: root/src/creature.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/creature.cc')
-rw-r--r--src/creature.cc211
1 files changed, 134 insertions, 77 deletions
diff --git a/src/creature.cc b/src/creature.cc
index 7060c10..5130362 100644
--- a/src/creature.cc
+++ b/src/creature.cc
@@ -10,23 +10,80 @@
#include <iostream>
#include <sstream>
#include <iomanip>
-
-using namespace std;
+#include <cmath>
namespace creature {
+
+ struct creatureImpl {
+ std::string givenName;
+ int hpMax;
+ int hp;
+ std::vector<std::shared_ptr<entry::Item>> inventory;
+ std::map<rules::Ability, int> stats;
+ std::map<rules::Skill, int> skills;
+ int prof;
+ std::string size;
+ std::string alignment;
+ int hit_die_count;
+ int hit_die_sides;
+ std::string speed;
+ std::vector<rules::Ability> saves;
+ std::vector<std::string> senses;
+ std::string langs;
+ double cr;
+ bool observant;
+ NatArmor natural_armor;
+ std::vector<dmgType> d_immunities;
+ std::vector<dmgType> d_resistances;
+ std::vector<dmgType> d_vulnerabilities;
+ std::vector<dmgType> c_immunities;
+ std::vector<std::shared_ptr<entry::Feature>> features;
+ };
+ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(creatureImpl, givenName, hpMax, hp, inventory, stats, skills, prof, size, alignment, hit_die_count, hit_die_sides, speed, saves, senses, langs, cr, observant, natural_armor, d_immunities, d_resistances, d_vulnerabilities, c_immunities, features);
+
+ NLOHMANN_FRIEND_DEFS(entry::Entry, Creature, data);
+
+ Creature::Creature() : data(new creatureImpl()) {}
+
+ // Pile of (simple) getters
+ std::string Creature::getCreatureName(void) const {return getName();}
+ std::string Creature::getGivenName(void) const {return data->givenName;}
+ std::string Creature::getSize(void) const {return data->size;}
+ std::string Creature::getAlignment(void) const {return data->alignment;}
+ double Creature::getCR(void) const {return data->cr;}
+ NatArmor Creature::getNaturalArmor(void) const {return data->natural_armor;}
+ std::string Creature::getLanguages(void) const {return data->langs;}
+ int Creature::getHP(void) const {return data->hp;}
+ int Creature::getHPMax(void) const {return data->hpMax;}
+ std::vector<std::string> Creature::getSenses(void) const {return data->senses;}
+ std::string Creature::getSpeed(void) const {return data->speed;}
+ int Creature::getScore(const rules::Ability& ability) const {return data->stats.at(ability);}
+ int Creature::getBonus(const rules::Ability& ability) const {return std::floor((getScore(ability) - 10) / 2.0);}
+ int Creature::getProficiency(void) const {return data->prof;}
+ std::vector<std::shared_ptr<entry::Feature>> Creature::getFeatures(void) const {return data->features;}
+ std::vector<std::shared_ptr<entry::Item>> Creature::getInventory(void) const {return data->inventory;}
+ std::vector<dmgType> Creature::getDmgImmunities(void) const {return data->d_immunities;}
+ std::vector<dmgType> Creature::getDmgResistances(void) const {return data->d_resistances;}
+ std::vector<dmgType> Creature::getDmgVulnerabilities(void) const {return data->d_vulnerabilities;}
+ std::vector<dmgType> Creature::getCondImmunities(void) const {return data->c_immunities;}
+
+ // Simple setters
+ void Creature::setGivenName(const std::string& name) {data->givenName = name;}
+ void Creature::setProficiency(int p) {data->prof = p;}
+
void Creature::init() {
- if(hpMax == -1) {
+ if(data->hpMax == -1) {
// Initialize hp
- hpMax = getBonus(rules::Ability::Con()) * hit_die_count;
- for(int i = 0; i < hit_die_count; i++) {
- hpMax += dice::roll(hit_die_sides);
+ data->hpMax = getBonus(rules::Ability::Con()) * data->hit_die_count;
+ for(int i = 0; i < data->hit_die_count; i++) {
+ data->hpMax += dice::roll(data->hit_die_sides);
}
- hp = hpMax;
+ data->hp = data->hpMax;
}
}
// True if type without matching qualifiers is in subdata
- bool conditionApplies(const string& type, const vector<rules::Qualifier>& qualifiers, const vector<dmgType> subdata) {
+ bool conditionApplies(const std::string& type, const std::vector<rules::Qualifier>& qualifiers, const std::vector<dmgType> subdata) {
bool applies = false;
for(dmgType con : subdata) {
if(con.type == type) {
@@ -41,66 +98,66 @@ namespace creature {
return applies;
}
- void Creature::applyDamage(int amount, const string& type, const vector<rules::Qualifier>& qualifiers) {
+ void Creature::applyDamage(int amount, const std::string& type, const std::vector<rules::Qualifier>& qualifiers) {
if(! conditionApplies(type, qualifiers, getDmgImmunities())) {
if(conditionApplies(type, qualifiers, getDmgResistances())) {
- hp -= amount / 2;
+ data->hp -= amount / 2;
} else if(conditionApplies(type, qualifiers, getDmgVulnerabilities())) {
- hp -= amount * 2;
+ data->hp -= amount * 2;
} else {
- hp -= amount;
+ data->hp -= amount;
}
}
}
void Creature::applyHealing(int amount) {
- hp += amount;
- if(hp > hpMax) {
- hp = hpMax;
+ data->hp += amount;
+ if(data->hp > data->hpMax) {
+ data->hp = data->hpMax;
}
}
int Creature::getSkillBonus(const rules::Skill& skill) const {
int bonus = this->getBonus(skill.getAbility());
- if(skills.contains(skill)) {
- bonus += skills.at(skill) * getProficiency();
+ if(data->skills.contains(skill)) {
+ bonus += data->skills.at(skill) * getProficiency();
}
return bonus;
}
int Creature::getAbilitySaveBonus(const rules::Ability& ability) const {
int bonus = this->getBonus(ability);
- if(find(saves.begin(), saves.end(), ability) != saves.end()) {
+ if(find(data->saves.begin(), data->saves.end(), ability) != data->saves.end()) {
bonus += getProficiency();
}
return bonus;
}
- void Creature::addInventoryItem(shared_ptr<entry::Item> item) {
- inventory.push_back(item);
+ void Creature::addInventoryItem(std::shared_ptr<entry::Item> item) {
+ data->inventory.push_back(item);
}
void Creature::addSpellcasting() {
if(getSpellcasting()) {
- throw runtime_error("Creature " + getName() + " already has spellcasting");
+ throw std::runtime_error("Creature " + getName() + " already has spellcasting");
}
std::shared_ptr<entry::Feature> sc(new entry::Spellcasting());
- features.push_back(sc);
+ data->features.push_back(sc);
}
- shared_ptr<entry::Spellcasting> Creature::getSpellcasting() const {
+ std::shared_ptr<entry::Spellcasting> Creature::getSpellcasting() const {
for(auto f : getFeatures()) {
if(f->getType() == "spells") {
return dynamic_pointer_cast<entry::Spellcasting>(f);
}
}
- return shared_ptr<entry::Spellcasting>();
+ return std::shared_ptr<entry::Spellcasting>();
}
- void Creature::addSpell(shared_ptr<entry::Spell> spell) {
+ void Creature::addSpell(std::shared_ptr<entry::Spell> spell) {
auto sc = getSpellcasting();
if(! sc) {
- throw runtime_error("Creature " + getName() + " has no spellcasting");
+ throw std::runtime_error("Creature " + getName() + " has no spellcasting");
}
std::size_t level = spell->getLevel();
while(sc->getSlotLevels().size() <= level) {
@@ -109,7 +166,7 @@ namespace creature {
sc->getSlotLevels()[level]->spells.push_back(spell);
}
- void Creature::removeSpell(shared_ptr<entry::Spell> spell) {
+ void Creature::removeSpell(std::shared_ptr<entry::Spell> spell) {
auto sc = getSpellcasting();
if(sc) {
if(sc->getSlotLevels().size() > (size_t) spell->getLevel()) {
@@ -124,26 +181,26 @@ namespace creature {
}
}
- void Creature::removeInventoryItem(shared_ptr<entry::Item> item) {
- for(auto it = inventory.begin(); it != inventory.end(); it++) {
+ void Creature::removeInventoryItem(std::shared_ptr<entry::Item> item) {
+ for(auto it = data->inventory.begin(); it != data->inventory.end(); it++) {
if(*it == item) {
- inventory.erase(it);
+ data->inventory.erase(it);
break;
}
}
}
- map<rules::Skill, int> Creature::getSkills() const {
- map<rules::Skill, int> s;
- for(auto skill : skills) {
+ std::map<rules::Skill, int> Creature::getSkills() const {
+ std::map<rules::Skill, int> s;
+ for(auto skill : data->skills) {
s.insert({skill.first, getSkillBonus(skill.first)});
}
return s;
}
- map<rules::Ability, int> Creature::getSaves() const {
- map<rules::Ability, int> s;
- for(auto save : saves) {
+ std::map<rules::Ability, int> Creature::getSaves() const {
+ std::map<rules::Ability, int> s;
+ for(auto save : data->saves) {
s.insert({save, this->getBonus(save) + getProficiency()});
}
return s;
@@ -151,23 +208,23 @@ namespace creature {
void Creature::setScore(const rules::Ability& ability, int score) {
int initBonus = getBonus(ability);
- stats[ability] = score;
+ data->stats[ability] = score;
if(ability == rules::Ability::Con()) {
int delta = getBonus(ability) - initBonus;
- hpMax += delta * hit_die_count;
- hp += delta * hit_die_count;
+ data->hpMax += delta * data->hit_die_count;
+ data->hp += delta * data->hit_die_count;
}
}
void Creature::setProfLevel(const rules::Skill& skill, int level) {
- skills[skill] = level;
+ data->skills[skill] = level;
if(level == 0) {
- skills.erase(skill);
+ data->skills.erase(skill);
}
}
void Creature::longRest() {
- hp = hpMax;
+ data->hp = data->hpMax;
}
const int getAC(const Creature& c) {
@@ -197,10 +254,10 @@ namespace creature {
return baseBonus + miscBonus;
}
- vector<shared_ptr<entry::Weapon>> getAttacks(const Creature& c) {
- vector<shared_ptr<entry::Weapon>> a = utils::castPtrs<entry::Item, entry::Weapon>(c.getInventory());
+ std::vector<std::shared_ptr<entry::Weapon>> getAttacks(const Creature& c) {
+ std::vector<std::shared_ptr<entry::Weapon>> a = utils::castPtrs<entry::Item, entry::Weapon>(c.getInventory());
for(auto attack : utils::castPtrs<entry::Feature, entry::Attack>(c.getFeatures())) {
- a.push_back(shared_ptr<entry::Weapon>(new entry::Weapon(attack->getWeapon())));
+ a.push_back(std::shared_ptr<entry::Weapon>(new entry::Weapon(attack->getWeapon())));
}
return a;
}
@@ -215,97 +272,97 @@ namespace creature {
return *bestA;
}
- template<typename T> vector<string> mapItems(const vector<shared_ptr<T>>& items) {
- vector<string> out;
+ template<typename T> std::vector<std::string> mapItems(const std::vector<std::shared_ptr<T>>& items) {
+ std::vector<std::string> out;
for(auto i : items) {
out.push_back(i->getName());
}
return out;
}
- vector<string> dmgTypes2text(vector<dmgType> dmg) {
- vector<string> ret;
+ std::vector<std::string> dmgTypes2text(std::vector<dmgType> dmg) {
+ std::vector<std::string> ret;
for(dmgType t : dmg) {
ret.push_back(t.getText());
}
return ret;
}
- string formatDmgTypeVector(string title, vector<dmgType> dmg) {
+ std::string formatDmgTypeVector(std::string title, std::vector<dmgType> dmg) {
return title + ": " + utils::join(dmgTypes2text(dmg), "; ");
}
- string Creature::getText() const {
- stringstream text;
+ std::string Creature::getText() const {
+ std::stringstream text;
text << getGivenName() << " (" << getCreatureName() << "): " << getHP() << "/" << getHPMax() << " hp, " << getAC(*this) << " ac";
if(! getNaturalArmor().name.empty()) {
text << " (" << getNaturalArmor().name << ")";
} else {
- string armor = utils::join(mapItems(utils::castPtrs<entry::Item, entry::Armor>(getInventory())), ", ");
+ std::string armor = utils::join(mapItems(utils::castPtrs<entry::Item, entry::Armor>(getInventory())), ", ");
if(! armor.empty()) {
text << " (" << armor << ")";
}
}
- text << ", speed " << getSpeed() << endl;
- text << "A cr " << getCR() << " " << getAlignment() << " " << getSize() << " " << getType() << "." << endl;
- text << "Stats:" << endl;
+ text << ", speed " << getSpeed() << std::endl;
+ text << "A cr " << getCR() << " " << getAlignment() << " " << getSize() << " " << getType() << "." << std::endl;
+ text << "Stats:" << std::endl;
using namespace rules;
- vector<rules::Ability> abilities {Ability::Str(), Ability::Dex(), Ability::Con(), Ability::Int(), Ability::Wis(), Ability::Cha()};
+ std::vector<rules::Ability> abilities {Ability::Str(), Ability::Dex(), Ability::Con(), Ability::Int(), Ability::Wis(), Ability::Cha()};
for(auto ability : abilities) {
- text << " " << setw(6) << std::left << ability.getAbbrev();
+ text << " " << std::setw(6) << std::left << ability.getAbbrev();
}
- text << endl;
+ text << std::endl;
for(auto ability : abilities) {
- text << setw(7) << std::left << (to_string(getScore(ability)) + "(" + to_string(getBonus(ability)) + ")");
+ text << std::setw(7) << std::left << (std::to_string(getScore(ability)) + "(" + std::to_string(getBonus(ability)) + ")");
}
- text << endl;
+ text << std::endl;
text << "Senses: ";
if(! getSenses().empty()) {
text << utils::join(getSenses(), ", ") << ". ";
}
- text << "Passive Perception " << 10 + getSkillBonus(rules::Skill::Perception()) << endl;
+ text << "Passive Perception " << 10 + getSkillBonus(rules::Skill::Perception()) << std::endl;
if(! getLanguages().empty()) {
- text << "Languages: " << getLanguages() << endl;
+ text << "Languages: " << getLanguages() << std::endl;
}
- text << "Proficiency: " << getProficiency() << endl;
+ text << "Proficiency: " << getProficiency() << std::endl;
if(! getSkills().empty()) {
- text << endl << "Skills:" << endl;
+ text << std::endl << "Skills:" << std::endl;
for(auto skill : getSkills()) {
- text << " * " << skill.first.getName() << " (+" << skill.second << ")" << endl;
+ text << " * " << skill.first.getName() << " (+" << skill.second << ")" << std::endl;
}
}
if(! getSaves().empty()) {
- text << endl << "Saves:" << endl;
+ text << std::endl << "Saves:" << std::endl;
for(auto save : getSaves()) {
- text << " * " << save.first.getAbbrev() << " (+" << save.second << ")" << endl;
+ text << " * " << save.first.getAbbrev() << " (+" << save.second << ")" << std::endl;
}
}
if(! getDmgImmunities().empty()) {
- text << formatDmgTypeVector("\nDamage Immunities", getDmgImmunities()) << endl;
+ text << formatDmgTypeVector("\nDamage Immunities", getDmgImmunities()) << std::endl;
}
if(! getDmgResistances().empty()) {
- text << formatDmgTypeVector("\nDamage Resistances", getDmgResistances()) << endl;
+ text << formatDmgTypeVector("\nDamage Resistances", getDmgResistances()) << std::endl;
}
if(! getDmgVulnerabilities().empty()) {
- text << formatDmgTypeVector("\nDamage Vulnerabilities", getDmgVulnerabilities()) << endl;
+ text << formatDmgTypeVector("\nDamage Vulnerabilities", getDmgVulnerabilities()) << std::endl;
}
if(! getCondImmunities().empty()) {
- text << formatDmgTypeVector("\nCondition Immunities", getCondImmunities()) << endl;
+ text << formatDmgTypeVector("\nCondition Immunities", getCondImmunities()) << std::endl;
}
if(! getFeatures().empty()) {
- text << endl << "Features:" << endl;
+ text << std::endl << "Features:" << std::endl;
for(auto f: getFeatures()) {
- text << " * " << f->getText(*this) << endl;
+ text << " * " << f->getText(*this) << std::endl;
}
}
if(! getInventory().empty()) {
- text << endl << "Inventory:" << endl;
+ text << std::endl << "Inventory:" << std::endl;
for(auto i : getInventory()) {
- text << " * " << i->getText(*this) << endl;
+ text << " * " << i->getText(*this) << std::endl;
}
}
if(! Entry::getText().empty()) {
- text << endl << Entry::getText() << endl;
+ text << std::endl << Entry::getText() << std::endl;
}
return text.str();