- Fix table references when reloading ui or logging out

- Block mounting when buff capped (can disable with NP_PreventMountingWhenBuffCapped)
- add some additional information to GetTrinkets
This commit is contained in:
avitasia
2025-12-23 10:23:09 -08:00
parent f1a278fef0
commit ed1ba92f1f
23 changed files with 11362 additions and 11228 deletions
+6 -2
View File
@@ -87,12 +87,16 @@ SET NP_TargetingQueueWindowMs "1000"
- `NP_PreventRightClickTargetChange` - Whether to prevent right-clicking from changing your current target when in combat. If you don't have a target right click will still change your target even with this on. This is mainly to prevent accidentally changing targets in combat when trying to adjust your camera. 0 to disable, 1 to enable. Default is 0.
- `NP_PreventRightClickPvPAttack` - Whether to prevent right-clicking on PvP flagged players to avoid accidental PvP attacks. 0 to disable, 1 to enable. Default is 1.
- `NP_PreventRightClickPvPAttack` - Whether to prevent right-clicking on PvP flagged players to avoid accidental PvP attacks. 0 to disable, 1 to enable. Default is 0.
- `NP_DoubleCastToEndChannelEarly` - Whether to allow double casting a spell within 350ms to end channeling on the next tick. Takes into account your ChannelLatencyReductionPercentage. 0 to disable, 1 to enable. Default is 0.
- `NP_SpamProtectionEnabled` - Whether to enable spam protection functionality that blocks spamming spells while waiting for the server to respond to your initial cast due to issues spamming can cause. 0 to disable, 1 to enable. Default is 1.
- `NP_PreventMountingWhenBuffCapped` - Whether to prevent mounting when you have 32 buffs (buff capped) and are not already mounted. This prevents the issue where you mount but cannot dismount because the mount aura fails to apply due to the buff cap. When blocked, displays an error message. 0 to disable, 1 to enable. Default is 1.
- `NP_EnableAuraCastEvents` - Whether to enable AURA_CAST_ON_SELF and AURA_CAST_ON_OTHER events. 0 to disable, 1 to enable. Default is 0.
- `NP_ChannelLatencyReductionPercentage` - The percentage of your latency to subtract from the end of a channel duration to optimize cast time while hopefully not losing any ticks (more explanation below). Default is 75.
- `NP_NameplateDistance` - The distance in yards to display nameplates. Defaults to whatever was set by the game or vanilla tweaks.
@@ -131,7 +135,7 @@ This includes functions for:
Cooldown detail tables now also expose `itemId`, `itemHasActiveSpell`, and `itemActiveSpellId` alongside the existing per-category timing data.
Use `GetTrinkets([copy])` to enumerate equipped trinkets and bagged trinkets (backpack/bags 1-4) with `itemId`, `trinketName`, `bagIndex` (nil when equipped), and 1-based `slotIndex`. It reuses cached tables by default; pass `1` (or any truthy value) to force a fresh copy.
Use `GetTrinkets([copy])` to enumerate equipped trinkets and bagged trinkets (backpack/bags 1-4) with `itemId`, `trinketName`, `texture`, `itemLevel`, `bagIndex` (nil when equipped), and 1-based `slotIndex`. It reuses cached tables by default; pass `1` (or any truthy value) to force a fresh copy.
## Custom Events
+40 -39
View File
@@ -223,34 +223,6 @@ UseItemIdOrName("Hearthstone")
UseItemIdOrName(13446, "player")
```
#### UseTrinket(slot|itemIdOrName, [target])
Uses a trinket from the equipped trinket slots (13 and 14 only).
**Parameters:**
- `slot|itemIdOrName` (number|string):
- `1` or `13` => use first trinket slot
- `2` or `14` => use second trinket slot
- Any other number => treat as item ID to find in trinket slots
- String => item name (case-insensitive) to find in trinket slots
- `target` (optional, string|number): Unit token or GUID. If omitted, uses `LockedTargetGuid` if set; otherwise falls back to active player GUID.
**Returns:**
- `1` if the trinket was found and `CGItem_C::Use(...)` returned non-zero
- `0` if the trinket was found but use returned zero
- `-1` if no matching trinket was found in slots 13/14
**Examples:**
```lua
-- Use first trinket slot
UseTrinket(1)
-- Use second trinket slot on current target
UseTrinket(2, "target")
-- Use by item id if present in either trinket slot
UseTrinket(18406)
-- Use by name
UseTrinket("Royal Seal of Eldre'Thalas")
```
#### GetEquippedItems(unitToken)
Returns a table reference containing all equipped items for the specified unit.
@@ -787,6 +759,24 @@ else
end
```
#### GetTrinkets([copy])
Returns a table of trinkets from equipped trinket slots and carried bags.
**Parameters:**
- `[copy]` (number|boolean, optional): Pass `1` (or any truthy value) to force creation of a fresh Lua table. By default the function reuses an internal table and entry tables for performance.
**Returns:**
A Lua table where each entry contains:
- `itemId` (number)
- `trinketName` (string, `"Unknown"` if no name available)
- `texture` (string): Texture name for the item icon
- `bagIndex` (number|nil): `nil` when equipped; `0` for backpack; `1-4` for equipped bags
- `slotIndex` (number): Lua 1-based slot within the container (or 1/2 for equipped trinket slots)
**Notes:**
- Scans only equipped trinket slots and bags 0-4 (backpack + equipped bags). Does not scan bank or keyring.
- Reuses cached Lua tables unless `copyTable` is truthy; prefer copies if you will mutate the returned tables.
-
#### GetTrinketCooldown(slot|itemIdOrName)
Returns cooldown information for the equipped trinket(s) in slots 13 or 14. Accepts slot shortcuts or item identifiers.
@@ -816,22 +806,33 @@ if cd ~= -1 then
end
```
#### GetTrinkets([copy])
Returns a table of trinkets from equipped trinket slots and carried bags.
#### UseTrinket(slot|itemIdOrName, [target])
Uses a trinket from the equipped trinket slots (13 and 14 only).
**Parameters:**
- `[copy]` (number|boolean, optional): Pass `1` (or any truthy value) to force creation of a fresh Lua table. By default the function reuses an internal table and entry tables for performance.
- `slot|itemIdOrName` (number|string):
- `1` or `13` => use first trinket slot
- `2` or `14` => use second trinket slot
- Any other number => treat as item ID to find in trinket slots
- String => item name (case-insensitive) to find in trinket slots
- `target` (optional, string|number): Unit token or GUID. If omitted, uses `LockedTargetGuid` if set; otherwise falls back to active player GUID.
**Returns:**
A Lua table where each entry contains:
- `itemId` (number)
- `trinketName` (string, `"Unknown"` if no name available)
- `bagIndex` (number|nil): `nil` when equipped; `0` for backpack; `1-4` for equipped bags
- `slotIndex` (number): Lua 1-based slot within the container (or 1/2 for equipped trinket slots)
- `1` if the trinket was found and `CGItem_C::Use(...)` returned non-zero
- `0` if the trinket was found but use returned zero
- `-1` if no matching trinket was found in slots 13/14
**Notes:**
- Scans only equipped trinket slots and bags 0-4 (backpack + equipped bags). Does not scan bank or keyring.
- Reuses cached Lua tables unless `copyTable` is truthy; prefer copies if you will mutate the returned tables.
**Examples:**
```lua
-- Use first trinket slot
UseTrinket(1)
-- Use second trinket slot on current target
UseTrinket(2, "target")
-- Use by item id if present in either trinket slot
UseTrinket(18406)
-- Use by name
UseTrinket("Royal Seal of Eldre'Thalas")
```
#### GetSpellIdForName(spellName)
Returns:
+10962 -10932
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -38,6 +38,8 @@ set(SOURCE_FILES
unit_fields.cpp
auras.hpp
auras.cpp
lua_refs.hpp
lua_refs.cpp
)
add_library(${DLL_NAME} SHARED ${SOURCE_FILES})
+3 -5
View File
@@ -3,6 +3,7 @@
#include "helper.hpp"
#include "game.hpp"
#include "items.hpp"
#include "lua_refs.hpp"
#include "offsets.hpp"
#include <cstring>
@@ -192,11 +193,7 @@ namespace Nampower {
static char isOnGcdCategoryCooldownKey[] = "isOnGcdCategoryCooldown";
// Get or create reusable table
if (cooldownDetailTableRef == LUA_REFNIL) {
lua_newtable(luaState);
cooldownDetailTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, cooldownDetailTableRef);
GetTableRef(luaState, cooldownDetailTableRef);
// Overall cooldown status
PushTableValue(luaState, isOnCooldownKey, detail.isOnCooldown ? 1 : 0);
@@ -376,4 +373,5 @@ namespace Nampower {
PushCooldownDetailTable(luaState, cooldown);
return 1;
}
}
+2 -7
View File
@@ -5,6 +5,7 @@
#pragma once
#include "main.hpp"
#include "lua_refs.hpp"
#include <unordered_map>
#include <string>
#include <cstddef>
@@ -151,13 +152,7 @@ namespace Nampower {
lua_pushstring(luaState, const_cast<char*>(field.name));
// Get or create reusable table for this specific field name
auto refIt = refMap.find(field.name);
if (refIt == refMap.end()) {
lua_newtable(luaState);
int ref = luaL_ref(luaState, LUA_REGISTRYINDEX);
refMap[field.name] = ref;
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, refMap[field.name]);
GetTableRef(luaState, refMap[field.name]);
const char* fieldPtr = reinterpret_cast<const char*>(obj) + field.offset;
+51
View File
@@ -196,4 +196,55 @@ namespace game {
return false;
}
}
bool UnitIsBuffCapped(uintptr_t *unit) {
if (!unit) {
return false;
}
auto *unitFields = *reinterpret_cast<UnitFields **>(unit + 68);
if (!unitFields) {
return false;
}
for (int i = 31; i >= 0; --i) {
if (unitFields->aura[i] == 0) {
return false;
}
}
return true;
}
bool UnitIsDebuffCapped(uintptr_t *unit) {
if (!unit) {
return false;
}
auto *unitFields = *reinterpret_cast<UnitFields **>(unit + 68);
if (!unitFields) {
return false;
}
for (int i = 47; i >= 32; --i) {
if (unitFields->aura[i] == 0) {
return false;
}
}
return true;
}
uint32_t UnitGetMountDisplayId(uintptr_t *unit) {
if (!unit) {
return 0;
}
auto *unitFields = *reinterpret_cast<UnitFields **>(unit + 68);
if (!unitFields) {
return 0;
}
return unitFields->mountDisplayId;
}
}
+6
View File
@@ -1666,4 +1666,10 @@ namespace game {
bool UnitIsPvpFlagged(uintptr_t *unit);
bool UnitIsInCombat(uintptr_t *unit);
bool UnitIsBuffCapped(uintptr_t *unit);
bool UnitIsDebuffCapped(uintptr_t *unit);
uint32_t UnitGetMountDisplayId(uintptr_t *unit);
}
+11
View File
@@ -16,6 +16,8 @@ namespace Nampower {
// Lua function pointers
lua_errorT lua_error = reinterpret_cast<lua_errorT>(Offsets::lua_error);
lua_gettopT lua_gettop = reinterpret_cast<lua_gettopT>(Offsets::lua_gettop);
lua_settopT lua_settop = reinterpret_cast<lua_settopT>(Offsets::lua_settop);
lua_typeT lua_type = reinterpret_cast<lua_typeT>(Offsets::lua_type);
lua_isstringT lua_isstring = reinterpret_cast<lua_isstringT>(Offsets::lua_isstring);
lua_isnumberT lua_isnumber = reinterpret_cast<lua_isnumberT>(Offsets::lua_isnumber);
lua_tostringT lua_tostring = reinterpret_cast<lua_tostringT>(Offsets::lua_tostring);
@@ -208,6 +210,15 @@ namespace Nampower {
spell->Effect[0] == game::SpellEffects::SPELL_EFFECT_OPEN_LOCK_ITEM);
}
bool SpellIsMounting(const game::SpellRec *spell) {
for (int i = 0; i < 3; ++i) {
if (spell->Effect[i] == game::SPELL_EFFECT_APPLY_AURA && spell->EffectApplyAuraName[i] == 78) {
return true;
}
}
return false;
}
// if the spell is off cooldown, this will return the gcd, otherwise the cooldown
uint32_t GetGcdOrCooldownForSpell(uint32_t spellId) {
uint32_t duration;
+13
View File
@@ -11,6 +11,8 @@ namespace Nampower {
// Lua function pointers
extern lua_errorT lua_error;
extern lua_gettopT lua_gettop;
extern lua_settopT lua_settop;
extern lua_typeT lua_type;
extern lua_isstringT lua_isstring;
extern lua_isnumberT lua_isnumber;
extern lua_tostringT lua_tostring;
@@ -30,6 +32,15 @@ namespace Nampower {
#define LUA_REFNIL (-2)
#endif
#ifndef LUA_TTABLE
#define LUA_TTABLE 5
#endif
// Lua helper function - lua_istable implementation
inline bool lua_istable(uintptr_t *luaState, int idx) {
return lua_type(luaState, idx) == LUA_TTABLE;
}
uint32_t GetSpellSlotAndTypeForName(const char *spellName, uint32_t *spellType);
uint32_t GetSpellIdFromSpellName(const char *spellName);
@@ -46,6 +57,8 @@ namespace Nampower {
bool SpellIsAttackTradeskillOrEnchant(const game::SpellRec *spell);
bool SpellIsMounting(const game::SpellRec *spell);
bool IsTargetingTerrainSpell();
uint32_t GetGcdOrCooldownForSpell(uint32_t spellId);
+26 -42
View File
@@ -3,6 +3,7 @@
#include "helper.hpp"
#include "items.hpp"
#include "logging.hpp"
#include "lua_refs.hpp"
#include "offsets.hpp"
#include <string>
@@ -35,6 +36,8 @@ namespace Nampower {
static char bagIndexKey[] = "bagIndex";
static char slotIndexKey[] = "slotIndex";
static char trinketNameKey[] = "trinketName";
static char textureKey[] = "texture";
static char itemLevelKey[] = "itemLevel";
void PushItemFoundResult(uintptr_t *luaState, int32_t bagIndex, uint32_t slot) {
uint32_t adjustedSlot = slot;
@@ -57,11 +60,7 @@ namespace Nampower {
}
// Get or create reusable table
if (basicItemInfoTableRef == LUA_REFNIL) {
lua_newtable(luaState);
basicItemInfoTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, basicItemInfoTableRef);
GetTableRef(luaState, basicItemInfoTableRef);
PushTableValue(luaState, itemIdKey, cgItem->itemId);
PushTableValue(luaState, permanentEnchantIdKey, cgItem->permanentEnchantId);
@@ -78,11 +77,7 @@ namespace Nampower {
auto itemFields = item->itemFields;
// Get or create reusable table
if (itemInfoTableRef == LUA_REFNIL) {
lua_newtable(luaState);
itemInfoTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, itemInfoTableRef);
GetTableRef(luaState, itemInfoTableRef);
PushTableValue(luaState, itemIdKey, itemId);
PushTableValue(luaState, stackCountKey, itemFields->stackCount);
@@ -311,6 +306,7 @@ namespace Nampower {
auto const getBagItem = reinterpret_cast<CGBag_C_GetItemAtSlotT>(Offsets::CGBag_C_GetItemAtSlot);
auto const getContainerGuid = reinterpret_cast<GetContainerGuidT>(Offsets::GetContainerGuid);
auto const getInventoryArt = reinterpret_cast<GetInventoryArtT>(Offsets::CGItem_C_GetInventoryArt);
auto playerGuid = game::ClntObjMgrGetActivePlayerGuid();
auto playerUnit = game::GetObjectPtr(playerGuid);
@@ -325,20 +321,10 @@ namespace Nampower {
trinketEntryRefsInitialized = true;
}
if (!copyTable && trinketsTableRef == LUA_REFNIL) {
lua_newtable(luaState);
trinketsTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
}
if (copyTable) {
lua_newtable(luaState);
} else {
lua_rawgeti(luaState, LUA_REGISTRYINDEX, trinketsTableRef);
for (uint32_t i = 1; i <= lastTrinketCount; ++i) {
lua_pushnumber(luaState, static_cast<double>(i));
lua_pushnil(luaState);
lua_settable(luaState, -3);
}
GetTableRef(luaState, trinketsTableRef);
}
if (!playerUnit) {
@@ -370,12 +356,7 @@ namespace Nampower {
if (copyTable || luaIndex - 2 >= MAX_TRINKET_ENTRY_TABLES) {
lua_newtable(luaState);
} else {
auto &entryRef = trinketEntryTableRefs[luaIndex - 2];
if (entryRef == LUA_REFNIL) {
lua_newtable(luaState);
entryRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, entryRef);
GetTableRef(luaState, trinketEntryTableRefs[luaIndex - 2]);
}
PushTableValue(luaState, itemIdKey, itemId);
if (bagIndex == EQUIPPED_BAG_INDEX) {
@@ -388,6 +369,20 @@ namespace Nampower {
PushTableValue(luaState, slotIndexKey, luaSlot);
const char *trinketName = itemStats->m_displayName[0] ? itemStats->m_displayName[0] : "Unknown";
PushTableValue(luaState, trinketNameKey, trinketName);
PushTableValue(luaState, itemLevelKey, itemStats->m_itemLevel);
// Get texture path using display ID
if (itemStats && itemStats->m_displayInfoID > 0) {
char *texturePath = getInventoryArt(itemStats->m_displayInfoID);
if (texturePath && texturePath[0] != '\0') {
PushTableValue(luaState, textureKey, texturePath);
} else {
PushTableValue(luaState, textureKey, reinterpret_cast<const char *>(Offsets::InvQuestionMark));
}
} else {
PushTableValue(luaState, textureKey, reinterpret_cast<const char *>(Offsets::InvQuestionMark));
}
lua_settable(luaState, -3);
};
@@ -457,11 +452,7 @@ namespace Nampower {
}
// Get or create reusable table
if (equippedItemsTableRef == LUA_REFNIL) {
lua_newtable(luaState);
equippedItemsTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, equippedItemsTableRef);
GetTableRef(luaState, equippedItemsTableRef);
auto playerGuid = game::ClntObjMgrGetActivePlayerGuid();
bool isPlayer = (guid == playerGuid);
@@ -700,11 +691,7 @@ namespace Nampower {
auto const getBagItem = reinterpret_cast<CGBag_C_GetItemAtSlotT>(Offsets::CGBag_C_GetItemAtSlot);
// Get or create reusable table
if (bagItemsTableRef == LUA_REFNIL) {
lua_newtable(luaState);
bagItemsTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, bagItemsTableRef);
GetTableRef(luaState, bagItemsTableRef);
auto playerGuid = game::ClntObjMgrGetActivePlayerGuid();
auto player = game::GetObjectPtr(playerGuid);
@@ -713,11 +700,7 @@ namespace Nampower {
lua_pushnumber(luaState, static_cast<double>(0));
// Get or create reusable bag table
if (bagTableRef == LUA_REFNIL) {
lua_newtable(luaState);
bagTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, bagTableRef);
GetTableRef(luaState, bagTableRef);
for (uint32_t slot = 23; slot <= 38; slot++) {
auto item = getBagItem(inventory, slot);
@@ -782,4 +765,5 @@ namespace Nampower {
return 1;
}
}
+6
View File
@@ -512,4 +512,10 @@ namespace Nampower {
DEBUG_LOG("Export initialized. ProcessItemExport will be called each frame from processQueues.");
}
void StartItemExport() {
isExporting = true;
currentExportItemId = 1;
pendingItemIds.clear();
}
}
+3
View File
@@ -11,6 +11,8 @@ namespace Nampower {
using DBCache_ItemCacheDBGetRowT = uint32_t * (__thiscall *)(void *this_ptr, uint32_t itemId, uint64_t *guid, TooltipItemStatsCallbackT callback, uintptr_t *userData, bool requestIfMissing);
using GetInventoryArtT = char * (__fastcall *)(uint32_t displayId);
constexpr int32_t EQUIPPED_BAG_INDEX = -3;
constexpr int32_t BANK_BAG_INDEX = -1;
constexpr int32_t KEYRING_BAG_INDEX = -2;
@@ -24,6 +26,7 @@ namespace Nampower {
};
void ExportAllItems();
void StartItemExport();
bool LoadItem(uint32_t itemId); // Returns true if item needs async load (caller should wait)
bool ProcessItemExport(); // Process one item export per frame, returns true if still exporting
game::ItemStats_C* GetItemStats(uint32_t itemId);
+39
View File
@@ -0,0 +1,39 @@
#include "lua_refs.hpp"
#include "helper.hpp"
#include "logging.hpp"
#include <vector>
namespace Nampower {
// Vector to store pointers to all registered table refs
static std::vector<int*> registeredTableRefs;
void RegisterTableRef(int* tableRefPtr) {
// Only register if not already in the list
for (auto ref : registeredTableRefs) {
if (ref == tableRefPtr) {
return;
}
}
registeredTableRefs.push_back(tableRefPtr);
}
void GetTableRef(uintptr_t* luaState, int& tableRef) {
// Create table if needed and push onto stack
if (tableRef == LUA_REFNIL) {
// Register this table ref if it's a new one
RegisterTableRef(&tableRef);
lua_newtable(luaState);
tableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, tableRef);
}
void CleanupAllLuaTableRefs() {
DEBUG_LOG("Clearing all LUA table references");
for (auto tableRefPtr : registeredTableRefs) {
*tableRefPtr = LUA_REFNIL;
}
registeredTableRefs.clear();
}
}
+18
View File
@@ -0,0 +1,18 @@
//
// Created for Lua table reference management
//
#pragma once
#include <cstdint>
namespace Nampower {
// Register a table ref to be cleaned up on shutdown
void RegisterTableRef(int* tableRefPtr);
// Get or create a table reference (renamed from EnsureValidTableRef)
void GetTableRef(uintptr_t* luaState, int& tableRef);
// Cleanup all registered table refs
void CleanupAllLuaTableRefs();
}
+88 -101
View File
@@ -42,6 +42,7 @@
#include "cooldown_scripts.hpp"
#include "item_scripts.hpp"
#include "auras.hpp"
#include "lua_refs.hpp"
#include <cstdint>
#include <memory>
@@ -145,8 +146,11 @@ namespace Nampower {
// Forward declarations for hook functions
void LoadScriptFunctionsHook(hadesmem::PatchDetourBase *detour);
void FrameScript_CreateEventsHook(hadesmem::PatchDetourBase *detour, int param_1, uint32_t maxEventId);
void Framescript_SetEventCountHook(hadesmem::PatchDetourBase *detour, void *thisPtr, void *dummy_edx, uint32_t count);
void Framescript_SetEventCountHook(hadesmem::PatchDetourBase *detour, void *thisPtr, void *dummy_edx,
uint32_t count);
uint32_t GetTime() {
return static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
@@ -643,6 +647,9 @@ namespace Nampower {
} else if (strcmp(cvar, "NP_EnableAuraCastEvents") == 0) {
gUserSettings.enableAuraCastEvents = atoi(value) != 0;
DEBUG_LOG("Set NP_EnableAuraCastEvents to " << gUserSettings.enableAuraCastEvents);
} else if (strcmp(cvar, "NP_PreventMountingWhenBuffCapped") == 0) {
gUserSettings.preventMountingWhenBuffCapped = atoi(value) != 0;
DEBUG_LOG("Set NP_PreventMountingWhenBuffCapped to " << gUserSettings.preventMountingWhenBuffCapped);
} else if (strcmp(cvar, "NP_MinBufferTimeMs") == 0) {
gUserSettings.minBufferTimeMs = atoi(value);
DEBUG_LOG("Set NP_MinBufferTimeMs and current buffer to " << gUserSettings.minBufferTimeMs);
@@ -761,42 +768,6 @@ namespace Nampower {
DEBUG_LOG("Loading nampower v" << MAJOR_VERSION << "." << MINOR_VERSION << "." << PATCH_VERSION);
// default values
gUserSettings.queueCastTimeSpells = true;
gUserSettings.queueInstantSpells = true;
gUserSettings.queueChannelingSpells = true;
gUserSettings.queueTargetingSpells = true;
gUserSettings.queueOnSwingSpells = false;
gUserSettings.queueSpellsOnCooldown = true;
gUserSettings.interruptChannelsOutsideQueueWindow = false;
gUserSettings.retryServerRejectedSpells = true;
gUserSettings.quickcastTargetingSpells = false;
gUserSettings.replaceMatchingNonGcdCategory = false;
gUserSettings.optimizeBufferUsingPacketTimings = false;
gUserSettings.preventRightClickTargetChange = false;
gUserSettings.preventRightClickPvPAttack = true;
gUserSettings.doubleCastToEndChannelEarly = false;
gUserSettings.quickcastOnDoubleCast = false;
gUserSettings.spamProtectionEnabled = true;
gUserSettings.enableAuraCastEvents = false;
gUserSettings.minBufferTimeMs = 55; // time in ms to buffer cast to minimize server failure
gUserSettings.nonGcdBufferTimeMs = 100; // time in ms to buffer non-GCD spells to minimize server failure
gUserSettings.maxBufferIncreaseMs = 30;
gUserSettings.spellQueueWindowMs = 500; // time in ms before cast to allow queuing spells
gUserSettings.onSwingBufferCooldownMs = 500; // time in ms to wait before queuing on swing spell after a swing
gUserSettings.channelQueueWindowMs = 1500; // time in ms before channel ends to allow queuing spells
gUserSettings.targetingQueueWindowMs = 500; // time in ms before cast to allow targeting
gUserSettings.cooldownQueueWindowMs = 250; // time in ms before cooldown is up to allow queuing spells
gUserSettings.channelLatencyReductionPercentage = 75; // percent of latency to reduce channel time by
char defaultTrue[] = "1";
char defaultFalse[] = "0";
@@ -977,6 +948,16 @@ namespace Nampower {
0, // unk2
0); // unk3
char NP_PreventMountingWhenBuffCapped[] = "NP_PreventMountingWhenBuffCapped";
CVarRegister(NP_PreventMountingWhenBuffCapped, // name
nullptr, // help
0, // unk1
gUserSettings.preventMountingWhenBuffCapped ? defaultTrue : defaultFalse, // default value address
nullptr, // callback
1, // category
0, // unk2
0); // unk3
char NP_OnSwingBufferCooldownMs[] = "NP_OnSwingBufferCooldownMs";
CVarRegister(NP_OnSwingBufferCooldownMs, // name
nullptr, // help
@@ -1103,6 +1084,7 @@ namespace Nampower {
loadUserVar("NP_SpamProtectionEnabled");
loadUserVar("NP_EnableAuraCastEvents");
loadUserVar("NP_PreventMountingWhenBuffCapped");
loadUserVar("NP_MinBufferTimeMs");
loadUserVar("NP_NonGcdBufferTimeMs");
@@ -1132,76 +1114,76 @@ namespace Nampower {
}
void initHooks() {
std::call_once(initHooksFlag, []() {
const hadesmem::Process process(::GetCurrentProcessId());
const hadesmem::Process process(::GetCurrentProcessId());
gSetCVarDetour = createHook<SetCVarT>(process, Offsets::Script_SetCVar, &Script_SetCVarHook);
gCGSpellBook_CastSpellDetour = createHook<CGSpellBook_CastSpellT>(
process, Offsets::CGSpellBook_CastSpell, &CGSpellBook_CastSpellHook);
gCGActionBar_UseActionDetour = createHook<CGActionBar_UseActionT>(
process, Offsets::CGActionBar_UseAction, &CGActionBar_UseActionHook);
gCastDetour = createHook<CastSpellT>(process, Offsets::Spell_C_CastSpell, &Spell_C_CastSpellHook);
gSendCastDetour = createHook<SendCastT>(process, Offsets::SendCast, &SendCastHook);
gCancelSpellDetour = createHook<CancelSpellT>(process, Offsets::CancelSpell, &CancelSpellHook);
gCastResultHandlerDetour = createHook<PacketHandlerT>(process, Offsets::CastResultHandler,
&CastResultHandlerHook);
gSpellStartHandlerDetour = createHook<FastCallPacketHandlerT>(process, Offsets::SpellStartHandler,
&SpellStartHandlerHook);
gPeriodicAuraLogHandlerDetour = createHook<FastCallPacketHandlerT>(process, Offsets::PeriodicAuraLogHandler,
&PeriodicAuraLogHandlerHook);
gSpellNonMeleeDmgLogHandlerDetour = createHook<FastCallPacketHandlerT>(process,
Offsets::SpellNonMeleeDmgLogHandler,
&SpellNonMeleeDmgLogHandlerHook);
gSpellChannelStartHandlerDetour = createHook<PacketHandlerT>(process, Offsets::SpellChannelStartHandler,
&SpellChannelStartHandlerHook);
gSpellChannelUpdateHandlerDetour = createHook<PacketHandlerT>(process, Offsets::SpellChannelUpdateHandler,
&SpellChannelUpdateHandlerHook);
gSpellFailedDetour = createHook<Spell_C_SpellFailedT>(process, Offsets::Spell_C_SpellFailed,
&Spell_C_SpellFailedHook);
gSpellGoDetour = createHook<SpellGoT>(process, Offsets::SpellGo, &SpellGoHook);
gSpellDelayedDetour = createHook<PacketHandlerT>(process, Offsets::SpellDelayed, &SpellDelayedHook);
gSpellTargetUnitDetour = createHook<LuaScriptT>(process, Offsets::Script_SpellTargetUnit,
&Script_SpellTargetUnitHook);
gSpellStopCastingDetour = createHook<LuaScriptT>(process, Offsets::Script_SpellStopCasting,
&Script_SpellStopCastingHook);
gSpell_C_TargetSpellDetour = createHook<Spell_C_TargetSpellT>(process, Offsets::Spell_C_TargetSpell,
&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);
gInvalidFunctionPtrCheckDetour = createHook<InvalidFunctionPtrCheckT>(process, Offsets::InvalidFunctionPtrCheck,
&InvalidFunctionPtrCheckHook);
gGetSpellSlotFromLuaDetour = createHook<GetSpellSlotFromLuaT>(process, Offsets::GetSpellSlotFromLua,
&GetSpellSlotFromLuaHook);
gCGUnit_C_OnAuraRemovedDetour = createHook<CGUnit_C_OnAuraRemovedT>(process, Offsets::CGUnit_C_OnAuraRemoved,
&CGUnit_C_OnAuraRemovedHook);
gCGUnit_C_OnAuraAddedDetour = createHook<CGUnit_C_OnAuraAddedT>(process, Offsets::CGUnit_C_OnAuraAdded,
&CGUnit_C_OnAuraAddedHook);
gCGUnit_C_OnAuraAddedStackDetour = createHook<CGUnit_C_OnAuraAddedStackT>(
process, Offsets::CGUnit_C_OnAuraAddedStack,
&CGUnit_C_OnAuraAddedStackHook);
gUnitCombatLogUnitDeadDetour = createHook<UnitCombatLogUnitDeadT>(process, Offsets::UnitCombatLogUnitDead,
&UnitCombatLogUnitDeadHook);
gLoadScriptFunctionsDetour = createHook<LoadScriptFunctionsT>(process, Offsets::LoadScriptFunctions,
&LoadScriptFunctionsHook);
gCreateEventsDetour = createHook<FrameScript_CreateEventsT>(process, Offsets::FrameScript_CreateEvents,
&FrameScript_CreateEventsHook);
gSetEventCountDetour = createHook<FramescriptSetEventCountT>(process, Offsets::Framescript_SetEventCount,
&Framescript_SetEventCountHook);
});
gSetCVarDetour = createHook<SetCVarT>(process, Offsets::Script_SetCVar, &Script_SetCVarHook);
gCGSpellBook_CastSpellDetour = createHook<CGSpellBook_CastSpellT>(
process, Offsets::CGSpellBook_CastSpell, &CGSpellBook_CastSpellHook);
gCGActionBar_UseActionDetour = createHook<CGActionBar_UseActionT>(
process, Offsets::CGActionBar_UseAction, &CGActionBar_UseActionHook);
gCastDetour = createHook<CastSpellT>(process, Offsets::Spell_C_CastSpell, &Spell_C_CastSpellHook);
gSendCastDetour = createHook<SendCastT>(process, Offsets::SendCast, &SendCastHook);
gCancelSpellDetour = createHook<CancelSpellT>(process, Offsets::CancelSpell, &CancelSpellHook);
gCastResultHandlerDetour = createHook<PacketHandlerT>(process, Offsets::CastResultHandler,
&CastResultHandlerHook);
gSpellStartHandlerDetour = createHook<FastCallPacketHandlerT>(process, Offsets::SpellStartHandler,
&SpellStartHandlerHook);
gPeriodicAuraLogHandlerDetour = createHook<FastCallPacketHandlerT>(process, Offsets::PeriodicAuraLogHandler,
&PeriodicAuraLogHandlerHook);
gSpellNonMeleeDmgLogHandlerDetour = createHook<FastCallPacketHandlerT>(process,
Offsets::SpellNonMeleeDmgLogHandler,
&SpellNonMeleeDmgLogHandlerHook);
gSpellChannelStartHandlerDetour = createHook<PacketHandlerT>(process, Offsets::SpellChannelStartHandler,
&SpellChannelStartHandlerHook);
gSpellChannelUpdateHandlerDetour = createHook<PacketHandlerT>(process, Offsets::SpellChannelUpdateHandler,
&SpellChannelUpdateHandlerHook);
gSpellFailedDetour = createHook<Spell_C_SpellFailedT>(process, Offsets::Spell_C_SpellFailed,
&Spell_C_SpellFailedHook);
gSpellGoDetour = createHook<SpellGoT>(process, Offsets::SpellGo, &SpellGoHook);
gSpellDelayedDetour = createHook<PacketHandlerT>(process, Offsets::SpellDelayed, &SpellDelayedHook);
gSpellTargetUnitDetour = createHook<LuaScriptT>(process, Offsets::Script_SpellTargetUnit,
&Script_SpellTargetUnitHook);
gSpellStopCastingDetour = createHook<LuaScriptT>(process, Offsets::Script_SpellStopCasting,
&Script_SpellStopCastingHook);
gSpell_C_TargetSpellDetour = createHook<Spell_C_TargetSpellT>(process, Offsets::Spell_C_TargetSpell,
&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);
gInvalidFunctionPtrCheckDetour = createHook<InvalidFunctionPtrCheckT>(process, Offsets::InvalidFunctionPtrCheck,
&InvalidFunctionPtrCheckHook);
gGetSpellSlotFromLuaDetour = createHook<GetSpellSlotFromLuaT>(process, Offsets::GetSpellSlotFromLua,
&GetSpellSlotFromLuaHook);
gCGUnit_C_OnAuraRemovedDetour = createHook<CGUnit_C_OnAuraRemovedT>(process, Offsets::CGUnit_C_OnAuraRemoved,
&CGUnit_C_OnAuraRemovedHook);
gCGUnit_C_OnAuraAddedDetour = createHook<CGUnit_C_OnAuraAddedT>(process, Offsets::CGUnit_C_OnAuraAdded,
&CGUnit_C_OnAuraAddedHook);
gCGUnit_C_OnAuraAddedStackDetour = createHook<CGUnit_C_OnAuraAddedStackT>(
process, Offsets::CGUnit_C_OnAuraAddedStack,
&CGUnit_C_OnAuraAddedStackHook);
gUnitCombatLogUnitDeadDetour = createHook<UnitCombatLogUnitDeadT>(process, Offsets::UnitCombatLogUnitDead,
&UnitCombatLogUnitDeadHook);
gLoadScriptFunctionsDetour = createHook<LoadScriptFunctionsT>(process, Offsets::LoadScriptFunctions,
&LoadScriptFunctionsHook);
gCreateEventsDetour = createHook<FrameScript_CreateEventsT>(process, Offsets::FrameScript_CreateEvents,
&FrameScript_CreateEventsHook);
gSetEventCountDetour = createHook<FramescriptSetEventCountT>(process, Offsets::Framescript_SetEventCount,
&Framescript_SetEventCountHook);
}
void SysMsgInitializeHook(hadesmem::PatchDetourBase *detour) {
auto const sysMsgInitialize = detour->GetTrampolineT<SysMsgInitializeT>();
sysMsgInitialize();
loadConfig();
initHooks();
std::call_once(initHooksFlag, []() {
loadConfig();
initHooks();
});
}
void addCustomEvent(uint32_t code, char *name) {
@@ -1286,6 +1268,8 @@ namespace Nampower {
auto const loadScriptFunctions = detour->GetTrampolineT<LoadScriptFunctionsT>();
loadScriptFunctions();
CleanupAllLuaTableRefs();
// register our own lua functions
DEBUG_LOG("Registering Custom Lua functions");
char queueSpellByName[] = "QueueSpellByName";
@@ -1329,6 +1313,9 @@ namespace Nampower {
char getItemStats[] = "GetItemStats";
RegisterLuaFunction(getItemStats, reinterpret_cast<uintptr_t *>(Script_GetItemStats));
char startItemExport[] = "StartItemExport";
RegisterLuaFunction(startItemExport, reinterpret_cast<uintptr_t *>(Script_StartItemExport));
char getSpellRec[] = "GetSpellRec";
RegisterLuaFunction(getSpellRec, reinterpret_cast<uintptr_t *>(Script_GetSpellRec));
+6 -3
View File
@@ -30,8 +30,8 @@ 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 = 19;
constexpr uint32_t PATCH_VERSION = 1;
constexpr uint32_t MINOR_VERSION = 20;
constexpr uint32_t PATCH_VERSION = 0;
constexpr int32_t LUA_REGISTRYINDEX = -10000;
constexpr int32_t LUA_GLOBALSINDEX = -10001;
@@ -125,6 +125,7 @@ namespace Nampower {
using GetUnitFromNameT = uintptr_t *(__fastcall *)(const char *);
using lua_gettableT = void (__fastcall *)(uintptr_t *luaState, int globalsIndex);
using lua_gettopT = int (__fastcall *)(uintptr_t *);
using lua_typeT = int (__fastcall *)(uintptr_t *, int);
using lua_isstringT = bool (__fastcall *)(uintptr_t *, int);
using lua_isnumberT = bool (__fastcall *)(uintptr_t *, int);
using lua_tostringT = char *(__fastcall *)(uintptr_t *, int);
@@ -172,6 +173,8 @@ namespace Nampower {
using InvalidFunctionPtrCheckT = void (__fastcall *)(uint32_t param_1);
using CGGameUI_DisplayErrorT = void (__cdecl *)(uint32_t errorCode);
void RegisterLuaFunction(char *, uintptr_t *func);
void LuaCall(const char *code);
@@ -206,4 +209,4 @@ namespace Nampower {
void SetAttackTarget(uint64_t target);
}
}
+13 -29
View File
@@ -8,6 +8,7 @@
#include "dbc_fields.hpp"
#include "unit_fields.hpp"
#include "helper.hpp"
#include "lua_refs.hpp"
#include <cstring>
namespace Nampower {
@@ -123,11 +124,7 @@ namespace Nampower {
}
// Get or create reusable table
if (castInfoTableRef == LUA_REFNIL) {
lua_newtable(luaState);
castInfoTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, castInfoTableRef);
GetTableRef(luaState, castInfoTableRef);
// Get current time and calculate offset to convert to WoW time
uint32_t currentTime = GetTime();
@@ -308,11 +305,7 @@ namespace Nampower {
if (useCopy) {
lua_newtable(luaState);
} else {
if (itemStatsTableRef == LUA_REFNIL) {
lua_newtable(luaState);
itemStatsTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, itemStatsTableRef);
GetTableRef(luaState, itemStatsTableRef);
}
// Push all simple fields using descriptors
@@ -401,13 +394,7 @@ namespace Nampower {
lua_newtable(luaState);
} else {
// Get or create reusable table for this specific field name
auto refIt = itemStatsArrayFieldRefs.find(fieldName);
if (refIt == itemStatsArrayFieldRefs.end()) {
lua_newtable(luaState);
int ref = luaL_ref(luaState, LUA_REGISTRYINDEX);
itemStatsArrayFieldRefs[fieldName] = ref;
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, itemStatsArrayFieldRefs[fieldName]);
GetTableRef(luaState, itemStatsArrayFieldRefs[fieldName]);
}
const char *fieldPtr = reinterpret_cast<const char *>(item) + field.offset;
@@ -454,6 +441,12 @@ namespace Nampower {
return 0;
}
// won't do anything unless you uncomment line in process queues
uint32_t Script_StartItemExport(uintptr_t *luaState) {
StartItemExport();
return 0;
}
uint32_t Script_GetUnitData(uintptr_t *luaState) {
luaState = GetLuaStatePtr(); // pcall leads to corrupted lua state pointer on added scripts, not sure why
@@ -495,11 +488,7 @@ namespace Nampower {
if (useCopy) {
lua_newtable(luaState);
} else {
if (unitDataTableRef == LUA_REFNIL) {
lua_newtable(luaState);
unitDataTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, unitDataTableRef);
GetTableRef(luaState, unitDataTableRef);
}
// Push all simple fields using descriptors
@@ -590,13 +579,7 @@ namespace Nampower {
lua_newtable(luaState);
} else {
// Get or create reusable table for this specific field name
auto refIt = unitFieldsArrayFieldRefs.find(fieldName);
if (refIt == unitFieldsArrayFieldRefs.end()) {
lua_newtable(luaState);
int ref = luaL_ref(luaState, LUA_REGISTRYINDEX);
unitFieldsArrayFieldRefs[fieldName] = ref;
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, unitFieldsArrayFieldRefs[fieldName]);
GetTableRef(luaState, unitFieldsArrayFieldRefs[fieldName]);
}
const char *fieldPtr = reinterpret_cast<const char *>(unitFields) + field.offset;
@@ -627,4 +610,5 @@ namespace Nampower {
lua_error(luaState, "Unknown field name");
return 0;
}
}
+3 -1
View File
@@ -28,5 +28,7 @@ namespace Nampower {
uint32_t Script_GetUnitField(uintptr_t *luaState);
uint32_t Script_StartItemExport(uintptr_t *luaState);
bool RunQueuedScript(int priority);
}
}
+5 -1
View File
@@ -58,6 +58,7 @@ enum class Offsets : std::uint32_t {
ChannelTargetGuid = 0xC4D980,
NameplateDistance = 0xC4D988, // float containing the distance squared ready to be pythagorean'd
DBCacheGetRecord = 0X0055BA30,
InvQuestionMark = 0X00847FE4,
ItemDBCache = 0xC0E2A0,
@@ -147,6 +148,7 @@ enum class Offsets : std::uint32_t {
lua_state_ptr = 0x7040D0,
lua_type = 0x006F3460,
lua_isstring = 0x006F3510,
lua_isnumber = 0X006F34D0,
lua_tostring = 0x006F3690,
@@ -168,7 +170,6 @@ enum class Offsets : std::uint32_t {
luaL_ref = 0x006F5310,
luaL_unref = 0x006F5400,
CGInputControlGetActive = 0XBE1148,
LastHardwareAction = 0X00CF0BC8,
CGInputControlSetReleaseAction = 0x514810,
@@ -181,6 +182,7 @@ enum class Offsets : std::uint32_t {
IntIntParamFormat = 0X00843342,
StringIntParamFormat = 0X00847FBC,
StringParamFormat = 0X0082E280,
QueueEventStringPtr = 0X00BE175C, // unused event 369 0x171
CastEventStringPtr = 0X00BE1A08, // unused event 540 0x21C
@@ -203,6 +205,7 @@ enum class Offsets : std::uint32_t {
CGCharacterInfo_UseItem = 0x004c7970,
CGItem_C_Use = 0x005D8D00,
CGItem_C_GetInventoryArt = 0x005D88B0,
DBCache_ItemCacheDBGetRow = 0x0055BA30,
@@ -211,4 +214,5 @@ enum class Offsets : std::uint32_t {
ClearCursor = 0x00495190,
CursorSetCursorMode = 0x00523d20,
CursorModelSetSequence = 0x00523c20,
CGGameUI_DisplayError = 0x00496720,
};
+4 -13
View File
@@ -4,8 +4,8 @@
#include "spell_scripts.hpp"
#include "helper.hpp"
#include "lua_refs.hpp"
#include "offsets.hpp"
#include "items.hpp"
#include "dbc_fields.hpp"
#include <cstring>
@@ -297,11 +297,7 @@ namespace Nampower {
if (useCopy) {
lua_newtable(luaState);
} else {
if (spellRecTableRef == LUA_REFNIL) {
lua_newtable(luaState);
spellRecTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, spellRecTableRef);
GetTableRef(luaState, spellRecTableRef);
}
// Push all simple fields using descriptors
@@ -394,13 +390,7 @@ namespace Nampower {
lua_newtable(luaState);
} else {
// Get or create reusable table for this specific field name
auto refIt = spellRecArrayFieldRefs.find(fieldName);
if (refIt == spellRecArrayFieldRefs.end()) {
lua_newtable(luaState);
int ref = luaL_ref(luaState, LUA_REGISTRYINDEX);
spellRecArrayFieldRefs[fieldName] = ref;
}
lua_rawgeti(luaState, LUA_REGISTRYINDEX, spellRecArrayFieldRefs[fieldName]);
GetTableRef(luaState, spellRecArrayFieldRefs[fieldName]);
}
const char *fieldPtr = reinterpret_cast<const char *>(spell) + field.offset;
@@ -569,4 +559,5 @@ namespace Nampower {
return 0;
}
}
+28 -27
View File
@@ -452,7 +452,10 @@ namespace Nampower {
// it is possible when spamming to attempt to cast before queues are processed
processQueues();
if (item == nullptr && casterUnit != game::GetObjectPtr(game::ClntObjMgrGetActivePlayerGuid())) {
auto playerGuid = game::ClntObjMgrGetActivePlayerGuid();
auto playerUnit = (playerGuid > 0) ? game::GetObjectPtr(playerGuid) : nullptr;
if (item == nullptr && casterUnit != playerUnit) {
DEBUG_LOG("Ignoring non active player cast of spell " << game::GetSpellName(spellId) << " " << spellId);
// just call original function if caster is not the active player
// happens with Doomguard rain of fire
@@ -471,6 +474,24 @@ namespace Nampower {
auto const spellIsChanneling = SpellIsChanneling(spell);
auto const spellIsTargeting = SpellIsTargeting(spell);
auto const isSpecialSpell = SpellIsAttackTradeskillOrEnchant(spell);
if (casterUnit == playerUnit && gUserSettings.preventMountingWhenBuffCapped) {
// Check for mount spell when player is buff capped
if (SpellIsMounting(spell)) {
if (playerUnit && game::UnitIsBuffCapped(playerUnit) && game::UnitGetMountDisplayId(playerUnit) == 0) {
DEBUG_LOG("Blocking mount spell " << spellName << " due to buff cap");
static char message[] = "Preventing mounting due to buff cap (breaks dismount)";
((int (__cdecl *)(int, char *, char *)) Offsets::SignalEventParam)(
game::UI_ERROR_MESSAGE,
(char *) Offsets::StringParamFormat,
message);
return false;
}
}
}
auto const currentTargetGuid = game::GetCurrentTargetGuid();
if (spellIsChanneling) {
@@ -505,10 +526,10 @@ namespace Nampower {
uint32_t itemId = 0;
if (item) {
itemId = game::GetItemId((game::CGItem_C *) item);
itemId = game::GetItemId(reinterpret_cast<game::CGItem_C *>(item));
}
DEBUG_LOG("Attempt cast " << spellName << " item " << item << " on guid " << guid << " target "
DEBUG_LOG("Attempt cast " << spellName << " itemId " << itemId << " on guid " << guid << " target "
<< currentTargetGuid
<< ", time since last cast " << currentTime - gLastCastData.startTimeMs);
@@ -856,7 +877,7 @@ namespace Nampower {
}
bool doesSpellApplyAura(const game::SpellRec *spell) {
for (unsigned int i : spell->Effect) {
for (unsigned int i: spell->Effect) {
switch (i) {
case game::SPELL_EFFECT_APPLY_AURA:
case game::SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
@@ -889,29 +910,8 @@ namespace Nampower {
auto *targetUnit = game::ClntObjMgrObjectPtr(
static_cast<game::TypeMask>(game::TYPEMASK_PLAYER | game::TYPEMASK_UNIT), targetGuid);
bool targetIsBuffCapped = false;
bool targetIsDebuffCapped = false;
if (targetUnit) {
auto *unitFields = *reinterpret_cast<game::UnitFields **>(targetUnit + 68);
if (unitFields) {
targetIsBuffCapped = true;
for (int i = 31; i >= 0; --i) {
if (unitFields->aura[i] == 0) {
targetIsBuffCapped = false;
break;
}
}
targetIsDebuffCapped = true;
for (int i = 47; i >= 32; --i) {
if (unitFields->aura[i] == 0) {
targetIsDebuffCapped = false;
break;
}
}
}
}
bool targetIsBuffCapped = game::UnitIsBuffCapped(targetUnit);
bool targetIsDebuffCapped = game::UnitIsDebuffCapped(targetUnit);
char *casterGuidStr = ConvertGuidToString(casterGuid);
char *targetGuidStr = ConvertGuidToString(targetGuid);
@@ -1005,6 +1005,7 @@ namespace Nampower {
if (gUserSettings.enableAuraCastEvents && doesSpellApplyAura(spell)) {
auto targetGuidVal = targetGUID ? *targetGUID : *casterGUID;
TriggerAuraCastEvent(spell, *casterGUID, targetGuidVal, activePlayerGuid, castByActivePlayer);
}
}
+27 -26
View File
@@ -8,39 +8,40 @@
#include <cstdint>
struct UserSettings {
bool queueCastTimeSpells;
bool queueInstantSpells;
bool queueOnSwingSpells;
bool queueChannelingSpells;
bool queueTargetingSpells;
bool queueSpellsOnCooldown;
bool queueCastTimeSpells = true;
bool queueInstantSpells = true;
bool queueOnSwingSpells = false;
bool queueChannelingSpells = true;
bool queueTargetingSpells = true;
bool queueSpellsOnCooldown = true;
bool interruptChannelsOutsideQueueWindow;
bool retryServerRejectedSpells;
bool quickcastTargetingSpells;
bool replaceMatchingNonGcdCategory;
bool optimizeBufferUsingPacketTimings;
bool interruptChannelsOutsideQueueWindow = false;
bool retryServerRejectedSpells = true;
bool quickcastTargetingSpells = false;
bool replaceMatchingNonGcdCategory = false;
bool optimizeBufferUsingPacketTimings = false;
bool preventRightClickTargetChange;
bool preventRightClickPvPAttack;
bool preventRightClickTargetChange = false;
bool preventRightClickPvPAttack = false;
bool doubleCastToEndChannelEarly;
bool quickcastOnDoubleCast;
bool doubleCastToEndChannelEarly = false;
bool quickcastOnDoubleCast = false;
bool spamProtectionEnabled;
bool enableAuraCastEvents;
bool spamProtectionEnabled = true;
bool enableAuraCastEvents = false;
bool preventMountingWhenBuffCapped = true;
uint32_t spellQueueWindowMs;
uint32_t onSwingBufferCooldownMs;
uint32_t channelQueueWindowMs;
uint32_t targetingQueueWindowMs;
uint32_t cooldownQueueWindowMs;
uint32_t spellQueueWindowMs = 500;
uint32_t onSwingBufferCooldownMs = 500;
uint32_t channelQueueWindowMs = 1500;
uint32_t targetingQueueWindowMs = 500;
uint32_t cooldownQueueWindowMs = 250;
uint32_t minBufferTimeMs;
uint32_t maxBufferIncreaseMs;
uint32_t nonGcdBufferTimeMs;
uint32_t minBufferTimeMs = 55;
uint32_t maxBufferIncreaseMs = 30;
uint32_t nonGcdBufferTimeMs = 100;
int32_t channelLatencyReductionPercentage;
int32_t channelLatencyReductionPercentage = 75;
};
enum CastType {