Furter rework on script hooks, simplifying required logic.

This commit is contained in:
Deukhoofd 2019-11-10 14:32:05 +01:00
parent f72fd5f905
commit 3488784409
18 changed files with 79 additions and 37 deletions

View File

@ -24,6 +24,10 @@ namespace CreatureLib::Battling{
[[nodiscard]] bool HasNext() const{ [[nodiscard]] bool HasNext() const{
return _current < _queue.size(); return _current < _queue.size();
} }
std::vector<const BaseTurnChoice*>& GetInnerQueue(){
return _queue;
}
}; };
} }

View File

@ -7,6 +7,9 @@ using namespace CreatureLib::Battling;
void TurnHandler::RunTurn(Battle* battle, ChoiceQueue* queue) { void TurnHandler::RunTurn(Battle* battle, ChoiceQueue* queue) {
//HOOK: On Before Turn hook for all choices //HOOK: On Before Turn hook for all choices
for (auto choice: queue->GetInnerQueue()){
HOOK(OnBeforeTurn, choice, choice);
}
while (queue->HasNext()){ while (queue->HasNext()){
if (!battle->HasRecalledSlots()){ if (!battle->HasRecalledSlots()){
return; return;
@ -83,25 +86,25 @@ void TurnHandler::ExecuteAttackChoice(const AttackTurnChoice *choice) {
void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, Creature *target, const ExecutingAttack::TargetData &targetData) { void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, Creature *target, const ExecutingAttack::TargetData &targetData) {
auto user = attack->GetUser(); auto user = attack->GetUser();
std::array<ScriptSource*, 1> targetSources = {target}; ScriptSource* targetSource = target;
std::array<ScriptSource*, 1> userSources = {user}; ScriptSource* userSource = attack;
bool fail = false; bool fail = false;
HOOK(FailIncomingAttack, targetSources, attack, target, fail); HOOK(FailIncomingAttack, targetSource, attack, target, fail);
if (fail){ if (fail){
//TODO: Fail handling. //TODO: Fail handling.
return; return;
} }
bool invulnerable = fail; bool invulnerable = fail;
HOOK(IsInvulnerable, targetSources, attack, target, invulnerable); HOOK(IsInvulnerable, targetSource, attack, target, invulnerable);
if (invulnerable){ if (invulnerable){
//TODO: We should probably do something when a target is invulnerable. //TODO: We should probably do something when a target is invulnerable.
return; return;
} }
if (!targetData.IsHit()){ if (!targetData.IsHit()){
HOOK(OnAttackMiss, targetSources, attack, target); HOOK(OnAttackMiss, targetSource, attack, target);
return; return;
} }
@ -122,15 +125,14 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, Creature *targe
auto hit = targetData.GetHit(hitIndex); auto hit = targetData.GetHit(hitIndex);
auto hitType = hit.GetType(); auto hitType = hit.GetType();
HOOK(ChangeAttackType, targetSources, attack, target, hitIndex, hitType); HOOK(ChangeAttackType, targetSource, attack, target, hitIndex, hitType);
hit.SetEffectiveness(library->GetTypeLibrary()->GetEffectiveness(hitType, target->GetTypes())); hit.SetEffectiveness(library->GetTypeLibrary()->GetEffectiveness(hitType, target->GetTypes()));
hit.SetCritical(library->GetCriticalLibrary()->IsCritical(attack, target, hitIndex)); hit.SetCritical(library->GetCriticalLibrary()->IsCritical(attack, target, hitIndex));
hit.SetBasePower(dmgLibrary->GetBasePower(attack, target, hitIndex)); hit.SetBasePower(dmgLibrary->GetBasePower(attack, target, hitIndex));
hit.SetDamage(dmgLibrary->GetDamage(attack, target, hitIndex)); hit.SetDamage(dmgLibrary->GetDamage(attack, target, hitIndex));
std::array<ScriptSource*, 1> attackSource = {attack};
if (attackData->GetCategory() == Library::AttackCategory::Status){ if (attackData->GetCategory() == Library::AttackCategory::Status){
HOOK(OnStatusMove, attackSource, attack, target, hitIndex); HOOK(OnStatusMove, userSource, attack, target, hitIndex);
} }
else{ else{
auto damage = hit.GetDamage(); auto damage = hit.GetDamage();
@ -142,15 +144,15 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, Creature *targe
target->Damage(damage, DamageSource::AttackDamage); target->Damage(damage, DamageSource::AttackDamage);
bool preventSecondary = false; bool preventSecondary = false;
HOOK(PreventSecondaryEffects, targetSources, attack, target, hitIndex, preventSecondary); HOOK(PreventSecondaryEffects, targetSource, attack, target, hitIndex, preventSecondary);
if (!preventSecondary){ if (!preventSecondary){
HOOK(OnSecondaryEffect, attackSource, attack, target, hitIndex); HOOK(OnSecondaryEffect, userSource, attack, target, hitIndex);
} }
} }
} }
} }
if (!user->IsFainted()){ if (!user->IsFainted()){
HOOK(OnAfterHits, userSources, attack, target); HOOK(OnAfterHits, userSource, attack, target);
} }
} }

View File

@ -14,7 +14,7 @@ const BattleLibrary *Battle::GetLibrary() const {
bool Battle::CanUse(const BaseTurnChoice *choice) { bool Battle::CanUse(const BaseTurnChoice *choice) {
if (choice->GetKind() == TurnChoiceKind::Attack){ if (choice->GetKind() == TurnChoiceKind::Attack){
//HOOK: change number of uses needed. //HOOK: change number of uses needed.
return static_cast<const AttackTurnChoice*>(choice)->GetAttack()->GetRemainingUses() > 1; return dynamic_cast<const AttackTurnChoice*>(choice)->GetAttack()->GetRemainingUses() > 1;
} }
return true; return true;
} }
@ -36,7 +36,7 @@ void Battle::CheckChoicesSetAndRun() {
auto choices = std::vector<const BaseTurnChoice*>(_numberOfSides * _creaturesPerSide); auto choices = std::vector<const BaseTurnChoice*>(_numberOfSides * _creaturesPerSide);
auto i = 0; auto i = 0;
for (auto side: _sides){ for (auto side: _sides){
for (auto choice: side->GetChoices()){ for (const BaseTurnChoice* choice: side->GetChoices()){
if (choice->GetKind() == TurnChoiceKind::Attack){ if (choice->GetKind() == TurnChoiceKind::Attack){
auto attack = dynamic_cast<const AttackTurnChoice*>(choice)->GetAttack(); auto attack = dynamic_cast<const AttackTurnChoice*>(choice)->GetAttack();
uint8_t uses = 1; uint8_t uses = 1;
@ -92,3 +92,7 @@ void Battle::FillRecall(uint8_t side, uint8_t, Creature *c) {
TurnHandler::RunTurn(this, _currentTurnQueue); TurnHandler::RunTurn(this, _currentTurnQueue);
} }
} }
void Battle::GetActiveScripts(ScriptAggregator &aggr) const {
aggr.Add(&_volatile);
}

View File

@ -9,7 +9,7 @@
#include "Target.hpp" #include "Target.hpp"
namespace CreatureLib::Battling { namespace CreatureLib::Battling {
class Battle { class Battle : public ScriptSource{
const BattleLibrary* _library; const BattleLibrary* _library;
uint8_t _numberOfSides; uint8_t _numberOfSides;
uint8_t _creaturesPerSide; uint8_t _creaturesPerSide;
@ -18,6 +18,7 @@ namespace CreatureLib::Battling {
ChoiceQueue* _currentTurnQueue = nullptr; ChoiceQueue* _currentTurnQueue = nullptr;
uint8_t _numberOfRecalledSlots = 0; uint8_t _numberOfRecalledSlots = 0;
ScriptSet _volatile;
public: public:
[[nodiscard]] const BattleLibrary* GetLibrary() const; [[nodiscard]] const BattleLibrary* GetLibrary() const;
@ -40,6 +41,8 @@ namespace CreatureLib::Battling {
void ForceRecall(uint8_t side, uint8_t index); void ForceRecall(uint8_t side, uint8_t index);
void FillRecall(uint8_t side, uint8_t, Creature* c); void FillRecall(uint8_t side, uint8_t, Creature* c);
void GetActiveScripts(ScriptAggregator &aggr) const override;
}; };
} }

View File

@ -1,6 +1,7 @@
#include "BattleSide.hpp" #include "BattleSide.hpp"
#include "../../Core/Exceptions/CreatureException.hpp" #include "../../Core/Exceptions/CreatureException.hpp"
#include <algorithm> #include <algorithm>
#include "Battle.hpp"
using namespace CreatureLib::Battling; using namespace CreatureLib::Battling;
@ -39,3 +40,8 @@ bool BattleSide::CreatureOnSide(const Creature *creature) const {
Creature *BattleSide::GetCreature(uint8_t index) const { Creature *BattleSide::GetCreature(uint8_t index) const {
return _creatures[index]; return _creatures[index];
} }
void BattleSide::GetActiveScripts(ScriptAggregator &aggr) const {
aggr.Add(&_volatile);
_battle->GetActiveScripts(aggr);
}

View File

@ -6,14 +6,16 @@
#include "../TurnChoices/BaseTurnChoice.hpp" #include "../TurnChoices/BaseTurnChoice.hpp"
namespace CreatureLib::Battling{ namespace CreatureLib::Battling{
class BattleSide { class BattleSide : public ScriptSource{
uint8_t _creaturesPerSide; uint8_t _creaturesPerSide;
std::vector<Creature*> _creatures; std::vector<Creature*> _creatures;
std::vector<const BaseTurnChoice*> _choices; std::vector<const BaseTurnChoice*> _choices;
uint8_t _choicesSet = 0; uint8_t _choicesSet = 0;
ScriptSet _volatile;
Battle* _battle;
public: public:
BattleSide(uint8_t creaturesPerSide) explicit BattleSide(Battle* battle, uint8_t creaturesPerSide)
: _creaturesPerSide(creaturesPerSide), _creatures(creaturesPerSide), _choices(creaturesPerSide) : _creaturesPerSide(creaturesPerSide), _creatures(creaturesPerSide), _choices(creaturesPerSide), _battle(battle)
{ {
ResetChoices(); ResetChoices();
} }
@ -29,6 +31,8 @@ namespace CreatureLib::Battling{
Creature* GetCreature(uint8_t index) const; Creature* GetCreature(uint8_t index) const;
bool CreatureOnSide(const Creature* creature) const; bool CreatureOnSide(const Creature* creature) const;
void GetActiveScripts(ScriptAggregator &aggr) const override;
}; };
} }

View File

@ -139,3 +139,9 @@ bool Battling::Creature::HasType(uint8_t type) const {
auto t = GetTypes(); auto t = GetTypes();
return std::find(t.begin(), t.end(), type) != t.end(); 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);
}

View File

@ -65,10 +65,7 @@ namespace CreatureLib::Battling{
[[nodiscard]] const std::vector<uint8_t>& GetTypes() const; [[nodiscard]] const std::vector<uint8_t>& GetTypes() const;
[[nodiscard]] bool HasType(uint8_t type) const; [[nodiscard]] bool HasType(uint8_t type) const;
void GetActiveScripts(ScriptAggregator& aggr) override{ void GetActiveScripts(ScriptAggregator& aggr) const override;
aggr.Add(_status);
aggr.Add(&_volatile);
}
//region Stat APIs //region Stat APIs

View File

@ -88,7 +88,7 @@ namespace CreatureLib::Battling {
return _attack; return _attack;
} }
void GetActiveScripts(ScriptAggregator &aggr) override { void GetActiveScripts(ScriptAggregator &aggr) const override {
aggr.Add(_script); aggr.Add(_script);
} }
}; };

View File

@ -7,6 +7,7 @@
#include <vector> #include <vector>
namespace CreatureLib::Battling{ namespace CreatureLib::Battling{
class BaseTurnChoice;
class ExecutingAttack; class ExecutingAttack;
class Creature; class Creature;
@ -23,6 +24,7 @@ namespace CreatureLib::Battling{
return _name; return _name;
} }
virtual void OnBeforeTurn(const BaseTurnChoice* choice);
virtual void FailIncomingAttack(ExecutingAttack* attack, Creature* target, bool& result){}; virtual void FailIncomingAttack(ExecutingAttack* attack, Creature* target, bool& result){};
virtual void IsInvulnerable(ExecutingAttack* attack, Creature* target , bool& result){}; virtual void IsInvulnerable(ExecutingAttack* attack, Creature* target , bool& result){};
virtual void OnAttackMiss(ExecutingAttack* attack, Creature* target){}; virtual void OnAttackMiss(ExecutingAttack* attack, Creature* target){};

View File

@ -5,13 +5,14 @@
#include <queue> #include <queue>
#include "Script.hpp" #include "Script.hpp"
#include "ScriptSet.hpp" #include "ScriptSet.hpp"
#include "../../Core/Exceptions/NotReachableException.hpp"
namespace CreatureLib::Battling{ namespace CreatureLib::Battling{
class ScriptAggregator{ class ScriptAggregator{
std::queue<std::any> _queue; std::queue<std::any> _queue;
bool _isSetSet = false; bool _isSetSet = false;
std::__detail::_Node_iterator<std::pair<const std::string, Script *>, false, true> _setIterator; std::__detail::_Node_const_iterator<std::pair<const std::string, Script *>, false, true> _setIterator;
std::__detail::_Node_iterator<std::pair<const std::string, Script *>, false, true> _setEnd; std::__detail::_Node_const_iterator<std::pair<const std::string, Script *>, false, true> _setEnd;
public: public:
ScriptAggregator() = default; ScriptAggregator() = default;
@ -19,7 +20,7 @@ namespace CreatureLib::Battling{
_queue.push(script); _queue.push(script);
} }
void Add(ScriptSet* scriptSet){ void Add(const ScriptSet* scriptSet){
_queue.push(scriptSet); _queue.push(scriptSet);
} }
@ -49,7 +50,7 @@ namespace CreatureLib::Battling{
return std::any_cast<Script*>(next); return std::any_cast<Script*>(next);
} }
else{ else{
auto set = std::any_cast<ScriptSet*>(next); auto set = std::any_cast<const ScriptSet*>(next);
if (set->Count() == 0) if (set->Count() == 0)
return GetNext(); return GetNext();
auto it = set->GetIterator(); auto it = set->GetIterator();

View File

@ -1,9 +1,7 @@
#define HOOK(hookName, sources, ... ) \ #define HOOK(hookName, source, ... ) \
{ \ { \
auto aggregator = CreatureLib::Battling::ScriptAggregator(); \ auto aggregator = CreatureLib::Battling::ScriptAggregator(); \
for (auto& source: sources){ \
source -> GetActiveScripts(aggregator); \ source -> GetActiveScripts(aggregator); \
} \
while (aggregator.HasNext()){ \ while (aggregator.HasNext()){ \
auto next = aggregator.GetNext(); \ auto next = aggregator.GetNext(); \
if (next == nullptr) continue; \ if (next == nullptr) continue; \

View File

@ -27,7 +27,7 @@ namespace CreatureLib::Battling{
return _scripts.size(); return _scripts.size();
} }
std::unordered_map<std::string, Script *> * GetIterator(){ const std::unordered_map<std::string, Script *> * GetIterator() const{
return &_scripts; return &_scripts;
} }
}; };

View File

@ -8,7 +8,7 @@
namespace CreatureLib::Battling{ namespace CreatureLib::Battling{
class ScriptSource { class ScriptSource {
public: public:
virtual void GetActiveScripts(ScriptAggregator& aggr) = 0; virtual void GetActiveScripts(ScriptAggregator& aggr) const = 0;
}; };
} }

View File

@ -9,6 +9,7 @@ namespace CreatureLib::Battling{
class AttackTurnChoice : public BaseTurnChoice { class AttackTurnChoice : public BaseTurnChoice {
LearnedAttack* _attack; LearnedAttack* _attack;
Target _target; Target _target;
Script* _attackScript;
public: public:
AttackTurnChoice(Creature* user, LearnedAttack* attack, const Target& target) AttackTurnChoice(Creature* user, LearnedAttack* attack, const Target& target)
: BaseTurnChoice(user), _attack(attack), _target(target){} : BaseTurnChoice(user), _attack(attack), _target(target){}
@ -29,6 +30,11 @@ namespace CreatureLib::Battling{
const Target& GetTarget() const{ const Target& GetTarget() const{
return _target; return _target;
} }
void GetActiveScripts(ScriptAggregator &aggr) const override {
aggr.Add(_attackScript);
GetUser()->GetActiveScripts(aggr);
}
}; };
} }

View File

@ -2,11 +2,12 @@
#define CREATURELIB_BASETURNCHOICE_HPP #define CREATURELIB_BASETURNCHOICE_HPP
#include "TurnChoiceKind.hpp" #include "TurnChoiceKind.hpp"
#include "../ScriptHandling/ScriptSource.hpp"
namespace CreatureLib::Battling{ namespace CreatureLib::Battling{
class Creature; class Creature;
class BaseTurnChoice { class BaseTurnChoice : public ScriptSource {
Creature* _user; Creature* _user;
protected: protected:
BaseTurnChoice(Creature* user) : _user(user){}; BaseTurnChoice(Creature* user) : _user(user){};
@ -16,6 +17,10 @@ namespace CreatureLib::Battling{
[[nodiscard]] inline Creature* GetUser() const{ [[nodiscard]] inline Creature* GetUser() const{
return _user; return _user;
} }
void GetActiveScripts(ScriptAggregator &aggr) const override {
}
}; };
} }

View File

@ -11,6 +11,10 @@ namespace CreatureLib::Battling {
TurnChoiceKind GetKind() const override { TurnChoiceKind GetKind() const override {
return TurnChoiceKind ::Pass; return TurnChoiceKind ::Pass;
} }
void GetActiveScripts(ScriptAggregator &aggr) const override {
GetUser()->GetActiveScripts(aggr);
}
}; };
} }

View File

@ -8,7 +8,7 @@
using namespace CreatureLib::Battling; using namespace CreatureLib::Battling;
TEST_CASE( "Set Choice one-sized side", "[Battling]" ) { TEST_CASE( "Set Choice one-sized side", "[Battling]" ) {
auto side = BattleSide(1); auto side = BattleSide(nullptr, 1);
auto c = CreateCreature(GetLibrary(), "testSpecies1", 5).Create(); auto c = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
side.SetCreature(c, 0); side.SetCreature(c, 0);
auto choice = new PassTurnChoice(c); auto choice = new PassTurnChoice(c);
@ -18,7 +18,7 @@ TEST_CASE( "Set Choice one-sized side", "[Battling]" ) {
} }
TEST_CASE( "Set Choice one-sized side, validate all choices set", "[Battling]" ) { TEST_CASE( "Set Choice one-sized side, validate all choices set", "[Battling]" ) {
auto side = BattleSide(1); auto side = BattleSide(nullptr, 1);
auto c = CreateCreature(GetLibrary(), "testSpecies1", 5).Create(); auto c = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
side.SetCreature(c, 0); side.SetCreature(c, 0);
auto choice = new PassTurnChoice(c); auto choice = new PassTurnChoice(c);
@ -30,7 +30,7 @@ TEST_CASE( "Set Choice one-sized side, validate all choices set", "[Battling]" )
} }
TEST_CASE( "Set Choice two-sized side", "[Battling]" ) { TEST_CASE( "Set Choice two-sized side", "[Battling]" ) {
auto side = BattleSide(2); auto side = BattleSide(nullptr, 2);
auto c1 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create(); auto c1 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
auto c2 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create(); auto c2 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
side.SetCreature(c1, 0); side.SetCreature(c1, 0);
@ -46,7 +46,7 @@ TEST_CASE( "Set Choice two-sized side", "[Battling]" ) {
} }
TEST_CASE( "Set Choice two-sized side, validate all choices set", "[Battling]" ) { TEST_CASE( "Set Choice two-sized side, validate all choices set", "[Battling]" ) {
auto side = BattleSide(2); auto side = BattleSide(nullptr, 2);
auto c1 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create(); auto c1 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
auto c2 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create(); auto c2 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
side.SetCreature(c1, 0); side.SetCreature(c1, 0);