This new version caches pointers to the pointers to scripts, so that we can build the data once and then simply iterate over it whenever we want to run a hook.
This commit is contained in:
parent
e1a8d80863
commit
d8332f9e40
src/Battling
Flow
Models
ScriptHandling
TurnChoices
tests/BattleTests
|
@ -7,12 +7,12 @@
|
|||
|
||||
namespace CreatureLib::Battling{
|
||||
class ChoiceQueue {
|
||||
std::vector<const BaseTurnChoice*> _queue;
|
||||
std::vector<BaseTurnChoice*> _queue;
|
||||
size_t _current = 0;
|
||||
public:
|
||||
bool HasCompletedQueue = false;
|
||||
|
||||
explicit ChoiceQueue(std::vector<const BaseTurnChoice*> queue)
|
||||
explicit ChoiceQueue(std::vector<BaseTurnChoice*> queue)
|
||||
:_queue(std::move(queue)){}
|
||||
|
||||
const BaseTurnChoice* Dequeue(){
|
||||
|
@ -25,7 +25,7 @@ namespace CreatureLib::Battling{
|
|||
return _current < _queue.size();
|
||||
}
|
||||
|
||||
std::vector<const BaseTurnChoice*>& GetInnerQueue(){
|
||||
std::vector<BaseTurnChoice*>& GetInnerQueue(){
|
||||
return _queue;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#include "TurnOrdering.hpp"
|
||||
#include "../TurnChoices/AttackTurnChoice.hpp"
|
||||
#include "../Models/Creature.hpp"
|
||||
#include "../Models/Battle.hpp"
|
||||
#include "../../Core/Exceptions/NotImplementedException.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -15,8 +13,8 @@ bool ___ChoiceOrderFunc(const BaseTurnChoice* a, const BaseTurnChoice* b, Core::
|
|||
if (aKind != bKind)
|
||||
return aKind > bKind;
|
||||
if (aKind == TurnChoiceKind::Attack){
|
||||
auto aPriority = static_cast<const AttackTurnChoice*>(a)->GetPriority();
|
||||
auto bPriority = static_cast<const AttackTurnChoice*>(b)->GetPriority();
|
||||
auto aPriority = dynamic_cast<const AttackTurnChoice*>(a)->GetPriority();
|
||||
auto bPriority = dynamic_cast<const AttackTurnChoice*>(b)->GetPriority();
|
||||
if (aPriority != bPriority)
|
||||
return aPriority > bPriority;
|
||||
}
|
||||
|
@ -29,7 +27,7 @@ bool ___ChoiceOrderFunc(const BaseTurnChoice* a, const BaseTurnChoice* b, Core::
|
|||
return randomValue == 0;
|
||||
}
|
||||
|
||||
void TurnOrdering::OrderChoices(std::vector<const BaseTurnChoice *> &vec, Core::Random& rand) {
|
||||
void TurnOrdering::OrderChoices(std::vector<BaseTurnChoice *> &vec, Core::Random& rand) {
|
||||
auto comp = [&](const BaseTurnChoice * a,const BaseTurnChoice * b)-> bool {
|
||||
return ___ChoiceOrderFunc(a,b,rand);
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
namespace CreatureLib::Battling {
|
||||
class TurnOrdering {
|
||||
public:
|
||||
static void OrderChoices(std::vector<const BaseTurnChoice*>& vec, CreatureLib::Core::Random& rand);
|
||||
static void OrderChoices(std::vector<BaseTurnChoice*>& vec, CreatureLib::Core::Random& rand);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -33,10 +33,10 @@ void Battle::CheckChoicesSetAndRun() {
|
|||
return;
|
||||
}
|
||||
}
|
||||
auto choices = std::vector<const BaseTurnChoice*>(_numberOfSides * _creaturesPerSide);
|
||||
auto choices = std::vector<BaseTurnChoice*>(_numberOfSides * _creaturesPerSide);
|
||||
auto i = 0;
|
||||
for (auto side: _sides){
|
||||
for (const BaseTurnChoice* choice: side->GetChoices()){
|
||||
for (BaseTurnChoice* choice: side->GetChoices()){
|
||||
if (choice->GetKind() == TurnChoiceKind::Attack){
|
||||
auto attack = dynamic_cast<const AttackTurnChoice*>(choice)->GetAttack();
|
||||
uint8_t uses = 1;
|
||||
|
@ -93,6 +93,6 @@ void Battle::FillRecall(uint8_t side, uint8_t, Creature *c) {
|
|||
}
|
||||
}
|
||||
|
||||
void Battle::GetActiveScripts(ScriptAggregator &aggr) const {
|
||||
aggr.Add(&_volatile);
|
||||
void Battle::GetActiveScripts(std::vector<ScriptWrapper> &scripts) {
|
||||
scripts.emplace_back(&_volatile);
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace CreatureLib::Battling {
|
|||
|
||||
void FillRecall(uint8_t side, uint8_t, Creature* c);
|
||||
|
||||
void GetActiveScripts(ScriptAggregator &aggr) const override;
|
||||
void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -16,11 +16,11 @@ void BattleSide::ResetChoices() {
|
|||
}
|
||||
}
|
||||
|
||||
const std::vector<const BaseTurnChoice *>& BattleSide::GetChoices() const{
|
||||
const std::vector<BaseTurnChoice *>& BattleSide::GetChoices() const{
|
||||
return _choices;
|
||||
}
|
||||
|
||||
void BattleSide::SetChoice(const BaseTurnChoice *choice) {
|
||||
void BattleSide::SetChoice(BaseTurnChoice *choice) {
|
||||
auto find = std::find(_creatures.begin(), _creatures.end(), choice->GetUser());
|
||||
if (find ==_creatures.end())
|
||||
throw CreatureException("User not found");
|
||||
|
@ -41,7 +41,7 @@ Creature *BattleSide::GetCreature(uint8_t index) const {
|
|||
return _creatures[index];
|
||||
}
|
||||
|
||||
void BattleSide::GetActiveScripts(ScriptAggregator &aggr) const {
|
||||
aggr.Add(&_volatile);
|
||||
_battle->GetActiveScripts(aggr);
|
||||
void BattleSide::GetActiveScripts(std::vector<ScriptWrapper> &scripts) {
|
||||
scripts.emplace_back(&_volatile);
|
||||
_battle->GetActiveScripts(scripts);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace CreatureLib::Battling{
|
|||
class BattleSide : public ScriptSource{
|
||||
uint8_t _creaturesPerSide;
|
||||
std::vector<Creature*> _creatures;
|
||||
std::vector<const BaseTurnChoice*> _choices;
|
||||
std::vector<BaseTurnChoice*> _choices;
|
||||
uint8_t _choicesSet = 0;
|
||||
ScriptSet _volatile;
|
||||
Battle* _battle;
|
||||
|
@ -21,9 +21,9 @@ namespace CreatureLib::Battling{
|
|||
}
|
||||
|
||||
[[nodiscard]] bool AllChoicesSet() const;
|
||||
[[nodiscard]] const std::vector<const BaseTurnChoice*>& GetChoices() const;
|
||||
[[nodiscard]] const std::vector<BaseTurnChoice*>& GetChoices() const;
|
||||
|
||||
void SetChoice(const BaseTurnChoice* choice);
|
||||
void SetChoice(BaseTurnChoice* choice);
|
||||
void ResetChoices();
|
||||
|
||||
void SetCreature(Creature* creature, uint8_t index);
|
||||
|
@ -31,7 +31,7 @@ namespace CreatureLib::Battling{
|
|||
Creature* GetCreature(uint8_t index) const;
|
||||
bool CreatureOnSide(const Creature* creature) const;
|
||||
|
||||
void GetActiveScripts(ScriptAggregator &aggr) const override;
|
||||
void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override;
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include "Creature.hpp"
|
||||
#include "../Models/Battle.hpp"
|
||||
|
||||
|
@ -20,9 +21,9 @@ Battling::Creature::Creature(const Library::CreatureSpecies* species, const Libr
|
|||
__Gender(gender),
|
||||
__Coloring(coloring),
|
||||
__HeldItem(heldItem),
|
||||
_nickname(nickname),
|
||||
_nickname(std::move(nickname)),
|
||||
_talentIndex(talent),
|
||||
_attacks(attacks)
|
||||
_attacks(std::move(attacks))
|
||||
{}
|
||||
|
||||
|
||||
|
@ -140,8 +141,8 @@ bool Battling::Creature::HasType(uint8_t type) const {
|
|||
return std::find(t.begin(), t.end(), type) != t.end();
|
||||
}
|
||||
|
||||
void Battling::Creature::GetActiveScripts(Battling::ScriptAggregator &aggr) const {
|
||||
aggr.Add(_status);
|
||||
aggr.Add(&_volatile);
|
||||
_side->GetActiveScripts(aggr);
|
||||
void Battling::Creature::GetActiveScripts(std::vector<ScriptWrapper> &scripts) {
|
||||
scripts.emplace_back(&_status);
|
||||
scripts.emplace_back(&_volatile);
|
||||
_side->GetActiveScripts(scripts);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@ namespace CreatureLib::Battling{
|
|||
|
||||
class Creature : public ScriptSource{
|
||||
GetProperty(const Library::CreatureSpecies*, Species);
|
||||
GetProperty(const Library::SpeciesVariant*, Variant);
|
||||
GetProperty(const Library::SpeciesVariant*, Variant)
|
||||
|
||||
GetProperty(uint8_t, Level);
|
||||
GetProperty(uint32_t, Experience);
|
||||
GetProperty(Core::StatisticSet<uint8_t >, StatExperience);
|
||||
|
@ -67,7 +68,7 @@ namespace CreatureLib::Battling{
|
|||
[[nodiscard]] const std::vector<uint8_t>& GetTypes() const;
|
||||
[[nodiscard]] bool HasType(uint8_t type) const;
|
||||
|
||||
void GetActiveScripts(ScriptAggregator& aggr) const override;
|
||||
void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override;
|
||||
|
||||
//region Stat APIs
|
||||
|
||||
|
@ -85,6 +86,7 @@ namespace CreatureLib::Battling{
|
|||
void RecalculateBoostedStats();
|
||||
void RecalculateFlatStat(Core::Statistic);
|
||||
void RecalculateBoostedStat(Core::Statistic);
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
|
|
@ -89,8 +89,10 @@ namespace CreatureLib::Battling {
|
|||
return _attack;
|
||||
}
|
||||
|
||||
void GetActiveScripts(ScriptAggregator &aggr) const override {
|
||||
aggr.Add(_script);
|
||||
protected:
|
||||
void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override {
|
||||
scripts.emplace_back(&_script);
|
||||
GetUser()->GetActiveScripts(scripts);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,26 +6,23 @@
|
|||
#include "Script.hpp"
|
||||
#include "ScriptSet.hpp"
|
||||
#include "../../Core/Exceptions/NotReachableException.hpp"
|
||||
#include "ScriptWrapper.hpp"
|
||||
|
||||
namespace CreatureLib::Battling{
|
||||
class ScriptAggregator{
|
||||
std::queue<std::any> _queue;
|
||||
__gnu_cxx::__normal_iterator<ScriptWrapper *, std::vector<ScriptWrapper>> _selfIterator;
|
||||
__gnu_cxx::__normal_iterator<ScriptWrapper *, std::vector<ScriptWrapper>> _selfEnd;
|
||||
bool _isSetSet = false;
|
||||
std::__detail::_Node_const_iterator<std::pair<const std::string, Script *>, false, true> _setIterator;
|
||||
std::__detail::_Node_const_iterator<std::pair<const std::string, Script *>, false, true> _setEnd;
|
||||
public:
|
||||
ScriptAggregator() = default;
|
||||
|
||||
void Add(Script* script){
|
||||
_queue.push(script);
|
||||
}
|
||||
|
||||
void Add(const ScriptSet* scriptSet){
|
||||
_queue.push(scriptSet);
|
||||
}
|
||||
ScriptAggregator(std::vector<ScriptWrapper> scripts){
|
||||
_selfIterator = scripts.begin();
|
||||
_selfEnd = scripts.end();
|
||||
};
|
||||
|
||||
bool HasNext(){
|
||||
return !_queue.empty() || _isSetSet;
|
||||
return _selfIterator != _selfEnd || _isSetSet;
|
||||
}
|
||||
|
||||
Script* GetNext(){
|
||||
|
@ -42,15 +39,17 @@ namespace CreatureLib::Battling{
|
|||
}
|
||||
return s;
|
||||
}
|
||||
if (_queue.empty())
|
||||
if (_selfIterator == _selfEnd)
|
||||
return nullptr;
|
||||
auto next = _queue.front();
|
||||
_queue.pop();
|
||||
if (next.type() == typeid(Script*)){
|
||||
return std::any_cast<Script*>(next);
|
||||
auto next = *_selfIterator;
|
||||
if (!next.IsSet()){
|
||||
auto scriptPtr = next.GetScript();
|
||||
if (scriptPtr == nullptr)
|
||||
return GetNext();
|
||||
return *scriptPtr;
|
||||
}
|
||||
else{
|
||||
auto set = std::any_cast<const ScriptSet*>(next);
|
||||
auto set = next.GetScriptSet();
|
||||
if (set->Count() == 0)
|
||||
return GetNext();
|
||||
auto it = set->GetIterator();
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#define HOOK(hookName, source, ... ) \
|
||||
{ \
|
||||
auto aggregator = CreatureLib::Battling::ScriptAggregator(); \
|
||||
source -> GetActiveScripts(aggregator); \
|
||||
auto aggregator = source -> GetScriptIterator(); \
|
||||
while (aggregator.HasNext()){ \
|
||||
auto next = aggregator.GetNext(); \
|
||||
if (next == nullptr) continue; \
|
||||
|
|
|
@ -7,8 +7,18 @@
|
|||
|
||||
namespace CreatureLib::Battling{
|
||||
class ScriptSource {
|
||||
bool _areScriptsInitialized = false;
|
||||
std::vector<ScriptWrapper> _scripts;
|
||||
protected:
|
||||
virtual void GetActiveScripts(std::vector<ScriptWrapper>& scripts) = 0;
|
||||
public:
|
||||
virtual void GetActiveScripts(ScriptAggregator& aggr) const = 0;
|
||||
ScriptAggregator GetScriptIterator(){
|
||||
if (!_areScriptsInitialized){
|
||||
GetActiveScripts(_scripts);
|
||||
_areScriptsInitialized = true;
|
||||
}
|
||||
return ScriptAggregator(_scripts);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
#include "ScriptWrapper.hpp"
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
|
||||
#ifndef CREATURELIB_SCRIPTWRAPPER_HPP
|
||||
#define CREATURELIB_SCRIPTWRAPPER_HPP
|
||||
|
||||
#include <variant>
|
||||
#include "Script.hpp"
|
||||
#include "ScriptSet.hpp"
|
||||
|
||||
namespace CreatureLib::Battling{
|
||||
class ScriptWrapper {
|
||||
std::variant<Script**, ScriptSet*> _value;
|
||||
bool _isSet;
|
||||
public:
|
||||
ScriptWrapper(Script** s) : _value(s), _isSet(false){}
|
||||
ScriptWrapper(ScriptSet* s) : _value(s), _isSet(true){}
|
||||
|
||||
bool IsSet() const{
|
||||
return _isSet;
|
||||
}
|
||||
|
||||
Script** GetScript() const{
|
||||
return std::get<Script**>(_value);
|
||||
}
|
||||
|
||||
ScriptSet* GetScriptSet() const{
|
||||
return std::get<ScriptSet*>(_value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //CREATURELIB_SCRIPTWRAPPER_HPP
|
|
@ -31,10 +31,12 @@ namespace CreatureLib::Battling{
|
|||
return _target;
|
||||
}
|
||||
|
||||
void GetActiveScripts(ScriptAggregator &aggr) const override {
|
||||
aggr.Add(_attackScript);
|
||||
GetUser()->GetActiveScripts(aggr);
|
||||
protected:
|
||||
void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override {
|
||||
scripts.emplace_back(&_attackScript);
|
||||
GetUser()->GetActiveScripts(scripts);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,6 @@ namespace CreatureLib::Battling{
|
|||
[[nodiscard]] inline Creature* GetUser() const{
|
||||
return _user;
|
||||
}
|
||||
|
||||
void GetActiveScripts(ScriptAggregator &aggr) const override {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,9 @@ namespace CreatureLib::Battling {
|
|||
return TurnChoiceKind ::Pass;
|
||||
}
|
||||
|
||||
void GetActiveScripts(ScriptAggregator &aggr) const override {
|
||||
GetUser()->GetActiveScripts(aggr);
|
||||
protected:
|
||||
void GetActiveScripts(std::vector<ScriptWrapper> &scripts) override {
|
||||
GetUser()->GetActiveScripts(scripts);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@ using namespace CreatureLib::Battling;
|
|||
TEST_CASE( "Turn ordering: Attack before pass", "[Battling]" ) {
|
||||
auto choice1 = new PassTurnChoice(nullptr);
|
||||
auto choice2 = new AttackTurnChoice(nullptr, nullptr, Target(0,0));
|
||||
auto vec = std::vector<const BaseTurnChoice*>{choice1, choice2};
|
||||
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
|
||||
auto rand = Core::Random();
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
vec = std::vector<const BaseTurnChoice*>{choice2, choice1};
|
||||
vec = std::vector<BaseTurnChoice*>{choice2, choice1};
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
|
@ -31,12 +31,12 @@ TEST_CASE( "Turn ordering: High priority goes before no priority", "[Battling]"
|
|||
auto a2 = new LearnedAttack(l->GetAttack("highPriority"), AttackLearnMethod::Unknown);
|
||||
auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0));
|
||||
auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0));
|
||||
auto vec = std::vector<const BaseTurnChoice*>{choice1, choice2};
|
||||
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
|
||||
auto rand = Core::Random();
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
vec = std::vector<const BaseTurnChoice*>{choice2, choice1};
|
||||
vec = std::vector<BaseTurnChoice*>{choice2, choice1};
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
|
@ -53,12 +53,12 @@ TEST_CASE( "Turn ordering: Higher priority goes before high priority", "[Battlin
|
|||
auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown);
|
||||
auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0));
|
||||
auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0));
|
||||
auto vec = std::vector<const BaseTurnChoice*>{choice1, choice2};
|
||||
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
|
||||
auto rand = Core::Random();
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
vec = std::vector<const BaseTurnChoice*>{choice2, choice1};
|
||||
vec = std::vector<BaseTurnChoice*>{choice2, choice1};
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
|
@ -75,12 +75,12 @@ TEST_CASE( "Turn ordering: High priority goes before low priority", "[Battling]"
|
|||
auto a2 = new LearnedAttack(l->GetAttack("higherPriority"), AttackLearnMethod::Unknown);
|
||||
auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0));
|
||||
auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0));
|
||||
auto vec = std::vector<const BaseTurnChoice*>{choice1, choice2};
|
||||
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
|
||||
auto rand = Core::Random();
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
vec = std::vector<const BaseTurnChoice*>{choice2, choice1};
|
||||
vec = std::vector<BaseTurnChoice*>{choice2, choice1};
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
|
@ -97,12 +97,12 @@ TEST_CASE( "Turn ordering: No priority goes before low priority", "[Battling]" )
|
|||
auto a2 = new LearnedAttack(l->GetAttack("standard"), AttackLearnMethod::Unknown);
|
||||
auto choice1 = new AttackTurnChoice(nullptr, a1, Target(0,0));
|
||||
auto choice2 = new AttackTurnChoice(nullptr, a2, Target(0,0));
|
||||
auto vec = std::vector<const BaseTurnChoice*>{choice1, choice2};
|
||||
auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
|
||||
auto rand = Core::Random();
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
vec = std::vector<const BaseTurnChoice*>{choice2, choice1};
|
||||
vec = std::vector<BaseTurnChoice*>{choice2, choice1};
|
||||
TurnOrdering::OrderChoices(vec,rand);
|
||||
CHECK(vec[0] == choice2);
|
||||
CHECK(vec[1] == choice1);
|
||||
|
|
Loading…
Reference in New Issue