diff --git a/src/Battling/Flow/TurnHandler.cpp b/src/Battling/Flow/TurnHandler.cpp index bcc584c..f3d58ba 100644 --- a/src/Battling/Flow/TurnHandler.cpp +++ b/src/Battling/Flow/TurnHandler.cpp @@ -1,6 +1,7 @@ #include "TurnHandler.hpp" #include "../Models/Creature.hpp" #include "../Models/Battle.hpp" +#include "../Models/ExecutingAttack.hpp" #include "../../Core/Exceptions/NotImplementedException.hpp" void CreatureLib::Battling::TurnHandler::RunTurn(CreatureLib::Battling::ChoiceQueue &queue) { @@ -52,6 +53,72 @@ void CreatureLib::Battling::TurnHandler::ExecuteAttackChoice(const CreatureLib:: //HOOK: Prevent attack + auto attack = ExecutingAttack(); + //HOOK: override targets + + if (!choice->GetAttack()->TryUse(1)){ + return; + } + + //HOOK: check if attack fails + + //HOOK: Check if attack stops after decreasing PP + + //HOOK: On Before Attack + + for (auto kv: attack.GetTargets()){ + HandleAttackForTarget(attack, kv.first, kv.second); + } } +void CreatureLib::Battling::TurnHandler::HandleAttackForTarget(CreatureLib::Battling::ExecutingAttack &attack, + CreatureLib::Battling::Creature *target, + CreatureLib::Battling::ExecutingAttack::TargetData &targetData) { + //HOOK: Check if attack fails on target + + //HOOK: Check if target is invulnerable + + + if (!targetData.IsHit()){ + //HOOK: On attack miss. + return; + } + + auto numHits = targetData.GetNumberOfHits(); + if (numHits == 0) + return; + auto user = attack.GetUser(); + auto attackData = attack.GetAttack()->GetAttack(); + for (uint8_t hitIndex = 0; hitIndex < numHits; hitIndex++){ + if (user->IsFainted()){ + break; + } + if (target->IsFainted()){ + // STOP, STOP! HE'S ALREADY DEAD ;_; + break; + } + auto hit = targetData.GetHit(hitIndex); + //TODO: calculate data for hit + if (attackData->GetCategory() == Library::AttackCategory::Status){ + //HOOK: Status attack + } + else{ + auto damage = hit.GetDamage(); + if (damage > target->GetCurrentHealth()){ + damage = target->GetCurrentHealth(); + hit.OverrideDamage(damage); + } + if (damage > 0){ + target->Damage(damage, DamageSource::AttackDamage); + //HOOK: Prevent secondary effects + + //HOOK: On Move Hit + } + } + } + + if (!user->IsFainted()){ + //HOOK: On After Hits + } +} diff --git a/src/Battling/Flow/TurnHandler.hpp b/src/Battling/Flow/TurnHandler.hpp index 81db395..cb13942 100644 --- a/src/Battling/Flow/TurnHandler.hpp +++ b/src/Battling/Flow/TurnHandler.hpp @@ -3,6 +3,7 @@ #include "ChoiceQueue.hpp" #include "../TurnChoices/AttackTurnChoice.hpp" +#include "../Models/ExecutingAttack.hpp" namespace CreatureLib::Battling { class Battle; @@ -11,6 +12,7 @@ namespace CreatureLib::Battling { static void ExecuteChoice(const BaseTurnChoice* choice); static void ExecuteAttackChoice(const AttackTurnChoice* choice); + static void HandleAttackForTarget(ExecutingAttack& attack, Creature* target, ExecutingAttack::TargetData& targetData); public: static void RunTurn(ChoiceQueue& queue); }; diff --git a/src/Battling/Models/Creature.cpp b/src/Battling/Models/Creature.cpp index 26b7ae1..7c0a21f 100644 --- a/src/Battling/Models/Creature.cpp +++ b/src/Battling/Models/Creature.cpp @@ -116,3 +116,11 @@ Battling::BattleSide *Battling::Creature::GetBattleSide() const { bool Battling::Creature::IsFainted() const { return this->__CurrentHealth <= 0; } + +void Battling::Creature::Damage(uint32_t damage, Battling::DamageSource source) { + if (damage > __CurrentHealth){ + damage = __CurrentHealth; + } + // HOOK: On Damage + __CurrentHealth -= damage; +} diff --git a/src/Battling/Models/Creature.hpp b/src/Battling/Models/Creature.hpp index 1c24698..b12c5ed 100644 --- a/src/Battling/Models/Creature.hpp +++ b/src/Battling/Models/Creature.hpp @@ -4,6 +4,7 @@ #include "../../GenericTemplates.cpp" #include "../Library/BattleLibrary.hpp" #include "LearnedAttack.hpp" +#include "DamageSource.hpp" namespace CreatureLib::Battling{ // Forward declare battle class @@ -45,11 +46,10 @@ namespace CreatureLib::Battling{ const std::string& GetNickname() const; const std::string& GetTalent() const; - void ChangeLevel(int8_t amount); + void Damage(uint32_t damage, DamageSource source); void SetBattleData(Battle* battle, BattleSide* side); - Battle* GetBattle() const; BattleSide* GetBattleSide() const; @@ -71,6 +71,8 @@ namespace CreatureLib::Battling{ void RecalculateFlatStat(Core::Statistic); void RecalculateBoostedStat(Core::Statistic); //endregion + + }; } diff --git a/src/Battling/Models/DamageSource.hpp b/src/Battling/Models/DamageSource.hpp new file mode 100644 index 0000000..0e02b6c --- /dev/null +++ b/src/Battling/Models/DamageSource.hpp @@ -0,0 +1,12 @@ +#ifndef CREATURELIB_DAMAGESOURCE_HPP +#define CREATURELIB_DAMAGESOURCE_HPP + +#include + +namespace CreatureLib::Battling { + enum class DamageSource : uint8_t { + AttackDamage, + }; +} + +#endif //CREATURELIB_DAMAGESOURCE_HPP diff --git a/src/Battling/Models/ExecutingAttack.cpp b/src/Battling/Models/ExecutingAttack.cpp new file mode 100644 index 0000000..b82c401 --- /dev/null +++ b/src/Battling/Models/ExecutingAttack.cpp @@ -0,0 +1 @@ +#include "ExecutingAttack.hpp" diff --git a/src/Battling/Models/ExecutingAttack.hpp b/src/Battling/Models/ExecutingAttack.hpp new file mode 100644 index 0000000..13812b3 --- /dev/null +++ b/src/Battling/Models/ExecutingAttack.hpp @@ -0,0 +1,89 @@ +#ifndef CREATURELIB_EXECUTINGATTACK_HPP +#define CREATURELIB_EXECUTINGATTACK_HPP + +#include +#include +#include +#include "Creature.hpp" + +namespace CreatureLib::Battling { + class ExecutingAttack { + public: + class HitData{ + bool _critical = false; + uint8_t _basePower = 0; + float _effectiveness = 1; + uint32_t _damage = 0; + public: + HitData(){} + + inline bool IsCritical() const{ return _critical;} + inline uint8_t GetBasePower() const{ return _basePower;} + inline float GetEffectiveness() const{ return _effectiveness;} + inline uint32_t GetDamage() const{ return _damage;} + + inline void SetCritical(bool value) {_critical = value;} + inline void SetBasePower(uint8_t value) { _basePower = value; } + inline void SetEffectiveness(float value) {_effectiveness = value;} + inline void OverrideDamage(uint32_t value) {_damage = value;} + }; + + class TargetData { + bool _isHit = true; + std::vector _hits; + public: + TargetData(uint8_t numberOfHits) : _hits(numberOfHits) + { + for (uint8_t i = 0; i < numberOfHits; i++){ + _hits[i] = HitData(); + } + } + TargetData(){} + + HitData& GetHit(uint8_t index){ + return _hits[index]; + } + + HitData* GetHitPtr(uint8_t index){ + return &_hits[index]; + } + + uint8_t GetNumberOfHits(){ + return _hits.size(); + } + + bool IsHit(){ + return _isHit; + } + + }; + + private: + std::unordered_map _targets; + Creature* _user; + LearnedAttack* _attack; + public: + + TargetData& GetAttackDataForTarget(Creature* creature){ + return _targets[creature]; + } + + bool IsCreatureTarget(Creature* creature){ + return _targets.find(creature) != _targets.end(); + } + + const std::unordered_map& GetTargets(){ + return _targets; + } + + Creature* GetUser(){ + return _user; + } + + LearnedAttack* GetAttack(){ + return _attack; + } + }; +} + +#endif //CREATURELIB_EXECUTINGATTACK_HPP