mirror of
https://github.com/brues-code/nampower.git
synced 2026-09-22 15:36:56 +00:00
refactor and make DisenchantAll default to ignoring soulbound
This commit is contained in:
+11
-7
@@ -930,13 +930,15 @@ Will stop channeling early on the next tick if you have queue channeling spells
|
||||
|
||||
### Utility Functions
|
||||
|
||||
#### DisenchantAll(itemIdOrName) or DisenchantAll(quality)
|
||||
#### DisenchantAll(itemIdOrName, [includeSoulbound]) or DisenchantAll(quality, [includeSoulbound])
|
||||
Automatically disenchants items in your inventory. Can disenchant a specific item by ID/name, or all weapons and armor of a specified quality.
|
||||
|
||||
**⚠️ WARNING ⚠️**
|
||||
**THIS FUNCTION WILL AUTOMATICALLY DISENCHANT ITEMS WITHOUT CONFIRMATION!**
|
||||
- **Use at your own risk** - there is no undo for disenchanting
|
||||
- Only disenchants items from **player inventory bags (0-4)** - does NOT touch bank items
|
||||
- **Quest items are ALWAYS protected** regardless of settings
|
||||
- **Soulbound items are protected by default** (can be overridden with optional parameter)
|
||||
- Make sure you have the Disenchant spell and the items are disenchantable before using
|
||||
- **Always double-check your bags** before running this command
|
||||
|
||||
@@ -946,12 +948,14 @@ Automatically disenchants items in your inventory. Can disenchant a specific ite
|
||||
- `itemIdOrName` (number|string): Item ID (number) or item name (string)
|
||||
- Disenchants all copies of the specified item found in your bags
|
||||
- Works on any disenchantable item type (weapons, armor, etc.)
|
||||
- `includeSoulbound` (number, optional): Pass any non-zero value (e.g., `1`) to include soulbound items (defaults to `0`)
|
||||
|
||||
**Mode 2: Disenchant by Quality** *(weapons and armor only)*
|
||||
- `quality` (string): Must be either:
|
||||
- `"greens"` - Disenchants all uncommon (green) quality weapons and armor
|
||||
- `"blues"` - Disenchants all rare (blue) quality weapons and armor
|
||||
- Only affects **weapons** (class 2) and **armor** (class 4)
|
||||
- `includeSoulbound` (number, optional): Pass any non-zero value (e.g., `1`) to include soulbound items (defaults to `0`)
|
||||
|
||||
**Returns:**
|
||||
- `1` if the first disenchant succeeded
|
||||
@@ -966,17 +970,17 @@ Automatically disenchants items in your inventory. Can disenchant a specific ite
|
||||
|
||||
**Examples:**
|
||||
```lua
|
||||
-- Disenchant all green weapons and armor in your bags
|
||||
-- Disenchant all green weapons and armor in your bags (excluding soulbound)
|
||||
DisenchantAll("greens")
|
||||
|
||||
-- Disenchant all blue weapons and armor in your bags
|
||||
DisenchantAll("blues")
|
||||
-- Disenchant all blue weapons and armor including soulbound items
|
||||
DisenchantAll("blues", 1)
|
||||
|
||||
-- Disenchant a specific item by ID
|
||||
-- Disenchant a specific item by ID (excluding soulbound)
|
||||
DisenchantAll(12345)
|
||||
|
||||
-- Disenchant a specific item by name
|
||||
DisenchantAll("Glowing Brightwood Staff")
|
||||
-- Disenchant a specific item by name including soulbound items
|
||||
DisenchantAll("Glowing Brightwood Staff", 1)
|
||||
```
|
||||
|
||||
**Important Notes:**
|
||||
|
||||
+8690
-8687
File diff suppressed because it is too large
Load Diff
+14
-1
@@ -217,7 +217,7 @@ namespace Nampower {
|
||||
return result;
|
||||
}
|
||||
|
||||
PlayerItemSearchResult FindPlayerDisenchantItem(int32_t quality) {
|
||||
PlayerItemSearchResult FindPlayerDisenchantItem(int32_t quality, bool includeSoulbound) {
|
||||
PlayerItemSearchResult result{};
|
||||
|
||||
auto const getBagItem = reinterpret_cast<CGBag_C_GetItemAtSlotT>(Offsets::CGBag_C_GetItemAtSlot);
|
||||
@@ -231,6 +231,9 @@ namespace Nampower {
|
||||
|
||||
auto inventory = game::GetPlayerInventoryPtr(playerUnit);
|
||||
|
||||
auto const itemIsQuestOrSoulbound = reinterpret_cast<CGItem_C_ItemIsQuestOrSoulboundT>(
|
||||
Offsets::CGItem_C_ItemIsQuestOrSoulbound);
|
||||
|
||||
auto matchesItem = [&](game::CGItem_C *item) {
|
||||
if (!item) {
|
||||
return false;
|
||||
@@ -242,6 +245,16 @@ namespace Nampower {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Always skip quest items (check by class or startQuestID)
|
||||
if (itemStats->m_class == game::ITEM_CLASS_QUEST || itemStats->m_startQuestID > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip soulbound items only if includeSoulbound is false
|
||||
if (!includeSoulbound && itemIsQuestOrSoulbound(item)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if item is weapon or armor
|
||||
if (itemStats->m_class != game::ITEM_CLASS_WEAPON &&
|
||||
itemStats->m_class != game::ITEM_CLASS_ARMOR) {
|
||||
|
||||
+2
-1
@@ -13,6 +13,7 @@ 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);
|
||||
using CGItem_C_ItemIsQuestOrSoulboundT = uint32_t (__fastcall *)(game::CGItem_C *item);
|
||||
|
||||
constexpr int32_t EQUIPPED_BAG_INDEX = -3;
|
||||
constexpr int32_t BANK_BAG_INDEX = -1;
|
||||
@@ -100,7 +101,7 @@ namespace Nampower {
|
||||
void CacheItemNameToId(const char *itemName, uint32_t itemId);
|
||||
bool DoesItemMatch(uint32_t itemId, uint32_t searchItemId, const char *searchItemName);
|
||||
PlayerItemSearchResult FindPlayerItem(uint32_t searchItemId, const char *searchItemName);
|
||||
PlayerItemSearchResult FindPlayerDisenchantItem(int32_t quality);
|
||||
PlayerItemSearchResult FindPlayerDisenchantItem(int32_t quality, bool includeSoulbound = false);
|
||||
uintptr_t *GetBagPtrFromContainer(uintptr_t *containerPtr);
|
||||
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ namespace Nampower {
|
||||
|
||||
uint32_t gDisenchantItemId = 0;
|
||||
int32_t gDisenchantQuality = -1; // -1 = unset
|
||||
bool gDisenchantIncludeSoulbound = false;
|
||||
uint32_t gNextDisenchantTimeMs = 0;
|
||||
|
||||
bool gForceQueueCast;
|
||||
@@ -370,6 +371,13 @@ namespace Nampower {
|
||||
gCastData.targetingSpellId = 0;
|
||||
}
|
||||
|
||||
void ResetDisenchantState() {
|
||||
gDisenchantItemId = 0;
|
||||
gDisenchantQuality = -1;
|
||||
gDisenchantIncludeSoulbound = false;
|
||||
gNextDisenchantTimeMs = 0;
|
||||
}
|
||||
|
||||
void checkForStopChanneling() {
|
||||
if (gUserSettings.queueChannelingSpells && IsNonSwingSpellQueued()) {
|
||||
// for channels just end channeling
|
||||
|
||||
+5
-1
@@ -30,7 +30,7 @@ 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 = 21;
|
||||
constexpr uint32_t MINOR_VERSION = 22;
|
||||
constexpr uint32_t PATCH_VERSION = 0;
|
||||
|
||||
constexpr int32_t LUA_REGISTRYINDEX = -10000;
|
||||
@@ -44,6 +44,7 @@ namespace Nampower {
|
||||
|
||||
extern uint32_t gDisenchantItemId;
|
||||
extern int32_t gDisenchantQuality;
|
||||
extern bool gDisenchantIncludeSoulbound;
|
||||
extern uint32_t gNextDisenchantTimeMs;
|
||||
|
||||
extern bool gForceQueueCast;
|
||||
@@ -203,6 +204,8 @@ namespace Nampower {
|
||||
|
||||
void ClearQueuedSpells();
|
||||
|
||||
void ResetDisenchantState();
|
||||
|
||||
bool processQueues();
|
||||
|
||||
uint32_t EffectiveCastEndMs();
|
||||
@@ -213,4 +216,5 @@ namespace Nampower {
|
||||
|
||||
void SetAttackTarget(uint64_t target);
|
||||
|
||||
|
||||
}
|
||||
|
||||
+17
-18
@@ -614,6 +614,7 @@ namespace Nampower {
|
||||
bool TryDisenchant() {
|
||||
DEBUG_LOG("Trying disenchant with quality filter " << gDisenchantQuality << " itemId " << gDisenchantItemId);
|
||||
if (gDisenchantQuality < 0 && gDisenchantItemId == 0) {
|
||||
ResetDisenchantState();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -624,15 +625,13 @@ namespace Nampower {
|
||||
itemSearchResult = FindPlayerItem(gDisenchantItemId, nullptr);
|
||||
} else {
|
||||
// Quality-based disenchanting (weapons and armor only)
|
||||
itemSearchResult = FindPlayerDisenchantItem(gDisenchantQuality);
|
||||
itemSearchResult = FindPlayerDisenchantItem(gDisenchantQuality, gDisenchantIncludeSoulbound);
|
||||
}
|
||||
|
||||
if (!itemSearchResult.found()) {
|
||||
// Item not found, stop disenchanting
|
||||
DEBUG_LOG("No disenchantable item found, stopping disenchant");
|
||||
gDisenchantItemId = 0;
|
||||
gDisenchantQuality = -1;
|
||||
gNextDisenchantTimeMs = 0;
|
||||
ResetDisenchantState();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -641,9 +640,7 @@ namespace Nampower {
|
||||
if (!item || !item->object.m_obj) {
|
||||
// Invalid item, stop disenchanting
|
||||
DEBUG_LOG("Invalid item, stopping disenchant");
|
||||
gDisenchantItemId = 0;
|
||||
gDisenchantQuality = -1;
|
||||
gNextDisenchantTimeMs = 0;
|
||||
ResetDisenchantState();
|
||||
return false;
|
||||
}
|
||||
uint64_t itemGuid = item->object.m_obj->m_guid;
|
||||
@@ -655,9 +652,7 @@ namespace Nampower {
|
||||
if (!playerUnit) {
|
||||
// No player unit, stop disenchanting
|
||||
DEBUG_LOG("No player unit, stopping disenchant");
|
||||
gDisenchantItemId = 0;
|
||||
gDisenchantQuality = -1;
|
||||
gNextDisenchantTimeMs = 0;
|
||||
ResetDisenchantState();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -672,9 +667,7 @@ namespace Nampower {
|
||||
if (!success) {
|
||||
// Cast failed, stop disenchanting
|
||||
DEBUG_LOG("Cast failed, stopping disenchant");
|
||||
gDisenchantItemId = 0;
|
||||
gDisenchantQuality = -1;
|
||||
gNextDisenchantTimeMs = 0;
|
||||
ResetDisenchantState();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -685,9 +678,10 @@ namespace Nampower {
|
||||
luaState = GetLuaStatePtr();
|
||||
|
||||
if (!lua_isnumber(luaState, 1) && !lua_isstring(luaState, 1)) {
|
||||
lua_error(luaState, "Usage: DisenchantAll(itemIdOrName) or DisenchantAll(quality)\n"
|
||||
lua_error(luaState, "Usage: DisenchantAll(itemIdOrName, [includeSoulbound]) or DisenchantAll(quality, [includeSoulbound])\n"
|
||||
"quality: \"greens\" for uncommon, \"blues\" for rare\n"
|
||||
"itemIdOrName: item ID (number) or item name (string)");
|
||||
"itemIdOrName: item ID (number) or item name (string)\n"
|
||||
"includeSoulbound: optional number - pass 1 to include soulbound items (defaults to 0)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -707,9 +701,8 @@ namespace Nampower {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reset both modes
|
||||
gDisenchantItemId = 0;
|
||||
gDisenchantQuality = -1;
|
||||
// Reset all modes
|
||||
ResetDisenchantState();
|
||||
|
||||
// Check number first (lua_isstring will also match numbers)
|
||||
if (lua_isnumber(luaState, 1)) {
|
||||
@@ -743,6 +736,12 @@ namespace Nampower {
|
||||
}
|
||||
}
|
||||
|
||||
// Parse optional includeSoulbound parameter (defaults to false)
|
||||
// Any non-zero integer enables it
|
||||
if (lua_isnumber(luaState, 2)) {
|
||||
gDisenchantIncludeSoulbound = (lua_tonumber(luaState, 2) != 0);
|
||||
}
|
||||
|
||||
// Try the first disenchant
|
||||
bool success = TryDisenchant();
|
||||
|
||||
|
||||
@@ -206,6 +206,7 @@ enum class Offsets : std::uint32_t {
|
||||
|
||||
CGItem_C_Use = 0x005D8D00,
|
||||
CGItem_C_GetInventoryArt = 0x005D88B0,
|
||||
CGItem_C_ItemIsQuestOrSoulbound = 0x005DA2C0,
|
||||
|
||||
DBCache_ItemCacheDBGetRow = 0x0055BA30,
|
||||
|
||||
|
||||
@@ -55,9 +55,7 @@ namespace Nampower {
|
||||
// Check for Disenchant (13262) failure and stop the disenchant loop
|
||||
if (spellId == 13262) {
|
||||
DEBUG_LOG("Disenchant spell failed with result " << int(spellResult) << ", stopping disenchant loop");
|
||||
gDisenchantItemId = 0;
|
||||
gDisenchantQuality = -1;
|
||||
gNextDisenchantTimeMs = 0;
|
||||
ResetDisenchantState();
|
||||
}
|
||||
|
||||
// ignore SPELL_FAILED_CANT_DO_THAT_YET for arcane surge gets sent all the time after success
|
||||
@@ -714,4 +712,4 @@ namespace Nampower {
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user