diff --git a/src/Battling/EventHooks/EventHook.hpp b/src/Battling/EventHooks/EventHook.hpp index 66ea46b..db1527e 100644 --- a/src/Battling/EventHooks/EventHook.hpp +++ b/src/Battling/EventHooks/EventHook.hpp @@ -7,7 +7,7 @@ #include "../../Library/Exceptions/CreatureException.hpp" #include "Events/EventData.hpp" -template concept Event = std::is_base_of::value; +template concept EventDataType = std::is_base_of::value; namespace CreatureLib::Battling { /// The Event Hook class allows users to write consumers for the battle events, for example to write User Interfaces @@ -41,7 +41,7 @@ namespace CreatureLib::Battling { size_t GetPosition() const noexcept { return _offset; } size_t GetCapacity() const noexcept { return _capacity; } - template void Trigger(parameters... args) { + template void Trigger(parameters... args) { if (_listeners.size() == 0) return; diff --git a/src/Battling/EventHooks/Events/AttackUseEvent.hpp b/src/Battling/EventHooks/Events/AttackUseEvent.hpp index ae5a8fe..531c4ce 100644 --- a/src/Battling/EventHooks/Events/AttackUseEvent.hpp +++ b/src/Battling/EventHooks/Events/AttackUseEvent.hpp @@ -1,5 +1,6 @@ #ifndef CREATURELIB_ATTACKUSEEVENT_HPP #define CREATURELIB_ATTACKUSEEVENT_HPP +#include "../../Models/ExecutingAttack.hpp" #include "EventData.hpp" namespace CreatureLib::Battling { diff --git a/src/Battling/EventHooks/Events/EventData.hpp b/src/Battling/EventHooks/Events/EventData.hpp index 3a77c31..3b75394 100644 --- a/src/Battling/EventHooks/Events/EventData.hpp +++ b/src/Battling/EventHooks/Events/EventData.hpp @@ -2,14 +2,9 @@ #define CREATURELIB_EVENTDATA_HPP #include -#include "../../Models/CreatureIndex.hpp" -#include "../../Models/DamageSource.hpp" #include "../EventDataKind.hpp" namespace CreatureLib::Battling { - // Predeclare some classes. - class Creature; - class EventData { public: virtual ~EventData() = default; diff --git a/src/Battling/EventHooks/Events/SwitchEvent.hpp b/src/Battling/EventHooks/Events/SwitchEvent.hpp index f40914c..fcf3f87 100644 --- a/src/Battling/EventHooks/Events/SwitchEvent.hpp +++ b/src/Battling/EventHooks/Events/SwitchEvent.hpp @@ -1,5 +1,6 @@ #ifndef CREATURELIB_SWITCHEVENT_HPP #define CREATURELIB_SWITCHEVENT_HPP +#include "../../Models/CreatureIndex.hpp" #include "EventData.hpp" namespace CreatureLib::Battling { diff --git a/src/Battling/Flow/TurnHandler.cpp b/src/Battling/Flow/TurnHandler.cpp index cb5803f..fd72756 100644 --- a/src/Battling/Flow/TurnHandler.cpp +++ b/src/Battling/Flow/TurnHandler.cpp @@ -3,6 +3,7 @@ #include #include "../../Library/Exceptions/NotImplementedException.hpp" #include "../EventHooks/EventDataClasses.hpp" +#include "../History/HistoryElements/AttackUseHistory.hpp" #include "../ScriptHandling/ScriptMacros.hpp" #include "ResolveTarget.hpp" @@ -68,8 +69,9 @@ void TurnHandler::ExecuteChoice(ArbUt::BorrowedPtr choice) { } } -void TurnHandler::ExecuteAttackChoice(ArbUt::BorrowedPtr choice) { +void TurnHandler::ExecuteAttackChoice(const ArbUt::BorrowedPtr& choice) { AssertNotNull(choice) + auto battle = choice->GetUser()->GetBattle(); auto attackName = choice->GetAttack()->GetAttack()->GetName(); HOOK(ChangeAttack, choice, choice.GetRaw(), &attackName); if (attackName != choice->GetAttack()->GetAttack()->GetName()) { @@ -78,24 +80,25 @@ void TurnHandler::ExecuteAttackChoice(ArbUt::BorrowedPtr choic auto targetType = choice->GetAttack()->GetAttack()->GetTarget(); ArbUt::List> targets; - try_creature(targets = - TargetResolver::ResolveTargets(choice->GetTarget(), targetType, choice->GetUser()->GetBattle()); + try_creature(targets = TargetResolver::ResolveTargets(choice->GetTarget(), targetType, battle); , "Exception during target determination"); auto attack = new ExecutingAttack(targets, 1, choice->GetUser(), choice->GetAttack(), choice->GetAttackScript()); bool prevented = false; HOOK(PreventAttack, attack, attack, &prevented); if (prevented) { + delete attack; return; } // HOOK: override targets - if (!choice->GetAttack()->TryUse(1)) { + delete attack; return; } - attack->GetUser()->GetBattle()->TriggerEventListener(attack); + battle->TriggerEventListener(attack); + battle->RegisterHistoryElement(attack); // HOOK: check if attack fails bool fail = false; @@ -116,8 +119,6 @@ void TurnHandler::ExecuteAttackChoice(ArbUt::BorrowedPtr choic auto target = attack->GetTargets()[i]; try_creature(HandleAttackForTarget(attack, target), "Exception occurred during handling attack for target"); } - - delete attack; } void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::BorrowedPtr& target) { diff --git a/src/Battling/Flow/TurnHandler.hpp b/src/Battling/Flow/TurnHandler.hpp index 26175b6..ec90748 100644 --- a/src/Battling/Flow/TurnHandler.hpp +++ b/src/Battling/Flow/TurnHandler.hpp @@ -13,7 +13,7 @@ namespace CreatureLib::Battling { class TurnHandler { static void ExecuteChoice(ArbUt::BorrowedPtr choice); - static void ExecuteAttackChoice(ArbUt::BorrowedPtr choice); + static void ExecuteAttackChoice(const ArbUt::BorrowedPtr& choice); static void HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::BorrowedPtr& target); static void ExecuteSwitchChoice(ArbUt::BorrowedPtr choice); diff --git a/src/Battling/History/HistoryElementKind.hpp b/src/Battling/History/HistoryElementKind.hpp new file mode 100644 index 0000000..923af95 --- /dev/null +++ b/src/Battling/History/HistoryElementKind.hpp @@ -0,0 +1,6 @@ +#ifndef CREATURELIB_HISTORYELEMENTKIND_HPP +#define CREATURELIB_HISTORYELEMENTKIND_HPP +#include + +ENUM(HistoryElementKind, uint8_t, AttackUse) +#endif // CREATURELIB_HISTORYELEMENTKIND_HPP diff --git a/src/Battling/History/HistoryElements/AttackUseHistory.hpp b/src/Battling/History/HistoryElements/AttackUseHistory.hpp new file mode 100644 index 0000000..00ae204 --- /dev/null +++ b/src/Battling/History/HistoryElements/AttackUseHistory.hpp @@ -0,0 +1,24 @@ +#ifndef CREATURELIB_ATTACKUSEHISTORY_HPP +#define CREATURELIB_ATTACKUSEHISTORY_HPP +#include "../../Models/ExecutingAttack.hpp" +#include "HistoryElement.hpp" + +namespace CreatureLib::Battling { + class AttackUseHistory : public HistoryElement { + std::unique_ptr _attack; + + protected: + void Clear() override { + _attack.reset(); + HistoryElement::Clear(); + } + + public: + AttackUseHistory(const ExecutingAttack* attack) : _attack(attack) {} + + HistoryElementKind GetKind() const noexcept override { return HistoryElementKind::AttackUse; } + ArbUt::BorrowedPtr GetAttack() { return _attack; } + }; +} + +#endif // CREATURELIB_ATTACKUSEHISTORY_HPP diff --git a/src/Battling/History/HistoryElements/HistoryElement.hpp b/src/Battling/History/HistoryElements/HistoryElement.hpp new file mode 100644 index 0000000..3860baf --- /dev/null +++ b/src/Battling/History/HistoryElements/HistoryElement.hpp @@ -0,0 +1,25 @@ +#ifndef CREATURELIB_HISTORYELEMENT_HPP +#define CREATURELIB_HISTORYELEMENT_HPP + +#include +#include "../HistoryElementKind.hpp" +namespace CreatureLib::Battling { + class HistoryElement { + friend class HistoryHolder; + HistoryElement* _previous; + + protected: + virtual void Clear() { + if (_previous != nullptr) { + _previous->Clear(); + } + } + + public: + virtual HistoryElementKind GetKind() const noexcept = 0; + ArbUt::BorrowedPtr GetPrevious() const noexcept { return _previous; } + }; + +} + +#endif // CREATURELIB_HISTORYELEMENT_HPP diff --git a/src/Battling/History/HistoryHolder.hpp b/src/Battling/History/HistoryHolder.hpp new file mode 100644 index 0000000..4875bfd --- /dev/null +++ b/src/Battling/History/HistoryHolder.hpp @@ -0,0 +1,68 @@ +#ifndef CREATURELIB_HISTORYHOLDER_HPP +#define CREATURELIB_HISTORYHOLDER_HPP + +#include +#include +#include "../../Library/Exceptions/CreatureException.hpp" +#include "HistoryElements/HistoryElement.hpp" + +template concept HistoryElementType = std::is_base_of::value; + +namespace CreatureLib::Battling { + class HistoryHolder { + size_t _offset; + size_t _capacity; + uint8_t* _memory = nullptr; + HistoryElement* _top = nullptr; + + static constexpr size_t initialSize = 2048; + static constexpr size_t stepSize = 1024; + + public: + HistoryHolder() : _offset(0), _capacity(2048) { + auto ptr = malloc(_capacity); + if (ptr == nullptr) { + THROW_CREATURE("Out of memory."); + } + _memory = static_cast(ptr); + } + HistoryHolder(const HistoryHolder&) = delete; + HistoryHolder& operator=(const HistoryHolder&) = delete; + + ~HistoryHolder() { + if (_top != nullptr) + _top->Clear(); + free(_memory); + } + + template void Register(parameters... args) { + if (_offset + sizeof(T) >= _capacity) { + _capacity += stepSize; + auto newPtr = realloc(_memory, _capacity); + if (newPtr == nullptr) { + THROW_CREATURE("Out of memory."); + } + _memory = static_cast(newPtr); + } + uint8_t* ptr = _memory + _offset; + T* element = new (ptr) T(args...); + _offset += sizeof(T); + element->_previous = _top; + _top = element; + } + + ArbUt::BorrowedPtr GetTopElement() const noexcept { return _top; } + + ArbUt::BorrowedPtr GetLastUsedAttack() const noexcept { + const auto* c = _top; + while (c != nullptr) { + if (c->GetKind() == HistoryElementKind::AttackUse) + return c; + c = c->_previous; + } + return nullptr; + } + }; +} + +#endif // CREATURELIB_HISTORYHOLDER_HPP diff --git a/src/Battling/Models/Battle.hpp b/src/Battling/Models/Battle.hpp index a51d956..542afd6 100644 --- a/src/Battling/Models/Battle.hpp +++ b/src/Battling/Models/Battle.hpp @@ -6,6 +6,7 @@ #include #include "../EventHooks/EventHook.hpp" #include "../Flow/ChoiceQueue.hpp" +#include "../History/HistoryHolder.hpp" #include "../Library/BattleLibrary.hpp" #include "../TurnChoices/BaseTurnChoice.hpp" #include "BattleParty.hpp" @@ -28,6 +29,8 @@ namespace CreatureLib::Battling { bool _hasEnded = false; BattleResult _battleResult = BattleResult::Empty(); EventHook _eventHook; + HistoryHolder _historyHolder; + uint32_t _currentTurn = 0; ScriptSet _volatile; @@ -95,14 +98,20 @@ namespace CreatureLib::Battling { void RemoveVolatileScript(Script* script); bool HasVolatileScript(const ArbUt::BasicStringView& name) const { return _volatile.Has(name); } bool HasVolatileScript(uint32_t keyHash) const { return _volatile.Has(keyHash); } + + void DisplayText(const ArbUt::StringView& text); + + void RegisterEventListener(EventHook::EventHookFunc listener) { this->_eventHook.RegisterListener(listener); } + template void TriggerEventListener(parameters... args) { + this->_eventHook.Trigger(args...); + } EventHook& GetEventHook() noexcept { return _eventHook; } const EventHook& GetEventHook() const noexcept { return _eventHook; } - void DisplayText(const ArbUt::StringView& text); - void RegisterEventListener(EventHook::EventHookFunc listener) { this->_eventHook.RegisterListener(listener); } - template void TriggerEventListener(parameters... args) { - this->_eventHook.Trigger(args...); + template void RegisterHistoryElement(parameters... args) { + this->_historyHolder.Register(args...); } + const HistoryHolder& GetHistory() const noexcept { return _historyHolder; } }; } diff --git a/src/Library/Exceptions/CreatureException.hpp b/src/Library/Exceptions/CreatureException.hpp index d78beb9..2cad284 100644 --- a/src/Library/Exceptions/CreatureException.hpp +++ b/src/Library/Exceptions/CreatureException.hpp @@ -1,6 +1,7 @@ #ifndef CREATURELIB_CREATUREEXCEPTION_HPP #define CREATURELIB_CREATUREEXCEPTION_HPP +#include #include #include #include