Support overriding attacks through script hooks.
continuous-integration/drone/push Build is passing Details

Signed-off-by: Deukhoofd <Deukhoofd@gmail.com>
This commit is contained in:
Deukhoofd 2021-05-13 13:16:52 +02:00
parent 188e88ab80
commit 13153b3119
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
4 changed files with 21 additions and 14 deletions

View File

@ -4,11 +4,13 @@ using namespace CreatureLib::Battling;
export uint8_t CreatureLib_ExecutingAttack_Construct(ExecutingAttack*& out, Creature* const* targets, export uint8_t CreatureLib_ExecutingAttack_Construct(ExecutingAttack*& out, Creature* const* targets,
size_t targetCount, uint8_t numberHits, Creature* user, size_t targetCount, uint8_t numberHits, Creature* user,
LearnedAttack* attack, BattleScript* script) { LearnedAttack* attack,
CreatureLib::Library::AttackData* attackData,
BattleScript* script) {
Try(auto ls = ArbUt::List<ArbUt::OptionalBorrowedPtr<Creature>>(targetCount); Try(auto ls = ArbUt::List<ArbUt::OptionalBorrowedPtr<Creature>>(targetCount);
for (size_t i = 0; i < targetCount; i++) { ls.Append(targets[i]); } auto s = for (size_t i = 0; i < targetCount; i++) { ls.Append(targets[i]); } auto s =
std::unique_ptr<BattleScript>(script); std::unique_ptr<BattleScript>(script);
out = new ExecutingAttack(ls, numberHits, user, attack, s);) out = new ExecutingAttack(ls, numberHits, user, attack, attackData, s);)
} }
export void CreatureLib_ExecutingAttack_Destruct(ExecutingAttack* p) { delete p; } export void CreatureLib_ExecutingAttack_Destruct(ExecutingAttack* p) { delete p; }
@ -29,6 +31,9 @@ export const Creature* const* CreatureLib_ExecutingAttack_GetTargets(ExecutingAt
export Creature* CreatureLib_ExecutingAttack_GetUser(ExecutingAttack* p) { return p->GetUser().GetRaw(); } export Creature* CreatureLib_ExecutingAttack_GetUser(ExecutingAttack* p) { return p->GetUser().GetRaw(); }
export LearnedAttack* CreatureLib_ExecutingAttack_GetAttack(ExecutingAttack* p) { return p->GetAttack().GetRaw(); } export LearnedAttack* CreatureLib_ExecutingAttack_GetAttack(ExecutingAttack* p) { return p->GetAttack().GetRaw(); }
export const CreatureLib::Library::AttackData* CreatureLib_ExecutingAttack_GetUseAttack(ExecutingAttack* p) {
return p->GetUseAttack().GetRaw();
}
#define HITDATA_GET_FUNC(name, returnType) \ #define HITDATA_GET_FUNC(name, returnType) \
export returnType CreatureLib_HitData##_##name(const ExecutingAttack::HitData* p) { return p->name(); } export returnType CreatureLib_HitData##_##name(const ExecutingAttack::HitData* p) { return p->name(); }

View File

@ -84,17 +84,19 @@ void TurnHandler::ExecuteChoice(const ArbUt::BorrowedPtr<BaseTurnChoice>& choice
void TurnHandler::ExecuteAttackChoice(const ArbUt::BorrowedPtr<AttackTurnChoice>& choice) { void TurnHandler::ExecuteAttackChoice(const ArbUt::BorrowedPtr<AttackTurnChoice>& choice) {
auto battle = choice->GetUser()->GetBattle(); auto battle = choice->GetUser()->GetBattle();
auto attackName = choice->GetAttack()->GetAttack()->GetName(); auto attackData = choice->GetAttack()->GetAttack();
auto attackName = attackData->GetName();
HOOK(ChangeAttack, choice, choice.GetRaw(), &attackName); HOOK(ChangeAttack, choice, choice.GetRaw(), &attackName);
if (attackName != choice->GetAttack()->GetAttack()->GetName()) { if (attackName != choice->GetAttack()->GetAttack()->GetName()) {
// TODO: Change attack attackData = battle.GetValue()->GetLibrary()->GetAttackLibrary()->Get(attackName);
} }
auto targetType = choice->GetAttack()->GetAttack()->GetTarget(); auto targetType = attackData->GetTarget();
ArbUt::List<ArbUt::OptionalBorrowedPtr<Creature>> targets; ArbUt::List<ArbUt::OptionalBorrowedPtr<Creature>> targets;
Ensure(battle.HasValue()); Ensure(battle.HasValue());
try_creature(targets = TargetResolver::ResolveTargets(choice->GetTarget(), targetType, battle.GetValue()); try_creature(targets = TargetResolver::ResolveTargets(choice->GetTarget(), targetType, battle.GetValue());
, "Exception during target determination"); , "Exception during target determination");
// HOOK: override targets
u8 numberHits = 1; u8 numberHits = 1;
HOOK(ModifyNumberOfHits, choice, choice, &numberHits); HOOK(ModifyNumberOfHits, choice, choice, &numberHits);
@ -102,15 +104,14 @@ void TurnHandler::ExecuteAttackChoice(const ArbUt::BorrowedPtr<AttackTurnChoice>
return; return;
} }
auto attackScoped = ArbUt::ScopedPtr<ExecutingAttack>( auto attackScoped = ArbUt::ScopedPtr<ExecutingAttack>(new ExecutingAttack(
new ExecutingAttack(targets, numberHits, choice->GetUser(), choice->GetAttack(), choice->GetAttackScript())); targets, numberHits, choice->GetUser(), choice->GetAttack(), attackData, choice->GetAttackScript()));
bool prevented = false; bool prevented = false;
HOOK(PreventAttack, attackScoped, attackScoped, &prevented); HOOK(PreventAttack, attackScoped, attackScoped, &prevented);
if (prevented) { if (prevented) {
return; return;
} }
// HOOK: override targets
if (!choice->GetAttack()->TryUse(1)) { if (!choice->GetAttack()->TryUse(1)) {
return; return;
} }
@ -119,7 +120,6 @@ void TurnHandler::ExecuteAttackChoice(const ArbUt::BorrowedPtr<AttackTurnChoice>
battle.GetValue()->TriggerEventListener<AttackUseEvent>(attack); battle.GetValue()->TriggerEventListener<AttackUseEvent>(attack);
battle.GetValue()->RegisterHistoryElement<AttackUseHistory>(attack); battle.GetValue()->RegisterHistoryElement<AttackUseHistory>(attack);
// HOOK: check if attack fails
bool fail = false; bool fail = false;
HOOK(FailAttack, attack, attack, &fail); HOOK(FailAttack, attack, attack, &fail);
if (fail) { if (fail) {
@ -173,8 +173,7 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::Bo
return; return;
} }
const auto& learnedAttack = attack->GetAttack(); const auto& attackData = attack->GetUseAttack();
const auto& attackData = learnedAttack->GetAttack();
const auto& library = battle.GetValue()->GetLibrary(); const auto& library = battle.GetValue()->GetLibrary();
const auto& dmgLibrary = library->GetDamageLibrary(); const auto& dmgLibrary = library->GetDamageLibrary();

View File

@ -20,7 +20,7 @@ uint8_t DamageLibrary::GetBasePower(ExecutingAttack* attack, Creature* target, u
[[maybe_unused]] const ExecutingAttack::HitData& hitData) const { [[maybe_unused]] const ExecutingAttack::HitData& hitData) const {
EnsureNotNull(attack) EnsureNotNull(attack)
EnsureNotNull(target) EnsureNotNull(target)
auto bp = attack->GetAttack()->GetAttack()->GetBasePower(); auto bp = attack->GetUseAttack()->GetBasePower();
HOOK(OverrideBasePower, attack, attack, target, hitIndex, &bp); HOOK(OverrideBasePower, attack, attack, target, hitIndex, &bp);
return bp; return bp;
} }
@ -34,7 +34,7 @@ float DamageLibrary::GetStatModifier(ExecutingAttack* attack, Creature* target,
HOOK(ChangeDamageStatsUser, attack, attack, target, hitIndex, &user); HOOK(ChangeDamageStatsUser, attack, attack, target, hitIndex, &user);
Library::Statistic offensiveStat; Library::Statistic offensiveStat;
Library::Statistic defensiveStat; Library::Statistic defensiveStat;
if (attack->GetAttack()->GetAttack()->GetCategory() == Library::AttackCategory::Physical) { if (attack->GetUseAttack()->GetCategory() == Library::AttackCategory::Physical) {
offensiveStat = Library::Statistic::PhysicalAttack; offensiveStat = Library::Statistic::PhysicalAttack;
defensiveStat = Library::Statistic::PhysicalDefense; defensiveStat = Library::Statistic::PhysicalDefense;
} else { } else {

View File

@ -37,15 +37,17 @@ namespace CreatureLib::Battling {
std::unique_ptr<HitData[]> _hits; std::unique_ptr<HitData[]> _hits;
ArbUt::BorrowedPtr<Creature> _user; ArbUt::BorrowedPtr<Creature> _user;
ArbUt::BorrowedPtr<LearnedAttack> _attack; ArbUt::BorrowedPtr<LearnedAttack> _attack;
ArbUt::BorrowedPtr<const Library::AttackData> _useAttack;
std::unique_ptr<BattleScript> _script = nullptr; std::unique_ptr<BattleScript> _script = nullptr;
ArbUt::List<ArbUt::OptionalBorrowedPtr<Creature>> _targets; ArbUt::List<ArbUt::OptionalBorrowedPtr<Creature>> _targets;
public: public:
ExecutingAttack(const ArbUt::List<ArbUt::OptionalBorrowedPtr<Creature>>& targets, uint8_t numberHits, ExecutingAttack(const ArbUt::List<ArbUt::OptionalBorrowedPtr<Creature>>& targets, uint8_t numberHits,
ArbUt::BorrowedPtr<Creature> user, const ArbUt::BorrowedPtr<LearnedAttack>& attack, ArbUt::BorrowedPtr<Creature> user, const ArbUt::BorrowedPtr<LearnedAttack>& attack,
const ArbUt::BorrowedPtr<const Library::AttackData>& useAttack,
const std::unique_ptr<BattleScript>& script) const std::unique_ptr<BattleScript>& script)
: _numberHits(numberHits), _hits(std::make_unique<HitData[]>(targets.Count() * numberHits)), _user(user), : _numberHits(numberHits), _hits(std::make_unique<HitData[]>(targets.Count() * numberHits)), _user(user),
_attack(attack), _targets(targets) { _attack(attack), _useAttack(useAttack), _targets(targets) {
// Take ownership of the script of the attack choice, and give attack choice our initial nullptr. // Take ownership of the script of the attack choice, and give attack choice our initial nullptr.
_script.swap(const_cast<std::unique_ptr<BattleScript>&>(script)); _script.swap(const_cast<std::unique_ptr<BattleScript>&>(script));
} }
@ -98,6 +100,7 @@ namespace CreatureLib::Battling {
inline const ArbUt::BorrowedPtr<Creature>& GetUser() noexcept { return _user; } inline const ArbUt::BorrowedPtr<Creature>& GetUser() noexcept { return _user; }
inline const ArbUt::BorrowedPtr<LearnedAttack>& GetAttack() noexcept { return _attack; } inline const ArbUt::BorrowedPtr<LearnedAttack>& GetAttack() noexcept { return _attack; }
inline const ArbUt::BorrowedPtr<const Library::AttackData>& GetUseAttack() noexcept { return _useAttack; }
size_t ScriptCount() const override { return _user->ScriptCount() + 1; } size_t ScriptCount() const override { return _user->ScriptCount() + 1; }
inline ArbUt::BorrowedPtr<BattleScript> GetScript() const noexcept { return _script; } inline ArbUt::BorrowedPtr<BattleScript> GetScript() const noexcept { return _script; }