mirror of
https://github.com/brues-code/nampower.git
synced 2026-10-16 18:20:50 +00:00
fix luaSlot not handling hidden buffs on BUFF/DEBUFF event, add IsAuraHidden function
This commit is contained in:
+125
-35
@@ -9,8 +9,115 @@
|
||||
#include "helper.hpp"
|
||||
|
||||
namespace Nampower {
|
||||
constexpr uint32_t SPELL_AURA_TRACK_CREATURES = 44;
|
||||
constexpr uint32_t SPELL_AURA_TRACK_RESOURCES = 45;
|
||||
constexpr uint32_t SPELL_AURA_TRACK_STEALTHED = 151;
|
||||
|
||||
uint32_t gAuraExpirationTime[MAX_AURA_SLOTS] = {};
|
||||
|
||||
static bool IsTrackingAura(const game::SpellRec *spellRec) {
|
||||
if (!spellRec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t auraName: spellRec->EffectApplyAuraName) {
|
||||
if (auraName == SPELL_AURA_TRACK_CREATURES ||
|
||||
auraName == SPELL_AURA_TRACK_RESOURCES ||
|
||||
auraName == SPELL_AURA_TRACK_STEALTHED) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAuraHiddenForLua(uint32_t spellId) {
|
||||
if (spellId == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto const *spellRec = game::GetSpellInfo(spellId);
|
||||
if (!spellRec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((spellRec->Attributes & game::SPELL_ATTR_HIDDEN_CLIENTSIDE) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((spellRec->AttributesEx & game::SPELL_ATTR_EX_NO_AURA_ICON) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsTrackingAura(spellRec)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsAuraVisibleInPackedFlags(const game::UnitFields *unitFields, uint32_t slot, uint8_t *packedOut = nullptr,
|
||||
uint8_t *nibbleOut = nullptr) {
|
||||
auto *auraFlags = reinterpret_cast<const uint8_t *>(unitFields->auraFlags);
|
||||
uint8_t packedSlotFlags = auraFlags[slot / 2];
|
||||
uint8_t nibble = (slot & 1u) != 0 ? (packedSlotFlags >> 4) : packedSlotFlags;
|
||||
if (packedOut) {
|
||||
*packedOut = packedSlotFlags;
|
||||
}
|
||||
if (nibbleOut) {
|
||||
*nibbleOut = nibble;
|
||||
}
|
||||
return (nibble & 0x0Eu) != 0; // (flags & (NEGATIVE | PASSIVE | PERMANENT)) != 0
|
||||
}
|
||||
|
||||
static bool CountsAsEmptyForLua(const game::UnitFields *unitFields, uint32_t slot) {
|
||||
uint32_t spellId = unitFields->aura[slot];
|
||||
if (spellId == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsAuraHiddenForLua(spellId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t packedSlotFlags = 0;
|
||||
uint8_t nibble = 0;
|
||||
bool isVisible = IsAuraVisibleInPackedFlags(unitFields, slot, &packedSlotFlags, &nibble);
|
||||
return !isVisible;
|
||||
}
|
||||
|
||||
static bool IsHiddenAura(const game::UnitFields *unitFields, uint32_t slot, uint32_t spellId, uint32_t state) {
|
||||
if (spellId != 0 && IsAuraHiddenForLua(spellId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Removed events run after the aura was cleared, so do not use slot/flags visibility there.
|
||||
if (state == 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return CountsAsEmptyForLua(unitFields, slot);
|
||||
}
|
||||
|
||||
static int CalculateLuaUnitSlotFromAuraSlot(const game::UnitFields *unitFields, uint32_t slot) {
|
||||
bool isBuff = slot < 32;
|
||||
int luaUnitSlot = static_cast<int>(slot) + 1;
|
||||
|
||||
if (!isBuff) {
|
||||
luaUnitSlot -= 32;
|
||||
}
|
||||
|
||||
uint32_t firstSlot = isBuff ? 0 : 32;
|
||||
int emptyCount = 0;
|
||||
for (uint32_t i = firstSlot; i < slot; ++i) {
|
||||
if (CountsAsEmptyForLua(unitFields, i)) {
|
||||
++emptyCount;
|
||||
}
|
||||
}
|
||||
|
||||
return luaUnitSlot - emptyCount;
|
||||
}
|
||||
|
||||
// Helper function to trigger buff/debuff events
|
||||
// state: 0 = newly added, 1 = newly removed, 2 = modified (stack change)
|
||||
void TriggerAuraEvent(uintptr_t *unit, uint32_t slot, uint32_t spellId, bool wasAdded, uint32_t state) {
|
||||
@@ -23,26 +130,16 @@ namespace Nampower {
|
||||
// Trigger the appropriate event based on buff/debuff, add/remove, and self/other
|
||||
game::Events eventToTrigger;
|
||||
|
||||
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);
|
||||
|
||||
auto auras = unitFields->aura;
|
||||
auto auraLevels = unitFields->auraLevels;
|
||||
auto auraStacks = unitFields->auraApplications;
|
||||
int luaUnitSlot = CalculateLuaUnitSlotFromAuraSlot(unitFields, slot);
|
||||
|
||||
auto luaStacks = (state == 1) ? auraStacks[slot] : auraStacks[slot] + 1; // for some crazy reason the stack count is 0 indexed but also 0 instead of -1 when removed
|
||||
auto luaStacks = (state == 1) ? auraStacks[slot] : auraStacks[slot] + 1;
|
||||
// for some crazy reason the stack count is 0 indexed but also 0 instead of -1 when removed
|
||||
|
||||
if (isBuff) {
|
||||
// count empty buff slots before slot to adjust luaSlot for actual buff/debuff index
|
||||
int emptyCount = 0;
|
||||
for (uint32_t i = 0; i < slot; ++i) {
|
||||
if (auras[i] == 0) {
|
||||
emptyCount++;
|
||||
}
|
||||
}
|
||||
luaUnitSlot = luaUnitSlot - emptyCount;
|
||||
|
||||
if (wasAdded) {
|
||||
// Buff added
|
||||
eventToTrigger = isSelf ? game::BUFF_ADDED_SELF : game::BUFF_ADDED_OTHER;
|
||||
@@ -51,17 +148,6 @@ namespace Nampower {
|
||||
eventToTrigger = isSelf ? game::BUFF_REMOVED_SELF : game::BUFF_REMOVED_OTHER;
|
||||
}
|
||||
} else {
|
||||
luaUnitSlot = luaUnitSlot - 32; // adjust slot for debuffs
|
||||
|
||||
// count empty debuff slots before slot to adjust luaSlot for actual buff/debuff index
|
||||
int emptyCount = 0;
|
||||
for (uint32_t i = 32; i < slot; ++i) {
|
||||
if (auras[i] == 0) {
|
||||
emptyCount++;
|
||||
}
|
||||
}
|
||||
luaUnitSlot = luaUnitSlot - emptyCount;
|
||||
|
||||
if (wasAdded) {
|
||||
// Debuff added
|
||||
eventToTrigger = isSelf ? game::DEBUFF_ADDED_SELF : game::DEBUFF_ADDED_OTHER;
|
||||
@@ -71,20 +157,23 @@ namespace Nampower {
|
||||
}
|
||||
}
|
||||
|
||||
bool isHidden = IsHiddenAura(unitFields, slot, spellId, state);
|
||||
static char format[] = "%s%d%d%d%d%d%d";
|
||||
char *guidStr = ConvertGuidToString(isSelf ? playerGuid : unitGuid);
|
||||
int eventLuaSlot = isHidden ? 0 : luaUnitSlot;
|
||||
|
||||
// Trigger the event with spellId as parameter
|
||||
((int (__cdecl *)(int, char *, char *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t)) Offsets::SignalEventParam)(
|
||||
eventToTrigger,
|
||||
format,
|
||||
guidStr,
|
||||
luaUnitSlot,
|
||||
spellId,
|
||||
luaStacks,
|
||||
auraLevels[slot],
|
||||
slot,
|
||||
state);
|
||||
((int (__cdecl *)(int, char *, char *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t))
|
||||
Offsets::SignalEventParam)(
|
||||
eventToTrigger,
|
||||
format,
|
||||
guidStr,
|
||||
eventLuaSlot,
|
||||
spellId,
|
||||
luaStacks,
|
||||
auraLevels[slot],
|
||||
slot,
|
||||
state);
|
||||
|
||||
FreeGuidString(guidStr);
|
||||
}
|
||||
@@ -109,7 +198,8 @@ namespace Nampower {
|
||||
TriggerAuraEvent(unit, slot, spellId, true, 0);
|
||||
}
|
||||
|
||||
void CGUnit_C_OnAuraStacksChangedHook(hadesmem::PatchDetourBase *detour, uintptr_t *unit, void *dummy_edx, int slot, uint8_t stackCount) {
|
||||
void CGUnit_C_OnAuraStacksChangedHook(hadesmem::PatchDetourBase *detour, uintptr_t *unit, void *dummy_edx, int slot,
|
||||
uint8_t stackCount) {
|
||||
auto const onAuraStacksChanged = detour->GetTrampolineT<CGUnit_C_OnAuraStacksChangedT>();
|
||||
|
||||
// Get spell ID from the aura slot
|
||||
|
||||
@@ -18,6 +18,8 @@ namespace Nampower {
|
||||
using UnitCombatLogUnitDeadT = void (__fastcall *)(uint64_t guid);
|
||||
using CGBuffBar_UpdateDurationT = void (__fastcall *)(uint8_t auraSlot, int durationMs);
|
||||
|
||||
bool IsAuraHiddenForLua(uint32_t spellId);
|
||||
|
||||
void CGUnit_C_OnAuraRemovedHook(hadesmem::PatchDetourBase *detour, uintptr_t *unit, void *dummy_edx, uint32_t slot, uint32_t spellId);
|
||||
void CGUnit_C_OnAuraAddedHook(hadesmem::PatchDetourBase *detour, uintptr_t *unit, void *dummy_edx, uint32_t slot, uint32_t spellId);
|
||||
void CGUnit_C_OnAuraStacksChangedHook(hadesmem::PatchDetourBase *detour, uintptr_t *unit, void *dummy_edx, int slot, uint8_t stackCount);
|
||||
|
||||
@@ -1837,6 +1837,9 @@ namespace Nampower {
|
||||
char unitGUID[] = "UnitGUID";
|
||||
RegisterLuaFunction(unitGUID, reinterpret_cast<uintptr_t *>(Script_UnitGUID));
|
||||
|
||||
char isAuraHidden[] = "IsAuraHidden";
|
||||
RegisterLuaFunction(isAuraHidden, reinterpret_cast<uintptr_t *>(Script_IsAuraHidden));
|
||||
|
||||
}
|
||||
|
||||
void load() {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ namespace Nampower {
|
||||
constexpr uint32_t DISENCHANT_QUALITY_PURPLE = 0x04; // Epic
|
||||
|
||||
constexpr uint32_t MAJOR_VERSION = 2;
|
||||
constexpr uint32_t MINOR_VERSION = 41;
|
||||
constexpr uint32_t MINOR_VERSION = 42;
|
||||
constexpr uint32_t PATCH_VERSION = 0;
|
||||
|
||||
constexpr int32_t LUA_REGISTRYINDEX = -10000;
|
||||
|
||||
@@ -945,6 +945,19 @@ namespace Nampower {
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t Script_IsAuraHidden(uintptr_t *luaState) {
|
||||
luaState = GetLuaStatePtr();
|
||||
|
||||
if (!lua_isnumber(luaState, 1)) {
|
||||
lua_error(luaState, "Usage: IsAuraHidden(spellId)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto const spellId = static_cast<uint32_t>(lua_tonumber(luaState, 1));
|
||||
lua_pushnumber(luaState, IsAuraHiddenForLua(spellId) ? 1 : 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64_t GetGUIDFromNameHook(hadesmem::PatchDetourBase *detour, const char *nameStr) {
|
||||
auto const original = detour->GetTrampolineT<GetGUIDFromNameT>();
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace Nampower {
|
||||
|
||||
uint32_t Script_SetMouseoverUnit(uintptr_t *luaState);
|
||||
uint32_t Script_UnitGUID(uintptr_t *luaState);
|
||||
uint32_t Script_IsAuraHidden(uintptr_t *luaState);
|
||||
|
||||
uint32_t CSimpleFrame_GetNameHook(hadesmem::PatchDetourBase *detour, uintptr_t *luaState);
|
||||
uint64_t GetGUIDFromNameHook(hadesmem::PatchDetourBase *detour, const char *nameStr);
|
||||
|
||||
Reference in New Issue
Block a user