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{
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) {
//HOOK: On Before Turn hook for all choices
for (auto choice: queue->GetInnerQueue()){
HOOK(OnBeforeTurn, choice, choice);
}
while (queue->HasNext()){
if (!battle->HasRecalledSlots()){
return;
@ -83,25 +86,25 @@ void TurnHandler::ExecuteAttackChoice(const AttackTurnChoice *choice) {
void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, Creature *target, const ExecutingAttack::TargetData &targetData) {
auto user = attack->GetUser();
std::array<ScriptSource*, 1> targetSources = {target};
std::array<ScriptSource*, 1> userSources = {user};
ScriptSource* targetSource = target;
ScriptSource* userSource = attack;
bool fail = false;
HOOK(FailIncomingAttack, targetSources, attack, target, fail);
HOOK(FailIncomingAttack, targetSource, attack, target, fail);
if (fail){
//TODO: Fail handling.
return;
}
bool invulnerable = fail;
HOOK(IsInvulnerable, targetSources, attack, target, invulnerable);
HOOK(IsInvulnerable, targetSource, attack, target, invulnerable);
if (invulnerable){
//TODO: We should probably do something when a target is invulnerable.
return;
}
if (!targetData.IsHit()){
HOOK(OnAttackMiss, targetSources, attack, target);
HOOK(OnAttackMiss, targetSource, attack, target);
return;
}
@ -122,15 +125,14 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, Creature *targe
auto hit = targetData.GetHit(hitIndex);
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.SetCritical(library->GetCriticalLibrary()->IsCritical(attack, target, hitIndex));
hit.SetBasePower(dmgLibrary->GetBasePower(attack, target, hitIndex));
hit.SetDamage(dmgLibrary->GetDamage(attack, target, hitIndex));
std::array<ScriptSource*, 1> attackSource = {attack};
if (attackData->GetCategory() == Library::AttackCategory::Status){
HOOK(OnStatusMove, attackSource, attack, target, hitIndex);
HOOK(OnStatusMove, userSource, attack, target, hitIndex);
}
else{
auto damage = hit.GetDamage();
@ -142,15 +144,15 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, Creature *targe
target->Damage(damage, DamageSource::AttackDamage);
bool preventSecondary = false;
HOOK(PreventSecondaryEffects, targetSources, attack, target, hitIndex, preventSecondary);
HOOK(PreventSecondaryEffects, targetSource, attack, target, hitIndex, preventSecondary);
if (!preventSecondary){
HOOK(OnSecondaryEffect, attackSource, attack, target, hitIndex);
HOOK(OnSecondaryEffect, userSource, attack, target, hitIndex);
}
}
}
}
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) {
if (choice->GetKind() == TurnChoiceKind::Attack){
//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;
}
@ -36,7 +36,7 @@ void Battle::CheckChoicesSetAndRun() {
auto choices = std::vector<const BaseTurnChoice*>(_numberOfSides * _creaturesPerSide);
auto i = 0;
for (auto side: _sides){
for (auto choice: side->GetChoices()){
for (const BaseTurnChoice* choice: side->GetChoices()){
if (choice->GetKind() == TurnChoiceKind::Attack){
auto attack = dynamic_cast<const AttackTurnChoice*>(choice)->GetAttack();
uint8_t uses = 1;
@ -92,3 +92,7 @@ void Battle::FillRecall(uint8_t side, uint8_t, Creature *c) {
TurnHandler::RunTurn(this, _currentTurnQueue);
}
}
void Battle::GetActiveScripts(ScriptAggregator &aggr) const {
aggr.Add(&_volatile);
}

View File

@ -9,7 +9,7 @@
#include "Target.hpp"
namespace CreatureLib::Battling {
class Battle {
class Battle : public ScriptSource{
const BattleLibrary* _library;
uint8_t _numberOfSides;
uint8_t _creaturesPerSide;
@ -18,6 +18,7 @@ namespace CreatureLib::Battling {
ChoiceQueue* _currentTurnQueue = nullptr;
uint8_t _numberOfRecalledSlots = 0;
ScriptSet _volatile;
public:
[[nodiscard]] const BattleLibrary* GetLibrary() const;
@ -40,6 +41,8 @@ namespace CreatureLib::Battling {
void ForceRecall(uint8_t side, uint8_t index);
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 "../../Core/Exceptions/CreatureException.hpp"
#include <algorithm>
#include "Battle.hpp"
using namespace CreatureLib::Battling;
@ -39,3 +40,8 @@ bool BattleSide::CreatureOnSide(const Creature *creature) const {
Creature *BattleSide::GetCreature(uint8_t index) const {
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"
namespace CreatureLib::Battling{
class BattleSide {
class BattleSide : public ScriptSource{
uint8_t _creaturesPerSide;
std::vector<Creature*> _creatures;
std::vector<const BaseTurnChoice*> _choices;
uint8_t _choicesSet = 0;
ScriptSet _volatile;
Battle* _battle;
public:
BattleSide(uint8_t creaturesPerSide)
: _creaturesPerSide(creaturesPerSide), _creatures(creaturesPerSide), _choices(creaturesPerSide)
explicit BattleSide(Battle* battle, uint8_t creaturesPerSide)
: _creaturesPerSide(creaturesPerSide), _creatures(creaturesPerSide), _choices(creaturesPerSide), _battle(battle)
{
ResetChoices();
}
@ -29,6 +31,8 @@ namespace CreatureLib::Battling{
Creature* GetCreature(uint8_t index) 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();
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]] bool HasType(uint8_t type) const;
void GetActiveScripts(ScriptAggregator& aggr) override{
aggr.Add(_status);
aggr.Add(&_volatile);
}
void GetActiveScripts(ScriptAggregator& aggr) const override;
//region Stat APIs

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@
using namespace CreatureLib::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();
side.SetCreature(c, 0);
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]" ) {
auto side = BattleSide(1);
auto side = BattleSide(nullptr, 1);
auto c = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
side.SetCreature(c, 0);
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]" ) {
auto side = BattleSide(2);
auto side = BattleSide(nullptr, 2);
auto c1 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
auto c2 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
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]" ) {
auto side = BattleSide(2);
auto side = BattleSide(nullptr, 2);
auto c1 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
auto c2 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
side.SetCreature(c1, 0);