Initial work on attack fail handling.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
Signed-off-by: Deukhoofd <Deukhoofd@gmail.com>
This commit is contained in:
parent
6ef8edc2df
commit
46307fe71f
|
@ -9,6 +9,7 @@
|
||||||
#include "Events/DisplayTextEvent.hpp"
|
#include "Events/DisplayTextEvent.hpp"
|
||||||
#include "Events/EventData.hpp"
|
#include "Events/EventData.hpp"
|
||||||
#include "Events/ExperienceGainEvent.hpp"
|
#include "Events/ExperienceGainEvent.hpp"
|
||||||
|
#include "Events/FailEvent.hpp"
|
||||||
#include "Events/FaintEvent.hpp"
|
#include "Events/FaintEvent.hpp"
|
||||||
#include "Events/HealEvent.hpp"
|
#include "Events/HealEvent.hpp"
|
||||||
#include "Events/MissEvent.hpp"
|
#include "Events/MissEvent.hpp"
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef FAILEVENT_HPP
|
||||||
|
#define FAILEVENT_HPP
|
||||||
|
#include "EventData.hpp"
|
||||||
|
|
||||||
|
namespace CreatureLib::Battling {
|
||||||
|
class FailEvent final : public EventData {
|
||||||
|
ArbUt::BorrowedPtr<Creature> _creature;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FailEvent(ArbUt::BorrowedPtr<Creature> c) noexcept : _creature(c) {}
|
||||||
|
EventDataKind GetKind() const noexcept override { return EventDataKind ::Faint; }
|
||||||
|
const ArbUt::BorrowedPtr<Creature>& GetCreature() const noexcept { return _creature; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FAILEVENT_HPP
|
|
@ -63,6 +63,13 @@ void TurnHandler::ExecuteChoice(ArbUt::BorrowedPtr<BaseTurnChoice> choice) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FAIL_HANDLING(source, user, target) \
|
||||||
|
battle.GetValue()->TriggerEventListener<FailEvent>(user); \
|
||||||
|
HOOK(OnFail, source, user) \
|
||||||
|
if ((target) != (void*)0) { \
|
||||||
|
HOOK(OnOpponentFail, (target), user) \
|
||||||
|
}
|
||||||
|
|
||||||
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 attackName = choice->GetAttack()->GetAttack()->GetName();
|
||||||
|
@ -77,20 +84,20 @@ void TurnHandler::ExecuteAttackChoice(const ArbUt::BorrowedPtr<AttackTurnChoice>
|
||||||
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");
|
||||||
|
|
||||||
auto attack = new ExecutingAttack(targets, 1, choice->GetUser(), choice->GetAttack(), choice->GetAttackScript());
|
auto attackScoped = ArbUt::ScopedPtr<ExecutingAttack>(
|
||||||
|
new ExecutingAttack(targets, 1, choice->GetUser(), choice->GetAttack(), choice->GetAttackScript()));
|
||||||
bool prevented = false;
|
bool prevented = false;
|
||||||
HOOK(PreventAttack, attack, attack, &prevented);
|
HOOK(PreventAttack, attackScoped, attackScoped, &prevented);
|
||||||
if (prevented) {
|
if (prevented) {
|
||||||
delete attack;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// HOOK: override targets
|
// HOOK: override targets
|
||||||
if (!choice->GetAttack()->TryUse(1)) {
|
if (!choice->GetAttack()->TryUse(1)) {
|
||||||
delete attack;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* attack = attackScoped.TakeOwnership();
|
||||||
battle.GetValue()->TriggerEventListener<AttackUseEvent>(attack);
|
battle.GetValue()->TriggerEventListener<AttackUseEvent>(attack);
|
||||||
battle.GetValue()->RegisterHistoryElement<AttackUseHistory>(attack);
|
battle.GetValue()->RegisterHistoryElement<AttackUseHistory>(attack);
|
||||||
|
|
||||||
|
@ -98,7 +105,7 @@ void TurnHandler::ExecuteAttackChoice(const ArbUt::BorrowedPtr<AttackTurnChoice>
|
||||||
bool fail = false;
|
bool fail = false;
|
||||||
HOOK(FailAttack, attack, attack, &fail);
|
HOOK(FailAttack, attack, attack, &fail);
|
||||||
if (fail) {
|
if (fail) {
|
||||||
// TODO: Fail handling.
|
FAIL_HANDLING(attack, choice->GetUser(), (ScriptSource*)nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,16 +127,17 @@ void TurnHandler::ExecuteAttackChoice(const ArbUt::BorrowedPtr<AttackTurnChoice>
|
||||||
|
|
||||||
void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::BorrowedPtr<Creature>& target) {
|
void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::BorrowedPtr<Creature>& target) {
|
||||||
EnsureNotNull(attack)
|
EnsureNotNull(attack)
|
||||||
auto& user = attack->GetUser();
|
const auto& user = attack->GetUser();
|
||||||
auto& battle = user->GetBattle();
|
const auto& battle = user->GetBattle();
|
||||||
Ensure(battle.HasValue())
|
Ensure(battle.HasValue())
|
||||||
if (battle.GetValue()->HasEnded())
|
if (battle.GetValue()->HasEnded()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool fail = false;
|
bool fail = false;
|
||||||
HOOK(FailIncomingAttack, target, attack, target.GetRaw(), &fail);
|
HOOK(FailIncomingAttack, target, attack, target.GetRaw(), &fail);
|
||||||
if (fail) {
|
if (fail) {
|
||||||
// TODO: Fail handling.
|
FAIL_HANDLING(attack, user, target);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,21 +155,22 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::Bo
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& learnedAttack = attack->GetAttack();
|
const auto& learnedAttack = attack->GetAttack();
|
||||||
auto& attackData = learnedAttack->GetAttack();
|
const auto& attackData = learnedAttack->GetAttack();
|
||||||
|
|
||||||
auto& library = battle.GetValue()->GetLibrary();
|
const auto& library = battle.GetValue()->GetLibrary();
|
||||||
auto& dmgLibrary = library->GetDamageLibrary();
|
const auto& dmgLibrary = library->GetDamageLibrary();
|
||||||
auto& typeLibrary = library->GetTypeLibrary();
|
const auto& typeLibrary = library->GetTypeLibrary();
|
||||||
auto& miscLibrary = library->GetMiscLibrary();
|
const auto& miscLibrary = library->GetMiscLibrary();
|
||||||
EnsureNotNull(dmgLibrary)
|
EnsureNotNull(dmgLibrary)
|
||||||
EnsureNotNull(typeLibrary)
|
EnsureNotNull(typeLibrary)
|
||||||
EnsureNotNull(miscLibrary)
|
EnsureNotNull(miscLibrary)
|
||||||
|
|
||||||
auto hitIterator = attack->GetTargetIteratorBegin(target);
|
auto* hitIterator = attack->GetTargetIteratorBegin(target);
|
||||||
for (uint8_t hitIndex = 0; hitIndex < numberOfHits; hitIndex++) {
|
for (uint8_t hitIndex = 0; hitIndex < numberOfHits; hitIndex++) {
|
||||||
if (battle.GetValue()->HasEnded())
|
if (battle.GetValue()->HasEnded()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
if (user->IsFainted()) {
|
if (user->IsFainted()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -182,16 +191,15 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::Bo
|
||||||
if (attackData->GetCategory() == Library::AttackCategory::Status) {
|
if (attackData->GetCategory() == Library::AttackCategory::Status) {
|
||||||
if (attackData->HasSecondaryEffect()) {
|
if (attackData->HasSecondaryEffect()) {
|
||||||
try {
|
try {
|
||||||
auto& effect = attackData->GetSecondaryEffect();
|
const auto& effect = attackData->GetSecondaryEffect();
|
||||||
bool hasSecondaryEffect;
|
bool hasSecondaryEffect =
|
||||||
if (effect->GetChance() == -1) {
|
effect->GetChance() == -1 ||
|
||||||
hasSecondaryEffect = true;
|
|
||||||
} else {
|
|
||||||
hasSecondaryEffect =
|
|
||||||
battle.GetValue()->GetRandom()->EffectChance(effect->GetChance(), attack, target.GetRaw());
|
battle.GetValue()->GetRandom()->EffectChance(effect->GetChance(), attack, target.GetRaw());
|
||||||
}
|
|
||||||
if (hasSecondaryEffect) {
|
if (hasSecondaryEffect) {
|
||||||
HOOK(OnSecondaryEffect, attack, attack, target.GetRaw(), hitIndex);
|
HOOK(OnSecondaryEffect, attack, attack, target.GetRaw(), hitIndex);
|
||||||
|
if (hit.HasFailed()) {
|
||||||
|
FAIL_HANDLING(attack, user, target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (const ArbUt::Exception& e) {
|
} catch (const ArbUt::Exception& e) {
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -213,17 +221,16 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::Bo
|
||||||
HOOK(PreventSecondaryEffects, target, attack, target.GetRaw(), hitIndex, &preventSecondary);
|
HOOK(PreventSecondaryEffects, target, attack, target.GetRaw(), hitIndex, &preventSecondary);
|
||||||
if (!preventSecondary) {
|
if (!preventSecondary) {
|
||||||
try {
|
try {
|
||||||
auto& effect = attackData->GetSecondaryEffect();
|
const auto& effect = attackData->GetSecondaryEffect();
|
||||||
bool hasSecondaryEffect;
|
bool hasSecondaryEffect =
|
||||||
if (effect->GetChance() == -1) {
|
effect->GetChance() == -1 || battle.GetValue()->GetRandom()->EffectChance(
|
||||||
hasSecondaryEffect = true;
|
effect->GetChance(), attack, target.GetRaw());
|
||||||
} else {
|
|
||||||
auto random = battle.GetValue()->GetRandom();
|
|
||||||
EnsureNotNull(random);
|
|
||||||
hasSecondaryEffect = random->EffectChance(effect->GetChance(), attack, target.GetRaw());
|
|
||||||
}
|
|
||||||
if (hasSecondaryEffect) {
|
if (hasSecondaryEffect) {
|
||||||
HOOK(OnSecondaryEffect, attack, attack, target.GetRaw(), hitIndex);
|
HOOK(OnSecondaryEffect, attack, attack, target.GetRaw(), hitIndex);
|
||||||
|
if (hit.HasFailed()) {
|
||||||
|
battle.GetValue()->TriggerEventListener<FailEvent>(user);
|
||||||
|
FAIL_HANDLING(attack, user, target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (const ArbUt::Exception& e) {
|
} catch (const ArbUt::Exception& e) {
|
||||||
throw e;
|
throw e;
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace CreatureLib::Battling {
|
||||||
float _effectiveness = 1;
|
float _effectiveness = 1;
|
||||||
uint32_t _damage = 0;
|
uint32_t _damage = 0;
|
||||||
uint8_t _type = 0;
|
uint8_t _type = 0;
|
||||||
|
bool _hasFailed = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HitData() noexcept {}
|
HitData() noexcept {}
|
||||||
|
@ -21,12 +22,14 @@ namespace CreatureLib::Battling {
|
||||||
[[nodiscard]] inline float GetEffectiveness() const noexcept { return _effectiveness; }
|
[[nodiscard]] inline float GetEffectiveness() const noexcept { return _effectiveness; }
|
||||||
[[nodiscard]] inline uint32_t GetDamage() const noexcept { return _damage; }
|
[[nodiscard]] inline uint32_t GetDamage() const noexcept { return _damage; }
|
||||||
[[nodiscard]] inline uint8_t GetType() const noexcept { return _type; }
|
[[nodiscard]] inline uint8_t GetType() const noexcept { return _type; }
|
||||||
|
[[nodiscard]] inline bool HasFailed() const noexcept { return _hasFailed; }
|
||||||
|
|
||||||
inline void SetCritical(bool value) noexcept { _critical = value; }
|
inline void SetCritical(bool value) noexcept { _critical = value; }
|
||||||
inline void SetBasePower(uint8_t value) noexcept { _basePower = value; }
|
inline void SetBasePower(uint8_t value) noexcept { _basePower = value; }
|
||||||
inline void SetEffectiveness(float value) noexcept { _effectiveness = value; }
|
inline void SetEffectiveness(float value) noexcept { _effectiveness = value; }
|
||||||
inline void SetDamage(uint32_t value) noexcept { _damage = value; }
|
inline void SetDamage(uint32_t value) noexcept { _damage = value; }
|
||||||
inline void SetType(uint8_t value) noexcept { _type = value; }
|
inline void SetType(uint8_t value) noexcept { _type = value; }
|
||||||
|
inline void Fail() noexcept { _hasFailed = true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -75,6 +75,9 @@ namespace CreatureLib::Battling {
|
||||||
[[maybe_unused]] Creature* target, [[maybe_unused]] float* chance){};
|
[[maybe_unused]] Creature* target, [[maybe_unused]] float* chance){};
|
||||||
virtual void ModifyIncomingEffectChance([[maybe_unused]] const ExecutingAttack* attack,
|
virtual void ModifyIncomingEffectChance([[maybe_unused]] const ExecutingAttack* attack,
|
||||||
[[maybe_unused]] Creature* target, [[maybe_unused]] float* chance){};
|
[[maybe_unused]] Creature* target, [[maybe_unused]] float* chance){};
|
||||||
|
|
||||||
|
virtual void OnFail([[maybe_unused]] Creature* target){};
|
||||||
|
virtual void OnOpponentFail([[maybe_unused]] Creature* target){};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue