Implemented better script handling.
This commit is contained in:
parent
c3bfbb569e
commit
ee14efe22e
|
@ -1,6 +1,7 @@
|
||||||
#include "TurnHandler.hpp"
|
#include "TurnHandler.hpp"
|
||||||
#include "../Models/Battle.hpp"
|
#include "../Models/Battle.hpp"
|
||||||
#include "../../Core/Exceptions/NotImplementedException.hpp"
|
#include "../../Core/Exceptions/NotImplementedException.hpp"
|
||||||
|
#include "../ScriptHandling/ScriptMacros.cpp"
|
||||||
|
|
||||||
using namespace CreatureLib::Battling;
|
using namespace CreatureLib::Battling;
|
||||||
|
|
||||||
|
@ -78,15 +79,15 @@ void TurnHandler::ExecuteAttackChoice(const AttackTurnChoice *choice) {
|
||||||
|
|
||||||
void TurnHandler::HandleAttackForTarget(ExecutingAttack &attack, Creature *target, ExecutingAttack::TargetData &targetData) {
|
void TurnHandler::HandleAttackForTarget(ExecutingAttack &attack, Creature *target, ExecutingAttack::TargetData &targetData) {
|
||||||
//HOOK: Check if attack fails on target
|
//HOOK: Check if attack fails on target
|
||||||
target->ExecuteScripts(Hook::IncomingAttackFails, {std::any(attack), std::any(target)});
|
std::array<ScriptSource*, 1> sources = {target};
|
||||||
|
HOOK(OnIncomingAttackFails, sources, &attack, target);
|
||||||
|
|
||||||
//HOOK: Check if target is invulnerable
|
//HOOK: Check if target is invulnerable
|
||||||
target->ExecuteScripts(Hook::IsInvulnerable, {std::any(attack), std::any(target)});
|
HOOK(IsInvulnerable, sources, &attack, target);
|
||||||
|
|
||||||
|
|
||||||
if (!targetData.IsHit()){
|
if (!targetData.IsHit()){
|
||||||
//HOOK: On attack miss.
|
//HOOK: On attack miss.
|
||||||
target->ExecuteScripts(Hook::AttackMiss, {std::any(attack), std::any(target)});
|
HOOK(OnAttackMiss, sources, &attack, target);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include "LearnedAttack.hpp"
|
#include "LearnedAttack.hpp"
|
||||||
#include "DamageSource.hpp"
|
#include "DamageSource.hpp"
|
||||||
#include "../ScriptHandling/ScriptSet.hpp"
|
#include "../ScriptHandling/ScriptSet.hpp"
|
||||||
|
#include "../ScriptHandling/ScriptAggregator.hpp"
|
||||||
|
#include "../ScriptHandling/ScriptSource.hpp"
|
||||||
|
|
||||||
namespace CreatureLib::Battling{
|
namespace CreatureLib::Battling{
|
||||||
// Forward declare battle class
|
// Forward declare battle class
|
||||||
|
@ -14,7 +16,7 @@ namespace CreatureLib::Battling{
|
||||||
class BattleSide;
|
class BattleSide;
|
||||||
class BattleLibrary;
|
class BattleLibrary;
|
||||||
|
|
||||||
class Creature {
|
class Creature : public ScriptSource{
|
||||||
GetProperty(const Library::CreatureSpecies*, Species);
|
GetProperty(const Library::CreatureSpecies*, Species);
|
||||||
GetProperty(const Library::SpeciesVariant*, Variant);
|
GetProperty(const Library::SpeciesVariant*, Variant);
|
||||||
GetProperty(uint8_t, Level);
|
GetProperty(uint8_t, Level);
|
||||||
|
@ -63,9 +65,9 @@ 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 ExecuteScripts(Hook hook, const std::vector<std::any>& args){
|
void GetActiveScripts(ScriptAggregator& aggr) override{
|
||||||
_status->Execute(hook, args);
|
aggr.Add(_status);
|
||||||
_volatile.Execute(hook, args);
|
aggr.Add(&_volatile);
|
||||||
}
|
}
|
||||||
|
|
||||||
//region Stat APIs
|
//region Stat APIs
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
#include "Hooks.hpp"
|
#include "Hooks.hpp"
|
||||||
|
|
||||||
namespace CreatureLib::Battling{
|
namespace CreatureLib::Battling{
|
||||||
|
class ExecutingAttack;
|
||||||
|
class Creature;
|
||||||
|
|
||||||
class Script{
|
class Script{
|
||||||
const std::string _name;
|
const std::string _name;
|
||||||
|
|
||||||
|
@ -15,12 +18,15 @@ namespace CreatureLib::Battling{
|
||||||
explicit Script(std::string name) :_name(std::move(name)){}
|
explicit Script(std::string name) :_name(std::move(name)){}
|
||||||
virtual ~Script() = default;
|
virtual ~Script() = default;
|
||||||
|
|
||||||
virtual void Execute(Hook hook, const std::vector<std::any>& args){};
|
|
||||||
virtual void Stack(){};
|
virtual void Stack(){};
|
||||||
|
|
||||||
const std::string& GetName(){
|
const std::string& GetName(){
|
||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void OnIncomingAttackFails(ExecutingAttack* attack, Creature* target){};
|
||||||
|
virtual void IsInvulnerable(ExecutingAttack* attack, Creature* target){};
|
||||||
|
virtual void OnAttackMiss(ExecutingAttack* attack, Creature* target){};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
#ifndef CREATURELIB_SCRIPTAGGREGATOR_HPP
|
||||||
|
#define CREATURELIB_SCRIPTAGGREGATOR_HPP
|
||||||
|
|
||||||
|
#include <any>
|
||||||
|
#include <queue>
|
||||||
|
#include "Script.hpp"
|
||||||
|
#include "ScriptSet.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;
|
||||||
|
public:
|
||||||
|
ScriptAggregator() = default;
|
||||||
|
|
||||||
|
void Add(Script* script){
|
||||||
|
_queue.push(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Add(ScriptSet* scriptSet){
|
||||||
|
_queue.push(scriptSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasNext(){
|
||||||
|
return !_queue.empty() || _isSetSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
Script* GetNext(){
|
||||||
|
// We can probably do this in a cleaner version once C++ 20 drops with Coroutine support.
|
||||||
|
if (_isSetSet){
|
||||||
|
if (_setIterator == _setEnd){
|
||||||
|
_isSetSet = false;
|
||||||
|
return GetNext();
|
||||||
|
}
|
||||||
|
auto s = _setIterator->second;
|
||||||
|
_setIterator.operator++();
|
||||||
|
if (_setIterator == _setEnd){
|
||||||
|
_isSetSet = false;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
if (_queue.empty())
|
||||||
|
return nullptr;
|
||||||
|
auto next = _queue.front();
|
||||||
|
_queue.pop();
|
||||||
|
if (next.type() == typeid(Script*)){
|
||||||
|
return std::any_cast<Script*>(next);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
auto set = std::any_cast<ScriptSet*>(next);
|
||||||
|
if (set->Count() == 0)
|
||||||
|
return GetNext();
|
||||||
|
auto it = set->GetIterator();
|
||||||
|
_setIterator = it->begin();
|
||||||
|
_setEnd = it->end();
|
||||||
|
_isSetSet = true;
|
||||||
|
return GetNext();
|
||||||
|
}
|
||||||
|
throw NotReachableException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //CREATURELIB_SCRIPTAGGREGATOR_HPP
|
|
@ -0,0 +1,14 @@
|
||||||
|
#define HOOK(hookName, sources, ... ) \
|
||||||
|
{ \
|
||||||
|
auto aggregator = CreatureLib::Battling::ScriptAggregator(); \
|
||||||
|
for (auto source: sources){ \
|
||||||
|
source -> GetActiveScripts(aggregator); \
|
||||||
|
} \
|
||||||
|
while (aggregator.HasNext()){ \
|
||||||
|
auto next = aggregator.GetNext(); \
|
||||||
|
if (next == nullptr) continue; \
|
||||||
|
next->hookName(__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,6 @@ namespace CreatureLib::Battling{
|
||||||
class ScriptSet{
|
class ScriptSet{
|
||||||
std::unordered_map<std::string, Script*> _scripts;
|
std::unordered_map<std::string, Script*> _scripts;
|
||||||
public:
|
public:
|
||||||
void Execute(Hook hook, const std::vector<std::any>& args){
|
|
||||||
for (auto s: _scripts){
|
|
||||||
s.second->Execute(hook, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Add(Script* script){
|
void Add(Script* script){
|
||||||
auto f = _scripts.find(script->GetName());
|
auto f = _scripts.find(script->GetName());
|
||||||
if (f != _scripts.end()){
|
if (f != _scripts.end()){
|
||||||
|
@ -28,6 +22,14 @@ namespace CreatureLib::Battling{
|
||||||
void Remove(const std::string& key){
|
void Remove(const std::string& key){
|
||||||
_scripts.erase(key);
|
_scripts.erase(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Count() const{
|
||||||
|
return _scripts.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::string, Script *> * GetIterator(){
|
||||||
|
return &_scripts;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef CREATURELIB_SCRIPTSOURCE_HPP
|
||||||
|
#define CREATURELIB_SCRIPTSOURCE_HPP
|
||||||
|
|
||||||
|
#include "ScriptAggregator.hpp"
|
||||||
|
|
||||||
|
namespace CreatureLib::Battling{
|
||||||
|
class ScriptSource {
|
||||||
|
public:
|
||||||
|
virtual void GetActiveScripts(ScriptAggregator& aggr) = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //CREATURELIB_SCRIPTSOURCE_HPP
|
Loading…
Reference in New Issue