#include "Battle.hpp" #include "../../Core/Exceptions/NotImplementedException.hpp" #include "../Flow/TurnHandler.hpp" #include "../Flow/TurnOrdering.hpp" using namespace CreatureLib; using namespace CreatureLib::Battling; const BattleLibrary* Battle::GetLibrary() const { return _library; } bool Battle::CanUse(const BaseTurnChoice* choice) { if (choice->GetKind() == TurnChoiceKind::Attack) { // HOOK: change number of uses needed. return dynamic_cast(choice)->GetAttack()->GetRemainingUses() > 1; } return true; } bool Battle::TrySetChoice(BaseTurnChoice* choice) { if (!CanUse(choice)) return false; choice->GetUser()->GetBattleSide()->SetChoice(choice); CheckChoicesSetAndRun(); return true; } void Battle::CheckChoicesSetAndRun() { for (auto side : _sides) { if (!side->AllChoicesSet()) { return; } } for (auto side : _sides) { if (!side->AllPossibleSlotsFilled()) { return; } } auto choices = std::vector(_numberOfSides * _creaturesPerSide); auto i = 0; for (auto side : _sides) { for (BaseTurnChoice* choice : side->GetChoices()) { if (choice == nullptr) { throw CreatureException("Choice was null"); } if (choice->GetKind() == TurnChoiceKind::Attack) { auto attack = (dynamic_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++; } side->ResetChoices(); } TurnOrdering::OrderChoices(choices, _random.GetRNG()); this->_currentTurnQueue = new ChoiceQueue(choices); TurnHandler::RunTurn(this, this->_currentTurnQueue); if (this->_currentTurnQueue->HasCompletedQueue) { delete this->_currentTurnQueue; this->_currentTurnQueue = nullptr; } } ChoiceQueue* Battle::GetCurrentTurnQueue() const { return _currentTurnQueue; } BattleRandom* Battle::GetRandom() { return &_random; } bool Battle::CreatureInField(const Creature* creature) const { for (auto s : _sides) { if (s->CreatureOnSide(creature)) return true; } return false; } void Battle::ForceRecall(uint8_t side, uint8_t index) { _sides[side]->SetCreature(nullptr, index); } void Battle::GetActiveScripts(std::vector& scripts) { scripts.emplace_back(&_volatile); } void Battle::SwitchCreature(uint8_t sideIndex, uint8_t index, Creature* c) { auto side = this->_sides[sideIndex]; side->SetCreature(c, index); } bool Battle::CanSlotBeFilled(uint8_t side, uint8_t index) const { for (const auto& party : _parties) { if (party.IsResponsibleForIndex(side, index)) { if (party.HasCreaturesNotInField()) return true; } } return false; } void Battle::ValidateBattleState() { bool survivingSideExists = false; uint8_t winningSide = 0; for (uint8_t i = 0; i < _sides.size(); i++) { auto side = _sides[i]; if (side->HasFled()) { this->_battleResult = BattleResult::Inconclusive(); this->_hasEnded = true; return; } if (!side->IsDefeated()) { if (survivingSideExists) { return; } survivingSideExists = true; winningSide = i; } } this->_battleResult = BattleResult::Conclusive(winningSide); this->_hasEnded = true; } void Battle::AddVolatileScript(const std::string& key) { auto script = _volatile.Get(key); if (script != nullptr) { script->Stack(); return; } script = _library->LoadScript(ScriptCategory::Battle, key); return _volatile.Add(script); } void Battle::AddVolatileScript(Script* script) { return _volatile.Add(script); } void Battle::RemoveVolatileScript(const std::string& name) { _volatile.Remove(name); } void Battle::RemoveVolatileScript(Script* script) { _volatile.Remove(script->GetName()); } void Battle::HasVolatileScript(const std::string& name) const { _volatile.Has(name); }