Adds support for History data, allowing us to store specific interesting occurrences in the data flow, and recall them later.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
Signed-off-by: Deukhoofd <Deukhoofd@gmail.com>
This commit is contained in:
parent
939fee3f50
commit
cb4765e0cc
|
@ -7,7 +7,7 @@
|
|||
#include "../../Library/Exceptions/CreatureException.hpp"
|
||||
#include "Events/EventData.hpp"
|
||||
|
||||
template <class T> concept Event = std::is_base_of<CreatureLib::Battling::EventData, T>::value;
|
||||
template <class T> concept EventDataType = std::is_base_of<CreatureLib::Battling::EventData, T>::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 <Event T, class... parameters> void Trigger(parameters... args) {
|
||||
template <EventDataType T, class... parameters> void Trigger(parameters... args) {
|
||||
if (_listeners.size() == 0)
|
||||
return;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef CREATURELIB_ATTACKUSEEVENT_HPP
|
||||
#define CREATURELIB_ATTACKUSEEVENT_HPP
|
||||
#include "../../Models/ExecutingAttack.hpp"
|
||||
#include "EventData.hpp"
|
||||
|
||||
namespace CreatureLib::Battling {
|
||||
|
|
|
@ -2,14 +2,9 @@
|
|||
#define CREATURELIB_EVENTDATA_HPP
|
||||
|
||||
#include <Arbutils/Memory/BorrowedPtr.hpp>
|
||||
#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;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef CREATURELIB_SWITCHEVENT_HPP
|
||||
#define CREATURELIB_SWITCHEVENT_HPP
|
||||
#include "../../Models/CreatureIndex.hpp"
|
||||
#include "EventData.hpp"
|
||||
|
||||
namespace CreatureLib::Battling {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <unordered_set>
|
||||
#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<BaseTurnChoice> choice) {
|
|||
}
|
||||
}
|
||||
|
||||
void TurnHandler::ExecuteAttackChoice(ArbUt::BorrowedPtr<AttackTurnChoice> choice) {
|
||||
void TurnHandler::ExecuteAttackChoice(const ArbUt::BorrowedPtr<AttackTurnChoice>& 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<AttackTurnChoice> choic
|
|||
|
||||
auto targetType = choice->GetAttack()->GetAttack()->GetTarget();
|
||||
ArbUt::List<ArbUt::BorrowedPtr<Creature>> 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<AttackUseEvent>(attack);
|
||||
battle->TriggerEventListener<AttackUseEvent>(attack);
|
||||
battle->RegisterHistoryElement<AttackUseHistory>(attack);
|
||||
|
||||
// HOOK: check if attack fails
|
||||
bool fail = false;
|
||||
|
@ -116,8 +119,6 @@ void TurnHandler::ExecuteAttackChoice(ArbUt::BorrowedPtr<AttackTurnChoice> 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<Creature>& target) {
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace CreatureLib::Battling {
|
|||
class TurnHandler {
|
||||
static void ExecuteChoice(ArbUt::BorrowedPtr<BaseTurnChoice> choice);
|
||||
|
||||
static void ExecuteAttackChoice(ArbUt::BorrowedPtr<AttackTurnChoice> choice);
|
||||
static void ExecuteAttackChoice(const ArbUt::BorrowedPtr<AttackTurnChoice>& choice);
|
||||
static void HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::BorrowedPtr<Creature>& target);
|
||||
|
||||
static void ExecuteSwitchChoice(ArbUt::BorrowedPtr<SwitchTurnChoice> choice);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef CREATURELIB_HISTORYELEMENTKIND_HPP
|
||||
#define CREATURELIB_HISTORYELEMENTKIND_HPP
|
||||
#include <Arbutils/Enum.hpp>
|
||||
|
||||
ENUM(HistoryElementKind, uint8_t, AttackUse)
|
||||
#endif // CREATURELIB_HISTORYELEMENTKIND_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<const ExecutingAttack> _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<const ExecutingAttack> GetAttack() { return _attack; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CREATURELIB_ATTACKUSEHISTORY_HPP
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef CREATURELIB_HISTORYELEMENT_HPP
|
||||
#define CREATURELIB_HISTORYELEMENT_HPP
|
||||
|
||||
#include <Arbutils/Memory/BorrowedPtr.hpp>
|
||||
#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<const HistoryElement> GetPrevious() const noexcept { return _previous; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CREATURELIB_HISTORYELEMENT_HPP
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef CREATURELIB_HISTORYHOLDER_HPP
|
||||
#define CREATURELIB_HISTORYHOLDER_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "../../Library/Exceptions/CreatureException.hpp"
|
||||
#include "HistoryElements/HistoryElement.hpp"
|
||||
|
||||
template <class T> concept HistoryElementType = std::is_base_of<CreatureLib::Battling::HistoryElement, T>::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<uint8_t*>(ptr);
|
||||
}
|
||||
HistoryHolder(const HistoryHolder&) = delete;
|
||||
HistoryHolder& operator=(const HistoryHolder&) = delete;
|
||||
|
||||
~HistoryHolder() {
|
||||
if (_top != nullptr)
|
||||
_top->Clear();
|
||||
free(_memory);
|
||||
}
|
||||
|
||||
template <HistoryElementType T, class... parameters> 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<uint8_t*>(newPtr);
|
||||
}
|
||||
uint8_t* ptr = _memory + _offset;
|
||||
T* element = new (ptr) T(args...);
|
||||
_offset += sizeof(T);
|
||||
element->_previous = _top;
|
||||
_top = element;
|
||||
}
|
||||
|
||||
ArbUt::BorrowedPtr<const HistoryElement> GetTopElement() const noexcept { return _top; }
|
||||
|
||||
ArbUt::BorrowedPtr<const HistoryElement> 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
|
|
@ -6,6 +6,7 @@
|
|||
#include <memory>
|
||||
#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 <EventDataType T, class... parameters> void TriggerEventListener(parameters... args) {
|
||||
this->_eventHook.Trigger<T>(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 <Event T, class... parameters> void TriggerEventListener(parameters... args) {
|
||||
this->_eventHook.Trigger<T>(args...);
|
||||
template <HistoryElementType T, class... parameters> void RegisterHistoryElement(parameters... args) {
|
||||
this->_historyHolder.Register<T>(args...);
|
||||
}
|
||||
const HistoryHolder& GetHistory() const noexcept { return _historyHolder; }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef CREATURELIB_CREATUREEXCEPTION_HPP
|
||||
#define CREATURELIB_CREATUREEXCEPTION_HPP
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
|
Loading…
Reference in New Issue