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/EventData.hpp"
|
||||
#include "Events/ExperienceGainEvent.hpp"
|
||||
#include "Events/FailEvent.hpp"
|
||||
#include "Events/FaintEvent.hpp"
|
||||
#include "Events/HealEvent.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) {
|
||||
auto battle = choice->GetUser()->GetBattle();
|
||||
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());
|
||||
, "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;
|
||||
HOOK(PreventAttack, attack, attack, &prevented);
|
||||
HOOK(PreventAttack, attackScoped, attackScoped, &prevented);
|
||||
if (prevented) {
|
||||
delete attack;
|
||||
return;
|
||||
}
|
||||
|
||||
// HOOK: override targets
|
||||
if (!choice->GetAttack()->TryUse(1)) {
|
||||
delete attack;
|
||||
return;
|
||||
}
|
||||
|
||||
auto* attack = attackScoped.TakeOwnership();
|
||||
battle.GetValue()->TriggerEventListener<AttackUseEvent>(attack);
|
||||
battle.GetValue()->RegisterHistoryElement<AttackUseHistory>(attack);
|
||||
|
||||
|
@ -98,7 +105,7 @@ void TurnHandler::ExecuteAttackChoice(const ArbUt::BorrowedPtr<AttackTurnChoice>
|
|||
bool fail = false;
|
||||
HOOK(FailAttack, attack, attack, &fail);
|
||||
if (fail) {
|
||||
// TODO: Fail handling.
|
||||
FAIL_HANDLING(attack, choice->GetUser(), (ScriptSource*)nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -120,16 +127,17 @@ void TurnHandler::ExecuteAttackChoice(const ArbUt::BorrowedPtr<AttackTurnChoice>
|
|||
|
||||
void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::BorrowedPtr<Creature>& target) {
|
||||
EnsureNotNull(attack)
|
||||
auto& user = attack->GetUser();
|
||||
auto& battle = user->GetBattle();
|
||||
const auto& user = attack->GetUser();
|
||||
const auto& battle = user->GetBattle();
|
||||
Ensure(battle.HasValue())
|
||||
if (battle.GetValue()->HasEnded())
|
||||
if (battle.GetValue()->HasEnded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool fail = false;
|
||||
HOOK(FailIncomingAttack, target, attack, target.GetRaw(), &fail);
|
||||
if (fail) {
|
||||
// TODO: Fail handling.
|
||||
FAIL_HANDLING(attack, user, target);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -147,21 +155,22 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::Bo
|
|||
return;
|
||||
}
|
||||
|
||||
auto& learnedAttack = attack->GetAttack();
|
||||
auto& attackData = learnedAttack->GetAttack();
|
||||
const auto& learnedAttack = attack->GetAttack();
|
||||
const auto& attackData = learnedAttack->GetAttack();
|
||||
|
||||
auto& library = battle.GetValue()->GetLibrary();
|
||||
auto& dmgLibrary = library->GetDamageLibrary();
|
||||
auto& typeLibrary = library->GetTypeLibrary();
|
||||
auto& miscLibrary = library->GetMiscLibrary();
|
||||
const auto& library = battle.GetValue()->GetLibrary();
|
||||
const auto& dmgLibrary = library->GetDamageLibrary();
|
||||
const auto& typeLibrary = library->GetTypeLibrary();
|
||||
const auto& miscLibrary = library->GetMiscLibrary();
|
||||
EnsureNotNull(dmgLibrary)
|
||||
EnsureNotNull(typeLibrary)
|
||||
EnsureNotNull(miscLibrary)
|
||||
|
||||
auto hitIterator = attack->GetTargetIteratorBegin(target);
|
||||
auto* hitIterator = attack->GetTargetIteratorBegin(target);
|
||||
for (uint8_t hitIndex = 0; hitIndex < numberOfHits; hitIndex++) {
|
||||
if (battle.GetValue()->HasEnded())
|
||||
if (battle.GetValue()->HasEnded()) {
|
||||
return;
|
||||
}
|
||||
if (user->IsFainted()) {
|
||||
break;
|
||||
}
|
||||
|
@ -182,16 +191,15 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::Bo
|
|||
if (attackData->GetCategory() == Library::AttackCategory::Status) {
|
||||
if (attackData->HasSecondaryEffect()) {
|
||||
try {
|
||||
auto& effect = attackData->GetSecondaryEffect();
|
||||
bool hasSecondaryEffect;
|
||||
if (effect->GetChance() == -1) {
|
||||
hasSecondaryEffect = true;
|
||||
} else {
|
||||
hasSecondaryEffect =
|
||||
const auto& effect = attackData->GetSecondaryEffect();
|
||||
bool hasSecondaryEffect =
|
||||
effect->GetChance() == -1 ||
|
||||
battle.GetValue()->GetRandom()->EffectChance(effect->GetChance(), attack, target.GetRaw());
|
||||
}
|
||||
if (hasSecondaryEffect) {
|
||||
HOOK(OnSecondaryEffect, attack, attack, target.GetRaw(), hitIndex);
|
||||
if (hit.HasFailed()) {
|
||||
FAIL_HANDLING(attack, user, target);
|
||||
}
|
||||
}
|
||||
} catch (const ArbUt::Exception& e) {
|
||||
throw e;
|
||||
|
@ -213,17 +221,16 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::Bo
|
|||
HOOK(PreventSecondaryEffects, target, attack, target.GetRaw(), hitIndex, &preventSecondary);
|
||||
if (!preventSecondary) {
|
||||
try {
|
||||
auto& effect = attackData->GetSecondaryEffect();
|
||||
bool hasSecondaryEffect;
|
||||
if (effect->GetChance() == -1) {
|
||||
hasSecondaryEffect = true;
|
||||
} else {
|
||||
auto random = battle.GetValue()->GetRandom();
|
||||
EnsureNotNull(random);
|
||||
hasSecondaryEffect = random->EffectChance(effect->GetChance(), attack, target.GetRaw());
|
||||
}
|
||||
const auto& effect = attackData->GetSecondaryEffect();
|
||||
bool hasSecondaryEffect =
|
||||
effect->GetChance() == -1 || battle.GetValue()->GetRandom()->EffectChance(
|
||||
effect->GetChance(), attack, target.GetRaw());
|
||||
if (hasSecondaryEffect) {
|
||||
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) {
|
||||
throw e;
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace CreatureLib::Battling {
|
|||
float _effectiveness = 1;
|
||||
uint32_t _damage = 0;
|
||||
uint8_t _type = 0;
|
||||
bool _hasFailed = false;
|
||||
|
||||
public:
|
||||
HitData() noexcept {}
|
||||
|
@ -21,12 +22,14 @@ namespace CreatureLib::Battling {
|
|||
[[nodiscard]] inline float GetEffectiveness() const noexcept { return _effectiveness; }
|
||||
[[nodiscard]] inline uint32_t GetDamage() const noexcept { return _damage; }
|
||||
[[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 SetBasePower(uint8_t value) noexcept { _basePower = value; }
|
||||
inline void SetEffectiveness(float value) noexcept { _effectiveness = value; }
|
||||
inline void SetDamage(uint32_t value) noexcept { _damage = value; }
|
||||
inline void SetType(uint8_t value) noexcept { _type = value; }
|
||||
inline void Fail() noexcept { _hasFailed = true; }
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
@ -75,6 +75,9 @@ namespace CreatureLib::Battling {
|
|||
[[maybe_unused]] Creature* target, [[maybe_unused]] float* chance){};
|
||||
virtual void ModifyIncomingEffectChance([[maybe_unused]] const ExecutingAttack* attack,
|
||||
[[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