From b0bf8c881250130b03c2c59e53ed3ed8f8eabe6a Mon Sep 17 00:00:00 2001 From: Mats391 Date: Tue, 30 Dec 2025 17:56:00 +0100 Subject: [PATCH 1/3] Adding new event for sending spell --- nampower/game.hpp | 2 ++ nampower/main.cpp | 3 +++ nampower/spellcast.cpp | 22 ++++++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/nampower/game.hpp b/nampower/game.hpp index 1fd1bed..b6dcc77 100644 --- a/nampower/game.hpp +++ b/nampower/game.hpp @@ -1441,6 +1441,8 @@ namespace game { AURA_CAST_ON_SELF = 560, AURA_CAST_ON_OTHER = 561, + + SPELL_SENDING_EVENT = 562, }; enum TypeMask { diff --git a/nampower/main.cpp b/nampower/main.cpp index 53f1932..b6fb9cc 100644 --- a/nampower/main.cpp +++ b/nampower/main.cpp @@ -1318,6 +1318,9 @@ namespace Nampower { char SPELL_DAMAGE_EVENT_OTHER[] = "SPELL_DAMAGE_EVENT_OTHER"; addCustomEvent(game::SPELL_DAMAGE_EVENT_OTHER, SPELL_DAMAGE_EVENT_OTHER); + char SPELL_SENDING_EVENT[] = "SPELL_SENDING_EVENT"; + addCustomEvent(game::SPELL_SENDING_EVENT, SPELL_SENDING_EVENT); + char DEBUFF_ADDED_SELF[] = "DEBUFF_ADDED_SELF"; addCustomEvent(game::DEBUFF_ADDED_SELF, DEBUFF_ADDED_SELF); diff --git a/nampower/spellcast.cpp b/nampower/spellcast.cpp index ff93c67..354e476 100644 --- a/nampower/spellcast.cpp +++ b/nampower/spellcast.cpp @@ -344,6 +344,21 @@ namespace Nampower { delete[] guidStr; } + void + TriggerSpellSendingEvent(uint32_t spellId, std::uint64_t guid) { + char format[] = "%d%s"; + char *guidStr = new char[21]; // 2 for 0x prefix, 18 for the number, and 1 for '\0' + std::snprintf(guidStr, 21, "0x%016llX", static_cast(guid)); + + ((int (__cdecl *)(int, char *, uint32_t, char *)) Offsets::SignalEventParam)( + game::SPELL_SENDING_EVENT, // SPELL_SENDING_EVENT event we are adding + format, + spellId, + guidStr); + + delete[] guidStr; + } + void clearCastingSpell() { // clearing current casting spell id if needed // this prevents client from failing to cast spells without a casttime @@ -1047,6 +1062,13 @@ namespace Nampower { } void SendCastHook(hadesmem::PatchDetourBase *detour, game::SpellCast *cast, char unk) { + + if (cast != nullptr && cast->itemTarget == 0 && cast->caster == game::ClntObjMgrGetActivePlayerGuid()) { + const auto guid = cast->unitTarget; + const auto spellId = cast->spellId; + TriggerSpellSendingEvent(spellId, guid); + } + auto const sendCast = detour->GetTrampolineT(); sendCast(cast, unk); From cf45f26d5a7cfa328a9324cd80520e700ee84255 Mon Sep 17 00:00:00 2001 From: Mats391 Date: Tue, 30 Dec 2025 18:09:44 +0100 Subject: [PATCH 2/3] Renaming to Begin Cast --- nampower/game.hpp | 2 +- nampower/main.cpp | 4 ++-- nampower/spellcast.cpp | 39 ++++++++++++++++++--------------------- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/nampower/game.hpp b/nampower/game.hpp index b6dcc77..184ba71 100644 --- a/nampower/game.hpp +++ b/nampower/game.hpp @@ -1442,7 +1442,7 @@ namespace game { AURA_CAST_ON_SELF = 560, AURA_CAST_ON_OTHER = 561, - SPELL_SENDING_EVENT = 562, + SPELL_BEGIN_CAST_EVENT = 562, }; enum TypeMask { diff --git a/nampower/main.cpp b/nampower/main.cpp index b6fb9cc..98bd1c8 100644 --- a/nampower/main.cpp +++ b/nampower/main.cpp @@ -1318,8 +1318,8 @@ namespace Nampower { char SPELL_DAMAGE_EVENT_OTHER[] = "SPELL_DAMAGE_EVENT_OTHER"; addCustomEvent(game::SPELL_DAMAGE_EVENT_OTHER, SPELL_DAMAGE_EVENT_OTHER); - char SPELL_SENDING_EVENT[] = "SPELL_SENDING_EVENT"; - addCustomEvent(game::SPELL_SENDING_EVENT, SPELL_SENDING_EVENT); + char SPELL_BEGIN_CAST_EVENT[] = "SPELL_BEGIN_CAST_EVENT"; + addCustomEvent(game::SPELL_BEGIN_CAST_EVENT, SPELL_BEGIN_CAST_EVENT); char DEBUFF_ADDED_SELF[] = "DEBUFF_ADDED_SELF"; addCustomEvent(game::DEBUFF_ADDED_SELF, DEBUFF_ADDED_SELF); diff --git a/nampower/spellcast.cpp b/nampower/spellcast.cpp index 354e476..060d8df 100644 --- a/nampower/spellcast.cpp +++ b/nampower/spellcast.cpp @@ -107,6 +107,21 @@ namespace Nampower { } } + void + TriggerSpellBeginCastEvent(uint32_t spellId, std::uint64_t guid) { + char format[] = "%d%s"; + char *guidStr = new char[21]; // 2 for 0x prefix, 18 for the number, and 1 for '\0' + std::snprintf(guidStr, 21, "0x%016llX", static_cast(guid)); + + ((int (__cdecl *)(int, char *, uint32_t, char *)) Offsets::SignalEventParam)( + game::SPELL_BEGIN_CAST_EVENT, // SPELL_BEGIN_CAST_EVENT event we are adding + format, + spellId, + guidStr); + + delete[] guidStr; + } + bool Spell_C_TargetSpellHook(hadesmem::PatchDetourBase *detour, uint32_t *player, uint32_t *spellId, @@ -236,6 +251,9 @@ namespace Nampower { } gLastCastData.startTimeMs = currentTime; + + + TriggerSpellBeginCastEvent(cast->spellId, cast->unitTarget); } void CastQueuedNonGcdSpell() { @@ -344,21 +362,6 @@ namespace Nampower { delete[] guidStr; } - void - TriggerSpellSendingEvent(uint32_t spellId, std::uint64_t guid) { - char format[] = "%d%s"; - char *guidStr = new char[21]; // 2 for 0x prefix, 18 for the number, and 1 for '\0' - std::snprintf(guidStr, 21, "0x%016llX", static_cast(guid)); - - ((int (__cdecl *)(int, char *, uint32_t, char *)) Offsets::SignalEventParam)( - game::SPELL_SENDING_EVENT, // SPELL_SENDING_EVENT event we are adding - format, - spellId, - guidStr); - - delete[] guidStr; - } - void clearCastingSpell() { // clearing current casting spell id if needed // this prevents client from failing to cast spells without a casttime @@ -1063,12 +1066,6 @@ namespace Nampower { void SendCastHook(hadesmem::PatchDetourBase *detour, game::SpellCast *cast, char unk) { - if (cast != nullptr && cast->itemTarget == 0 && cast->caster == game::ClntObjMgrGetActivePlayerGuid()) { - const auto guid = cast->unitTarget; - const auto spellId = cast->spellId; - TriggerSpellSendingEvent(spellId, guid); - } - auto const sendCast = detour->GetTrampolineT(); sendCast(cast, unk); From 92e91ad50e9a5297ef59e05127c9a56583b60355 Mon Sep 17 00:00:00 2001 From: Mats391 Date: Wed, 31 Dec 2025 10:26:56 +0100 Subject: [PATCH 3/3] Added documentation --- EVENTS.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/EVENTS.md b/EVENTS.md index 1f65c97..ec9d8e3 100644 --- a/EVENTS.md +++ b/EVENTS.md @@ -7,6 +7,7 @@ For custom Lua functions, see [SCRIPTS.md](SCRIPTS.md). For general usage inform ## Table of Contents - [SPELL_QUEUE_EVENT](#spell_queue_event) - [SPELL_CAST_EVENT](#spell_cast_event) +- [SPELL_BEGIN_CAST_EVENT](#spell_begin_cast_event) - [SPELL_DAMAGE_EVENT_SELF and SPELL_DAMAGE_EVENT_OTHER](#spell_damage_event_self-and-spell_damage_event_other) - [Buff/Debuff Events](#buffdebuff-events) - [AURA_CAST_ON_SELF and AURA_CAST_ON_OTHER](#aura_cast_on_self-and-aura_cast_on_other) @@ -90,6 +91,23 @@ Cursive:RegisterEvent("SPELL_CAST_EVENT", function(success, spellId, castType, t end); ``` +### SPELL_BEGIN_CAST_EVENT +Event you can register in game to get updates when the clien is about to attempt casting a spell. At this stage the spell is ready and has a valid target, but the spell cast might still be rejected based on line of sight or other factors. + +The event is `SPELL_BEGIN_CAST_EVENT` and has 2 parameters: +1. int spellId +2. string targetGuid - guid string like "0xF5300000000000A5" + +targetGuid will be “0x0000000000000000” if the spell requires no target + +Example (uses ace RegisterEvent): +``` +Cursive:RegisterEvent("SPELL_BEING_CAST_EVENT", function(spellId, targetGuid) + print(spellId) + print(targetGuid) +end); +``` + ### SPELL_DAMAGE_EVENT_SELF and SPELL_DAMAGE_EVENT_OTHER New events you can register in game to get updates whenever spell damage occurs. SPELL_DAMAGE_EVENT_SELF will only trigger for damage you deal, while SPELL_DAMAGE_EVENT_OTHER will only trigger for damage dealt by others.