diff --git a/src/Battling/Flow/TurnHandler.cpp b/src/Battling/Flow/TurnHandler.cpp index f077c11..bcc584c 100644 --- a/src/Battling/Flow/TurnHandler.cpp +++ b/src/Battling/Flow/TurnHandler.cpp @@ -1,14 +1,40 @@ #include "TurnHandler.hpp" +#include "../Models/Creature.hpp" +#include "../Models/Battle.hpp" #include "../../Core/Exceptions/NotImplementedException.hpp" void CreatureLib::Battling::TurnHandler::RunTurn(CreatureLib::Battling::ChoiceQueue &queue) { + //HOOK: On Before Turn hook for all choices while (queue.HasNext()){ ExecuteChoice(queue.Dequeue()); } } void CreatureLib::Battling::TurnHandler::ExecuteChoice(const CreatureLib::Battling::BaseTurnChoice *choice) { - switch (choice->GetKind()){ + if (choice == nullptr) + { + return; + } + auto choiceKind = choice->GetKind(); + if (choiceKind == TurnChoiceKind::Pass) { + return; + } + auto user = choice->GetUser(); + // If the user is fainted, we don't want to execute its choice. + if (user->IsFainted()){ + return; + } + auto battle = user->GetBattle(); + // If the user is not in the field, we don't want to execute its choice. + if (!battle->CreatureInField(user)){ + return; + } + // If the choice is not valid, we don't want to execute it. + if (!battle->CanUse(choice)){ + return; + } + + switch (choiceKind){ case TurnChoiceKind::Pass: return; case TurnChoiceKind::Attack: return ExecuteAttackChoice(static_cast(choice)); @@ -17,9 +43,15 @@ void CreatureLib::Battling::TurnHandler::ExecuteChoice(const CreatureLib::Battli case TurnChoiceKind::RunAway: throw NotImplementedException(); } + + delete choice; } void CreatureLib::Battling::TurnHandler::ExecuteAttackChoice(const CreatureLib::Battling::AttackTurnChoice *choice) { + //HOOK: Change attack + + //HOOK: Prevent attack + } diff --git a/src/Battling/Flow/TurnOrdering.cpp b/src/Battling/Flow/TurnOrdering.cpp index e01ab5d..ac0eb0f 100644 --- a/src/Battling/Flow/TurnOrdering.cpp +++ b/src/Battling/Flow/TurnOrdering.cpp @@ -2,6 +2,7 @@ #include "../TurnChoices/AttackTurnChoice.hpp" #include "../Models/Creature.hpp" #include "../Models/Battle.hpp" +#include "../../Core/Exceptions/NotImplementedException.hpp" #include diff --git a/src/Battling/Models/Battle.cpp b/src/Battling/Models/Battle.cpp index 0a5643c..da8c092 100644 --- a/src/Battling/Models/Battle.cpp +++ b/src/Battling/Models/Battle.cpp @@ -2,6 +2,7 @@ #include "../Flow/TurnHandler.hpp" #include "../TurnChoices/AttackTurnChoice.hpp" #include "../Flow/TurnOrdering.hpp" +#include "../../Core/Exceptions/NotImplementedException.hpp" using namespace CreatureLib; using namespace CreatureLib::Battling; @@ -10,10 +11,10 @@ const BattleLibrary *Battle::GetLibrary() const { return _library; } -bool Battle::CanUse(BaseTurnChoice *choice) { +bool Battle::CanUse(const BaseTurnChoice *choice) { if (choice->GetKind() == TurnChoiceKind::Attack){ //HOOK: change number of uses needed. - return static_cast(choice)->GetAttack()->GetRemainingUses() > 1; + return static_cast(choice)->GetAttack()->GetRemainingUses() > 1; } return true; } @@ -36,6 +37,16 @@ void Battle::CheckChoicesSetAndRun() { auto i = 0; for (auto side: _sides){ for (auto choice: side->GetChoices()){ + if (choice->GetKind() == TurnChoiceKind::Attack){ + auto attack = static_cast(choice)->GetAttack(); + uint8_t uses = 1; + //HOOK: change number of uses needed. + if (attack->GetRemainingUses() < uses){ + //TODO: Implement default move + throw NotImplementedException("Not enough remaining uses, change to default move."); + } + //HOOK: Check if we need to change the move + } choices[i] = choice; i++; } @@ -54,3 +65,11 @@ ChoiceQueue* Battle::GetCurrentTurnQueue() const { Core::Random &Battle::GetRandom(){ return _random; } + +bool Battle::CreatureInField(const Creature *creature) const { + for (auto s: _sides){ + if (s->CreatureOnSide(creature)) + return true; + } + return false; +} diff --git a/src/Battling/Models/Battle.hpp b/src/Battling/Models/Battle.hpp index 781bcc5..b91cbd1 100644 --- a/src/Battling/Models/Battle.hpp +++ b/src/Battling/Models/Battle.hpp @@ -6,6 +6,7 @@ #include "../Library/BattleLibrary.hpp" #include "../TurnChoices/BaseTurnChoice.hpp" #include "../Flow/ChoiceQueue.hpp" +#include "Target.hpp" namespace CreatureLib::Battling { class Battle { @@ -19,13 +20,19 @@ namespace CreatureLib::Battling { public: const BattleLibrary* GetLibrary() const; - virtual bool CanUse(BaseTurnChoice* choice); + virtual bool CanUse(const BaseTurnChoice* choice); virtual bool TrySetChoice(BaseTurnChoice* choice); void CheckChoicesSetAndRun(); ChoiceQueue* GetCurrentTurnQueue() const; Core::Random& GetRandom(); + + bool CreatureInField(const Creature* creature) const; + + Creature* GetTarget(const Target& target){ + return _sides[target.GetSideIndex()]->GetCreature(target.GetCreatureIndex()); + } }; } diff --git a/src/Battling/Models/BattleSide.cpp b/src/Battling/Models/BattleSide.cpp index a98d20b..162b0a7 100644 --- a/src/Battling/Models/BattleSide.cpp +++ b/src/Battling/Models/BattleSide.cpp @@ -34,3 +34,11 @@ void BattleSide::SetChoice(const BaseTurnChoice *choice) { void BattleSide::SetCreature(Creature *creature, uint8_t index) { _creatures[index] = creature; } + +bool BattleSide::CreatureOnSide(const Creature *creature) const { + return std::find(_creatures.begin(), _creatures.end(), creature) != _creatures.end(); +} + +Creature *BattleSide::GetCreature(uint8_t index) const { + return _creatures[index]; +} diff --git a/src/Battling/Models/BattleSide.hpp b/src/Battling/Models/BattleSide.hpp index ac0f31c..cec2dcb 100644 --- a/src/Battling/Models/BattleSide.hpp +++ b/src/Battling/Models/BattleSide.hpp @@ -25,6 +25,9 @@ namespace CreatureLib::Battling{ void SetCreature(Creature* creature, uint8_t index); + Creature* GetCreature(uint8_t index) const; + bool CreatureOnSide(const Creature* creature) const; + }; } diff --git a/src/Battling/Models/Creature.cpp b/src/Battling/Models/Creature.cpp index 4469a09..26b7ae1 100644 --- a/src/Battling/Models/Creature.cpp +++ b/src/Battling/Models/Creature.cpp @@ -103,6 +103,8 @@ void Battling::Creature::RecalculateBoostedStat(Core::Statistic stat) { this->_boostedStats.SetStat(stat, s); } +//endregion + Battling::Battle *Battling::Creature::GetBattle() const{ return _battle; } @@ -111,5 +113,6 @@ Battling::BattleSide *Battling::Creature::GetBattleSide() const { return _side; } - -//endregion +bool Battling::Creature::IsFainted() const { + return this->__CurrentHealth <= 0; +} diff --git a/src/Battling/Models/Creature.hpp b/src/Battling/Models/Creature.hpp index dfefec0..1c24698 100644 --- a/src/Battling/Models/Creature.hpp +++ b/src/Battling/Models/Creature.hpp @@ -53,6 +53,8 @@ namespace CreatureLib::Battling{ Battle* GetBattle() const; BattleSide* GetBattleSide() const; + bool IsFainted() const; + //region Stat APIs void SetBattle(Battle* battle); diff --git a/src/Battling/Models/Target.hpp b/src/Battling/Models/Target.hpp new file mode 100644 index 0000000..81acf42 --- /dev/null +++ b/src/Battling/Models/Target.hpp @@ -0,0 +1,24 @@ +#ifndef CREATURELIB_TARGET_HPP +#define CREATURELIB_TARGET_HPP + +#include +#include "Creature.hpp" + +namespace CreatureLib::Battling { + class Target { + uint8_t _side; + uint8_t _creature; + public: + Target(uint8_t side, uint8_t creature) : _side(side), _creature(creature){} + + uint8_t GetSideIndex() const{ + return _side; + } + + uint8_t GetCreatureIndex() const{ + return _creature; + } + }; +} + +#endif //CREATURELIB_TARGET_HPP diff --git a/src/Battling/TurnChoices/AttackTurnChoice.hpp b/src/Battling/TurnChoices/AttackTurnChoice.hpp index 1efcc0c..7ffc48a 100644 --- a/src/Battling/TurnChoices/AttackTurnChoice.hpp +++ b/src/Battling/TurnChoices/AttackTurnChoice.hpp @@ -3,13 +3,15 @@ #include "BaseTurnChoice.hpp" #include "../Models/LearnedAttack.hpp" +#include "../Models/Target.hpp" namespace CreatureLib::Battling{ class AttackTurnChoice : public BaseTurnChoice { LearnedAttack* _attack; + Target _target; public: - AttackTurnChoice(Creature* c, LearnedAttack* attack) - : BaseTurnChoice(c), _attack(attack){} + AttackTurnChoice(Creature* user, LearnedAttack* attack, const Target& target) + : BaseTurnChoice(user), _attack(attack), _target(target){} inline LearnedAttack* GetAttack() const{ return _attack; @@ -23,6 +25,10 @@ namespace CreatureLib::Battling{ //HOOK: Change priority return _attack->GetAttack()->GetPriority(); } + + const Target& GetTarget() const{ + return _target; + } }; } diff --git a/tests/BattleTests/TurnOrderTests.cpp b/tests/BattleTests/TurnOrderTests.cpp index d3fc302..d888084 100644 --- a/tests/BattleTests/TurnOrderTests.cpp +++ b/tests/BattleTests/TurnOrderTests.cpp @@ -10,7 +10,7 @@ using namespace CreatureLib::Battling; TEST_CASE( "Turn ordering: Attack before pass", "[Battling]" ) { auto choice1 = new PassTurnChoice(nullptr); - auto choice2 = new AttackTurnChoice(nullptr, nullptr); + auto choice2 = new AttackTurnChoice(nullptr, nullptr, Target(0,0)); auto vec = std::vector{choice1, choice2}; auto rand = Core::Random(); TurnOrdering::OrderChoices(vec,rand); @@ -29,8 +29,8 @@ TEST_CASE( "Turn ordering: High priority goes before no priority", "[Battling]" auto l = GetLibrary()->GetAttackLibrary(); auto a1 = new LearnedAttack(l->GetAttack("standard"), AttackLearnMethod::Unknown); auto a2 = new LearnedAttack(l->GetAttack("highPriority"), AttackLearnMethod::Unknown); - auto choice1 = new AttackTurnChoice(nullptr, a1); - auto choice2 = new AttackTurnChoice(nullptr, a2); + auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0)); + auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0)); auto vec = std::vector{choice1, choice2}; auto rand = Core::Random(); TurnOrdering::OrderChoices(vec,rand); @@ -51,8 +51,8 @@ TEST_CASE( "Turn ordering: Higher priority goes before high priority", "[Battlin auto l = GetLibrary()->GetAttackLibrary(); auto a1 = new LearnedAttack(l->GetAttack("highPriority"), AttackLearnMethod::Unknown); auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown); - auto choice1 = new AttackTurnChoice(nullptr, a1); - auto choice2 = new AttackTurnChoice(nullptr, a2); + auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0)); + auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0)); auto vec = std::vector{choice1, choice2}; auto rand = Core::Random(); TurnOrdering::OrderChoices(vec,rand); @@ -73,8 +73,8 @@ TEST_CASE( "Turn ordering: High priority goes before low priority", "[Battling]" auto l = GetLibrary()->GetAttackLibrary(); auto a1 = new LearnedAttack(l->GetAttack("lowPriority"), AttackLearnMethod::Unknown); auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown); - auto choice1 = new AttackTurnChoice(nullptr, a1); - auto choice2 = new AttackTurnChoice(nullptr, a2); + auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0)); + auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0)); auto vec = std::vector{choice1, choice2}; auto rand = Core::Random(); TurnOrdering::OrderChoices(vec,rand); @@ -95,8 +95,8 @@ TEST_CASE( "Turn ordering: No priority goes before low priority", "[Battling]" ) auto l = GetLibrary()->GetAttackLibrary(); auto a1 = new LearnedAttack(l->GetAttack("lowPriority"), AttackLearnMethod::Unknown); auto a2 = new LearnedAttack(l->GetAttack("standard"), AttackLearnMethod::Unknown); - auto choice1 = new AttackTurnChoice(nullptr, a1); - auto choice2 = new AttackTurnChoice(nullptr, a2); + auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0)); + auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0)); auto vec = std::vector{choice1, choice2}; auto rand = Core::Random(); TurnOrdering::OrderChoices(vec,rand);