fix target in AURA_CAST events

This commit is contained in:
avitasia
2026-01-02 14:17:48 -08:00
parent 69e0b07944
commit 95f134f42d
10 changed files with 9633 additions and 9579 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ assignees: ''
A clear and concise description of what the bug is.
**Debug logs**
Please include the relevant nampower_debug.log which will be in the same directory as WoW.exe. It helps significantly with figuring out what happened.
Please include the relevant nampower_debug.log which will be in the Logs folder in the same directory as WoW.exe. It helps significantly with figuring out what happened.
**To Reproduce**
Steps to reproduce the behavior:
+1
View File
@@ -10,3 +10,4 @@
/cmake-build*/
/nampower/cmake-build*/
.claude/
/Logs/
+9452 -9445
View File
File diff suppressed because it is too large Load Diff
+12 -12
View File
@@ -19,7 +19,7 @@ namespace Nampower {
// Trigger the appropriate event based on buff/debuff, add/remove, and self/other
game::Events eventToTrigger;
int luaSlot = slot + 1; // lua uses 1-based indexing for slots
int luaUnitSlot = slot + 1; // lua uses 1-based indexing for slots. This is the slot for UnitBuff/UnitDebuff
auto *unitFields = *reinterpret_cast<game::UnitFields **>(unit + 68);
@@ -37,7 +37,7 @@ namespace Nampower {
emptyCount++;
}
}
luaSlot = luaSlot - emptyCount;
luaUnitSlot = luaUnitSlot - emptyCount;
if (wasAdded) {
luaStacks += 1; // count offset by 1
@@ -49,7 +49,7 @@ namespace Nampower {
eventToTrigger = isSelf ? game::BUFF_REMOVED_SELF : game::BUFF_REMOVED_OTHER;
}
} else {
luaSlot = luaSlot - 32; // adjust slot for debuffs
luaUnitSlot = luaUnitSlot - 32; // adjust slot for debuffs
// count empty debuff slots before slot to adjust luaSlot for actual buff/debuff index
int emptyCount = 0;
@@ -58,7 +58,7 @@ namespace Nampower {
emptyCount++;
}
}
luaSlot = luaSlot - emptyCount;
luaUnitSlot = luaUnitSlot - emptyCount;
if (wasAdded) {
luaStacks += 1; // count offset by 1
@@ -80,14 +80,14 @@ namespace Nampower {
}
// Trigger the event with spellId as parameter
((int (__cdecl *)(int, char *, char *, uint32_t, uint32_t, uint32_t, uint32_t)) Offsets::SignalEventParam)(
eventToTrigger,
format,
guidStr,
luaSlot,
spellId,
luaStacks,
auraLevels[slot]);
((int (__cdecl *)(int, char *, char *, uint32_t, uint32_t, uint32_t, uint32_t)) Offsets::SignalEventParam)(
eventToTrigger,
format,
guidStr,
luaUnitSlot,
spellId,
luaStacks,
auraLevels[slot]);
delete[] guidStr;
}
+95 -93
View File
@@ -34,96 +34,92 @@
namespace game {
#pragma pack(push, 1)
enum ItemClass
{
ITEM_CLASS_CONSUMABLE = 0,
ITEM_CLASS_CONTAINER = 1,
ITEM_CLASS_WEAPON = 2,
ITEM_CLASS_GEM = 3,
ITEM_CLASS_ARMOR = 4,
ITEM_CLASS_REAGENT = 5,
ITEM_CLASS_PROJECTILE = 6,
ITEM_CLASS_TRADE_GOODS = 7,
ITEM_CLASS_GENERIC = 8,
ITEM_CLASS_RECIPE = 9,
ITEM_CLASS_MONEY = 10,
ITEM_CLASS_QUIVER = 11,
ITEM_CLASS_QUEST = 12,
ITEM_CLASS_KEY = 13,
ITEM_CLASS_PERMANENT = 14,
ITEM_CLASS_JUNK = 15
enum ItemClass {
ITEM_CLASS_CONSUMABLE = 0,
ITEM_CLASS_CONTAINER = 1,
ITEM_CLASS_WEAPON = 2,
ITEM_CLASS_GEM = 3,
ITEM_CLASS_ARMOR = 4,
ITEM_CLASS_REAGENT = 5,
ITEM_CLASS_PROJECTILE = 6,
ITEM_CLASS_TRADE_GOODS = 7,
ITEM_CLASS_GENERIC = 8,
ITEM_CLASS_RECIPE = 9,
ITEM_CLASS_MONEY = 10,
ITEM_CLASS_QUIVER = 11,
ITEM_CLASS_QUEST = 12,
ITEM_CLASS_KEY = 13,
ITEM_CLASS_PERMANENT = 14,
ITEM_CLASS_JUNK = 15
};
enum ItemSubclassWeapon
{
ITEM_SUBCLASS_WEAPON_AXE = 0,
ITEM_SUBCLASS_WEAPON_AXE2 = 1,
ITEM_SUBCLASS_WEAPON_BOW = 2,
ITEM_SUBCLASS_WEAPON_GUN = 3,
ITEM_SUBCLASS_WEAPON_MACE = 4,
ITEM_SUBCLASS_WEAPON_MACE2 = 5,
ITEM_SUBCLASS_WEAPON_POLEARM = 6,
ITEM_SUBCLASS_WEAPON_SWORD = 7,
ITEM_SUBCLASS_WEAPON_SWORD2 = 8,
ITEM_SUBCLASS_WEAPON_obsolete = 9,
ITEM_SUBCLASS_WEAPON_STAFF = 10,
ITEM_SUBCLASS_WEAPON_EXOTIC = 11,
ITEM_SUBCLASS_WEAPON_EXOTIC2 = 12,
ITEM_SUBCLASS_WEAPON_FIST = 13,
ITEM_SUBCLASS_WEAPON_MISC = 14,
ITEM_SUBCLASS_WEAPON_DAGGER = 15,
ITEM_SUBCLASS_WEAPON_THROWN = 16,
ITEM_SUBCLASS_WEAPON_SPEAR = 17,
ITEM_SUBCLASS_WEAPON_CROSSBOW = 18,
ITEM_SUBCLASS_WEAPON_WAND = 19,
ITEM_SUBCLASS_WEAPON_FISHING_POLE = 20
enum ItemSubclassWeapon {
ITEM_SUBCLASS_WEAPON_AXE = 0,
ITEM_SUBCLASS_WEAPON_AXE2 = 1,
ITEM_SUBCLASS_WEAPON_BOW = 2,
ITEM_SUBCLASS_WEAPON_GUN = 3,
ITEM_SUBCLASS_WEAPON_MACE = 4,
ITEM_SUBCLASS_WEAPON_MACE2 = 5,
ITEM_SUBCLASS_WEAPON_POLEARM = 6,
ITEM_SUBCLASS_WEAPON_SWORD = 7,
ITEM_SUBCLASS_WEAPON_SWORD2 = 8,
ITEM_SUBCLASS_WEAPON_obsolete = 9,
ITEM_SUBCLASS_WEAPON_STAFF = 10,
ITEM_SUBCLASS_WEAPON_EXOTIC = 11,
ITEM_SUBCLASS_WEAPON_EXOTIC2 = 12,
ITEM_SUBCLASS_WEAPON_FIST = 13,
ITEM_SUBCLASS_WEAPON_MISC = 14,
ITEM_SUBCLASS_WEAPON_DAGGER = 15,
ITEM_SUBCLASS_WEAPON_THROWN = 16,
ITEM_SUBCLASS_WEAPON_SPEAR = 17,
ITEM_SUBCLASS_WEAPON_CROSSBOW = 18,
ITEM_SUBCLASS_WEAPON_WAND = 19,
ITEM_SUBCLASS_WEAPON_FISHING_POLE = 20
};
enum ItemSubclassArmor
{
ITEM_SUBCLASS_ARMOR_MISC = 0,
ITEM_SUBCLASS_ARMOR_CLOTH = 1,
ITEM_SUBCLASS_ARMOR_LEATHER = 2,
ITEM_SUBCLASS_ARMOR_MAIL = 3,
ITEM_SUBCLASS_ARMOR_PLATE = 4,
ITEM_SUBCLASS_ARMOR_BUCKLER = 5,
ITEM_SUBCLASS_ARMOR_SHIELD = 6,
ITEM_SUBCLASS_ARMOR_LIBRAM = 7,
ITEM_SUBCLASS_ARMOR_IDOL = 8,
ITEM_SUBCLASS_ARMOR_TOTEM = 9
enum ItemSubclassArmor {
ITEM_SUBCLASS_ARMOR_MISC = 0,
ITEM_SUBCLASS_ARMOR_CLOTH = 1,
ITEM_SUBCLASS_ARMOR_LEATHER = 2,
ITEM_SUBCLASS_ARMOR_MAIL = 3,
ITEM_SUBCLASS_ARMOR_PLATE = 4,
ITEM_SUBCLASS_ARMOR_BUCKLER = 5,
ITEM_SUBCLASS_ARMOR_SHIELD = 6,
ITEM_SUBCLASS_ARMOR_LIBRAM = 7,
ITEM_SUBCLASS_ARMOR_IDOL = 8,
ITEM_SUBCLASS_ARMOR_TOTEM = 9
};
enum InventoryType
{
INVTYPE_NON_EQUIP = 0,
INVTYPE_HEAD = 1,
INVTYPE_NECK = 2,
INVTYPE_SHOULDERS = 3,
INVTYPE_BODY = 4,
INVTYPE_CHEST = 5,
INVTYPE_WAIST = 6,
INVTYPE_LEGS = 7,
INVTYPE_FEET = 8,
INVTYPE_WRISTS = 9,
INVTYPE_HANDS = 10,
INVTYPE_FINGER = 11,
INVTYPE_TRINKET = 12,
INVTYPE_WEAPON = 13,
INVTYPE_SHIELD = 14,
INVTYPE_RANGED = 15,
INVTYPE_CLOAK = 16,
INVTYPE_2HWEAPON = 17,
INVTYPE_BAG = 18,
INVTYPE_TABARD = 19,
INVTYPE_ROBE = 20,
INVTYPE_WEAPONMAINHAND = 21,
INVTYPE_WEAPONOFFHAND = 22,
INVTYPE_HOLDABLE = 23,
INVTYPE_AMMO = 24,
INVTYPE_THROWN = 25,
INVTYPE_RANGEDRIGHT = 26,
INVTYPE_QUIVER = 27,
INVTYPE_RELIC = 28
enum InventoryType {
INVTYPE_NON_EQUIP = 0,
INVTYPE_HEAD = 1,
INVTYPE_NECK = 2,
INVTYPE_SHOULDERS = 3,
INVTYPE_BODY = 4,
INVTYPE_CHEST = 5,
INVTYPE_WAIST = 6,
INVTYPE_LEGS = 7,
INVTYPE_FEET = 8,
INVTYPE_WRISTS = 9,
INVTYPE_HANDS = 10,
INVTYPE_FINGER = 11,
INVTYPE_TRINKET = 12,
INVTYPE_WEAPON = 13,
INVTYPE_SHIELD = 14,
INVTYPE_RANGED = 15,
INVTYPE_CLOAK = 16,
INVTYPE_2HWEAPON = 17,
INVTYPE_BAG = 18,
INVTYPE_TABARD = 19,
INVTYPE_ROBE = 20,
INVTYPE_WEAPONMAINHAND = 21,
INVTYPE_WEAPONOFFHAND = 22,
INVTYPE_HOLDABLE = 23,
INVTYPE_AMMO = 24,
INVTYPE_THROWN = 25,
INVTYPE_RANGEDRIGHT = 26,
INVTYPE_QUIVER = 27,
INVTYPE_RELIC = 28
};
struct SpellRec {
@@ -262,6 +258,13 @@ namespace game {
uint32_t field_unknown3;
};
struct CGBuffDesc {
uint32_t m_auraIndex;
uint32_t m_auraSpell;
uint32_t m_auraFlags;
uint32_t m_untilCancelled;
};
struct CSpriteClickEvent {
unsigned __int64 objectGUID;
unsigned int button;
@@ -336,15 +339,14 @@ namespace game {
int charges;
};
enum ItemQualities
{
ITEM_QUALITY_POOR = 0, // GREY
ITEM_QUALITY_NORMAL = 1, // WHITE
ITEM_QUALITY_UNCOMMON = 2, // GREEN
ITEM_QUALITY_RARE = 3, // BLUE
ITEM_QUALITY_EPIC = 4, // PURPLE
ITEM_QUALITY_LEGENDARY = 5, // ORANGE
ITEM_QUALITY_ARTIFACT = 6 // LIGHT YELLOW
enum ItemQualities {
ITEM_QUALITY_POOR = 0, // GREY
ITEM_QUALITY_NORMAL = 1, // WHITE
ITEM_QUALITY_UNCOMMON = 2, // GREEN
ITEM_QUALITY_RARE = 3, // BLUE
ITEM_QUALITY_EPIC = 4, // PURPLE
ITEM_QUALITY_LEGENDARY = 5, // ORANGE
ITEM_QUALITY_ARTIFACT = 6 // LIGHT YELLOW
};
struct CGObject {
+19 -5
View File
@@ -54,6 +54,7 @@
#include <sstream>
#include <cstdio>
#include <windows.h>
#include <sys/stat.h>
BOOL WINAPI DllMain(HINSTANCE, uint32_t, void *);
@@ -780,15 +781,28 @@ namespace Nampower {
gStartTime = static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch()).count());
// create logs directory if it doesn't exist
CreateDirectoryA("Logs", NULL);
// move any existing logs from root directory to Logs folder
if (GetFileAttributesA("nampower_debug.log") != INVALID_FILE_ATTRIBUTES)
safeRename("nampower_debug.log", "Logs\\nampower_debug.log");
if (GetFileAttributesA("nampower_debug.log.1") != INVALID_FILE_ATTRIBUTES)
safeRename("nampower_debug.log.1", "Logs\\nampower_debug.log.1");
if (GetFileAttributesA("nampower_debug.log.2") != INVALID_FILE_ATTRIBUTES)
safeRename("nampower_debug.log.2", "Logs\\nampower_debug.log.2");
if (GetFileAttributesA("nampower_debug.log.3") != INVALID_FILE_ATTRIBUTES)
safeRename("nampower_debug.log.3", "Logs\\nampower_debug.log.3");
// remove/rename previous logs
safeRemove("nampower_debug.log.3");
safeRename("nampower_debug.log.2", "nampower_debug.log.3");
safeRename("nampower_debug.log.1", "nampower_debug.log.2");
safeRename("nampower_debug.log", "nampower_debug.log.1");
safeRemove("Logs\\nampower_debug.log.3");
safeRename("Logs\\nampower_debug.log.2", "Logs\\nampower_debug.log.3");
safeRename("Logs\\nampower_debug.log.1", "Logs\\nampower_debug.log.2");
safeRename("Logs\\nampower_debug.log", "Logs\\nampower_debug.log.1");
// open new log file
debugLogFile.open("nampower_debug.log");
debugLogFile.open("Logs\\nampower_debug.log");
DEBUG_LOG("Loading nampower v" << MAJOR_VERSION << "." << MINOR_VERSION << "." << PATCH_VERSION);
+1 -1
View File
@@ -36,7 +36,7 @@ namespace Nampower {
constexpr uint32_t MAJOR_VERSION = 2;
constexpr uint32_t MINOR_VERSION = 23;
constexpr uint32_t PATCH_VERSION = 1;
constexpr uint32_t PATCH_VERSION = 2;
constexpr int32_t LUA_REGISTRYINDEX = -10000;
constexpr int32_t LUA_GLOBALSINDEX = -10001;
+2 -1
View File
@@ -56,7 +56,7 @@ enum class Offsets : std::uint32_t {
GetSpellSlotFromLua = 0X004B3EC0,
OsGetAsyncTimeMs = 0X0042B790,
ChannelTargetGuid = 0xC4D980,
NameplateDistance = 0xC4D988, // float containing the distance squared ready to be pythagorean'd
NameplateDistance = 0xC4D988, // float containing the distance squared ready to be pythagorean'd
DBCacheGetRecord = 0X0055BA30,
InvQuestionMark = 0X00847FE4,
@@ -187,6 +187,7 @@ enum class Offsets : std::uint32_t {
QueueEventStringPtr = 0X00BE175C, // unused event 369 0x171
CastEventStringPtr = 0X00BE1A08, // unused event 540 0x21C
CGBuffBar__m_buffs = 0X00BC6040,
GetBuffByIndex = 0X004E4430,
CGUnit_C_ClearCastingSpell = 0x0060d040,
+42 -16
View File
@@ -941,17 +941,17 @@ namespace Nampower {
auto auraCapStatus = static_cast<uint32_t>(targetIsBuffCapped) |
(static_cast<uint32_t>(targetIsDebuffCapped) << 1);
((int (__cdecl *)(int eventCode,
char *fmt,
uint32_t spellIdParam,
char *casterGuidStrParam,
char *targetGuidStrParam,
uint32_t effectParam,
uint32_t auraNameParam,
uint32_t effectAmplitudeParam,
uint32_t effectMiscValueParam,
uint32_t durationParam,
uint32_t auraCapStatusParam)) Offsets::SignalEventParam)(
reinterpret_cast<int (__cdecl *)(int eventCode,
char *fmt,
uint32_t spellIdParam,
char *casterGuidStrParam,
char *targetGuidStrParam,
uint32_t effectParam,
uint32_t auraNameParam,
uint32_t effectAmplitudeParam,
uint32_t effectMiscValueParam,
uint32_t durationParam,
uint32_t auraCapStatusParam)>(Offsets::SignalEventParam)(
eventToTrigger,
format,
spell->Id,
@@ -975,11 +975,30 @@ namespace Nampower {
}
void
SpellGoHook(hadesmem::PatchDetourBase *detour, uint64_t *casterGUID, uint64_t *targetGUID,
SpellGoHook(hadesmem::PatchDetourBase *detour, uint64_t *itemGUID, uint64_t *casterGUID,
uint32_t spellId,
CDataStore *spellData) {
auto const rpos = spellData->m_read;
int16_t castFlags;
spellData->Get(castFlags);
uint8_t numTargets;
spellData->Get(numTargets);
uint64_t targetGuid;
for (int i = 0; i < numTargets; ++i) {
// spell go uses the last target in the list, I think target list is usually just length 1
spellData->Get(targetGuid);
}
// reset read pointer
spellData->m_read = rpos;
auto const spellGo = detour->GetTrampolineT<SpellGoT>();
spellGo(casterGUID, targetGUID, spellId, spellData);
// if this wasn't triggered by an item, itemGUID will just be the casterGUID duplicated
spellGo(itemGUID, casterGUID, spellId, spellData);
auto const activePlayerGuid = game::ClntObjMgrGetActivePlayerGuid();
auto const castByActivePlayer = activePlayerGuid == *casterGUID;
@@ -1017,9 +1036,16 @@ namespace Nampower {
}
if (gUserSettings.enableAuraCastEvents && doesSpellApplyAura(spell)) {
auto targetGuidVal = targetGUID ? *targetGUID : *casterGUID;
TriggerAuraCastEvent(spell, *casterGUID, targetGuidVal, activePlayerGuid, castByActivePlayer);
// not enough available args for itemId currently
// uint32_t itemId = 0;
// if (itemGUID && itemGUID != casterGUID) {
// auto *item = reinterpret_cast<game::CGItem_C *>(game::ClntObjMgrObjectPtr(
// game::TYPEMASK_ITEM, *itemGUID));
// if (item) {
// itemId = game::GetItemId(item);
// }
// }
TriggerAuraCastEvent(spell, *casterGUID, targetGuid, activePlayerGuid, castByActivePlayer);
}
}
+8 -5
View File
@@ -17,17 +17,19 @@ namespace Nampower {
void TriggerSpellQueuedEvent(QueueEvents queueEventCode, uint32_t spellId);
void CGSpellBook_CastSpellHook(hadesmem::PatchDetourBase *detour, uint32_t spellSlot, int bookType, uint64_t target);
void CGSpellBook_CastSpellHook(hadesmem::PatchDetourBase *detour, uint32_t spellSlot, int bookType,
uint64_t target);
void CGActionBar_UseActionHook(hadesmem::PatchDetourBase *detour, uint32_t actionSlot, int param_2, int param_3);
bool Spell_C_CastSpellHook(hadesmem::PatchDetourBase *detour, uint32_t *casterUnit, uint32_t spellId, game::CGItem_C *item,
bool Spell_C_CastSpellHook(hadesmem::PatchDetourBase *detour, uint32_t *casterUnit, uint32_t spellId,
game::CGItem_C *item,
std::uint64_t guid);
void
CancelSpellHook(hadesmem::PatchDetourBase *detour, bool failed, bool notifyServer, game::SpellCastResult reason);
void SpellGoHook(hadesmem::PatchDetourBase *detour, uint64_t *casterGUID, uint64_t *targetGUID, uint32_t spellId,
void SpellGoHook(hadesmem::PatchDetourBase *detour, uint64_t *itemGUID, uint64_t *casterGUID, uint32_t spellId,
CDataStore *spellData);
bool Spell_C_TargetSpellHook(hadesmem::PatchDetourBase *detour,
@@ -38,9 +40,10 @@ 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);
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);
}
}