add new texture functions, fix tooltip/description missing on spellrec

This commit is contained in:
avitasia
2026-02-02 08:49:30 -08:00
parent 701b0a3c98
commit 4e25ef66a2
12 changed files with 11081 additions and 10887 deletions
+8
View File
@@ -75,6 +75,7 @@ Related structs live in `nampower/game.hpp` (notably `SpellRec` and `ItemStats_C
- `castingTimeIndex`
- `channelInterruptFlags`
- `dispel`
- `description` (string, defaults to current language)
- `dmgClass`
- `durationIndex`
- `equippedItemClass`
@@ -87,6 +88,7 @@ Related structs live in `nampower/game.hpp` (notably `SpellRec` and `ItemStats_C
- `manaCostPerlevel`
- `manaPerSecond`
- `manaPerSecondPerLevel`
- `name` (string, defaults to current language)
- `maxAffectedTargets`
- `maxLevel`
- `maxTargetLevel`
@@ -100,6 +102,7 @@ Related structs live in `nampower/game.hpp` (notably `SpellRec` and `ItemStats_C
- `procCharges`
- `procFlags`
- `rangeIndex`
- `rank` (string, defaults to current language)
- `recoveryTime`
- `requiredAuraVision`
- `school`
@@ -118,8 +121,10 @@ Related structs live in `nampower/game.hpp` (notably `SpellRec` and `ItemStats_C
- `targetAuraState`
- `targetCreatureType`
- `targets`
- `tooltip` (string, defaults to current language)
### SpellRec Array Fields (alphabetical)
- `description` (char* x8, one per language)
- `dmgMultiplier`
- `effect`
- `effectAmplitude`
@@ -139,6 +144,9 @@ Related structs live in `nampower/game.hpp` (notably `SpellRec` and `ItemStats_C
- `effectRadiusIndex`
- `effectRealPointsPerLevel`
- `effectTriggerSpell`
- `name` (char* x8, one per language)
- `rank` (char* x8, one per language)
- `reagent`
- `reagentCount`
- `tooltip` (char* x8, one per language)
- `totem`
+44
View File
@@ -26,6 +26,8 @@ For installation, configuration, and general usage information, see the main [RE
- [GetSpellSlotTypeIdForName](#getspellslottypeidfornamenspellname)
- [GetNampowerVersion](#getnampowerversion)
- [GetItemLevel](#getitemlevelitemid)
- [GetItemTexture](#getitemtexturedisplayinfoid)
- [GetSpellTexture](#getspelltexturespelliconid)
- [Spell Casting and Queuing](#spell-casting-and-queuing)
- [QueueSpellByName](#queuespellbynamespellname)
- [CastSpellByNameNoQueue](#castspellbynamenoqueuespellname)
@@ -929,6 +931,48 @@ Examples:
should print 90 for atiesh
```
#### GetItemTexture(displayInfoId)
Returns the texture path for an item given its display info ID. Returns nil if the texture is not found or is the question mark placeholder texture.
**Parameters:**
- `displayInfoId` (number): The item's display info ID (can be obtained from `GetItemStatsField(itemId, "displayInfoID")`)
**Returns:**
- The texture path string (e.g., "Interface\\Icons\\INV_Sword_04"), or nil if not found
**Examples:**
```lua
-- Get texture for an item
local displayInfoId = GetItemStatsField(19019, "displayInfoID")
local texture = GetItemTexture(displayInfoId)
if texture then
print("Texture: " .. texture)
else
print("No texture found")
end
```
#### GetSpellTexture(spellIconId)
Returns the texture path for a spell given its spell icon ID. Returns nil if the texture is not found or is the question mark placeholder texture.
**Parameters:**
- `spellIconId` (number): The spell's icon ID (can be obtained from `GetSpellRecField(spellId, "spellIconID")`)
**Returns:**
- The texture path string with `Interface\Icons\` prefix (e.g., "Interface\\Icons\\Spell_Frost_FrostBolt02"), or nil if not found
**Examples:**
```lua
-- Get texture for Frostbolt
local spellIconId = GetSpellRecField(116, "spellIconID")
local texture = GetSpellTexture(spellIconId)
if texture then
print("Texture: " .. texture)
else
print("No texture found")
end
```
#### ChannelStopCastingNextTick()
Will stop channeling early on the next tick if you have queue channeling spells enabled and try to cast a spell before the next tick (didn't know how to cancel channels without casting another spell). Uses your ChannelLatencyReductionPercentage to determine when to stop the channel.
+10923 -10863
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -124,7 +124,7 @@ namespace game {
auto const language = *reinterpret_cast<std::uint32_t *>(Offsets::Language);
return spell->SpellName[language];
return spell->Name[language];
}
std::uint64_t ClntObjMgrGetActivePlayerGuid() {
+4 -4
View File
@@ -192,13 +192,13 @@ namespace game {
unsigned int SpellIconID;
unsigned int activeIconID;
unsigned int spellPriority;
const char *SpellName[8];
const char *Name[8];
unsigned int SpellNameFlag;
unsigned int Rank[8];
const char *Rank[8];
unsigned int RankFlags;
unsigned int Description[8];
const char *Description[8];
unsigned int DescriptionFlags;
unsigned int ToolTip[8];
const char *ToolTip[8];
unsigned int ToolTipFlags;
unsigned int ManaCostPercentage;
unsigned int StartRecoveryCategory;
+1 -1
View File
@@ -74,7 +74,7 @@ namespace Nampower {
}
auto const language = *reinterpret_cast<uint32_t *>(Offsets::Language);
auto const actualName = reinterpret_cast<const char *>(spell->SpellName[language]);
auto const actualName = reinterpret_cast<const char *>(spell->Name[language]);
if (!actualName) {
return false;
}
+6
View File
@@ -1646,6 +1646,12 @@ namespace Nampower {
char disenchantAll[] = "DisenchantAll";
RegisterLuaFunction(disenchantAll, reinterpret_cast<uintptr_t *>(Script_DisenchantAll));
char getItemTexture[] = "GetItemTexture";
RegisterLuaFunction(getItemTexture, reinterpret_cast<uintptr_t *>(Script_GetItemTexture));
char getSpellTexture[] = "GetSpellTexture";
RegisterLuaFunction(getSpellTexture, reinterpret_cast<uintptr_t *>(Script_GetSpellTexture));
}
void load() {
+1 -1
View File
@@ -35,7 +35,7 @@ namespace Nampower {
constexpr uint32_t DISENCHANT_QUALITY_PURPLE = 0x04; // Epic
constexpr uint32_t MAJOR_VERSION = 2;
constexpr uint32_t MINOR_VERSION = 26;
constexpr uint32_t MINOR_VERSION = 27;
constexpr uint32_t PATCH_VERSION = 0;
constexpr int32_t LUA_REGISTRYINDEX = -10000;
+59 -3
View File
@@ -660,9 +660,9 @@ namespace Nampower {
// Display which item is being disenchanted
char luaCode[256];
snprintf(luaCode, sizeof(luaCode),
"local itemLink = GetContainerItemLink(%d, %d); "
"if itemLink then DEFAULT_CHAT_FRAME:AddMessage(\"Disenchanting \" .. itemLink .. \" move during cast to cancel.\") end",
itemSearchResult.bagIndex, itemSearchResult.slot + 1); // Lua slots are 1-indexed
"local itemLink = GetContainerItemLink(%d, %d); "
"if itemLink then DEFAULT_CHAT_FRAME:AddMessage(\"Disenchanting \" .. itemLink .. \" move during cast to cancel.\") end",
itemSearchResult.bagIndex, itemSearchResult.slot + 1); // Lua slots are 1-indexed
LuaCall(luaCode);
// Set timer for next disenchant attempt (5 seconds to allow time for inventory to update)
@@ -785,4 +785,60 @@ namespace Nampower {
return 1;
}
uint32_t Script_GetItemTexture(uintptr_t *luaState) {
luaState = GetLuaStatePtr(); // pcall leads to corrupted lua state pointer on added scripts, not sure why
if (!lua_isnumber(luaState, 1)) {
lua_error(luaState, "Usage: GetItemTexture(displayInfoId)");
return 0;
}
uint32_t displayInfoId = static_cast<uint32_t>(lua_tonumber(luaState, 1));
auto const getInventoryArt = reinterpret_cast<GetInventoryArtT>(Offsets::CGItem_C_GetInventoryArt);
char *texturePath = getInventoryArt(displayInfoId);
if (texturePath && texturePath[0] != '\0' && !strstr(texturePath, "QuestionMark")) {
lua_pushstring(luaState, texturePath);
} else {
lua_pushnil(luaState);
}
return 1;
}
uint32_t Script_GetSpellTexture(uintptr_t *luaState) {
luaState = GetLuaStatePtr(); // pcall leads to corrupted lua state pointer on added scripts, not sure why
if (!lua_isnumber(luaState, 1)) {
lua_error(luaState, "Usage: GetSpellTexture(spellIconId)");
return 0;
}
int32_t iconId = static_cast<int32_t>(lua_tonumber(luaState, 1));
int32_t maxIconId = *reinterpret_cast<int32_t *>(Offsets::SpellIconDBMaxId);
uintptr_t *iconArray = *reinterpret_cast<uintptr_t **>(Offsets::SpellIconDBArray);
if (iconId < 0 || iconId > maxIconId) {
lua_pushnil(luaState);
return 1;
}
uintptr_t iconEntry = reinterpret_cast<uintptr_t *>(iconArray)[iconId];
if (iconEntry == 0) {
lua_pushnil(luaState);
return 1;
}
char *texturePath = *reinterpret_cast<char **>(iconEntry + 4);
if (texturePath && texturePath[0] != '\0' && !strstr(texturePath, "QuestionMark")) {
lua_pushstring(luaState, texturePath);
} else {
lua_pushnil(luaState);
}
return 1;
}
}
+4
View File
@@ -34,5 +34,9 @@ namespace Nampower {
uint32_t Script_DisenchantAll(uintptr_t *luaState);
uint32_t Script_GetItemTexture(uintptr_t *luaState);
uint32_t Script_GetSpellTexture(uintptr_t *luaState);
bool RunQueuedScript(int priority);
}
+3
View File
@@ -215,6 +215,9 @@ enum class Offsets : std::uint32_t {
CGItem_C_GetInventoryArt = 0x005D88B0,
CGItem_C_ItemIsQuestOrSoulbound = 0x005DA2C0,
SpellIconDBMaxId = 0x00c0d7f0,
SpellIconDBArray = 0x00c0d7ec,
DBCache_ItemCacheDBGetRow = 0x0055BA30,
InvalidFunctionPtrCheck = 0x0042A320,
+27 -14
View File
@@ -204,7 +204,7 @@ namespace Nampower {
if (spell) {
auto const language = *reinterpret_cast<std::uint32_t *>(Offsets::Language);
lua_pushstring(luaState, (char *) spell->SpellName[language]);
lua_pushstring(luaState, (char *) spell->Name[language]);
lua_pushstring(luaState, (char *) spell->Rank[language]);
return 2;
} else {
@@ -306,12 +306,17 @@ namespace Nampower {
// Push string fields manually (require language)
auto const language = *reinterpret_cast<uint32_t *>(Offsets::Language);
PushTableValue(luaState, const_cast<char *>("name"),
spell->SpellName[language] ? const_cast<char *>(spell->SpellName[language])
: const_cast<char *>(""));
spell->Name[language] ? const_cast<char *>(spell->Name[language])
: const_cast<char *>(""));
PushTableValue(luaState, const_cast<char *>("rank"),
reinterpret_cast<const char *>(spell->Rank[language])
? const_cast<char *>(reinterpret_cast<const char *>(spell->Rank[language]))
: const_cast<char *>(""));
spell->Rank[language] ? const_cast<char *>(spell->Rank[language])
: const_cast<char *>(""));
PushTableValue(luaState, const_cast<char *>("description"),
spell->Description[language] ? const_cast<char *>(spell->Description[language])
: const_cast<char *>(""));
PushTableValue(luaState, const_cast<char *>("tooltip"),
spell->ToolTip[language] ? const_cast<char *>(spell->ToolTip[language])
: const_cast<char *>(""));
// Push all array fields using descriptors with or without references based on copy parameter
if (useCopy) {
@@ -420,18 +425,26 @@ namespace Nampower {
return 1;
}
// Check for special string fields
// Check for special string fields (localized, need language index)
auto const language = *reinterpret_cast<uint32_t *>(Offsets::Language);
if (strcmp(fieldName, "name") == 0) {
auto const language = *reinterpret_cast<uint32_t *>(Offsets::Language);
lua_pushstring(luaState, spell->SpellName[language] ? const_cast<char *>(spell->SpellName[language])
: const_cast<char *>(""));
lua_pushstring(luaState, spell->Name[language] ? const_cast<char *>(spell->Name[language])
: const_cast<char *>(""));
return 1;
}
if (strcmp(fieldName, "rank") == 0) {
auto const language = *reinterpret_cast<uint32_t *>(Offsets::Language);
lua_pushstring(luaState, reinterpret_cast<const char *>(spell->Rank[language])
? const_cast<char *>(reinterpret_cast<const char *>(spell->Rank[language]))
: const_cast<char *>(""));
lua_pushstring(luaState, spell->Rank[language] ? const_cast<char *>(spell->Rank[language])
: const_cast<char *>(""));
return 1;
}
if (strcmp(fieldName, "description") == 0) {
lua_pushstring(luaState, spell->Description[language] ? const_cast<char *>(spell->Description[language])
: const_cast<char *>(""));
return 1;
}
if (strcmp(fieldName, "tooltip") == 0) {
lua_pushstring(luaState, spell->ToolTip[language] ? const_cast<char *>(spell->ToolTip[language])
: const_cast<char *>(""));
return 1;
}