CreatureLib/src/Battling/Models/Battle.hpp

144 lines
6.3 KiB
C++

#ifndef CREATURELIB_BATTLE_HPP
#define CREATURELIB_BATTLE_HPP
#include "../EventHooks/EventHook.hpp"
#include "../Flow/ChoiceQueue.hpp"
#include "../History/HistoryHolder.hpp"
#include "../Library/BattleLibrary.hpp"
#include "../TurnChoices/BaseTurnChoice.hpp"
#include "BattleParty.hpp"
#include "BattleRandom.hpp"
#include "BattleResult.hpp"
#include "BattleSide.hpp"
#include "CreatureIndex.hpp"
namespace CreatureLib::Battling {
class Battle : public ScriptSource {
protected:
ArbUt::BorrowedPtr<const BattleLibrary> _library;
ArbUt::UniquePtrList<BattleParty> _parties;
bool _canFlee;
u8 _numberOfSides;
u8 _creaturesPerSide;
ArbUt::UniquePtrList<BattleSide> _sides;
BattleRandom _random;
std::unique_ptr<ChoiceQueue> _currentTurnQueue = nullptr;
bool _hasEnded = false;
BattleResult _battleResult = BattleResult::Empty();
EventHook _eventHook;
ArbUt::UniquePtr<HistoryHolder> _historyHolder = new HistoryHolder([this]() { return GetCurrentTurn(); });
u32 _currentTurn = 0;
ScriptSet _volatile;
long _lastTurnTime;
public:
Battle(const BattleLibrary* library, ArbUt::List<BattleParty*> parties, bool canFlee = true,
u8 numberOfSides = 2, u8 creaturesPerSide = 1,
uint_fast32_t randomSeed = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count())
: _library(library), _parties(parties.GetStdList()), _canFlee(canFlee), _numberOfSides(numberOfSides),
_creaturesPerSide(creaturesPerSide), _sides(numberOfSides), _random(randomSeed) {
EnsureAllNotNull(parties);
for (size_t i = 0; i < numberOfSides; i++) {
_sides.Append(new BattleSide(i, this, creaturesPerSide));
}
}
virtual ~Battle() { ClearBattle(); }
[[nodiscard]] const ArbUt::BorrowedPtr<const BattleLibrary>& GetLibrary() const noexcept;
[[nodiscard]] u32 GetCurrentTurn() const noexcept { return _currentTurn; }
inline u8 GetCreaturesPerSide() const noexcept { return _creaturesPerSide; }
virtual bool CanUse(const ArbUt::BorrowedPtr<BaseTurnChoice>& choice);
virtual bool TrySetChoice(BaseTurnChoice* choice);
bool CanFlee() const noexcept { return _canFlee; }
void CheckChoicesSetAndRun();
[[nodiscard]] ArbUt::BorrowedPtr<ChoiceQueue> GetCurrentTurnQueue() const noexcept;
BattleRandom* GetRandom() noexcept;
bool CreatureInField(ArbUt::BorrowedPtr<Creature> creature) const;
const ArbUt::OptionalBorrowedPtr<Creature>& GetCreature(const CreatureIndex& target) const {
return _sides[target.GetSideIndex()]->GetCreature(target.GetCreatureIndex());
}
const ArbUt::OptionalBorrowedPtr<Creature>& GetCreature(u8 side, u8 target) const {
return _sides[side]->GetCreature(target);
}
void ForceRecall(u8 side, u8 index);
void SwitchCreature(u8 side, u8 index, Creature* c);
bool CanSlotBeFilled(u8 side, u8 index) const;
size_t ScriptCount() const override;
void GetActiveScripts(ArbUt::List<ScriptWrapper>& scripts) override;
void GetOwnScripts(ArbUt::List<ScriptWrapper>& scripts) override;
void ValidateBattleState();
inline bool HasEnded() const noexcept { return _hasEnded; }
inline const BattleResult& GetResult() const noexcept { return _battleResult; }
const ArbUt::UniquePtrList<BattleParty>& GetParties() const noexcept { return _parties; }
ArbUt::OptionalBorrowedPtr<BattleParty> FindPartyForCreature(const ArbUt::BorrowedPtr<Creature>&);
const ArbUt::UniquePtrList<BattleSide>& GetSides() const noexcept { return _sides; }
ArbUt::OptionalBorrowedPtr<BattleScript> GetVolatileScript(const ArbUt::StringView& key) const {
return _volatile.Get(key);
}
ArbUt::OptionalBorrowedPtr<BattleScript> GetVolatileScript(u32 keyHash) const noexcept {
return _volatile.Get(keyHash);
}
BattleScript* AddVolatileScript(const ArbUt::StringView& key);
BattleScript* AddVolatileScript(BattleScript* script);
void RemoveVolatileScript(const ArbUt::BasicStringView& name) { _volatile.Remove(name); }
void RemoveVolatileScript(u32 keyHash) { _volatile.Remove(keyHash); }
void RemoveVolatileScript(BattleScript* script);
bool HasVolatileScript(const ArbUt::BasicStringView& name) const { return _volatile.Has(name); }
bool HasVolatileScript(u32 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) {
try_creature(this->_eventHook.Trigger<T>(args...);, "Exception occurred during event trigger.");
}
EventHook& GetEventHook() noexcept { return _eventHook; }
const EventHook& GetEventHook() const noexcept { return _eventHook; }
template <HistoryElementType T, class... parameters> void RegisterHistoryElement(parameters... args) {
try_creature(this->_historyHolder->Register<T>(this->GetCurrentTurn(), args...);
, "Exception occurred during history element registration.");
}
const HistoryHolder* GetHistory() const noexcept { return _historyHolder.GetRaw(); }
long GetLastTurnTimeMicroseconds() const noexcept { return _lastTurnTime; }
void EndBattle() { this->_hasEnded = true; }
void ClearBattle() {
for (size_t i = 0; i < _numberOfSides; i++) {
auto side = _sides[i];
for (auto c : side->GetCreatures()) {
if (c.HasValue()) {
if (c.GetValue()->GetBattle() == this) {
c.GetValue()->ClearBattleData();
}
}
}
}
}
virtual Battle* Clone() const;
};
}
#endif // CREATURELIB_BATTLE_HPP