From 649de39571489df9e4f92eefeea3aaa401d94001 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 14 Dec 2019 13:28:23 +0100 Subject: [PATCH] Implements experience gain on opponent faint. --- src/Battling/Library/BattleLibrary.cpp | 5 +-- src/Battling/Library/BattleLibrary.hpp | 9 ++++- src/Battling/Library/ExperienceLibrary.cpp | 13 ++++++++ src/Battling/Library/ExperienceLibrary.hpp | 16 +++++++++ src/Battling/Models/Creature.cpp | 28 +++++++++++++--- src/Battling/Models/Creature.hpp | 3 ++ src/Library/GrowthRates/GrowthRateLibrary.hpp | 2 ++ src/Library/GrowthRates/LookupGrowthRate.hpp | 33 +++++++++++++++++++ tests/TestLibrary/TestLibrary.cpp | 31 +++++++++-------- 9 files changed, 119 insertions(+), 21 deletions(-) create mode 100644 src/Battling/Library/ExperienceLibrary.cpp create mode 100644 src/Battling/Library/ExperienceLibrary.hpp create mode 100644 src/Library/GrowthRates/LookupGrowthRate.hpp diff --git a/src/Battling/Library/BattleLibrary.cpp b/src/Battling/Library/BattleLibrary.cpp index 1ae0b90..48a819a 100644 --- a/src/Battling/Library/BattleLibrary.cpp +++ b/src/Battling/Library/BattleLibrary.cpp @@ -5,15 +5,16 @@ using namespace CreatureLib::Battling; BattleLibrary::BattleLibrary(CreatureLib::Library::DataLibrary* staticLib, BattleStatCalculator* statCalculator, DamageLibrary* damageLibrary, CriticalLibrary* criticalLibrary, - ScriptResolver* scriptResolver) + ExperienceLibrary* experienceLibrary, ScriptResolver* scriptResolver) : _staticLib(staticLib), _statCalculator(statCalculator), _damageLibrary(damageLibrary), - _criticalLibrary(criticalLibrary), _scriptResolver(scriptResolver) {} + _criticalLibrary(criticalLibrary), _experienceLibrary(experienceLibrary), _scriptResolver(scriptResolver) {} BattleLibrary::~BattleLibrary() { delete _staticLib; delete _statCalculator; delete _damageLibrary; delete _criticalLibrary; + delete _experienceLibrary; delete _scriptResolver; } diff --git a/src/Battling/Library/BattleLibrary.hpp b/src/Battling/Library/BattleLibrary.hpp index a8afbd2..238eb29 100644 --- a/src/Battling/Library/BattleLibrary.hpp +++ b/src/Battling/Library/BattleLibrary.hpp @@ -6,6 +6,7 @@ #include "BattleStatCalculator.hpp" #include "CriticalLibrary.hpp" #include "DamageLibrary.hpp" +#include "ExperienceLibrary.hpp" namespace CreatureLib::Battling { class BattleLibrary { @@ -13,11 +14,13 @@ namespace CreatureLib::Battling { BattleStatCalculator* _statCalculator = nullptr; DamageLibrary* _damageLibrary = nullptr; CriticalLibrary* _criticalLibrary = nullptr; + ExperienceLibrary* _experienceLibrary = nullptr; ScriptResolver* _scriptResolver = nullptr; public: BattleLibrary(Library::DataLibrary* staticLib, BattleStatCalculator* statCalculator, - DamageLibrary* damageLibrary, CriticalLibrary* criticalLibrary, ScriptResolver* scriptResolver); + DamageLibrary* damageLibrary, CriticalLibrary* criticalLibrary, + ExperienceLibrary* experienceLibrary, ScriptResolver* scriptResolver); ~BattleLibrary(); [[nodiscard]] const Library::LibrarySettings& GetSettings() const; @@ -25,10 +28,14 @@ namespace CreatureLib::Battling { [[nodiscard]] const Library::ItemLibrary* GetItemLibrary() const; [[nodiscard]] const Library::AttackLibrary* GetAttackLibrary() const; [[nodiscard]] const Library::TypeLibrary* GetTypeLibrary() const; + [[nodiscard]] const Library::GrowthRateLibrary* GetGrowthRateLibrary() const { + return _staticLib->GetGrowthRates(); + } [[nodiscard]] const BattleStatCalculator* GetStatCalculator() const; [[nodiscard]] const DamageLibrary* GetDamageLibrary() const; [[nodiscard]] const CriticalLibrary* GetCriticalLibrary() const; + [[nodiscard]] const ExperienceLibrary* GetExperienceLibrary() const { return _experienceLibrary; } [[nodiscard]] Script* LoadScript(ScriptResolver::ScriptCategory category, const std::string& scriptName) const; }; diff --git a/src/Battling/Library/ExperienceLibrary.cpp b/src/Battling/Library/ExperienceLibrary.cpp new file mode 100644 index 0000000..03d1b3e --- /dev/null +++ b/src/Battling/Library/ExperienceLibrary.cpp @@ -0,0 +1,13 @@ +#include "ExperienceLibrary.hpp" +#include "../Models/Creature.hpp" + +void CreatureLib::Battling::ExperienceLibrary::HandleExperienceGain( + CreatureLib::Battling::Creature* faintedMon, const std::unordered_set& opponents) const { + for (auto opponent : opponents) { + auto levelDiff = faintedMon->GetLevel() - opponent->GetLevel() + 10; + if (levelDiff <= 0) + continue; + auto experienceGain = levelDiff * 10; + opponent->AddExperience(static_cast(experienceGain)); + } +} diff --git a/src/Battling/Library/ExperienceLibrary.hpp b/src/Battling/Library/ExperienceLibrary.hpp new file mode 100644 index 0000000..c59880e --- /dev/null +++ b/src/Battling/Library/ExperienceLibrary.hpp @@ -0,0 +1,16 @@ +#ifndef CREATURELIB_EXPERIENCELIBRARY_HPP +#define CREATURELIB_EXPERIENCELIBRARY_HPP +#include + +namespace CreatureLib::Battling { + class Creature; + + class ExperienceLibrary { + public: + virtual ~ExperienceLibrary() = default; + + virtual void HandleExperienceGain(Creature* faintedMon, const std::unordered_set& opponents) const; + }; +} + +#endif // CREATURELIB_EXPERIENCELIBRARY_HPP diff --git a/src/Battling/Models/Creature.cpp b/src/Battling/Models/Creature.cpp index 7c6c67e..04c546b 100644 --- a/src/Battling/Models/Creature.cpp +++ b/src/Battling/Models/Creature.cpp @@ -92,6 +92,16 @@ Battling::BattleSide* Battling::Creature::GetBattleSide() const { return _side; bool Battling::Creature::IsFainted() const { return this->__CurrentHealth <= 0; } +void Battling::Creature::OnFaint() { + // HOOK: On Faint + _library->GetExperienceLibrary()->HandleExperienceGain(this, _seenOpponents); + + if (!_battle->CanSlotBeFilled(_side->GetSideIndex(), _side->GetCreatureIndex(this))) { + _side->MarkSlotAsUnfillable(this); + } + _battle->ValidateBattleState(); +} + void Battling::Creature::Damage(uint32_t damage, Battling::DamageSource source) { if (damage > __CurrentHealth) { damage = __CurrentHealth; @@ -100,10 +110,7 @@ void Battling::Creature::Damage(uint32_t damage, Battling::DamageSource source) __CurrentHealth -= damage; if (IsFainted() && damage > 0) { - if (!_battle->CanSlotBeFilled(_side->GetSideIndex(), _side->GetCreatureIndex(this))) { - _side->MarkSlotAsUnfillable(this); - } - _battle->ValidateBattleState(); + OnFaint(); } } @@ -130,3 +137,16 @@ void Battling::Creature::GetActiveScripts(std::vector& scripts) { _side->GetActiveScripts(scripts); } void Battling::Creature::ClearVolatileScripts() { _volatile.Clear(); } +void Battling::Creature::AddExperience(uint32_t amount) { + auto maxLevel = _library->GetSettings().GetMaximalLevel(); + if (__Level >= maxLevel) { + return; + } + auto exp = __Experience + amount; + auto level = _library->GetGrowthRateLibrary()->CalculateLevel(this->GetSpecies()->GetGrowthRate(), exp); + if (level >= maxLevel) { + exp = _library->GetGrowthRateLibrary()->CalculateExperience(this->GetSpecies()->GetGrowthRate(), maxLevel); + } + __Experience = exp; + __Level = level; +} diff --git a/src/Battling/Models/Creature.hpp b/src/Battling/Models/Creature.hpp index c48b036..2887297 100644 --- a/src/Battling/Models/Creature.hpp +++ b/src/Battling/Models/Creature.hpp @@ -54,6 +54,8 @@ namespace CreatureLib::Battling { Script* _status = nullptr; ScriptSet _volatile = {}; + void OnFaint(); + public: Creature(const BattleLibrary* library, const Library::CreatureSpecies* species, const Library::SpeciesVariant* variant, uint8_t level, uint32_t experience, @@ -83,6 +85,7 @@ namespace CreatureLib::Battling { void ChangeLevel(int8_t amount); void Damage(uint32_t damage, DamageSource source); void OverrideActiveTalent(const std::string& talent); + void AddExperience(uint32_t amount); void MarkOpponentAsSeen(Creature* creature) { _seenOpponents.insert(creature); } const std::unordered_set& GetSeenOpponents() const { return _seenOpponents; } diff --git a/src/Library/GrowthRates/GrowthRateLibrary.hpp b/src/Library/GrowthRates/GrowthRateLibrary.hpp index 21b7289..3430ba8 100644 --- a/src/Library/GrowthRates/GrowthRateLibrary.hpp +++ b/src/Library/GrowthRates/GrowthRateLibrary.hpp @@ -14,6 +14,8 @@ namespace CreatureLib::Library { public: [[nodiscard]] uint8_t CalculateLevel(const std::string& growthRate, uint32_t experience) const; [[nodiscard]] uint32_t CalculateExperience(const std::string& growthRate, uint8_t level) const; + + void AddGrowthRate(std::string name, GrowthRate* rate) { _growthRates.insert({name, rate}); } }; } diff --git a/src/Library/GrowthRates/LookupGrowthRate.hpp b/src/Library/GrowthRates/LookupGrowthRate.hpp new file mode 100644 index 0000000..9aa65ff --- /dev/null +++ b/src/Library/GrowthRates/LookupGrowthRate.hpp @@ -0,0 +1,33 @@ +#ifndef CREATURELIB_LOOKUPGROWTHRATE_HPP +#define CREATURELIB_LOOKUPGROWTHRATE_HPP + +#include +#include "GrowthRate.hpp" +namespace CreatureLib::Library { + class LookupGrowthRate : public GrowthRate { + protected: + std::vector _experience = { + 0, 15, 52, 122, 237, 406, 637, 942, 1326, 1800, 2369, 3041, 3822, + 4719, 5737, 6881, 8155, 9564, 11111, 12800, 14632, 16610, 18737, 21012, 23437, 26012, + 28737, 31610, 34632, 37800, 41111, 44564, 48155, 51881, 55737, 59719, 63822, 68041, 72369, + 76800, 81326, 85942, 90637, 95406, 100237, 105122, 110052, 115015, 120001, 125000, 131324, 137795, + 144410, 151165, 158056, 165079, 172229, 179503, 186894, 194400, 202013, 209728, 217540, 225443, 233431, + 241496, 249633, 257834, 267406, 276458, 286328, 296358, 305767, 316074, 326531, 336255, 346965, 357812, + 367807, 378880, 390077, 400293, 411686, 423190, 433572, 445239, 457001, 467489, 479378, 491346, 501878, + 513934, 526049, 536557, 548720, 560922, 571333, 583539, 591882, 600000}; + + public: + uint8_t CalculateLevel(uint32_t experience) const override { + for (uint8_t i = 0; i < _experience.size(); i++) { + if (_experience[i] > experience) { + return i; + } + } + return _experience[_experience.size() - 1]; + } + + uint32_t CalculateExperience(uint8_t level) const override { return _experience[level - 1]; } + }; +} + +#endif // CREATURELIB_LOOKUPGROWTHRATE_HPP diff --git a/tests/TestLibrary/TestLibrary.cpp b/tests/TestLibrary/TestLibrary.cpp index 9217541..f371db1 100644 --- a/tests/TestLibrary/TestLibrary.cpp +++ b/tests/TestLibrary/TestLibrary.cpp @@ -1,35 +1,37 @@ #ifdef TESTS_BUILD #include "TestLibrary.hpp" +#include "../../src/Library/GrowthRates/LookupGrowthRate.hpp" using namespace CreatureLib::Core; using namespace CreatureLib::Library; using namespace CreatureLib::Battling; BattleLibrary* TestLibrary::_library = nullptr; -BattleLibrary *TestLibrary::Get() { - if (TestLibrary::_library == nullptr){ - auto l = new DataLibrary(LibrarySettings(100, 4), BuildSpeciesLibrary(), BuildAttackLibrary(), BuildItemLibrary(), - BuildGrowthRateLibrary(), BuildTypeLibrary()); +BattleLibrary* TestLibrary::Get() { + if (TestLibrary::_library == nullptr) { + auto l = new DataLibrary(LibrarySettings(100, 4), BuildSpeciesLibrary(), BuildAttackLibrary(), + BuildItemLibrary(), BuildGrowthRateLibrary(), BuildTypeLibrary()); auto statCalc = new BattleStatCalculator(); - auto battleLib = new BattleLibrary(l, statCalc, new DamageLibrary(), new CriticalLibrary(), new ScriptResolver()); + auto battleLib = new BattleLibrary(l, statCalc, new DamageLibrary(), new CriticalLibrary(), + new ExperienceLibrary(), new ScriptResolver()); TestLibrary::_library = battleLib; } return TestLibrary::_library; } -SpeciesLibrary *TestLibrary::BuildSpeciesLibrary() { +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, 100)); + 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, 100)); return l; } -AttackLibrary *TestLibrary::BuildAttackLibrary() { +AttackLibrary* TestLibrary::BuildAttackLibrary() { auto l = new AttackLibrary(); l->LoadAttack("standard", new AttackData("standard", "normal", AttackCategory::Physical, 20, 100, 30, AttackTarget::AdjacentOpponent, 0, {})); @@ -42,17 +44,18 @@ AttackLibrary *TestLibrary::BuildAttackLibrary() { return l; } -ItemLibrary *TestLibrary::BuildItemLibrary() { +ItemLibrary* TestLibrary::BuildItemLibrary() { auto l = new ItemLibrary(); return l; } -GrowthRateLibrary *TestLibrary::BuildGrowthRateLibrary() { +GrowthRateLibrary* TestLibrary::BuildGrowthRateLibrary() { auto l = new GrowthRateLibrary(); + l->AddGrowthRate("testGrowthRate", new LookupGrowthRate()); return l; } -TypeLibrary *TestLibrary::BuildTypeLibrary() { +TypeLibrary* TestLibrary::BuildTypeLibrary() { auto l = new TypeLibrary(); l->RegisterType("testType1"); l->RegisterType("testType2");