allow targeting aoe spells while queuing

This commit is contained in:
avitasia
2025-12-06 14:09:12 -08:00
parent 46c26689e4
commit 06323e6b7f
5 changed files with 45 additions and 23 deletions
+3 -3
View File
@@ -105,6 +105,7 @@ namespace Nampower {
std::unique_ptr<hadesmem::PatchDetour<OnSpriteRightClickT>> gOnSpriteRightClickDetour;
std::unique_ptr<hadesmem::PatchDetour<Spell_C_HandleSpriteClickT>> gSpell_C_HandleSpriteClickDetour;
std::unique_ptr<hadesmem::PatchDetour<Spell_C_HandleTerrainClickT>> gSpell_C_HandleTerrainClickDetour;
std::unique_ptr<hadesmem::PatchDetour<CGWorldFrame_OnLayerTrackTerrainT>> gCGWorldFrame_OnLayerTrackTerrainDetour;
std::unique_ptr<hadesmem::PatchDetour<Spell_C_TargetSpellT>> gSpell_C_TargetSpellDetour;
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT>> gSpellCooldownDetour;
@@ -1131,6 +1132,8 @@ namespace Nampower {
&Spell_C_TargetSpellHook);
gSpell_C_HandleTerrainClickDetour = createHook<Spell_C_HandleTerrainClickT>(process, Offsets::Spell_C_HandleTerrainClick,
&Spell_C_HandleTerrainClickHook);
gCGWorldFrame_OnLayerTrackTerrainDetour = createHook<CGWorldFrame_OnLayerTrackTerrainT>(process, Offsets::CGWorldFrame_OnLayerTrackTerrain,
&CGWorldFrame_OnLayerTrackTerrainHook);
gOnSpriteRightClickDetour = createHook<OnSpriteRightClickT>(process, Offsets::OnSpriteRightClick,
OnSpriteRightClickHook);
gIEndSceneDetour = createHook<ISceneEndT>(process, Offsets::ISceneEndPtr, &ISceneEndHook);
@@ -1138,9 +1141,6 @@ namespace Nampower {
&InvalidFunctionPtrCheckHook);
gGetSpellSlotFromLuaDetour = createHook<GetSpellSlotFromLuaT>(process, Offsets::GetSpellSlotFromLua,
&GetSpellSlotFromLuaHook);
gSpell_C_GetSpellRadiusDetour = createHook<Spell_C_GetSpellRadiusT>(process, Offsets::Spell_C_GetSpellRadius,
&Spell_C_GetSpellRadiusHook);
}
void SpellVisualsInitializeHook(hadesmem::PatchDetourBase *detour) {
+2 -1
View File
@@ -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,
+3
View File
@@ -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,
};
+35 -19
View File
@@ -36,6 +36,16 @@ namespace Nampower {
SetControlBit(0);
}
void EnableSpellTargeting(const game::SpellRec *spell) {
// set s_needtargets 00cecac0
auto s_needtargets = reinterpret_cast<uint32_t *>(Offsets::SpellNeedsTargets);
*s_needtargets = spell->Targets;
auto const CursorSetCursorMode = reinterpret_cast<void (__fastcall *)(uint32_t)>(Offsets::CursorSetCursorMode);
CursorSetCursorMode(2); // CAST_CURSOR
auto const CursorModelSetSequence = reinterpret_cast<void (__fastcall *)(uint32_t)>(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<uint32_t*>(Offsets::VisualSpellId);
auto originalCasterGuid = *reinterpret_cast<uint64_t*>(Offsets::CasterGuid);
if(gCastData.targetingSpellQueued){
// switch out visual spellid to the queued spell so that we get the correct radius/range
*reinterpret_cast<uint32_t*>(Offsets::VisualSpellId) = gCastData.targetingSpellId;
// set casterguid to active player so range checks work correctly
*reinterpret_cast<uint64_t*>(Offsets::CasterGuid) = game::ClntObjMgrGetActivePlayerGuid();
}
auto const onLayerTrackTerrain = detour->GetTrampolineT<CGWorldFrame_OnLayerTrackTerrainT>();
onLayerTrackTerrain(thisptr, dummy_edx, param_1);
if(gCastData.targetingSpellQueued){
// switch back to originalSpellId
*reinterpret_cast<uint32_t*>(Offsets::VisualSpellId) = originalSpellId;
// restore original caster guid
*reinterpret_cast<uint64_t*>(Offsets::CasterGuid) = originalCasterGuid;
}
}
float Spell_C_GetSpellRadiusHook(hadesmem::PatchDetourBase *detour) {
auto originalSpellId = *reinterpret_cast<uint32_t*>(Offsets::VisualSpellId);
if(gCastData.targetingSpellQueued){
@@ -55,25 +87,9 @@ namespace Nampower {
auto const getSpellRadius = detour->GetTrampolineT<Spell_C_GetSpellRadiusT>();
auto radius = getSpellRadius();
if(gCastData.targetingSpellQueued){
// switch back to originalSpellId
*reinterpret_cast<uint32_t*>(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<uint32_t *>(Offsets::SpellNeedsTargets);
*s_needtargets = spell->Targets;
auto const CursorSetCursorMode = reinterpret_cast<void (__fastcall *)(uint32_t)>(Offsets::CursorSetCursorMode);
CursorSetCursorMode(1); // CAST_CURSOR
auto const CursorModelSetSequence = reinterpret_cast<void (__fastcall *)(uint32_t)>(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
+2
View File
@@ -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);