diff --git a/src/Battling/Models/CreateCreature.cpp b/src/Battling/Models/CreateCreature.cpp index 0370069..25fb11e 100644 --- a/src/Battling/Models/CreateCreature.cpp +++ b/src/Battling/Models/CreateCreature.cpp @@ -24,14 +24,14 @@ CreateCreature* CreateCreature::WithAttack(const std::string& attackName, Attack if (_attacks.size() >= _library->GetSettings()->GetMaximalMoves()) throw CreatureException("You have already set the maximum amount of allowed moves."); - auto attackData = _library->GetAttackLibrary()->GetAttack(attackName); + auto attackData = _library->GetAttackLibrary()->Get(attackName.c_str()); _attacks.emplace_back(attackData, learnMethod); return this; } Creature* CreateCreature::Create() { auto rand = Core::Random(); - auto species = this->_library->GetSpeciesLibrary()->GetSpecies(this->_species); + auto species = this->_library->GetSpeciesLibrary()->Get(this->_species.c_str()); auto variant = species->GetVariant(this->_variant); int8_t talent; if (this->_talent.empty()) { @@ -49,7 +49,9 @@ Creature* CreateCreature::Create() { } const Library::Item* heldItem = nullptr; if (!this->_heldItem.empty()) { - heldItem = _library->GetItemLibrary()->GetItem(this->_heldItem); + if (!_library->GetItemLibrary()->TryGet(this->_heldItem.c_str(), heldItem)) { + throw CreatureException("Invalid held item."); + } } // FIXME: implement experience auto experience = 0; diff --git a/src/Library/AttackLibrary.cpp b/src/Library/AttackLibrary.cpp index 01d6500..e70236c 100644 --- a/src/Library/AttackLibrary.cpp +++ b/src/Library/AttackLibrary.cpp @@ -1,37 +1 @@ #include "AttackLibrary.hpp" - -bool CreatureLib::Library::AttackLibrary::TryGetAttack(const std::string& name, - const CreatureLib::Library::AttackData*& move) const { - std::string key = name; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - auto find = _attacks.find(key); - if (find == _attacks.end()) { - move = nullptr; - return false; - } - move = find->second; - return true; -} - -const CreatureLib::Library::AttackData* CreatureLib::Library::AttackLibrary::GetAttack(const std::string& name) const { - std::string key = name; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - return this->_attacks.at(key); -} - -const CreatureLib::Library::AttackData* CreatureLib::Library::AttackLibrary::operator[](const std::string& name) const { - return GetAttack(name); -} - -void CreatureLib::Library::AttackLibrary::LoadAttack(const std::string& name, - const CreatureLib::Library::AttackData* attack) { - std::string key = name; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - this->_attacks.insert({key, attack}); -} - -void CreatureLib::Library::AttackLibrary::DeleteAttack(const std::string& name) { - std::string key = name; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - this->_attacks.erase(key); -} diff --git a/src/Library/AttackLibrary.hpp b/src/Library/AttackLibrary.hpp index 805f6d4..7ae927b 100644 --- a/src/Library/AttackLibrary.hpp +++ b/src/Library/AttackLibrary.hpp @@ -4,31 +4,11 @@ #include #include #include "Attacks/AttackData.hpp" - +#include "BaseLibrary.hpp" namespace CreatureLib::Library { - class AttackLibrary { - private: - std::unordered_map _attacks; - + class AttackLibrary : public BaseLibrary { public: - AttackLibrary(size_t initialCapacity = 32) - : _attacks(std::unordered_map(initialCapacity)){}; - - virtual ~AttackLibrary() { - for (auto attack : _attacks) { - delete attack.second; - } - _attacks.clear(); - } - - [[nodiscard]] bool TryGetAttack(const std::string& name, const AttackData*& move) const; - [[nodiscard]] const AttackData* GetAttack(const std::string& name) const; - [[nodiscard]] const AttackData* operator[](const std::string& name) const; - - void LoadAttack(const std::string& name, const AttackData* attack); - void DeleteAttack(const std::string& name); - - const std::unordered_map& GetIterator() { return _attacks; } + AttackLibrary(size_t initialCapacity = 32) : BaseLibrary(initialCapacity){}; }; } diff --git a/src/Library/BaseLibrary.cpp b/src/Library/BaseLibrary.cpp new file mode 100644 index 0000000..d1c7673 --- /dev/null +++ b/src/Library/BaseLibrary.cpp @@ -0,0 +1 @@ +#include "BaseLibrary.hpp" diff --git a/src/Library/BaseLibrary.hpp b/src/Library/BaseLibrary.hpp new file mode 100644 index 0000000..d730468 --- /dev/null +++ b/src/Library/BaseLibrary.hpp @@ -0,0 +1,50 @@ +#ifndef CREATURELIB_BASELIBRARY_HPP +#define CREATURELIB_BASELIBRARY_HPP + +#include +#include +#include +namespace CreatureLib::Library { + template class BaseLibrary { + inline static constexpr char charToLower(const char c) { return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; } + inline static uint32_t constexpr Hash(char const* input) { + return charToLower(*input) ? static_cast(charToLower(*input)) + 33 * Hash(input + 1) : 5381; + } + + std::unordered_map _values; + + public: + BaseLibrary(size_t initialCapacity = 32) : _values(initialCapacity) {} + + virtual ~BaseLibrary() { + for (const auto& v : _values) { + delete v.second; + } + _values.clear(); + } + + inline void Insert(const char* key, const T* value) { _values.insert({Hash(key), value}); } + + inline void Delete(const char* key) { _values.erase(Hash(key)); } + + bool TryGet(const char* name, const T*& out) const { + auto find = this->_values.find(Hash(name)); + if (find == this->_values.end()) { + out = nullptr; + return false; + } + out = find->second; + return true; + } + + inline const T* Get(const char* name) const { return _values.at(Hash(name)); } + + inline const T* operator[](const char* name) const { return Get(name); } + + inline const std::unordered_map& GetIterator() const { return _values; } + + size_t GetCount() const { return _values.count(); } + }; +} + +#endif // CREATURELIB_BASELIBRARY_HPP diff --git a/src/Library/ItemLibrary.cpp b/src/Library/ItemLibrary.cpp index eafd8eb..06f8145 100644 --- a/src/Library/ItemLibrary.cpp +++ b/src/Library/ItemLibrary.cpp @@ -1,36 +1 @@ #include "ItemLibrary.hpp" - -bool CreatureLib::Library::ItemLibrary::TryGetItem(const std::string& name, - const CreatureLib::Library::Item*& item) const { - std::string key = name; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - auto find = this->_items.find(key); - if (find == this->_items.end()) { - item = nullptr; - return false; - } - item = find->second; - return true; -} - -const CreatureLib::Library::Item* CreatureLib::Library::ItemLibrary::GetItem(const std::string& name) const { - std::string key = name; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - return this->_items.at(key); -} - -const CreatureLib::Library::Item* CreatureLib::Library::ItemLibrary::operator[](const std::string& name) const { - return this->GetItem(name); -} - -void CreatureLib::Library::ItemLibrary::LoadItem(const std::string& name, const CreatureLib::Library::Item* item) { - std::string key = name; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - this->_items.insert({key, item}); -} - -void CreatureLib::Library::ItemLibrary::DeleteItem(const std::string& name) { - std::string key = name; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - this->_items.erase(key); -} diff --git a/src/Library/ItemLibrary.hpp b/src/Library/ItemLibrary.hpp index a5909bd..ab84bb4 100644 --- a/src/Library/ItemLibrary.hpp +++ b/src/Library/ItemLibrary.hpp @@ -3,26 +3,13 @@ #include #include +#include "BaseLibrary.hpp" #include "Items/Item.hpp" namespace CreatureLib::Library { - class ItemLibrary { - private: - std::unordered_map _items; - + class ItemLibrary : public BaseLibrary { public: - ItemLibrary(size_t initialCapacity = 32) - : _items(std::unordered_map(initialCapacity)){}; - virtual ~ItemLibrary() { _items.clear(); } - - [[nodiscard]] bool TryGetItem(const std::string& name, const Item*& item) const; - [[nodiscard]] const Item* GetItem(const std::string& name) const; - [[nodiscard]] const Item* operator[](const std::string& name) const; - - void LoadItem(const std::string& name, const Item* item); - void DeleteItem(const std::string& name); - - const std::unordered_map& GetIterator() { return _items; } + ItemLibrary(size_t initialCapacity = 32) : BaseLibrary(initialCapacity){}; }; } diff --git a/src/Library/SpeciesLibrary.cpp b/src/Library/SpeciesLibrary.cpp index 7328a90..aac3139 100644 --- a/src/Library/SpeciesLibrary.cpp +++ b/src/Library/SpeciesLibrary.cpp @@ -1,39 +1 @@ #include "SpeciesLibrary.hpp" - -bool CreatureLib::Library::SpeciesLibrary::TryGetSpecies( - const std::string& name, const CreatureLib::Library::CreatureSpecies*& outSpecies) const { - std::string key = name; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - auto find = _species.find(key); - if (find == _species.end()) { - outSpecies = nullptr; - return false; - } - outSpecies = find->second; - return true; -} - -const CreatureLib::Library::CreatureSpecies* -CreatureLib::Library::SpeciesLibrary::GetSpecies(const std::string& name) const { - std::string key = name; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - return _species.at(key); -} - -const CreatureLib::Library::CreatureSpecies* - CreatureLib::Library::SpeciesLibrary::operator[](const std::string& name) const { - return GetSpecies(name); -} - -void CreatureLib::Library::SpeciesLibrary::LoadSpecies(const std::string& name, - const CreatureLib::Library::CreatureSpecies* species) { - std::string key = name; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - _species.insert({key, species}); -} - -void CreatureLib::Library::SpeciesLibrary::DeleteSpecies(const std::string& name) { - std::string key = name; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - _species.erase(key); -} diff --git a/src/Library/SpeciesLibrary.hpp b/src/Library/SpeciesLibrary.hpp index a86d8af..a92aae3 100644 --- a/src/Library/SpeciesLibrary.hpp +++ b/src/Library/SpeciesLibrary.hpp @@ -3,33 +3,14 @@ #include #include +#include "BaseLibrary.hpp" #include "CreatureData/CreatureSpecies.hpp" namespace CreatureLib::Library { - class SpeciesLibrary { + class SpeciesLibrary : public BaseLibrary { private: - std::unordered_map _species; - public: - SpeciesLibrary(size_t initialCapacity = 32) - : _species(std::unordered_map(initialCapacity)){}; - - virtual ~SpeciesLibrary() { - for (auto s : _species) - delete s.second; - _species.clear(); - } - - [[nodiscard]] bool TryGetSpecies(const std::string& name, const CreatureSpecies*& outSpecies) const; - [[nodiscard]] const CreatureSpecies* GetSpecies(const std::string& name) const; - [[nodiscard]] const CreatureSpecies* operator[](const std::string& name) const; - - void LoadSpecies(const std::string& name, const CreatureSpecies* species); - void DeleteSpecies(const std::string& name); - - size_t GetCount() const { return _species.size(); } - - const std::unordered_map& GetIterator() { return _species; } + SpeciesLibrary(size_t initialCapacity = 32) : BaseLibrary(initialCapacity){}; }; } diff --git a/tests/BattleTests/TurnOrderTests.cpp b/tests/BattleTests/TurnOrderTests.cpp index 564fa87..dcdc9b2 100644 --- a/tests/BattleTests/TurnOrderTests.cpp +++ b/tests/BattleTests/TurnOrderTests.cpp @@ -28,8 +28,8 @@ TEST_CASE("Turn ordering: Attack before pass", "[Battling]") { TEST_CASE("Turn ordering: High priority goes before no priority", "[Battling]") { auto l = TestLibrary::Get()->GetAttackLibrary(); - auto a1 = new LearnedAttack(l->GetAttack("standard"), AttackLearnMethod::Unknown); - auto a2 = new LearnedAttack(l->GetAttack("highPriority"), AttackLearnMethod::Unknown); + auto a1 = new LearnedAttack(l->Get("standard"), AttackLearnMethod::Unknown); + auto a2 = new LearnedAttack(l->Get("highPriority"), AttackLearnMethod::Unknown); auto choice1 = new AttackTurnChoice(nullptr, a1, CreatureIndex(0, 0)); auto choice2 = new AttackTurnChoice(nullptr, a2, CreatureIndex(0, 0)); auto vec = std::vector{choice1, choice2}; @@ -50,8 +50,8 @@ TEST_CASE("Turn ordering: High priority goes before no priority", "[Battling]") TEST_CASE("Turn ordering: Higher priority goes before high priority", "[Battling]") { auto l = TestLibrary::Get()->GetAttackLibrary(); - auto a1 = new LearnedAttack(l->GetAttack("highPriority"), AttackLearnMethod::Unknown); - auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown); + auto a1 = new LearnedAttack(l->Get("highPriority"), AttackLearnMethod::Unknown); + auto a2 = new LearnedAttack(l->Get("higherPriority"), AttackLearnMethod::Unknown); auto choice1 = new AttackTurnChoice(nullptr, a1, CreatureIndex(0, 0)); auto choice2 = new AttackTurnChoice(nullptr, a2, CreatureIndex(0, 0)); auto vec = std::vector{choice1, choice2}; @@ -72,8 +72,8 @@ TEST_CASE("Turn ordering: Higher priority goes before high priority", "[Battling TEST_CASE("Turn ordering: High priority goes before low priority", "[Battling]") { auto l = TestLibrary::Get()->GetAttackLibrary(); - auto a1 = new LearnedAttack(l->GetAttack("lowPriority"), AttackLearnMethod::Unknown); - auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown); + auto a1 = new LearnedAttack(l->Get("lowPriority"), AttackLearnMethod::Unknown); + auto a2 = new LearnedAttack(l->Get("higherPriority"), AttackLearnMethod::Unknown); auto choice1 = new AttackTurnChoice(nullptr, a1, CreatureIndex(0, 0)); auto choice2 = new AttackTurnChoice(nullptr, a2, CreatureIndex(0, 0)); auto vec = std::vector{choice1, choice2}; @@ -94,8 +94,8 @@ TEST_CASE("Turn ordering: High priority goes before low priority", "[Battling]") TEST_CASE("Turn ordering: No priority goes before low priority", "[Battling]") { auto l = TestLibrary::Get()->GetAttackLibrary(); - auto a1 = new LearnedAttack(l->GetAttack("lowPriority"), AttackLearnMethod::Unknown); - auto a2 = new LearnedAttack(l->GetAttack("standard"), AttackLearnMethod::Unknown); + auto a1 = new LearnedAttack(l->Get("lowPriority"), AttackLearnMethod::Unknown); + auto a2 = new LearnedAttack(l->Get("standard"), AttackLearnMethod::Unknown); auto choice1 = new AttackTurnChoice(nullptr, a1, CreatureIndex(0, 0)); auto choice2 = new AttackTurnChoice(nullptr, a2, CreatureIndex(0, 0)); auto vec = std::vector{choice1, choice2}; diff --git a/tests/TestLibrary/TestLibrary.cpp b/tests/TestLibrary/TestLibrary.cpp index 0ab4819..c21c881 100644 --- a/tests/TestLibrary/TestLibrary.cpp +++ b/tests/TestLibrary/TestLibrary.cpp @@ -22,25 +22,25 @@ BattleLibrary* TestLibrary::Get() { SpeciesLibrary* TestLibrary::BuildSpeciesLibrary() { auto l = new SpeciesLibrary(); - l->LoadSpecies("testSpecies1", - new CreatureSpecies( - 0, "testSpecies1", - new SpeciesVariant("default", 1, 1, 10, {0, 1}, StatisticSet(10, 10, 10, 10, 10, 10), - {"testTalent"}, {"testSecretTalent"}, new LearnableAttacks(100)), - 0.5f, "testGrowthRate", 5)); + l->Insert("testSpecies1", + new CreatureSpecies(0, "testSpecies1", + new SpeciesVariant("default", 1, 1, 10, {0, 1}, + StatisticSet(10, 10, 10, 10, 10, 10), {"testTalent"}, + {"testSecretTalent"}, new LearnableAttacks(100)), + 0.5f, "testGrowthRate", 5)); return l; } AttackLibrary* TestLibrary::BuildAttackLibrary() { auto l = new AttackLibrary(); - l->LoadAttack("standard", new AttackData("standard", 0, AttackCategory::Physical, 20, 100, 30, - AttackTarget::AdjacentOpponent, 0, {})); - l->LoadAttack("highPriority", new AttackData("highPriority", 0, AttackCategory::Physical, 20, 100, 30, - AttackTarget::AdjacentOpponent, 1, {})); - l->LoadAttack("higherPriority", new AttackData("higherPriority", 0, AttackCategory::Physical, 20, 100, 30, - AttackTarget::AdjacentOpponent, 2, {})); - l->LoadAttack("lowPriority", new AttackData("lowPriority", 0, AttackCategory::Physical, 20, 100, 30, - AttackTarget::AdjacentOpponent, -1, {})); + l->Insert("standard", new AttackData("standard", 0, AttackCategory::Physical, 20, 100, 30, + AttackTarget::AdjacentOpponent, 0, {})); + l->Insert("highPriority", new AttackData("highPriority", 0, AttackCategory::Physical, 20, 100, 30, + AttackTarget::AdjacentOpponent, 1, {})); + l->Insert("higherPriority", new AttackData("higherPriority", 0, AttackCategory::Physical, 20, 100, 30, + AttackTarget::AdjacentOpponent, 2, {})); + l->Insert("lowPriority", new AttackData("lowPriority", 0, AttackCategory::Physical, 20, 100, 30, + AttackTarget::AdjacentOpponent, -1, {})); return l; }