Initial work on attack fail handling.
All checks were successful
continuous-integration/drone/push Build is passing

Signed-off-by: Deukhoofd <Deukhoofd@gmail.com>
This commit is contained in:
2021-03-27 12:30:12 +01:00
parent 6ef8edc2df
commit 46307fe71f
5 changed files with 64 additions and 34 deletions

View File

@@ -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 =
battle.GetValue()->GetRandom()->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()) {
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;