diff --git a/nampower/main.cpp b/nampower/main.cpp index 16cdcfe..5b63d7a 100644 --- a/nampower/main.cpp +++ b/nampower/main.cpp @@ -105,6 +105,7 @@ namespace Nampower { std::unique_ptr> gOnSpriteRightClickDetour; std::unique_ptr> gSpell_C_HandleSpriteClickDetour; std::unique_ptr> gSpell_C_HandleTerrainClickDetour; + std::unique_ptr> gCGWorldFrame_OnLayerTrackTerrainDetour; std::unique_ptr> gSpell_C_TargetSpellDetour; std::unique_ptr> gSpellCooldownDetour; @@ -1131,6 +1132,8 @@ namespace Nampower { &Spell_C_TargetSpellHook); gSpell_C_HandleTerrainClickDetour = createHook(process, Offsets::Spell_C_HandleTerrainClick, &Spell_C_HandleTerrainClickHook); + gCGWorldFrame_OnLayerTrackTerrainDetour = createHook(process, Offsets::CGWorldFrame_OnLayerTrackTerrain, + &CGWorldFrame_OnLayerTrackTerrainHook); gOnSpriteRightClickDetour = createHook(process, Offsets::OnSpriteRightClick, OnSpriteRightClickHook); gIEndSceneDetour = createHook(process, Offsets::ISceneEndPtr, &ISceneEndHook); @@ -1138,9 +1141,6 @@ namespace Nampower { &InvalidFunctionPtrCheckHook); gGetSpellSlotFromLuaDetour = createHook(process, Offsets::GetSpellSlotFromLua, &GetSpellSlotFromLuaHook); - gSpell_C_GetSpellRadiusDetour = createHook(process, Offsets::Spell_C_GetSpellRadius, - &Spell_C_GetSpellRadiusHook); - } void SpellVisualsInitializeHook(hadesmem::PatchDetourBase *detour) { diff --git a/nampower/main.hpp b/nampower/main.hpp index b72b1a3..6079aa8 100644 --- a/nampower/main.hpp +++ b/nampower/main.hpp @@ -30,7 +30,7 @@ namespace Nampower { constexpr uint32_t BUFFER_DECREASE_FREQUENCY = 10000; // time in ms between changes to lower buffer constexpr uint32_t MAJOR_VERSION = 2; - constexpr uint32_t MINOR_VERSION = 12; + constexpr uint32_t MINOR_VERSION = 13; constexpr uint32_t PATCH_VERSION = 0; constexpr int32_t LUA_REGISTRYINDEX = -10000; @@ -85,6 +85,7 @@ namespace Nampower { using SpellGoT = void (__fastcall *)(uint64_t *, uint64_t *, uint32_t, CDataStore *); using Spell_C_HandleSpriteClickT = bool (__fastcall *)(game::CSpriteClickEvent *event); using Spell_C_HandleTerrainClickT = uint32_t (__fastcall *)(game::CTerrainClickEvent *event); + using CGWorldFrame_OnLayerTrackTerrainT = void (__fastcall *)(void *thisptr, int dummy_edx, int param_1); using Spell_C_TargetSpellT = bool (__fastcall *)( uint32_t *player, uint32_t *spellId, diff --git a/nampower/offsets.hpp b/nampower/offsets.hpp index d4e9bf5..4ab1c76 100644 --- a/nampower/offsets.hpp +++ b/nampower/offsets.hpp @@ -49,6 +49,7 @@ enum class Offsets : std::uint32_t { AutoRepeatingSpellId = 0xCEAC30, SpellNeedsTargets = 0X00CECAC0, VisualSpellId = 0X00CEAC58, + CasterGuid = 0X00CEAC50, GetSpellSlotAndType = 0X004B3950, GetSpellSlotFromLua = 0X004B3EC0, OsGetAsyncTimeMs = 0X0042B790, @@ -102,6 +103,7 @@ enum class Offsets : std::uint32_t { Spell_C_GetAutoRepeatingSpell = 0x006E9FD0, Spell_C_HandleSpriteClick = 0x006E5B10, Spell_C_HandleTerrainClick = 0x006E60F0, + CGWorldFrame_OnLayerTrackTerrain = 0x004820F0, Spell_C_TargetSpell = 0x006E5250, Spell_C_GetSpellCooldown = 0X006E2EA0, Spell_C_IsSpellUsable = 0X006E3D60, @@ -178,6 +180,7 @@ enum class Offsets : std::uint32_t { InvalidFunctionPtrCheck = 0x0042A320, + ClearCursor = 0x00495190, CursorSetCursorMode = 0x00523d20, CursorModelSetSequence = 0x00523c20, }; diff --git a/nampower/spellcast.cpp b/nampower/spellcast.cpp index d661cc5..cec09ab 100644 --- a/nampower/spellcast.cpp +++ b/nampower/spellcast.cpp @@ -36,6 +36,16 @@ namespace Nampower { SetControlBit(0); } + void EnableSpellTargeting(const game::SpellRec *spell) { + // set s_needtargets 00cecac0 + auto s_needtargets = reinterpret_cast(Offsets::SpellNeedsTargets); + *s_needtargets = spell->Targets; + + auto const CursorSetCursorMode = reinterpret_cast(Offsets::CursorSetCursorMode); + CursorSetCursorMode(2); // CAST_CURSOR + auto const CursorModelSetSequence = reinterpret_cast(Offsets::CursorModelSetSequence); + CursorModelSetSequence(2); // CAST_CURSOR + } uint32_t Spell_C_HandleTerrainClickHook(hadesmem::PatchDetourBase *detour, game::CTerrainClickEvent *event) { if(!gCastData.targetingSpellQueued){ @@ -45,6 +55,28 @@ namespace Nampower { return 0; } + void CGWorldFrame_OnLayerTrackTerrainHook(hadesmem::PatchDetourBase *detour, void *thisptr, int dummy_edx, int param_1) { + auto originalSpellId = *reinterpret_cast(Offsets::VisualSpellId); + auto originalCasterGuid = *reinterpret_cast(Offsets::CasterGuid); + + if(gCastData.targetingSpellQueued){ + // switch out visual spellid to the queued spell so that we get the correct radius/range + *reinterpret_cast(Offsets::VisualSpellId) = gCastData.targetingSpellId; + // set casterguid to active player so range checks work correctly + *reinterpret_cast(Offsets::CasterGuid) = game::ClntObjMgrGetActivePlayerGuid(); + } + + auto const onLayerTrackTerrain = detour->GetTrampolineT(); + onLayerTrackTerrain(thisptr, dummy_edx, param_1); + + if(gCastData.targetingSpellQueued){ + // switch back to originalSpellId + *reinterpret_cast(Offsets::VisualSpellId) = originalSpellId; + // restore original caster guid + *reinterpret_cast(Offsets::CasterGuid) = originalCasterGuid; + } + } + float Spell_C_GetSpellRadiusHook(hadesmem::PatchDetourBase *detour) { auto originalSpellId = *reinterpret_cast(Offsets::VisualSpellId); if(gCastData.targetingSpellQueued){ @@ -55,25 +87,9 @@ namespace Nampower { auto const getSpellRadius = detour->GetTrampolineT(); auto radius = getSpellRadius(); - if(gCastData.targetingSpellQueued){ - // switch back to originalSpellId - *reinterpret_cast(Offsets::VisualSpellId) = originalSpellId; - } - return radius; } - void EnableSpellTargeting(uint32_t *casterUnit, const game::SpellRec *spell, uintptr_t *unk, uint64_t guid) { - // set s_needtargets 00cecac0 - auto s_needtargets = reinterpret_cast(Offsets::SpellNeedsTargets); - *s_needtargets = spell->Targets; - - auto const CursorSetCursorMode = reinterpret_cast(Offsets::CursorSetCursorMode); - CursorSetCursorMode(1); // CAST_CURSOR - auto const CursorModelSetSequence = reinterpret_cast(Offsets::CursorModelSetSequence); - CursorModelSetSequence(22); // CAST_CURSOR - } - bool Spell_C_TargetSpellHook(hadesmem::PatchDetourBase *detour, uint32_t *player, uint32_t *spellId, @@ -491,7 +507,7 @@ namespace Nampower { if (castTime > 0 && inSpellQueueWindow) { if (gUserSettings.queueCastTimeSpells) { // call EnableSpellTargeting to set s_needTargets and trigger the targeting indicator - EnableSpellTargeting(casterUnit, spell, nullptr, guid); + EnableSpellTargeting(spell); DEBUG_LOG("Queuing targeting for after cast/gcd: " << remainingCD << "ms " << spellName); TriggerSpellQueuedEvent(NORMAL_QUEUED, spellId); @@ -504,7 +520,7 @@ namespace Nampower { if (gUserSettings.queueInstantSpells) { if (spellOnGcd) { // call EnableSpellTargeting to set s_needTargets and trigger the targeting indicator - EnableSpellTargeting(casterUnit, spell, nullptr, guid); + EnableSpellTargeting(spell); DEBUG_LOG("Queuing instant cast targeting for after cast/gcd: " << remainingCD << "ms " << spellName); @@ -521,7 +537,7 @@ namespace Nampower { return false; } else { // call EnableSpellTargeting to set s_needTargets and trigger the targeting indicator - EnableSpellTargeting(casterUnit, spell, nullptr, guid); + EnableSpellTargeting(spell); DEBUG_LOG("Queuing instant cast non GCD targeting for after cast/gcd: " << remainingEffectiveCastTime << "ms " << spellName diff --git a/nampower/spellcast.hpp b/nampower/spellcast.hpp index 6438793..7308c79 100644 --- a/nampower/spellcast.hpp +++ b/nampower/spellcast.hpp @@ -34,6 +34,8 @@ namespace Nampower { uint32_t Spell_C_HandleTerrainClickHook(hadesmem::PatchDetourBase *detour, game::CTerrainClickEvent *event); + void CGWorldFrame_OnLayerTrackTerrainHook(hadesmem::PatchDetourBase *detour, void *thisptr, int dummy_edx, int param_1); + float Spell_C_GetSpellRadiusHook(hadesmem::PatchDetourBase *detour); void SendCastHook(hadesmem::PatchDetourBase *detour, game::SpellCast *cast, char unk);