fix bugs with getEquippedItems, add randomPropertiesId, add quest functions

This commit is contained in:
avitasia
2026-04-13 10:54:04 -07:00
parent 7a5205871f
commit cdddc604dc
7 changed files with 12756 additions and 12673 deletions
+8 -5
View File
@@ -332,8 +332,9 @@ Returns a table reference containing all equipped items for the specified unit.
- `unitToken` (string): Can be a standard unit token ("player", "target", "pet", etc.) or a GUID string
**Returns:**
- A Lua table reference with equipment slot indices as keys (0-18) and item info tables as values
- A Lua table reference with equipment slot indices as keys (1-19) and item info tables as values. Empty slots are nil.
- Returns nil if the unit cannot be found or inspected
- Player and non-player calls return separate table references, so results do not overwrite each other
For the player, item info includes:
- `itemId`: The item's ID
@@ -341,6 +342,7 @@ For the player, item info includes:
- `duration`: Item duration in milliseconds
- `spellChargesRemaining`: Remaining spell charges as a single number. It uses the largest absolute value found in the internal 5-slot spell-charge array.
- `flags`: Item flags
- `randomPropertiesId`: Random property ID (e.g. for randomly enchanted items)
- `permanentEnchantId`: Permanent enchantment ID
- `tempEnchantId`: Temporary enchantment ID
- `tempEnchantmentTimeLeftMs`: Time remaining on temp enchant in milliseconds
@@ -350,6 +352,7 @@ For the player, item info includes:
For other inspected units (limited data):
- `itemId`: The item's ID
- `randomPropertiesId`: Random property ID
- `permanentEnchantId`: Permanent enchantment ID
- `tempEnchantId`: Temporary enchantment ID
@@ -368,8 +371,8 @@ end
-- Check player's weapon durability
local items = GetEquippedItems("player")
if items and items[15] then -- slot 15 is main hand
local weapon = items[15]
if items and items[16] then -- slot 16 is main hand
local weapon = items[16]
print("Weapon durability: " .. weapon.durability .. "/" .. weapon.maxDurability)
end
```
@@ -379,14 +382,14 @@ Returns item info for a specific equipment slot on the specified unit.
**Parameters:**
- `unitToken` (string): Can be a standard unit token ("player", "target", "pet", etc.) or a GUID string
- `slot` (number): Equipment slot number (0-18)
- `slot` (number): Equipment slot number (1-19)
- 1 = Head, 2 = Neck, 3 = Shoulder, 4 = Shirt, 5 = Chest
- 6 = Waist, 7 = Legs, 8 = Feet, 9 = Wrist, 10 = Hands
- 11 = Finger 1, 12 = Finger 2, 13 = Trinket 1, 14 = Trinket 2
- 15 = Back, 16 = Main Hand, 17 = Off Hand, 18 = Ranged, 19 = Tabard
**Returns:**
- A Lua table reference containing the item info (same fields as GetEquippedItems)
- A Lua table reference containing the item info (same fields as GetEquippedItems for the respective unit type)
- Returns nil if the slot is empty, unit cannot be found, or unit cannot be inspected
**Examples:**
+12662 -12650
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -529,6 +529,12 @@ namespace game {
uint32_t itemId;
uint32_t permanentEnchantId;
uint32_t tempEnchantId;
uint32_t unk2;
uint32_t unk3;
uint32_t unk4;
uint32_t unk5;
uint32_t unk6;
uint32_t randomPropertiesId;
};
+35 -11
View File
@@ -16,6 +16,7 @@ namespace Nampower {
static int basicItemInfoTableRef = LUA_REFNIL;
static int itemInfoTableRef = LUA_REFNIL;
static int equippedItemsTableRef = LUA_REFNIL;
static int targetEquippedItemsTableRef = LUA_REFNIL;
static int bagItemsTableRef = LUA_REFNIL;
static int trinketsTableRef = LUA_REFNIL;
static uint32_t lastTrinketCount = 0;
@@ -33,13 +34,21 @@ namespace Nampower {
// Item entry table references: 2D matrix [bagIndex][slot] for direct mapping
static std::array<std::array<int, MAX_BAG_SLOTS>, MAX_BAGS> itemEntryTableRefs{};
// Equipped item table references (slots 0-18)
// Equipped item table references for player (slots 0-18)
static std::array<int, MAX_EQUIPPED_SLOTS> equippedItemTableRefs{};
// Equipped item table references for non-player (target) inspections (slots 0-18)
static std::array<int, MAX_EQUIPPED_SLOTS> targetEquippedItemTableRefs{};
// Trinket-specific table references (separate from equippedItemTableRefs/itemEntryTableRefs)
static std::array<int, MAX_EQUIPPED_SLOTS> equippedTrinketTableRefs{};
static std::array<std::array<int, MAX_BAG_SLOTS>, MAX_BAGS> bagTrinketTableRefs{};
// String keys used when pushing item data to Lua
static char itemIdKey[] = "itemId";
static char permanentEnchantIdKey[] = "permanentEnchantId";
static char tempEnchantIdKey[] = "tempEnchantId";
static char randomPropertiesIdKey[] = "randomPropertiesId";
static char stackCountKey[] = "stackCount";
static char durationKey[] = "duration";
static char spellChargesRemainingKey[] = "spellChargesRemaining";
@@ -117,6 +126,7 @@ namespace Nampower {
PushTableValue(luaState, itemIdKey, cgItem->itemId);
PushTableValue(luaState, permanentEnchantIdKey, cgItem->permanentEnchantId);
PushTableValue(luaState, tempEnchantIdKey, cgItem->tempEnchantId);
PushTableValue(luaState, randomPropertiesIdKey, cgItem->randomPropertiesId);
}
void CreateItemInfoTable(uintptr_t *luaState, game::CGItem_C *item) {
@@ -136,6 +146,7 @@ namespace Nampower {
PushTableValue(luaState, durationKey, itemFields->duration);
PushTableValue(luaState, spellChargesRemainingKey, GetMaxSpellChargesRemaining(itemFields->spellChargesRemaining));
PushTableValue(luaState, flagsKey, itemFields->flags);
PushTableValue(luaState, randomPropertiesIdKey, itemFields->randomPropertiesId);
PushTableValue(luaState, permanentEnchantIdKey, itemFields->permEnchantmentSlot.id);
PushTableValue(luaState, tempEnchantIdKey, itemFields->tempEnchantmentSlot.id);
PushTableValue(luaState, tempEnchantmentTimeLeftMsKey, itemFields->tempEnchantmentSlot.duration);
@@ -203,6 +214,7 @@ namespace Nampower {
currentData.duration = itemFields->duration;
currentData.spellChargesRemaining = GetMaxSpellChargesRemaining(itemFields->spellChargesRemaining);
currentData.flags = itemFields->flags;
currentData.randomPropertiesId = itemFields->randomPropertiesId;
currentData.permanentEnchantId = itemFields->permEnchantmentSlot.id;
currentData.tempEnchantId = itemFields->tempEnchantmentSlot.id;
currentData.tempEnchantmentTimeLeftMs = itemFields->tempEnchantmentSlot.duration;
@@ -276,6 +288,7 @@ namespace Nampower {
PushTableValue(luaState, durationKey, itemFields->duration);
PushTableValue(luaState, spellChargesRemainingKey, GetMaxSpellChargesRemaining(itemFields->spellChargesRemaining));
PushTableValue(luaState, flagsKey, itemFields->flags);
PushTableValue(luaState, randomPropertiesIdKey, itemFields->randomPropertiesId);
PushTableValue(luaState, permanentEnchantIdKey, itemFields->permEnchantmentSlot.id);
PushTableValue(luaState, tempEnchantIdKey, itemFields->tempEnchantmentSlot.id);
PushTableValue(luaState, tempEnchantmentTimeLeftMsKey, itemFields->tempEnchantmentSlot.duration);
@@ -571,10 +584,10 @@ namespace Nampower {
if (copyTable) {
lua_newtable(luaState);
} else {
// Get table ref based on location (direct 2D mapping)
// Use dedicated trinket table refs, separate from GetEquippedItems/GetBagItems refs
if (bagIndex == EQUIPPED_BAG_INDEX) {
if (slot < MAX_EQUIPPED_SLOTS) {
GetTableRef(luaState, equippedItemTableRefs[slot]);
GetTableRef(luaState, equippedTrinketTableRefs[slot]);
} else {
lua_newtable(luaState);
}
@@ -589,7 +602,7 @@ namespace Nampower {
}
if (adjustedSlot < MAX_BAG_SLOTS) {
GetTableRef(luaState, itemEntryTableRefs[cacheIndexForTableRef][adjustedSlot]);
GetTableRef(luaState, bagTrinketTableRefs[cacheIndexForTableRef][adjustedSlot]);
} else {
lua_newtable(luaState);
}
@@ -612,7 +625,7 @@ namespace Nampower {
PushTableValue(luaState, itemLevelKey, itemStats->m_itemLevel);
// Get texture path using display ID
if (itemStats && itemStats->m_displayInfoID > 0) {
if (itemStats->m_displayInfoID > 0) {
char *texturePath = getInventoryArt(itemStats->m_displayInfoID);
if (texturePath && texturePath[0] != '\0') {
PushTableValue(luaState, textureKey, texturePath);
@@ -707,12 +720,13 @@ namespace Nampower {
return 0;
}
// Get or create reusable table
GetTableRef(luaState, equippedItemsTableRef);
auto playerGuid = game::ClntObjMgrGetActivePlayerGuid();
bool isPlayer = (guid == playerGuid);
// Use separate outer tables for player vs target to avoid cross-contamination
GetTableRef(luaState, isPlayer ? equippedItemsTableRef : targetEquippedItemsTableRef);
if (isPlayer) {
auto const getBagItem = reinterpret_cast<CGBag_C_GetItemAtSlotT>(Offsets::CGBag_C_GetItemAtSlot);
auto inventory = game::GetPlayerInventoryPtr(unit);
@@ -721,6 +735,10 @@ namespace Nampower {
auto item = getBagItem(inventory, slot);
if (item) {
PushBagCGItemToTable(luaState, -999, slot, item);
} else {
lua_pushnumber(luaState, static_cast<double>(slot + 1));
lua_pushnil(luaState);
lua_settable(luaState, -3);
}
}
} else {
@@ -729,11 +747,17 @@ namespace Nampower {
for (uint32_t slot = 0; slot <= 18; slot++) {
auto cgItem = getEquippedItem(unit, slot);
lua_pushnumber(luaState, static_cast<double>(slot+1)); // lua is 1 indexed
if (cgItem) {
lua_pushnumber(luaState, static_cast<double>(slot+1)); // lua is 1 indexed
CreateBasicItemInfoTable(luaState, cgItem);
lua_settable(luaState, -3);
GetTableRef(luaState, targetEquippedItemTableRefs[slot]);
PushTableValue(luaState, itemIdKey, cgItem->itemId);
PushTableValue(luaState, permanentEnchantIdKey, cgItem->permanentEnchantId);
PushTableValue(luaState, tempEnchantIdKey, cgItem->tempEnchantId);
PushTableValue(luaState, randomPropertiesIdKey, cgItem->randomPropertiesId);
} else {
lua_pushnil(luaState);
}
lua_settable(luaState, -3);
}
}
+3
View File
@@ -41,6 +41,7 @@ namespace Nampower {
uint32_t duration;
int32_t spellChargesRemaining;
uint32_t flags;
uint32_t randomPropertiesId;
uint32_t permanentEnchantId;
uint32_t tempEnchantId;
uint32_t tempEnchantmentTimeLeftMs;
@@ -49,6 +50,7 @@ namespace Nampower {
uint32_t maxDurability;
CachedItemData() : itemId(0), stackCount(0), duration(0), spellChargesRemaining(0), flags(0),
randomPropertiesId(0),
permanentEnchantId(0), tempEnchantId(0),
tempEnchantmentTimeLeftMs(0), tempEnchantmentCharges(0),
durability(0), maxDurability(0) {}
@@ -59,6 +61,7 @@ namespace Nampower {
duration == other.duration &&
spellChargesRemaining == other.spellChargesRemaining &&
flags == other.flags &&
randomPropertiesId == other.randomPropertiesId &&
permanentEnchantId == other.permanentEnchantId &&
tempEnchantId == other.tempEnchantId &&
tempEnchantmentTimeLeftMs == other.tempEnchantmentTimeLeftMs &&
+1 -1
View File
@@ -26,7 +26,7 @@ namespace Nampower {
constexpr uint32_t DISENCHANT_QUALITY_PURPLE = 0x04; // Epic
constexpr uint32_t MAJOR_VERSION = 4;
constexpr uint32_t MINOR_VERSION = 5;
constexpr uint32_t MINOR_VERSION = 6;
constexpr uint32_t PATCH_VERSION = 0;
constexpr int32_t LUA_REGISTRYINDEX = -10000;
+41 -6
View File
@@ -6,9 +6,11 @@
#include "offsets.hpp"
#include "helper.hpp"
#include "lua_refs.hpp"
namespace Nampower {
enum class QuestDialogKind : int32_t {
enum class QuestDialogKind : uint32_t {
UNKNOWN = 0,
DETAIL = 1,
PROGRESS = 2,
COMPLETE = 3,
@@ -22,6 +24,8 @@ namespace Nampower {
};
static constexpr uint32_t kQuestLogMaxRows = 256;
static int questLogQuestIdsTableRef = LUA_REFNIL;
static uint32_t questLogQuestIdsCount = 0;
static uint32_t *GetQuestLogEntryCountPtr() {
return reinterpret_cast<uint32_t *>(Offsets::QuestLogEntryCount);
@@ -31,14 +35,18 @@ namespace Nampower {
return reinterpret_cast<QuestLogEntryRaw *>(Offsets::QuestLogEntries);
}
static int32_t GetQuestDialogStateCode() {
return *reinterpret_cast<int32_t *>(Offsets::QuestDialogState);
static QuestDialogKind GetQuestDialogStateCode() {
auto const raw = *reinterpret_cast<uint32_t *>(Offsets::QuestDialogState);
if (raw == 0 || raw > static_cast<uint32_t>(QuestDialogKind::COMPLETE)) {
return QuestDialogKind::UNKNOWN;
}
return static_cast<QuestDialogKind>(raw);
}
static uint32_t GetQuestDialogQuestIdRaw() {
auto const state = GetQuestDialogStateCode();
if (state < static_cast<int32_t>(QuestDialogKind::DETAIL) ||
state > static_cast<int32_t>(QuestDialogKind::COMPLETE)) {
if (state == QuestDialogKind::UNKNOWN) {
return 0;
}
@@ -49,10 +57,27 @@ namespace Nampower {
uint32_t Script_GetQuestLogQuestIds(uintptr_t *luaState) {
luaState = GetLuaStatePtr();
lua_newtable(luaState);
bool useCopy = false;
if (lua_isnumber(luaState, 1)) {
useCopy = static_cast<int>(lua_tonumber(luaState, 1)) != 0;
}
if (useCopy) {
lua_newtable(luaState);
} else {
GetTableRef(luaState, questLogQuestIdsTableRef);
}
auto const rowCount = *GetQuestLogEntryCountPtr();
if (rowCount == 0 || rowCount > kQuestLogMaxRows) {
if (!useCopy && questLogQuestIdsCount != 0) {
for (uint32_t i = 1; i <= questLogQuestIdsCount; ++i) {
lua_pushnumber(luaState, static_cast<double>(i));
lua_pushnil(luaState);
lua_settable(luaState, -3);
}
questLogQuestIdsCount = 0;
}
return 1;
}
@@ -71,6 +96,16 @@ namespace Nampower {
++outIndex;
}
auto const currentCount = static_cast<uint32_t>(outIndex - 1);
if (!useCopy) {
for (uint32_t i = currentCount + 1; i <= questLogQuestIdsCount; ++i) {
lua_pushnumber(luaState, static_cast<double>(i));
lua_pushnil(luaState);
lua_settable(luaState, -3);
}
questLogQuestIdsCount = currentCount;
}
return 1;
}