diff --git a/CInterface/Battling/ExecutingAttack.cpp b/CInterface/Battling/ExecutingAttack.cpp index ca25d1d..d7470e9 100644 --- a/CInterface/Battling/ExecutingAttack.cpp +++ b/CInterface/Battling/ExecutingAttack.cpp @@ -22,7 +22,7 @@ export bool CreatureLib_ExecutingAttack_IsCreatureTarget(ExecutingAttack* p, Cre } export uint8_t CreatureLib_ExecutingAttack_GetTargetCount(ExecutingAttack* p) { return p->GetTargetCount(); } export const Creature* const* CreatureLib_ExecutingAttack_GetTargets(ExecutingAttack* p) { - return reinterpret_cast(p->GetTargets()); + return reinterpret_cast(p->GetTargets().RawData()); } export Creature* CreatureLib_ExecutingAttack_GetUser(ExecutingAttack* p) { return p->GetUser().GetRaw(); } diff --git a/CInterface/Core.hpp b/CInterface/Core.hpp index 1fcfdc5..20784c0 100644 --- a/CInterface/Core.hpp +++ b/CInterface/Core.hpp @@ -1,6 +1,7 @@ #ifndef CREATURELIB_CORE_HPP #define CREATURELIB_CORE_HPP +#include #include #include #include @@ -14,6 +15,12 @@ class ExceptionHandler { static std::string _creatureLibLastException; public: + static void SetLastException(std::string function, const ArbUt::Exception& e) { + std::stringstream ss; + ss << "[" << function << "] " << e.what() << std::endl; + ss << e.GetStacktrace(); + _creatureLibLastException = ss.str(); + } static void SetLastException(std::string function, const std::exception& e) { std::stringstream ss; ss << "[" << function << "] " << e.what(); @@ -26,6 +33,9 @@ public: try { \ data; \ return 0; \ + } catch (const ArbUt::Exception& e) { \ + ExceptionHandler::SetLastException(__FUNCTION__, e); \ + return CreatureLibException; \ } catch (const std::exception& e) { \ ExceptionHandler::SetLastException(__FUNCTION__, e); \ return CreatureLibException; \ diff --git a/src/Battling/Flow/TurnHandler.cpp b/src/Battling/Flow/TurnHandler.cpp index fd72756..028b622 100644 --- a/src/Battling/Flow/TurnHandler.cpp +++ b/src/Battling/Flow/TurnHandler.cpp @@ -122,24 +122,24 @@ void TurnHandler::ExecuteAttackChoice(const ArbUt::BorrowedPtr } void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::BorrowedPtr& target) { - auto user = attack->GetUser(); + AssertNotNull(attack) + auto& user = attack->GetUser(); AssertNotNull(user) AssertNotNull(target) - if (user->GetBattle()->HasEnded()) + auto& battle = user->GetBattle(); + AssertNotNull(battle) + if (battle->HasEnded()) return; - const auto& targetSource = target; - auto userSource = attack; - bool fail = false; - HOOK(FailIncomingAttack, targetSource, attack, target.GetRaw(), &fail); + HOOK(FailIncomingAttack, target, attack, target.GetRaw(), &fail); if (fail) { // TODO: Fail handling. return; } bool invulnerable = false; - HOOK(IsInvulnerable, targetSource, attack, target.GetRaw(), &invulnerable); + HOOK(IsInvulnerable, target, attack, target.GetRaw(), &invulnerable); if (invulnerable) { // TODO: We should probably do something when a target is invulnerable. return; @@ -147,18 +147,28 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::Bo auto numberOfHits = attack->GetNumberOfHits(); if (numberOfHits == 0) { - HOOK(OnAttackMiss, targetSource, attack, target.GetRaw()); - user->GetBattle()->TriggerEventListener(user); + HOOK(OnAttackMiss, target, attack, target.GetRaw()); + battle->TriggerEventListener(user); return; } - auto attackData = attack->GetAttack()->GetAttack(); - auto library = user->GetBattle()->GetLibrary(); + auto& learnedAttack = attack->GetAttack(); + AssertNotNull(learnedAttack); + auto& attackData = learnedAttack->GetAttack(); + AssertNotNull(attackData); + + auto& library = battle->GetLibrary(); AssertNotNull(library) auto& dmgLibrary = library->GetDamageLibrary(); - auto hitIterator = attack->GetTargetIteratorBegin(target.GetRaw()); + auto& typeLibrary = library->GetTypeLibrary(); + auto& miscLibrary = library->GetMiscLibrary(); + AssertNotNull(dmgLibrary) + AssertNotNull(typeLibrary) + AssertNotNull(miscLibrary) + + auto hitIterator = attack->GetTargetIteratorBegin(target); for (uint8_t hitIndex = 0; hitIndex < numberOfHits; hitIndex++) { - if (user->GetBattle()->HasEnded()) + if (battle->HasEnded()) return; if (user->IsFainted()) { break; @@ -167,28 +177,34 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::Bo break; } auto& hit = hitIterator[hitIndex]; - uint8_t hitType = attack->GetAttack()->GetAttack()->GetType(); - HOOK(ChangeAttackType, targetSource, attack, target.GetRaw(), hitIndex, &hitType); + uint8_t hitType = attackData->GetType(); + HOOK(ChangeAttackType, target, attack, target.GetRaw(), hitIndex, &hitType); hit.SetType(hitType); - auto effectiveness = library->GetTypeLibrary()->GetEffectiveness(hitType, target->GetTypes()); + auto effectiveness = typeLibrary->GetEffectiveness(hitType, target->GetTypes()); HOOK(ChangeEffectiveness, attack, attack, target.GetRaw(), hitIndex, &effectiveness) hit.SetEffectiveness(effectiveness); - hit.SetCritical(library->GetMiscLibrary()->IsCritical(attack, target.GetRaw(), hitIndex)); + hit.SetCritical(miscLibrary->IsCritical(attack, target.GetRaw(), hitIndex)); hit.SetBasePower(dmgLibrary->GetBasePower(attack, target.GetRaw(), hitIndex, hit)); hit.SetDamage(dmgLibrary->GetDamage(attack, target.GetRaw(), hitIndex, hit)); if (attackData->GetCategory() == Library::AttackCategory::Status) { if (attackData->HasSecondaryEffect()) { - auto& effect = attackData->GetSecondaryEffect(); - bool hasSecondaryEffect; - if (effect->GetChance() == -1) { - hasSecondaryEffect = true; - } else { - hasSecondaryEffect = - user->GetBattle()->GetRandom()->EffectChance(effect->GetChance(), attack, target.GetRaw()); - } - if (hasSecondaryEffect) { - HOOK(OnSecondaryEffect, userSource, attack, target.GetRaw(), hitIndex); + try { + auto& effect = attackData->GetSecondaryEffect(); + bool hasSecondaryEffect; + if (effect->GetChance() == -1) { + hasSecondaryEffect = true; + } else { + hasSecondaryEffect = + battle->GetRandom()->EffectChance(effect->GetChance(), attack, target.GetRaw()); + } + if (hasSecondaryEffect) { + HOOK(OnSecondaryEffect, user, attack, target.GetRaw(), hitIndex); + } + } catch (const CreatureException& e) { + throw e; + } catch (const std::exception& e) { + THROW_CREATURE("Exception during status attack effect handling: " << e.what() << "."); } } } else { @@ -202,18 +218,26 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::Bo if (attackData->HasSecondaryEffect() && !user->IsFainted()) { bool preventSecondary = false; - HOOK(PreventSecondaryEffects, targetSource, attack, target.GetRaw(), hitIndex, &preventSecondary); + HOOK(PreventSecondaryEffects, target, attack, target.GetRaw(), hitIndex, &preventSecondary); if (!preventSecondary) { - auto& effect = attackData->GetSecondaryEffect(); - bool hasSecondaryEffect; - if (effect->GetChance() == -1) { - hasSecondaryEffect = true; - } else { - hasSecondaryEffect = user->GetBattle()->GetRandom()->EffectChance(effect->GetChance(), - attack, target.GetRaw()); - } - if (hasSecondaryEffect) { - HOOK(OnSecondaryEffect, userSource, attack, target.GetRaw(), hitIndex); + try { + auto& effect = attackData->GetSecondaryEffect(); + bool hasSecondaryEffect; + if (effect->GetChance() == -1) { + hasSecondaryEffect = true; + } else { + auto random = battle->GetRandom(); + AssertNotNull(random); + hasSecondaryEffect = random->EffectChance(effect->GetChance(), attack, target.GetRaw()); + } + if (hasSecondaryEffect) { + HOOK(OnSecondaryEffect, user, attack, target.GetRaw(), hitIndex); + } + } catch (const CreatureException& e) { + throw e; + } catch (const std::exception& e) { + THROW_CREATURE("Exception during offensive attack secondary effect handling: " << e.what() + << "."); } } } @@ -222,7 +246,7 @@ void TurnHandler::HandleAttackForTarget(ExecutingAttack* attack, const ArbUt::Bo } if (!user->IsFainted()) { - HOOK(OnAfterHits, userSource, attack, target.GetRaw()); + HOOK(OnAfterHits, user, attack, target.GetRaw()); } } diff --git a/src/Battling/Models/Battle.hpp b/src/Battling/Models/Battle.hpp index 542afd6..2cb4897 100644 --- a/src/Battling/Models/Battle.hpp +++ b/src/Battling/Models/Battle.hpp @@ -103,13 +103,14 @@ namespace CreatureLib::Battling { void RegisterEventListener(EventHook::EventHookFunc listener) { this->_eventHook.RegisterListener(listener); } template void TriggerEventListener(parameters... args) { - this->_eventHook.Trigger(args...); + try_creature(this->_eventHook.Trigger(args...);, "Exception occurred during event trigger."); } EventHook& GetEventHook() noexcept { return _eventHook; } const EventHook& GetEventHook() const noexcept { return _eventHook; } template void RegisterHistoryElement(parameters... args) { - this->_historyHolder.Register(args...); + try_creature(this->_historyHolder.Register(args...); + , "Exception occurred during history element registration."); } const HistoryHolder& GetHistory() const noexcept { return _historyHolder; } }; diff --git a/src/Battling/Models/ExecutingAttack.hpp b/src/Battling/Models/ExecutingAttack.hpp index 1fee080..9025609 100644 --- a/src/Battling/Models/ExecutingAttack.hpp +++ b/src/Battling/Models/ExecutingAttack.hpp @@ -36,20 +36,19 @@ namespace CreatureLib::Battling { }; private: - const ArbUt::BorrowedPtr* _targets; - uint8_t _targetCount; uint8_t _numberHits; std::unique_ptr _hits; ArbUt::BorrowedPtr _user; ArbUt::BorrowedPtr _attack; std::unique_ptr