Support for cloning battles for AI purposes.
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
a3b7002cd4
commit
84a14cff2b
|
@ -1,5 +1,5 @@
|
||||||
Checks: 'readability-*,clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-alpha*,performance-*,cppcoreguidelines-*,
|
Checks: 'readability-*,clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-alpha*,performance-*,cppcoreguidelines-*,
|
||||||
bugprone-*,modernize-*,-modernize-use-trailing-return-type'
|
bugprone-*,modernize-*,-modernize-use-trailing-return-type,-cppcoreguidelines-non-private-member-variables-in-classes'
|
||||||
HeaderFilterRegex: ''
|
HeaderFilterRegex: ''
|
||||||
AnalyzeTemporaryDtors: false
|
AnalyzeTemporaryDtors: false
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
|
|
|
@ -9,7 +9,9 @@ namespace CreatureLib::Battling {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Clear() override {
|
void Clear() override {
|
||||||
_attack.reset();
|
if (_attack != nullptr) {
|
||||||
|
_attack.reset();
|
||||||
|
}
|
||||||
HistoryElement::Clear();
|
HistoryElement::Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,18 +6,24 @@
|
||||||
namespace CreatureLib::Battling {
|
namespace CreatureLib::Battling {
|
||||||
class HistoryElement {
|
class HistoryElement {
|
||||||
friend class HistoryHolder;
|
friend class HistoryHolder;
|
||||||
HistoryElement* _previous;
|
u8* _previousOffset = nullptr;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Clear() {
|
virtual void Clear() {
|
||||||
if (_previous != nullptr) {
|
if (_previousOffset != nullptr) {
|
||||||
_previous->Clear();
|
GetPrevious()->Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual HistoryElementKind GetKind() const noexcept = 0;
|
virtual HistoryElementKind GetKind() const noexcept = 0;
|
||||||
ArbUt::BorrowedPtr<const HistoryElement> GetPrevious() const noexcept { return _previous; }
|
ArbUt::BorrowedPtr<const HistoryElement> GetPrevious() const noexcept {
|
||||||
|
return reinterpret_cast<HistoryElement*>((u8*)this - _previousOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArbUt::BorrowedPtr<HistoryElement> GetPrevious() noexcept {
|
||||||
|
return reinterpret_cast<HistoryElement*>((u8*)this - _previousOffset);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,14 @@
|
||||||
#include "../../Library/Exceptions/CreatureException.hpp"
|
#include "../../Library/Exceptions/CreatureException.hpp"
|
||||||
#include "HistoryElements/HistoryElement.hpp"
|
#include "HistoryElements/HistoryElement.hpp"
|
||||||
|
|
||||||
template <class T> concept HistoryElementType = std::is_base_of<CreatureLib::Battling::HistoryElement, T>::value;
|
template <class T>
|
||||||
|
concept HistoryElementType = std::is_base_of<CreatureLib::Battling::HistoryElement, T>::value;
|
||||||
|
|
||||||
namespace CreatureLib::Battling {
|
namespace CreatureLib::Battling {
|
||||||
class HistoryHolder {
|
class HistoryHolder {
|
||||||
size_t _offset;
|
size_t _offset;
|
||||||
size_t _capacity;
|
size_t _capacity;
|
||||||
uint8_t* _memory = nullptr;
|
u8* _memory = nullptr;
|
||||||
HistoryElement* _top = nullptr;
|
HistoryElement* _top = nullptr;
|
||||||
|
|
||||||
static constexpr size_t initialSize = 2048;
|
static constexpr size_t initialSize = 2048;
|
||||||
|
@ -22,7 +23,7 @@ namespace CreatureLib::Battling {
|
||||||
if (ptr == nullptr) {
|
if (ptr == nullptr) {
|
||||||
THROW("Out of memory.");
|
THROW("Out of memory.");
|
||||||
}
|
}
|
||||||
_memory = static_cast<uint8_t*>(ptr);
|
_memory = static_cast<u8*>(ptr);
|
||||||
}
|
}
|
||||||
HistoryHolder(const HistoryHolder&) = delete;
|
HistoryHolder(const HistoryHolder&) = delete;
|
||||||
HistoryHolder& operator=(const HistoryHolder&) = delete;
|
HistoryHolder& operator=(const HistoryHolder&) = delete;
|
||||||
|
@ -33,19 +34,25 @@ namespace CreatureLib::Battling {
|
||||||
free(_memory);
|
free(_memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Resize() {
|
||||||
|
_capacity += stepSize;
|
||||||
|
auto newPtr = realloc(_memory, _capacity);
|
||||||
|
if (newPtr == nullptr) {
|
||||||
|
THROW("Out of memory.");
|
||||||
|
}
|
||||||
|
_memory = static_cast<u8*>(newPtr);
|
||||||
|
}
|
||||||
|
|
||||||
template <HistoryElementType T, class... parameters> void Register(parameters... args) {
|
template <HistoryElementType T, class... parameters> void Register(parameters... args) {
|
||||||
if (_offset + sizeof(T) >= _capacity) {
|
if (_offset + sizeof(T) >= _capacity) {
|
||||||
_capacity += stepSize;
|
Resize();
|
||||||
auto newPtr = realloc(_memory, _capacity);
|
|
||||||
if (newPtr == nullptr) {
|
|
||||||
THROW("Out of memory.");
|
|
||||||
}
|
|
||||||
_memory = static_cast<uint8_t*>(newPtr);
|
|
||||||
}
|
}
|
||||||
uint8_t* ptr = _memory + _offset;
|
u8* ptr = _memory + _offset;
|
||||||
T* element = new (ptr) T(args...);
|
T* element = new (ptr) T(args...);
|
||||||
_offset += sizeof(T);
|
_offset += sizeof(T);
|
||||||
element->_previous = _top;
|
if (_top != nullptr) {
|
||||||
|
element->_previousOffset = (u8*)sizeof(T);
|
||||||
|
}
|
||||||
_top = element;
|
_top = element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,10 +63,23 @@ namespace CreatureLib::Battling {
|
||||||
while (c != nullptr) {
|
while (c != nullptr) {
|
||||||
if (c->GetKind() == HistoryElementKind::AttackUse)
|
if (c->GetKind() == HistoryElementKind::AttackUse)
|
||||||
return c;
|
return c;
|
||||||
c = c->_previous;
|
c = c->GetPrevious();
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CloneOnto(HistoryHolder& other) {
|
||||||
|
if (other._top != nullptr) {
|
||||||
|
other._top->Clear();
|
||||||
|
}
|
||||||
|
free(other._memory);
|
||||||
|
other._offset = _offset;
|
||||||
|
other._capacity = _capacity;
|
||||||
|
other._memory = static_cast<uint8_t*>(malloc(_capacity));
|
||||||
|
if (_top != nullptr) {
|
||||||
|
other._top = reinterpret_cast<HistoryElement*>(other._memory + ((u8*)_top - _memory));
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -168,3 +168,45 @@ BattleScript* Battle::AddVolatileScript(const ArbUt::StringView& key) {
|
||||||
BattleScript* Battle::AddVolatileScript(BattleScript* script) { return _volatile.Add(script); }
|
BattleScript* Battle::AddVolatileScript(BattleScript* script) { return _volatile.Add(script); }
|
||||||
void Battle::RemoveVolatileScript(BattleScript* script) { _volatile.Remove(script->GetName()); }
|
void Battle::RemoveVolatileScript(BattleScript* script) { _volatile.Remove(script->GetName()); }
|
||||||
void Battle::DisplayText(const ArbUt::StringView& text) { TriggerEventListener<DisplayTextEvent>(text); }
|
void Battle::DisplayText(const ArbUt::StringView& text) { TriggerEventListener<DisplayTextEvent>(text); }
|
||||||
|
|
||||||
|
Battle* Battle::Clone() {
|
||||||
|
auto parties = ArbUt::List<BattleParty*>(_parties.Count());
|
||||||
|
for (auto* party : _parties) {
|
||||||
|
parties.Append(party->Clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* battle = new Battle(_library, parties, _canFlee, _numberOfSides, _creaturesPerSide);
|
||||||
|
|
||||||
|
for (int i = 0; i < _numberOfSides; ++i) {
|
||||||
|
battle->_sides.Set(i, _sides[i]->CloneWithoutCreatures());
|
||||||
|
// FIXME: This is horrible code to translate the creature from the old battle into the same creature in the
|
||||||
|
// new battle. This needs to be cleaned up, as it's ugly and slow.
|
||||||
|
for (int creatureIndex = 0; creatureIndex < _creaturesPerSide; ++creatureIndex) {
|
||||||
|
auto creature = _sides[i]->GetCreature(creatureIndex);
|
||||||
|
if (!creature.HasValue()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (size_t j = 0; j < _parties.Count(); ++j) {
|
||||||
|
auto party = _parties[j];
|
||||||
|
if (!party->IsResponsibleForIndex(i, creatureIndex)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto partyIndex = party->GetParty()->GetParty().IndexOf(creature.GetValue());
|
||||||
|
if (partyIndex != -1U) {
|
||||||
|
auto c = battle->_parties.At(j)->GetParty()->GetParty()[partyIndex];
|
||||||
|
battle->_sides.At(i)->SetCreature(c, creatureIndex);
|
||||||
|
j = _parties.Count();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
battle->_random = _random;
|
||||||
|
battle->_hasEnded = _hasEnded;
|
||||||
|
battle->_battleResult = _battleResult;
|
||||||
|
_historyHolder.CloneOnto(battle->_historyHolder);
|
||||||
|
battle->_currentTurn = _currentTurn;
|
||||||
|
_volatile.Clone(battle->_volatile);
|
||||||
|
|
||||||
|
return battle;
|
||||||
|
}
|
||||||
|
|
|
@ -131,6 +131,8 @@ namespace CreatureLib::Battling {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Battle* Clone();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@ namespace CreatureLib::Battling {
|
||||||
BattleParty(CreatureParty* party, const ArbUt::List<CreatureIndex>& responsibleIndices)
|
BattleParty(CreatureParty* party, const ArbUt::List<CreatureIndex>& responsibleIndices)
|
||||||
: _party(party), _responsibleIndices(responsibleIndices) {}
|
: _party(party), _responsibleIndices(responsibleIndices) {}
|
||||||
|
|
||||||
|
virtual ~BattleParty() = default;
|
||||||
|
|
||||||
inline const ArbUt::BorrowedPtr<CreatureParty>& GetParty() const { return _party; }
|
inline const ArbUt::BorrowedPtr<CreatureParty>& GetParty() const { return _party; }
|
||||||
inline const ArbUt::List<CreatureIndex>& GetResponsibleIndices() const { return _responsibleIndices; }
|
inline const ArbUt::List<CreatureIndex>& GetResponsibleIndices() const { return _responsibleIndices; }
|
||||||
|
|
||||||
|
@ -40,6 +42,8 @@ namespace CreatureLib::Battling {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual BattleParty* Clone() { return new BattleParty(_party->Clone(), _responsibleIndices); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,3 +123,10 @@ bool BattleSide::SwapPositions(u8 a, u8 b) {
|
||||||
_battle->TriggerEventListener<SwapEvent>(_index, a, b);
|
_battle->TriggerEventListener<SwapEvent>(_index, a, b);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
BattleSide* BattleSide::CloneWithoutCreatures() {
|
||||||
|
auto* side = new BattleSide(_index, _battle, _creaturesPerSide);
|
||||||
|
side->_choicesSet = _choicesSet;
|
||||||
|
_volatile.Clone(side->_volatile);
|
||||||
|
side->_hasFled = _hasFled;
|
||||||
|
return side;
|
||||||
|
}
|
||||||
|
|
|
@ -87,6 +87,8 @@ namespace CreatureLib::Battling {
|
||||||
uint8_t GetRandomCreatureIndex();
|
uint8_t GetRandomCreatureIndex();
|
||||||
|
|
||||||
bool SwapPositions(u8 a, u8 b);
|
bool SwapPositions(u8 a, u8 b);
|
||||||
|
|
||||||
|
BattleSide* CloneWithoutCreatures();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "Creature.hpp"
|
#include "Creature.hpp"
|
||||||
|
#include <utility>
|
||||||
#include "../EventHooks/EventDataClasses.hpp"
|
#include "../EventHooks/EventDataClasses.hpp"
|
||||||
#include "../Models/Battle.hpp"
|
#include "../Models/Battle.hpp"
|
||||||
#include "../ScriptHandling/ScriptMacros.hpp"
|
#include "../ScriptHandling/ScriptMacros.hpp"
|
||||||
|
@ -6,11 +7,11 @@
|
||||||
using namespace CreatureLib;
|
using namespace CreatureLib;
|
||||||
|
|
||||||
namespace CreatureLib::Battling {
|
namespace CreatureLib::Battling {
|
||||||
Creature::Creature(ArbUt::BorrowedPtr<const BattleLibrary> library,
|
Creature::Creature(const ArbUt::BorrowedPtr<const BattleLibrary>& library,
|
||||||
const ArbUt::BorrowedPtr<const Library::CreatureSpecies>& species,
|
const ArbUt::BorrowedPtr<const Library::CreatureSpecies>& species,
|
||||||
const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& variant, level_int_t level,
|
const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& variant, level_int_t level,
|
||||||
uint32_t experience, uint32_t uid, Library::Gender gender, uint8_t coloring,
|
uint32_t experience, uint32_t uid, Library::Gender gender, uint8_t coloring,
|
||||||
const ArbUt::OptionalBorrowedPtr<const Library::Item> heldItem, const std::string& nickname,
|
ArbUt::OptionalBorrowedPtr<const Library::Item> heldItem, std::string nickname,
|
||||||
const Library::TalentIndex& talent, const std::vector<LearnedAttack*>& attacks,
|
const Library::TalentIndex& talent, const std::vector<LearnedAttack*>& attacks,
|
||||||
bool allowedExperienceGain)
|
bool allowedExperienceGain)
|
||||||
: _library(library), _species(species), _variant(variant), _level(level), _experience(experience),
|
: _library(library), _species(species), _variant(variant), _level(level), _experience(experience),
|
||||||
|
@ -110,10 +111,11 @@ namespace CreatureLib::Battling {
|
||||||
bool Creature::ChangeStatBoost(Library::Statistic stat, int8_t diffAmount) {
|
bool Creature::ChangeStatBoost(Library::Statistic stat, int8_t diffAmount) {
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
auto oldValue = this->_statBoost.GetStat(stat);
|
auto oldValue = this->_statBoost.GetStat(stat);
|
||||||
if (diffAmount > 0)
|
if (diffAmount > 0) {
|
||||||
changed = this->_statBoost.IncreaseStatBy(stat, diffAmount);
|
changed = this->_statBoost.IncreaseStatBy(stat, diffAmount);
|
||||||
else
|
} else if (diffAmount < 0) {
|
||||||
changed = this->_statBoost.DecreaseStatBy(stat, -diffAmount);
|
changed = this->_statBoost.DecreaseStatBy(stat, -diffAmount);
|
||||||
|
}
|
||||||
if (this->GetBattle().HasValue()) {
|
if (this->GetBattle().HasValue()) {
|
||||||
auto newValue = this->_statBoost.GetStat(stat);
|
auto newValue = this->_statBoost.GetStat(stat);
|
||||||
this->GetBattle().GetValue()->TriggerEventListener<ChangeStatBoostEvent>(this, stat, oldValue, newValue);
|
this->GetBattle().GetValue()->TriggerEventListener<ChangeStatBoostEvent>(this, stat, oldValue, newValue);
|
||||||
|
@ -123,7 +125,7 @@ namespace CreatureLib::Battling {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Creature::RecalculateFlatStats() {
|
void Creature::RecalculateFlatStats() {
|
||||||
auto& statCalc = this->_library->GetStatCalculator();
|
const auto& statCalc = this->_library->GetStatCalculator();
|
||||||
this->_flatStats = statCalc->CalculateFlatStats(this);
|
this->_flatStats = statCalc->CalculateFlatStats(this);
|
||||||
RecalculateBoostedStats();
|
RecalculateBoostedStats();
|
||||||
}
|
}
|
||||||
|
@ -329,4 +331,41 @@ namespace CreatureLib::Battling {
|
||||||
_attacks.Set(index, attack);
|
_attacks.Set(index, attack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Creature* Creature::Clone() {
|
||||||
|
auto attacks = std::vector<LearnedAttack*>(_attacks.Count());
|
||||||
|
auto i = 0;
|
||||||
|
for (auto* attack : _attacks) {
|
||||||
|
if (attack == nullptr) {
|
||||||
|
attacks[i++] = nullptr;
|
||||||
|
} else {
|
||||||
|
attacks[i++] = attack->Clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* c = new Creature(_library, _species, _variant, _level, _experience, _uniqueIdentifier, _gender, _coloring,
|
||||||
|
_heldItem, _nickname, _talentIndex, attacks, _allowedExperienceGain);
|
||||||
|
c->_displaySpecies = _displaySpecies;
|
||||||
|
c->_displayVariant = _displayVariant;
|
||||||
|
c->_currentHealth = _currentHealth;
|
||||||
|
c->_statBoost = _statBoost;
|
||||||
|
c->_flatStats = _flatStats;
|
||||||
|
c->_boostedStats = _boostedStats;
|
||||||
|
c->_battle = _battle;
|
||||||
|
c->_side = _side;
|
||||||
|
c->_onBattleField = _onBattleField;
|
||||||
|
if (_activeTalent != nullptr) {
|
||||||
|
c->_activeTalent = std::unique_ptr<BattleScript>(_activeTalent->Clone());
|
||||||
|
}
|
||||||
|
c->_hasOverridenTalent = _hasOverridenTalent;
|
||||||
|
c->_overridenTalentName = _overridenTalentName;
|
||||||
|
if (_status != nullptr) {
|
||||||
|
c->_status = std::unique_ptr<BattleScript>(_status->Clone());
|
||||||
|
}
|
||||||
|
_volatile.Clone(c->_volatile);
|
||||||
|
c->_types = std::vector<u8>(_types);
|
||||||
|
c->RecalculateFlatStats();
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -43,7 +43,7 @@ namespace CreatureLib::Battling {
|
||||||
ArbUt::OptionalBorrowedPtr<BattleSide> _side = nullptr;
|
ArbUt::OptionalBorrowedPtr<BattleSide> _side = nullptr;
|
||||||
bool _onBattleField = false;
|
bool _onBattleField = false;
|
||||||
|
|
||||||
std::string _nickname = "";
|
std::string _nickname;
|
||||||
CreatureLib::Library::TalentIndex _talentIndex;
|
CreatureLib::Library::TalentIndex _talentIndex;
|
||||||
std::unique_ptr<BattleScript> _activeTalent = nullptr;
|
std::unique_ptr<BattleScript> _activeTalent = nullptr;
|
||||||
|
|
||||||
|
@ -57,17 +57,17 @@ namespace CreatureLib::Battling {
|
||||||
std::unique_ptr<BattleScript> _status = nullptr;
|
std::unique_ptr<BattleScript> _status = nullptr;
|
||||||
ScriptSet _volatile = {};
|
ScriptSet _volatile = {};
|
||||||
|
|
||||||
std::vector<uint8_t> _types;
|
std::vector<u8> _types;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnFaint();
|
void OnFaint();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Creature(ArbUt::BorrowedPtr<const BattleLibrary> library,
|
Creature(const ArbUt::BorrowedPtr<const BattleLibrary>& library,
|
||||||
const ArbUt::BorrowedPtr<const Library::CreatureSpecies>& species,
|
const ArbUt::BorrowedPtr<const Library::CreatureSpecies>& species,
|
||||||
const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& variant, level_int_t level,
|
const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& variant, level_int_t level,
|
||||||
uint32_t experience, uint32_t uid, Library::Gender gender, uint8_t coloring,
|
uint32_t experience, uint32_t uid, Library::Gender gender, uint8_t coloring,
|
||||||
const ArbUt::OptionalBorrowedPtr<const Library::Item> heldItem, const std::string& nickname,
|
ArbUt::OptionalBorrowedPtr<const Library::Item> heldItem, std::string nickname,
|
||||||
const Library::TalentIndex& talent, const std::vector<LearnedAttack*>& attacks,
|
const Library::TalentIndex& talent, const std::vector<LearnedAttack*>& attacks,
|
||||||
bool allowedExperienceGain = true);
|
bool allowedExperienceGain = true);
|
||||||
|
|
||||||
|
@ -186,6 +186,8 @@ namespace CreatureLib::Battling {
|
||||||
void RecalculateBoostedStat(Library::Statistic);
|
void RecalculateBoostedStat(Library::Statistic);
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
virtual Creature* Clone();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,18 @@ namespace CreatureLib::Battling {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual CreatureParty* Clone() {
|
||||||
|
auto party = new CreatureParty(_party.Count());
|
||||||
|
auto i = 0;
|
||||||
|
for (auto c : _party) {
|
||||||
|
if (c != nullptr) {
|
||||||
|
party->SwapInto(i, c->Clone());
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return party;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,12 @@ namespace CreatureLib::Battling {
|
||||||
virtual void DecreaseUses(uint8_t amount) noexcept;
|
virtual void DecreaseUses(uint8_t amount) noexcept;
|
||||||
virtual void RestoreUses(uint8_t amount) noexcept;
|
virtual void RestoreUses(uint8_t amount) noexcept;
|
||||||
virtual void RestoreAllUses() noexcept;
|
virtual void RestoreAllUses() noexcept;
|
||||||
|
|
||||||
|
virtual LearnedAttack* Clone() {
|
||||||
|
auto* attack = new LearnedAttack(_attack, _maxUses, _learnMethod);
|
||||||
|
attack->_remainingUses = _remainingUses;
|
||||||
|
return attack;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace CreatureLib::Battling {
|
||||||
|
|
||||||
virtual ~BattleScript() = default;
|
virtual ~BattleScript() = default;
|
||||||
|
|
||||||
|
virtual BattleScript* Clone() = 0;
|
||||||
|
|
||||||
virtual void Stack(){};
|
virtual void Stack(){};
|
||||||
virtual void OnRemove(){};
|
virtual void OnRemove(){};
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,12 @@ namespace CreatureLib::Battling {
|
||||||
static constexpr size_t defaultCapacity = 8;
|
static constexpr size_t defaultCapacity = 8;
|
||||||
ScriptSet() : _scripts(defaultCapacity), _lookup(defaultCapacity){};
|
ScriptSet() : _scripts(defaultCapacity), _lookup(defaultCapacity){};
|
||||||
|
|
||||||
|
void Clone(ScriptSet& s) {
|
||||||
|
for (auto* script : _scripts) {
|
||||||
|
s.Add(script->Clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BattleScript* Add(BattleScript* script) {
|
BattleScript* Add(BattleScript* script) {
|
||||||
auto v = _lookup.TryGet(script->GetName());
|
auto v = _lookup.TryGet(script->GetName());
|
||||||
if (v.has_value()) {
|
if (v.has_value()) {
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
#ifdef TESTS_BUILD
|
||||||
|
|
||||||
|
#include "../../extern/doctest.hpp"
|
||||||
|
#include "../../src/Battling/History/HistoryElements/AttackUseHistory.hpp"
|
||||||
|
#include "../../src/Battling/Models/Battle.hpp"
|
||||||
|
#include "../../src/Battling/Models/BattleSide.hpp"
|
||||||
|
#include "../../src/Battling/Models/CreateCreature.hpp"
|
||||||
|
#include "../../src/Battling/TurnChoices/PassTurnChoice.hpp"
|
||||||
|
#include "../TestLibrary/TestLibrary.hpp"
|
||||||
|
|
||||||
|
using namespace CreatureLib::Battling;
|
||||||
|
|
||||||
|
TEST_CASE("Clone battle, test basic functionality") {
|
||||||
|
auto lib = TestLibrary::Get();
|
||||||
|
|
||||||
|
auto creature = CreateCreature(lib, "testSpecies1"_cnc, 1).Create();
|
||||||
|
auto party = CreatureParty(6);
|
||||||
|
party.SwapInto(0, creature);
|
||||||
|
|
||||||
|
auto bp = ArbUt::List<BattleParty*>();
|
||||||
|
bp.Append(new BattleParty(&party, {CreatureIndex(0, 0)}));
|
||||||
|
auto battle = Battle(lib, bp);
|
||||||
|
battle.SwitchCreature(0, 0, creature);
|
||||||
|
|
||||||
|
auto clone = battle.Clone();
|
||||||
|
|
||||||
|
REQUIRE_NE(battle.GetCreature(0, 0), clone->GetCreature(0, 0));
|
||||||
|
REQUIRE(battle.GetCreature(0, 0).GetValue()->GetSpecies() == clone->GetCreature(0, 0).GetValue()->GetSpecies());
|
||||||
|
|
||||||
|
auto clonedParty = clone->GetParties().At(0)->GetParty().GetRaw();
|
||||||
|
delete clone;
|
||||||
|
delete clonedParty;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Clone battle, test history history holder") {
|
||||||
|
auto lib = TestLibrary::Get();
|
||||||
|
auto battle = Battle(lib, {});
|
||||||
|
auto side = BattleSide(0, &battle, 1);
|
||||||
|
auto c = CreateCreature(TestLibrary::Get(), "testSpecies1"_cnc, 5).Create();
|
||||||
|
side.SetCreature(c, 0);
|
||||||
|
|
||||||
|
auto clone = battle.Clone();
|
||||||
|
clone->RegisterHistoryElement<AttackUseHistory>(nullptr);
|
||||||
|
clone->RegisterHistoryElement<AttackUseHistory>(nullptr);
|
||||||
|
|
||||||
|
delete c;
|
||||||
|
delete clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -12,10 +12,11 @@ private:
|
||||||
ArbUt::StringView _name;
|
ArbUt::StringView _name;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TestScript(const std::string& name) : _name(name.c_str(), name.length()){};
|
explicit TestScript(const ArbUt::StringView& name) : _name(name){};
|
||||||
const ArbUt::StringView& GetName() const noexcept override { return _name; }
|
const ArbUt::StringView& GetName() const noexcept override { return _name; }
|
||||||
|
|
||||||
void TestMethod(int& runCount) { runCount++; }
|
void TestMethod(int& runCount) { runCount++; }
|
||||||
|
BattleScript* Clone() override { return new TestScript(_name); }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_CASE("Script Aggregator properly iterates containing script.") {
|
TEST_CASE("Script Aggregator properly iterates containing script.") {
|
||||||
|
|
|
@ -12,8 +12,10 @@ private:
|
||||||
ArbUt::StringView _name;
|
ArbUt::StringView _name;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TestScript(const std::string& name) : _name(name.c_str(), name.length()){};
|
explicit TestScript(const ArbUt::StringView& name) : _name(name){};
|
||||||
const ArbUt::StringView& GetName() const noexcept override { return _name; }
|
const ArbUt::StringView& GetName() const noexcept override { return _name; }
|
||||||
|
|
||||||
|
BattleScript* Clone() override { return new TestScript(_name); }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_CASE("Empty script set count == 0") {
|
TEST_CASE("Empty script set count == 0") {
|
||||||
|
|
|
@ -11,10 +11,11 @@ private:
|
||||||
ArbUt::StringView _name;
|
ArbUt::StringView _name;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TestScript(const std::string& name) : _name(name.c_str(), name.length()){};
|
explicit TestScript(const ArbUt::StringView& name) : _name(name){};
|
||||||
const ArbUt::StringView& GetName() const noexcept override { return _name; }
|
const ArbUt::StringView& GetName() const noexcept override { return _name; }
|
||||||
|
|
||||||
void TestMethod(int& runCount) { runCount++; }
|
void TestMethod(int& runCount) { runCount++; }
|
||||||
|
BattleScript* Clone() override { return new TestScript(_name); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScriptSourceWithScriptPtr : public ScriptSource {
|
class ScriptSourceWithScriptPtr : public ScriptSource {
|
||||||
|
|
Loading…
Reference in New Issue