This commit is contained in:
DuvelCorp
2026-02-27 18:57:24 +01:00
parent ee8328e903
commit 2c94650993
85 changed files with 30197 additions and 820 deletions
+116 -96
View File
@@ -446,6 +446,120 @@ local function AB_ResolveAmmoByName(name)
return row.itemId, row.subtype
end
local function AB_GetInventoryBagSlotByContainerId(containerId)
local toInv = _G and _G["ContainerIDToInventoryID"] or nil
if type(toInv) == "function" then
local invSlot = tonumber(toInv(containerId))
if invSlot and invSlot > 0 then
return invSlot
end
end
local bag = tonumber(containerId)
if bag and bag >= 1 and bag <= 4 then
return bag + 19
end
return nil
end
local function AB_GetSpecialAmmoBagTargets()
local targets = {
arrow = {},
bullet = {},
}
local getInvLink = _G and _G["GetInventoryItemLink"] or nil
if type(getInvLink) ~= "function" then
return targets
end
for bag = 1, 4 do
local invSlot = AB_GetInventoryBagSlotByContainerId(bag)
if invSlot then
local bagLink = getInvLink("player", invSlot)
local bagItemId = AB_ParseItemIdFromLink(bagLink)
local bagRow = (MTH_DS_BagItems and bagItemId) and MTH_DS_BagItems[tonumber(bagItemId) or bagItemId] or nil
local bagSubtype = bagRow and string.lower(tostring(bagRow.subtype or "")) or ""
if bagSubtype == "quiver" then
table.insert(targets.arrow, { bag = bag, invSlot = invSlot, itemId = bagItemId, subtype = bagSubtype })
elseif bagSubtype == "ammo pouch" then
table.insert(targets.bullet, { bag = bag, invSlot = invSlot, itemId = bagItemId, subtype = bagSubtype })
end
end
end
return targets
end
local function AB_MoveAmmoStacksToSpecialBags(maxMoves)
local getSlots = _G and _G["GetContainerNumSlots"] or nil
local getLink = _G and _G["GetContainerItemLink"] or nil
local pick = _G and _G["PickupContainerItem"] or nil
local putInBag = _G and _G["PutItemInBag"] or nil
local hasCursor = _G and _G["CursorHasItem"] or nil
local clearCursor = _G and _G["ClearCursor"] or nil
if type(getSlots) ~= "function" or type(getLink) ~= "function"
or type(pick) ~= "function" or type(putInBag) ~= "function"
or type(hasCursor) ~= "function" or type(clearCursor) ~= "function" then
return 0
end
local targets = AB_GetSpecialAmmoBagTargets()
local arrowTargets = targets.arrow or {}
local bulletTargets = targets.bullet or {}
if table.getn(arrowTargets) == 0 and table.getn(bulletTargets) == 0 then
return 0
end
local moves = 0
local moveLimit = math.floor(tonumber(maxMoves) or 200)
if moveLimit < 1 then moveLimit = 200 end
local isTargetBag = {}
for i = 1, table.getn(arrowTargets) do
local bagId = tonumber(arrowTargets[i].bag)
if bagId then
isTargetBag[bagId] = true
end
end
for i = 1, table.getn(bulletTargets) do
local bagId = tonumber(bulletTargets[i].bag)
if bagId then
isTargetBag[bagId] = true
end
end
for sourceBag = 0, 4 do
local isSpecialSource = isTargetBag[tonumber(sourceBag)] and true or false
if not isSpecialSource then
local slots = tonumber(getSlots(sourceBag)) or 0
for sourceSlot = 1, slots do
local link = getLink(sourceBag, sourceSlot)
local itemId = AB_ParseItemIdFromLink(link)
local ammoSubtype = itemId and AB_GetAmmoSubtypeByItemId(itemId) or nil
if ammoSubtype then
local destinationTargets = ammoSubtype == "arrow" and arrowTargets or bulletTargets
if table.getn(destinationTargets) > 0 then
pick(sourceBag, sourceSlot)
if hasCursor() then
for i = 1, table.getn(destinationTargets) do
putInBag(destinationTargets[i].invSlot)
if not hasCursor() then
moves = moves + 1
break
end
end
if hasCursor() then
clearCursor()
end
if moves >= moveLimit then
return moves
end
end
end
end
end
end
end
return moves
end
local function AB_DefaultRule()
return {
enabled = false,
@@ -475,16 +589,6 @@ local function AB_EnsureRuleList(bucket)
return bucket
end
local function AB_Log(message, severity)
if type(MTH_Log) == "function" then
MTH_Log("[AutoBuy] " .. tostring(message or ""), severity)
end
end
local function AB_Trace(message)
return
end
function Engine:GetConfigStore()
if MTH and MTH.GetModuleSavedVariables then
local store = MTH:GetModuleSavedVariables("autobuy")
@@ -501,9 +605,6 @@ function Engine:EnsureDefaults()
if store.enabled == nil then
store.enabled = true
end
if store.debug == nil then
store.debug = false
end
if type(store.food) ~= "table" then
store.food = {}
end
@@ -607,30 +708,8 @@ function Engine:IsEnabled()
return store.enabled and true or false
end
function Engine:IsDebugEnabled()
local store = self:EnsureDefaults()
return store.debug and true or false
end
function Engine:IsTraceEnabled()
if self:IsDebugEnabled() then
return true
end
if MTH and MTH.debug then
return true
end
return false
end
function Engine:Debug(message)
if self:IsTraceEnabled() then
AB_Log(message, "debug")
end
end
function Engine:Init()
self:EnsureDefaults()
self:Debug("engine initialized")
end
function Engine:ScanMerchant()
@@ -1152,92 +1231,34 @@ end
function Engine:OnMerchantEvent(eventName)
if eventName == "MERCHANT_SHOW" then
self._merchantSessionExecuted = false
AB_Trace("merchant session reset on MERCHANT_SHOW")
elseif eventName == "MERCHANT_UPDATE" and self._merchantSessionExecuted then
AB_Trace("skip MERCHANT_UPDATE: session already executed")
return
end
self:Debug("OnMerchantEvent enter event=" .. tostring(eventName))
AB_Trace("OnMerchantEvent " .. tostring(eventName))
if not self:IsEnabled() then
self:Debug("OnMerchantEvent abort: engine store disabled")
local store = self:EnsureDefaults()
AB_Trace("abort: store.enabled=" .. tostring(store and store.enabled)
.. " projectiles.enabled=" .. tostring(store and store.projectiles and store.projectiles.enabled))
return
end
local snapshot = self:ScanMerchant()
self:Debug("snapshot count=" .. tostring(snapshot and snapshot.count or 0))
AB_Trace("merchant item count=" .. tostring(snapshot and snapshot.count or 0))
local foodPlan = self:BuildFoodPlan(snapshot)
local ammoPlan = self:BuildAmmoPlan(snapshot)
self:Debug(tostring(eventName) .. " merchant items=" .. tostring(snapshot.count)
.. " foodActions=" .. tostring(table.getn(foodPlan.actions or {}))
.. " ammoActions=" .. tostring(table.getn(ammoPlan.actions or {})))
self:Debug("ammoPlan reason=" .. tostring(ammoPlan.reason or ""))
AB_Trace("ammoPlan reason=" .. tostring(ammoPlan.reason or "")
.. " actions=" .. tostring(table.getn(ammoPlan.actions or {})))
AB_Trace("foodPlan reason=" .. tostring(foodPlan.reason or "")
.. " actions=" .. tostring(table.getn(foodPlan.actions or {})))
for i = 1, table.getn(foodPlan.debugLines or {}) do
self:Debug("foodPlan " .. tostring(foodPlan.debugLines[i]))
end
for i = 1, table.getn(ammoPlan.debugLines or {}) do
self:Debug("ammoPlan " .. tostring(ammoPlan.debugLines[i]))
end
local totalRequestedStacks = 0
if table.getn(foodPlan.actions or {}) > 0 then
for i = 1, table.getn(foodPlan.actions or {}) do
local action = foodPlan.actions[i]
self:Debug("food action#" .. tostring(i)
.. " idx=" .. tostring(action.index)
.. " item=" .. tostring(action.itemId)
.. " diet=" .. tostring(action.diet)
.. " qtyStacks=" .. tostring(action.quantityStacks)
.. " targetStacks=" .. tostring(action.targetStacks)
.. " ownedStacks=" .. tostring(action.ownedStacks)
.. " deficit=" .. tostring(action.deficit)
.. " pets=" .. tostring(action.petCount)
.. " families=" .. tostring(action.familyCount))
end
local _, requestedStacks = self:ExecutePlan(foodPlan)
totalRequestedStacks = totalRequestedStacks + requestedStacks
AB_Trace("executed food requestedStacks=" .. tostring(requestedStacks))
if requestedStacks > 0 then
AB_AnnouncePurchases(foodPlan.actions)
end
else
self:Debug("no food actions to execute")
AB_Trace("no food actions to execute")
end
if table.getn(ammoPlan.actions or {}) > 0 then
for i = 1, table.getn(ammoPlan.actions or {}) do
local action = ammoPlan.actions[i]
self:Debug("action#" .. tostring(i)
.. " idx=" .. tostring(action.index)
.. " item=" .. tostring(action.itemId)
.. " qtyStacks=" .. tostring(action.quantityStacks)
.. " qtyItems=" .. tostring(action.quantityItems)
.. " desiredStacks=" .. tostring(action.desiredStacks)
.. " ownedStacks=" .. tostring(action.ownedStacks)
.. " deficit=" .. tostring(action.deficit)
.. " stackCount=" .. tostring(action.stackCount))
end
local executedActions, requestedStacks = self:ExecutePlan(ammoPlan)
local _, requestedStacks = self:ExecutePlan(ammoPlan)
totalRequestedStacks = totalRequestedStacks + requestedStacks
AB_Trace("executed actions=" .. tostring(executedActions) .. " requestedStacks=" .. tostring(requestedStacks))
if requestedStacks > 0 then
AB_MoveAmmoStacksToSpecialBags(300)
AB_AnnouncePurchases(ammoPlan.actions)
end
self:Debug("executed ammo actions=" .. tostring(table.getn(ammoPlan.actions or {})))
else
self:Debug("no ammo actions to execute")
AB_Trace("no actions to execute")
end
if totalRequestedStacks > 0 then
@@ -1247,7 +1268,6 @@ end
function Engine:OnMerchantClosed()
self._merchantSessionExecuted = false
AB_Trace("merchant session reset on MERCHANT_CLOSED")
end
function MTH_AutoBuy_GetMerchantSnapshot()
+1 -1
View File
@@ -6,7 +6,7 @@
local MTH_AutoBuy = {
name = "autobuy",
enabled = false,
version = "1.0.3",
version = "1.0.4",
events = {
"VARIABLES_LOADED",
"MERCHANT_SHOW",
+7
View File
@@ -47,6 +47,13 @@ function MTH_ChronometerHunterInstallData(engine)
engine:AddTimer(engine.EVENT, BS["Piercing Shot"], 8, 1, 0, 1, { a = 1, cr = "PURPLE", tx = "Interface\\Icons\\Ability_Hunter_DisarmingShot" })
engine:AddTimer(engine.EVENT, BS["Quick Shots"], 12, 0, 1, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\Ability_Hunter_Quickshot" })
engine:AddTimer(engine.EVENT, BS["Scorpid Poison"], 10, 1, 0, 0, { gr = 3, cr = "PURPLE", a = 1, dn = 1 })
engine:AddTimer(engine.EVENT, BS["Devilsaur Fury"], 20, 0, 1, 1, { a = 1, cr = "PURPLE", xn = BS["Devilsaur Eye"], tx = "Interface\\Icons\\Ability_Hunter_Pet_Raptor" })
engine:AddTimer(engine.EVENT, BS["Restless Strength"], 20, 0, 1, 1, { a = 1, cr = "PURPLE", xn = BS["Zandalarian Hero Medallion"], tx = "Interface\\Icons\\INV_Jewelry_Necklace_13" })
engine:AddTimer(engine.EVENT, BS["Earthstrike"], 20, 0, 1, 1, { a = 1, cr = "PURPLE", tx = "Interface\\Icons\\Spell_Nature_AbolishMagic" })
engine:AddTimer(engine.EVENT, BS["Badge of the Swarmguard"], 30, 0, 1, 1, { a = 1, cr = "PURPLE", tx = "Interface\\Icons\\INV_Misc_AhnQirajTrinket_04" })
engine:AddTimer(engine.EVENT, BS["Jom Gabbar"], 20, 0, 1, 1, { a = 1, cr = "PURPLE", tx = "Interface\\Icons\\Ability_Poisons" })
engine:AddTimer(engine.EVENT, BS["Kiss of the Spider"], 15, 0, 1, 1, { a = 1, cr = "PURPLE", tx = "Interface\\Icons\\INV_Trinket_Naxxramas04" })
engine:AddTimer(engine.EVENT, BS["Slayer's Crest"], 20, 0, 1, 1, { a = 1, cr = "PURPLE", tx = "Interface\\Icons\\INV_Trinket_Naxxramas03" })
end
local _, race = UnitRace("player")
+1 -1
View File
@@ -1,7 +1,7 @@
local MTH_ChronometerModule = {
name = "chronometer",
enabled = true,
version = "1.0.3",
version = "1.0.4",
events = {},
initialized = false,
}
+5 -7
View File
@@ -4,8 +4,6 @@
FOM_VERSION = "11200.2";
------------------------------------------------------
-- TODO: if you don't auto-feed, have an option to make the need to feed more noticeable (e.g., pulsing halo around the pet-happiness icon).
-- constants
FOM_WARNING_INTERVAL = 10; -- don't warn more than once per this many seconds
MAX_QUALITY = 35 * 60 + 1; -- We store a notion of a food's "quality": its best happiness-per-tick multiplied by the pet's level as of when that tick occurred. We use "best" because a pet that's closer to "sated" (maximum happiness) will receive less happiness per tick than he would from the same food if he were hungrier. (So, a food that gives 35 happiness per tick to a level 60 pet is "better" than a food that's worth 35 happiness per tick to a level 30 pet.) Foods whose quality hasn't been observed yet are given this value when sorting, so we can prioritize the discovery of new foods' quality ratings.
@@ -366,9 +364,7 @@ function MTH_GetMerchantFoodsByDiet()
end
local function FOM_DebugLog(message)
if (type(MTH_Log) == "function") then
MTH_Log("[FeedOMatic] " .. tostring(message or ""), "debug");
end
return;
end
local function FOM_DebugLogMerchantFoods(sourceEvent)
@@ -1551,8 +1547,10 @@ function FOM_CheckHappiness()
else
msg = FOM_PET_VERY_HUNGRY;
end
GFWUtils.Print(string.format(msg, pet));
GFWUtils.Note(string.format(msg, pet));
if (not (MTH and MTH.IsMessageEnabled) or MTH:IsMessageEnabled("petHungry", false)) then
GFWUtils.Print(string.format(msg, pet));
GFWUtils.Note(string.format(msg, pet));
end
end
FOM_PlayHungrySound();
FOM_LastWarning = GetTime();
+1 -1
View File
@@ -6,7 +6,7 @@
local MTH_FeedOMatic = {
name = "feedomatic",
enabled = false,
version = "1.0.3",
version = "1.0.4",
events = {
"VARIABLES_LOADED",
"MERCHANT_SHOW",
+146 -44
View File
@@ -15,7 +15,10 @@ local function MTHSmartAmmo_IsSmartEnabled()
return moduleStore.smartEnabled and true or false
end
local saved = MTHSmartAmmo_GetSaved()
return saved["enabled"]
if saved["enabled"] == nil then
return true
end
return saved["enabled"] and true or false
end
local function MTHSmartAmmo_IsReloadEnabled()
@@ -30,6 +33,18 @@ local function MTHSmartAmmo_IsReloadEnabled()
return saved["reload"] and true or false
end
local function MTHSmartAmmo_IsWeaponSwapEnabled()
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" and moduleStore.weaponSwapEnabled ~= nil then
return moduleStore.weaponSwapEnabled and true or false
end
local saved = MTHSmartAmmo_GetSaved()
if saved["weaponSwap"] == nil then
return true
end
return saved["weaponSwap"] and true or false
end
local MTHSmartAmmo_InitializeHooks
MTHSmartAmmo_EnsureHooks = nil
@@ -83,8 +98,24 @@ function MTHSmartAmmo_GetReloadEnabled()
return MTHSmartAmmo_IsReloadEnabled() and true or false
end
local function MTHSmartAmmo_Log(msg)
return
function MTHSmartAmmo_SetWeaponSwapEnabled(enabled, silent)
local saved = MTHSmartAmmo_GetSaved()
if enabled then
saved["weaponSwap"] = 1
else
saved["weaponSwap"] = false
end
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" then
moduleStore.weaponSwapEnabled = enabled and true or false
end
if not silent and DEFAULT_CHAT_FRAME then
MTH_SA_Print("Smart Ammo weapon-swap auto-equip " .. (enabled and "Enabled." or "Disabled."))
end
end
function MTHSmartAmmo_GetWeaponSwapEnabled()
return MTHSmartAmmo_IsWeaponSwapEnabled() and true or false
end
local MTHSmartAmmo_CastSpell_Hook
@@ -142,6 +173,10 @@ MTH_SA_Quantity = 0
MTH_SA_LastFallbackAttempt = 0
MTH_SA_LastKnownEquippedName = nil
MTH_SA_LastFallbackNotice = { key = nil, time = 0 }
MTH_SA_LastKnownWeaponAmmoType = nil
MTH_SA_LastWeaponCheck = 0
MTH_SA_StartupProtectUntil = (GetTime() or 0) + 2.0
MTH_SA_StartupPrimed = nil
local function MTHSmartAmmo_RefreshAmmoButtonDisplay()
local createButtons = getglobal("zButtonAmmo_CreateButtons")
@@ -211,6 +246,10 @@ local function MTHSmartAmmo_HandleFallbackResult(previousAmmo)
end
local function MTHSmartAmmo_TryFallbackEquip(reason)
local now = GetTime() or 0
if now < (MTH_SA_StartupProtectUntil or 0) then
return
end
if not MTH_SA_IsModuleEnabled() then
return
end
@@ -224,20 +263,107 @@ local function MTHSmartAmmo_TryFallbackEquip(reason)
return
end
local now = GetTime() or 0
now = GetTime() or 0
if MTH_SA_LastFallbackAttempt and (now - MTH_SA_LastFallbackAttempt) < 0.5 then
return
end
MTH_SA_LastFallbackAttempt = now
local previousAmmo = MTH_SA_GetEquippedAmmoName() or MTH_SA_LastKnownEquippedName
MTHSmartAmmo_Log("Fallback equip attempt reason=" .. tostring(reason or "unknown"))
if MTH_SA_Check() or MTH_SA_FindAmmo() then
MTH_SA_EquipAmmo()
MTHSmartAmmo_HandleFallbackResult(previousAmmo)
end
end
local function MTHSmartAmmo_FindBestAmmoForType(ammoType)
if not ammoType then
return nil
end
local rankMap = (ammoType == "Bullets" and MTH_AMMO_BULLET_RANK) or MTH_AMMO_ARROW_RANK or {}
local best = nil
for bag = 4, 0, -1 do
for slot = GetContainerNumSlots(bag), 1, -1 do
local itemName = MTH_SA_GetContainerItemName(bag, slot)
if itemName then
local value = rankMap[itemName]
if value and (not best or value > best.value) then
best = {
name = itemName,
value = value,
bag = bag,
slot = slot,
}
end
end
end
end
return best
end
local function MTHSmartAmmo_EquipAmmoFromSlot(bag, slot)
if not bag or not slot then
return false
end
PickupContainerItem(bag, slot)
if CursorHasItem and CursorHasItem() then
EquipCursorItem(0)
end
if CursorHasItem and CursorHasItem() then
if ClearCursor then
ClearCursor()
end
return false
end
return true
end
local function MTHSmartAmmo_HandleWeaponSwapAutoEquip(reason)
local now = GetTime() or 0
if now < (MTH_SA_StartupProtectUntil or 0) then
return
end
if not MTH_SA_IsModuleEnabled() then
return
end
if not MTHSmartAmmo_IsWeaponSwapEnabled() then
return
end
local weaponAmmoType = MTH_SA_GetEquippedWeaponAmmoType()
if not weaponAmmoType then
MTH_SA_LastKnownWeaponAmmoType = nil
MTH_SA_StartupPrimed = true
return
end
if not MTH_SA_StartupPrimed then
MTH_SA_LastKnownWeaponAmmoType = weaponAmmoType
MTH_SA_StartupPrimed = true
return
end
if MTH_SA_LastKnownWeaponAmmoType == weaponAmmoType then
return
end
MTH_SA_LastKnownWeaponAmmoType = weaponAmmoType
local bestAmmo = MTHSmartAmmo_FindBestAmmoForType(weaponAmmoType)
if not bestAmmo then
return
end
local equippedNow = MTH_SA_GetEquippedAmmoName()
if equippedNow and equippedNow == bestAmmo.name then
return
end
if MTHSmartAmmo_EquipAmmoFromSlot(bestAmmo.bag, bestAmmo.slot) then
MTH_SA_LastKnownEquippedName = bestAmmo.name
MTHSmartAmmo_RefreshAmmoButtonDisplay()
end
end
local frame = CreateFrame("Frame")
frame:RegisterEvent("START_AUTOREPEAT_SPELL")
frame:RegisterEvent("STOP_AUTOREPEAT_SPELL")
@@ -245,6 +371,7 @@ frame:RegisterEvent("SPELLCAST_INTERRUPTED")
frame:RegisterEvent("SPELLCAST_FAILED")
frame:RegisterEvent("SPELLCAST_STOP")
frame:RegisterEvent("SPELLCAST_DELAYED")
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
frame:SetScript("OnEvent", function()
@@ -252,28 +379,28 @@ frame:SetScript("OnEvent", function()
if MTHSmartAmmo_EnsureHooks then
MTHSmartAmmo_EnsureHooks("EVENT:START_AUTOREPEAT_SPELL")
end
local castHook, actionHook, byNameHook = MTHSmartAmmo_AreHooksInstalled()
MTHSmartAmmo_Log("EVENT START_AUTOREPEAT_SPELL smart=" .. tostring(MTHSmartAmmo_IsSmartEnabled()) .. " module=" .. tostring(MTH_SA_IsModuleEnabled()) .. " hooks=" .. tostring(castHook) .. "/" .. tostring(actionHook) .. "/" .. tostring(byNameHook))
MTH_SA_AutoShot = 1
MTHSmartAmmo_TryFallbackEquip("START_AUTOREPEAT_SPELL")
elseif event == "STOP_AUTOREPEAT_SPELL" then
MTHSmartAmmo_Log("EVENT STOP_AUTOREPEAT_SPELL")
MTH_SA_AutoShot = nil
elseif event == "PLAYER_ENTERING_WORLD" then
local now = GetTime() or 0
MTH_SA_StartupProtectUntil = now + 2.0
MTH_SA_StartupPrimed = nil
MTH_SA_LastKnownWeaponAmmoType = MTH_SA_GetEquippedWeaponAmmoType()
MTH_SA_LastKnownEquippedName = MTH_SA_GetEquippedAmmoName()
MTH_SA_LastWeaponCheck = now
elseif event == "SPELLCAST_START" then
--DEFAULT_CHAT_FRAME:AddMessage("SPELLCAST_START ", 0, 1, 1)
elseif event == "SPELLCAST_STOP" or event == "SPELLCAST_FAILED" or event == "SPELLCAST_INTERRUPTED" or event == "SPELLCAST_DELAYED" then
local castHook, actionHook, byNameHook = MTHSmartAmmo_AreHooksInstalled()
MTHSmartAmmo_Log("EVENT " .. tostring(event) .. " waitJunk=" .. tostring(MTH_SA_IsWaitingSwapJunk) .. " waitGood=" .. tostring(MTH_SA_IsWaitingSwapGood) .. " lastSpell=" .. tostring(MTH_SA_LastSpell) .. " smart=" .. tostring(MTHSmartAmmo_IsSmartEnabled()) .. " module=" .. tostring(MTH_SA_IsModuleEnabled()) .. " hooks=" .. tostring(castHook) .. "/" .. tostring(actionHook) .. "/" .. tostring(byNameHook))
if MTH_SA_IsWaitingSwapJunk then
MTHSmartAmmo_Log("EVENT swap request -> JUNK equipped=" .. tostring(MTH_SA_GetEquippedAmmoName()) .. " current=" .. tostring(MTH_SA.curname))
MTH_SA_EquipAmmo(1)
elseif MTH_SA_IsWaitingSwapGood then
MTHSmartAmmo_Log("EVENT swap request -> GOOD equipped=" .. tostring(MTH_SA_GetEquippedAmmoName()) .. " current=" .. tostring(MTH_SA.curname))
MTH_SA_EquipAmmo()
end
MTHSmartAmmo_Log("EVENT clear pending flags")
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
MTH_SA_LastSpell = nil
@@ -298,19 +425,21 @@ frame:SetScript("OnUpdate", function(self, elapsed)
end
if MTH_SA_AmmoLastSwitch and (GetTime()-MTH_SA_AmmoLastSwitch > 0.5) and (MTH_SA_IsWaitingSwapJunk or MTH_SA_IsWaitingSwapGood) then
MTHSmartAmmo_Log("OnUpdate pending swap elapsed>0.5 equipped=" .. tostring(MTH_SA_GetEquippedAmmoName()) .. " waitJunk=" .. tostring(MTH_SA_IsWaitingSwapJunk) .. " waitGood=" .. tostring(MTH_SA_IsWaitingSwapGood))
if MTH_SA_IsWaitingSwapJunk then
MTHSmartAmmo_Log("OnUpdate swap request -> JUNK")
MTH_SA_EquipAmmo(1)
elseif MTH_SA_IsWaitingSwapGood then
MTHSmartAmmo_Log("OnUpdate swap request -> GOOD")
MTH_SA_EquipAmmo()
end
MTHSmartAmmo_Log("OnUpdate clear pending flags")
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
MTH_SA_LastSpell = nil
end
local now = GetTime() or 0
if (now - (MTH_SA_LastWeaponCheck or 0)) >= 0.25 then
MTH_SA_LastWeaponCheck = now
MTHSmartAmmo_HandleWeaponSwapAutoEquip("OnUpdate-weapon-check")
end
end)
function MTH_SA_CountEquippedAmmo()
@@ -358,12 +487,9 @@ function MTH_SA_GetContainerItemName(bag, slot)
end
function MTH_SA_EquipAmmo(junk)
MTHSmartAmmo_Log("EquipAmmo enter junk=" .. tostring(junk) .. " equipped=" .. tostring(MTH_SA_GetEquippedAmmoName()) .. " cur=" .. tostring(MTH_SA.curname) .. " junk=" .. tostring(MTH_SA.junkname))
if not MTH_SA_AmmoLastSwitch then MTH_SA_AmmoLastSwitch = GetTime() end
if not (MTH_SA_Check() or MTH_SA_FindAmmo()) then
MTHSmartAmmo_Log("EquipAmmo abort: cache invalid and FindAmmo failed")
return
end
local bag, slot
@@ -377,15 +503,12 @@ function MTH_SA_EquipAmmo(junk)
if MTH_SA_GetEquippedAmmoName() ~= MTH_SA.curname and GetTime()-MTH_SA_AmmoLastSwitch > 0.5 then
if not MTH_SA_FindAmmo() then
MTHSmartAmmo_Log("EquipAmmo abort: AMMO NOT FOUND during junk swap")
return
end
end
bag, slot = MTH_SA.junkbag, MTH_SA.junkslot
MTHSmartAmmo_Log("Swap GOOD->JUNK bag=" .. tostring(bag) .. " slot=" .. tostring(slot) .. " cur=" .. tostring(MTH_SA.curname) .. " curSlot=" .. tostring(MTH_SA.curslot) .. " junk=" .. tostring(MTH_SA.junkname) .. " junkSlot=" .. tostring(MTH_SA.junkslot))
else
bag, slot = MTH_SA.curbag, MTH_SA.curslot
MTHSmartAmmo_Log("Swap JUNK->GOOD bag=" .. tostring(bag) .. " slot=" .. tostring(slot) .. " cur=" .. tostring(MTH_SA.curname) .. " curSlot=" .. tostring(MTH_SA.curslot) .. " junk=" .. tostring(MTH_SA.junkname) .. " junkSlot=" .. tostring(MTH_SA.junkslot))
end
@@ -393,7 +516,6 @@ function MTH_SA_EquipAmmo(junk)
--UseContainerItem(bag, slot)
PickupContainerItem(bag,slot)
EquipCursorItem(0)
MTHSmartAmmo_Log("EquipCursorItem applied bag=" .. tostring(bag) .. " slot=" .. tostring(slot))
if junk then
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = 1
@@ -401,7 +523,6 @@ function MTH_SA_EquipAmmo(junk)
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
end
MTHSmartAmmo_Log("Pending flags set waitJunk=" .. tostring(MTH_SA_IsWaitingSwapJunk) .. " waitGood=" .. tostring(MTH_SA_IsWaitingSwapGood))
--PickupInventoryItem(0)
--AutoEquipCursorItem()
--EquipCursorItem(0)
@@ -410,20 +531,16 @@ function MTH_SA_EquipAmmo(junk)
end
function MTH_SA_FindAmmo()
MTHSmartAmmo_Log("FindAmmo start")
MTH_SA = {}
MTH_SA_List = {}
local ammotype = MTH_SA_GetEquippedWeaponAmmoType()
if not ammotype then
MTHSmartAmmo_Log("FindAmmo abort: no ranged weapon ammo type")
return
end
local curammo = MTH_SA_GetEquippedAmmoName()
if not curammo and not MTHSmartAmmo_IsReloadEnabled() then
MTHSmartAmmo_Log("FindAmmo abort: no equipped ammo and reload disabled")
return
end
MTHSmartAmmo_Log("FindAmmo type=" .. tostring(ammotype) .. " equipped=" .. tostring(curammo))
local ammolist = (ammotype == "Bullets" and MTH_AMMO_BULLET_RANK) or MTH_AMMO_ARROW_RANK or {}
MTH_SA_List = ammolist
local item, value
@@ -473,11 +590,9 @@ function MTH_SA_FindAmmo()
end
end
if not goodvalue or junkvalue > goodvalue then
MTHSmartAmmo_Log("FindAmmo failed: goodvalue=" .. tostring(goodvalue) .. " junkvalue=" .. tostring(junkvalue))
MTH_SA.error = 1
return
end
MTHSmartAmmo_Log("FindAmmo selected cur=" .. tostring(MTH_SA.curname) .. " junk=" .. tostring(MTH_SA.junkname) .. " curValue=" .. tostring(MTH_SA.curvalue) .. " junkValue=" .. tostring(junkvalue))
return 1
end
@@ -502,11 +617,8 @@ MTHSmartAmmo_CastSpell_Hook = function(spell, tab)
if MTHSmartAmmo_IsSmartEnabled() then
local name = GetSpellName(spell, tab)
MTH_SA_LastSpell = name
MTHSmartAmmo_Log("HOOK CastSpell name=" .. tostring(name))
if name and MTH_AMMO_JUNKSHOT_SET and MTH_AMMO_JUNKSHOT_SET[name] then
MTHSmartAmmo_Log("HOOK CastSpell junk-shot detected name=" .. tostring(name))
if MTH_SA_Check() or MTH_SA_FindAmmo() then
MTHSmartAmmo_Log("HOOK CastSpell pre-swap -> junk")
MTH_SA_EquipAmmo(1)
end
end
@@ -539,11 +651,8 @@ MTHSmartAmmo_UseAction_Hook = function(slot, checkCursor, onSelf)
MTH_SA_Tooltip:SetAction(slot)
local name = MTH_SA_TooltipTextLeft1:GetText()
MTH_SA_LastSpell = name
MTHSmartAmmo_Log("HOOK UseAction slot=" .. tostring(slot) .. " name=" .. tostring(name))
if name and MTH_AMMO_JUNKSHOT_SET and MTH_AMMO_JUNKSHOT_SET[name] then
MTHSmartAmmo_Log("HOOK UseAction junk-shot detected name=" .. tostring(name))
if MTH_SA_Check() or MTH_SA_FindAmmo() then
MTHSmartAmmo_Log("HOOK UseAction pre-swap -> junk")
MTH_SA_EquipAmmo(1)
end
end
@@ -573,11 +682,8 @@ MTHSmartAmmo_CastSpellByName_Hook = function(spell, onSelf)
local _, _, name = string.find(spell or "", "([%w%'%s]+)")
MTH_SA_LastSpell = name
MTHSmartAmmo_Log("HOOK CastSpellByName name=" .. tostring(name))
if name and MTHSmartAmmo_IsSmartEnabled() and MTH_AMMO_JUNKSHOT_SET and MTH_AMMO_JUNKSHOT_SET[name] then
MTHSmartAmmo_Log("HOOK CastSpellByName junk-shot detected name=" .. tostring(name))
if MTH_SA_Check() or MTH_SA_FindAmmo() then
MTHSmartAmmo_Log("HOOK CastSpellByName pre-swap -> junk")
MTH_SA_EquipAmmo(1)
end
end
@@ -598,26 +704,22 @@ end
-- Defer hooking until after tables are initialized
MTHSmartAmmo_InitializeHooks = function()
if not MTH_SA_IsModuleEnabled() then
MTHSmartAmmo_Log("InitializeHooks skip: module disabled")
return
end
if CastSpell ~= MTHSmartAmmo_CastSpell_Hook then
MTH_SA_CastSpell = CastSpell
CastSpell = MTHSmartAmmo_CastSpell_Hook
MTHSmartAmmo_Log("InitializeHooks: CastSpell hook installed")
end
if UseAction ~= MTHSmartAmmo_UseAction_Hook then
MTH_SA_UseAction = UseAction
UseAction = MTHSmartAmmo_UseAction_Hook
MTHSmartAmmo_Log("InitializeHooks: UseAction hook installed")
end
if CastSpellByName ~= MTHSmartAmmo_CastSpellByName_Hook then
MTH_SA_CastSpellByName = CastSpellByName
CastSpellByName = MTHSmartAmmo_CastSpellByName_Hook
MTHSmartAmmo_Log("InitializeHooks: CastSpellByName hook installed")
end
end
+15 -1
View File
@@ -7,7 +7,7 @@ MTH_SA_MANAGED_HOOKS = true
local MTH_SmartAmmo = {
name = "smartammo",
enabled = true,
version = "1.0.3",
version = "1.0.4",
events = {
"VARIABLES_LOADED",
"PLAYER_ENTERING_WORLD",
@@ -80,6 +80,9 @@ local function MTH_SA_ApplySavedState()
if moduleStore.reloadEnabled ~= nil then
saved["reload"] = moduleStore.reloadEnabled and 1 or false
end
if moduleStore.weaponSwapEnabled ~= nil then
saved["weaponSwap"] = moduleStore.weaponSwapEnabled and 1 or false
end
end
if saved["enabled"] == nil then
saved["enabled"] = 1
@@ -90,11 +93,22 @@ local function MTH_SA_ApplySavedState()
if saved["reload"] == nil and type(moduleStore) == "table" then
moduleStore.reloadEnabled = saved["reload"] ~= false
end
if saved["weaponSwap"] == nil then
saved["weaponSwap"] = 1
if type(moduleStore) == "table" then
moduleStore.weaponSwapEnabled = true
end
elseif type(moduleStore) == "table" and moduleStore.weaponSwapEnabled == nil then
moduleStore.weaponSwapEnabled = saved["weaponSwap"] ~= false
end
MTHSmartAmmo_SetSmartEnabled(saved["enabled"] and 1 or nil, 1)
if type(MTHSmartAmmo_SetReloadEnabled) == "function" then
MTHSmartAmmo_SetReloadEnabled(saved["reload"] ~= false and 1 or nil, 1)
end
if type(MTHSmartAmmo_SetWeaponSwapEnabled) == "function" then
MTHSmartAmmo_SetWeaponSwapEnabled(saved["weaponSwap"] ~= false and 1 or nil, 1)
end
if type(MTHSmartAmmo_EnsureHooks) == "function" then
MTHSmartAmmo_EnsureHooks("module-apply")
end
+1 -1
View File
@@ -6,7 +6,7 @@
local MTH_Tooltips = {
name = "tooltips",
enabled = true,
version = "1.0.3",
version = "1.0.4",
events = {
"UPDATE_MOUSEOVER_UNIT",
"UNIT_NAME_UPDATE",
+12 -1
View File
@@ -64,6 +64,8 @@ local function ZHunterMod_EnsureButtonFrame(buttonName)
created:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
elseif buttonName == "zButtonTrap" then
created:SetPoint("CENTER", UIParent, "CENTER", 60, 0)
elseif buttonName == "zButtonRanged" then
created:SetPoint("CENTER", UIParent, "CENTER", 120, 0)
elseif buttonName == "zButtonPet" then
created:SetPoint("CENTER", UIParent, "CENTER", 0, 60)
elseif buttonName == "zButtonMounts" then
@@ -86,6 +88,7 @@ function ZHunterMod_DeferredInit()
local aspect = ZHunterMod_EnsureButtonFrame("zButtonAspect")
local track = ZHunterMod_EnsureButtonFrame("zButtonTrack")
local trap = ZHunterMod_EnsureButtonFrame("zButtonTrap")
local ranged = ZHunterMod_EnsureButtonFrame("zButtonRanged")
local ammo = ZHunterMod_EnsureButtonFrame("zButtonAmmo")
local mounts = ZHunterMod_EnsureButtonFrame("zButtonMounts")
local companions = ZHunterMod_EnsureButtonFrame("zButtonCompanions")
@@ -95,6 +98,7 @@ function ZHunterMod_DeferredInit()
ZHunterMod_LogDeferred("DeferredInit: Aspect=" .. tostring(aspect ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Track=" .. tostring(track ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Trap=" .. tostring(trap ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Ranged=" .. tostring(ranged ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Ammo=" .. tostring(ammo ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Mounts=" .. tostring(mounts ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Companions=" .. tostring(companions ~= nil))
@@ -106,6 +110,7 @@ function ZHunterMod_DeferredInit()
if not aspect then table.insert(missing, "Aspect") end
if not track then table.insert(missing, "Track") end
if not trap then table.insert(missing, "Trap") end
if not ranged then table.insert(missing, "Ranged") end
if not ammo then table.insert(missing, "Ammo") end
if not mounts then table.insert(missing, "Mounts") end
if not companions then table.insert(missing, "Companions") end
@@ -115,7 +120,7 @@ function ZHunterMod_DeferredInit()
MTH_ZH_Print("[ZHUNTER] Warning: missing frames: " .. table.concat(missing, ", ") .. ". Continuing with available buttons.", "error")
end
if not (pet or aspect or track or trap or ammo or mounts or companions or toys) then
if not (pet or aspect or track or trap or ranged or ammo or mounts or companions or toys) then
MTH_ZH_Print("zhunter buttons not created - check for addon conflicts!", "error")
return
end
@@ -159,6 +164,12 @@ function ZHunterMod_DeferredInit()
initialized = initialized + 1
end
end
if ranged and zButtonRanged_OnEvent then
if ZHunterMod_SafeRunButtonInit(ranged, zButtonRanged_OnEvent, "zButtonRanged") then
initialized = initialized + 1
end
end
if ammo and zButtonAmmo_OnEvent then
if ZHunterMod_SafeRunButtonInit(ammo, zButtonAmmo_OnEvent, "zButtonAmmo") then
+56 -20
View File
@@ -189,11 +189,17 @@ function ZSpellButton_SetSize(parent, size, setChildren)
local button
for i=1, parent.count do
button = getglobal(parent.name..i)
button:SetHeight(size)
button:SetWidth(size)
button.background:SetWidth(size * bgscale)
button.background:SetHeight(size * bgscale)
button.cooldown:SetModelScale(size * cdscale)
if button then
button:SetHeight(size)
button:SetWidth(size)
if button.background then
button.background:SetWidth(size * bgscale)
button.background:SetHeight(size * bgscale)
end
if button.cooldown then
button.cooldown:SetModelScale(size * cdscale)
end
end
end
else
local cscale = 100/36
@@ -208,16 +214,22 @@ function ZSpellButton_SetSize(parent, size, setChildren)
end
parent:SetHeight(size)
parent:SetWidth(size)
parent.background:SetWidth(size * bgscale)
parent.background:SetHeight(size * bgscale)
parent.cooldown:SetModelScale(size * cdscale)
parent.circle:SetWidth(size * cscale)
parent.circle:SetHeight(size * cscale)
parent.circle:SetPoint("CENTER", size * cxscale, size * cyscale)
if circleVisible then
parent.circle:Show()
else
parent.circle:Hide()
if parent.background then
parent.background:SetWidth(size * bgscale)
parent.background:SetHeight(size * bgscale)
end
if parent.cooldown then
parent.cooldown:SetModelScale(size * cdscale)
end
if parent.circle then
parent.circle:SetWidth(size * cscale)
parent.circle:SetHeight(size * cscale)
parent.circle:SetPoint("CENTER", size * cxscale, size * cyscale)
if circleVisible then
parent.circle:Show()
else
parent.circle:Hide()
end
end
end
end
@@ -253,6 +265,13 @@ end
function ZSpellButton_CreateChildren(parent, name, count)
if not (parent and name and count) then return end
if parent.children and parent.count and parent.name == name then
parent.count = count
if type(ZSpellButton_ApplyChildrenExpanded) == "function" then
ZSpellButton_ApplyChildrenExpanded(parent)
end
return
end
parent.children = CreateFrame("Frame", parent:GetName().."Children", UIParent)
parent.count = count
parent.name = name
@@ -309,6 +328,7 @@ function ZSpellButton_GetChildrenExpanded(parent)
return expanded
end
function ZSpellButton_SetChildrenExpanded(parent, expanded)
if not (parent and parent.name) then
return
@@ -322,11 +342,31 @@ function ZSpellButton_SetChildrenExpanded(parent, expanded)
if parent.children then
parent.children:Show()
end
if parent.count then
for i = 1, parent.count do
local child = getglobal(parent.name .. i)
if child then
if child.id then
child:Show()
else
child:Hide()
end
end
end
end
else
saved["children"]["expanded"] = 0
if parent.children then
parent.children:Hide()
end
if parent.count then
for i = 1, parent.count do
local child = getglobal(parent.name .. i)
if child then
child:Hide()
end
end
end
end
end
@@ -334,11 +374,7 @@ function ZSpellButton_ApplyChildrenExpanded(parent)
if not (parent and parent.children) then
return
end
if ZSpellButton_GetChildrenExpanded(parent) then
parent.children:Show()
else
parent.children:Hide()
end
ZSpellButton_SetChildrenExpanded(parent, ZSpellButton_GetChildrenExpanded(parent))
end
function ZSpellButton_OnEnter()
+3
View File
@@ -16,6 +16,7 @@ Loads all zhunter addon code and wraps it in the MTH module system
<Include file="zButtonAspect.xml"/>
<Include file="zButtonTrack.xml"/>
<Include file="zButtonTrap.xml"/>
<Include file="zButtonRanged.xml"/>
<Include file="zButtonAmmo.xml"/>
<Include file="zButtonPet.xml"/>
<Include file="zButtonMounts.xml"/>
@@ -34,6 +35,8 @@ Loads all zhunter addon code and wraps it in the MTH module system
<Include file="zButtonTrack.lua"/>
<Include file="zButtonTrap.lua"/>
<Include file="zButtonRanged.lua"/>
<Include file="zButtonAmmo.lua"/>
+35 -13
View File
@@ -8,7 +8,7 @@ MTH_ZH_MANAGED_HOOKS = true
local MTH_ZHunter = {
name = "zhunter",
enabled = true,
version = "1.0.3",
version = "1.0.4",
events = {
"VARIABLES_LOADED",
"PLAYER_ENTERING_WORLD",
@@ -18,6 +18,7 @@ local MTH_ZHunter = {
aspect = true,
tracking = true,
traps = true,
ranged = true,
ammo = true,
pet = true,
}
@@ -60,6 +61,7 @@ local function MTH_ZH_ApplyDefaultWidgetSpawnLayoutOnce()
"zButtonAmmo",
"zButtonTrack",
"zButtonTrap",
"zButtonRanged",
"zButtonPet",
"zButtonMounts",
"zButtonCompanions",
@@ -195,6 +197,7 @@ MTH_ZH_SetButtonsVisible = function(visible)
"zButtonAspect",
"zButtonTrack",
"zButtonTrap",
"zButtonRanged",
"zButtonAmmo",
"zButtonPet",
"zButtonMounts",
@@ -207,13 +210,34 @@ MTH_ZH_SetButtonsVisible = function(visible)
return
end
local showChildren = false
if show then
if type(ZSpellButton_GetChildrenExpanded) == "function" then
showChildren = ZSpellButton_GetChildrenExpanded(parentButton)
else
showChildren = true
if not show then
if parentButton.children then
parentButton.children:Hide()
end
if not parentButton.count then
return
end
local hideBaseName = parentButton.name or parentName
if not hideBaseName then
return
end
for index = 1, parentButton.count do
local child = getglobal(hideBaseName .. index)
if child then
child:Hide()
end
end
return
end
local showChildren = false
if type(ZSpellButton_GetChildrenExpanded) == "function" then
showChildren = ZSpellButton_GetChildrenExpanded(parentButton)
else
showChildren = true
end
if parentButton.children then
@@ -233,17 +257,15 @@ MTH_ZH_SetButtonsVisible = function(visible)
return
end
for index = 1, parentButton.count do
local child = getglobal(baseName .. index)
if child then
if showChildren then
if showChildren then
for index = 1, parentButton.count do
local child = getglobal(baseName .. index)
if child then
if child.id then
child:Show()
else
child:Hide()
end
else
child:Hide()
end
end
end
+46 -156
View File
@@ -22,13 +22,13 @@ if not root["zButtonAmmo"] then
root["zButtonAmmo"]["children"]["hideonclick"] = 1
root["zButtonAmmo"]["showammoname"] = 1
root["zButtonAmmo"]["lastEquipped"] = nil
root["zButtonAmmo"]["debug"] = false
end
ZHunterMod_Ammo_Buttons = nil
local ZHUNTER_AMMO_MAX_COUNT = math.max(table.getn(MTH_AMMO_ARROWS or {}), table.getn(MTH_AMMO_BULLETS or {}))
local zButtonAmmo_Cache = {}
local zButtonAmmo_LastCacheSignature = nil
local function zButtonAmmo_GetSaved()
local currentRoot = zButtonAmmo_GetRoot()
@@ -257,6 +257,17 @@ local function zButtonAmmo_AssignButtonFromAmmoInfo(button, ammoInfo)
return true
end
local function zButtonAmmo_GetCacheSignature()
local names = {}
for ammoName, ammoInfo in pairs(zButtonAmmo_Cache or {}) do
if ammoName and ammoInfo and (tonumber(ammoInfo.count) or 0) > 0 then
table.insert(names, tostring(ammoName))
end
end
table.sort(names)
return table.concat(names, "|")
end
local function zButtonAmmo_GetEquippedAmmoInfo()
local ammoLink = zButtonAmmo_GetEquippedAmmoLink()
if not ammoLink then
@@ -350,6 +361,26 @@ end
function zButtonAmmo_SetButtons(parent, ammoList)
zButtonAmmo_RebuildCache()
local previousByName = {}
for i = 1, parent.count do
local previous = getglobal(parent.name .. i)
if previous and previous.ammoname and not previous.isspell then
previousByName[previous.ammoname] = {
ammo = previous.ammoname,
brol = previous.ammobrol,
quality = previous.ammoqual,
lvl = previous.ammolvl,
type = previous.ammotype,
bag = nil,
slot = nil,
id = previous.ammoid or previous.id,
link = previous.ammolink,
icon = previous.icon,
count = 0,
equip = nil,
}
end
end
for i = 1, parent.count do
local button = getglobal(parent.name .. i)
@@ -375,21 +406,12 @@ function zButtonAmmo_SetButtons(parent, ammoList)
end
local ammoName = ammoList[i]
local ammoInfo = ammoName and zButtonAmmo_Cache[ammoName] or nil
if not ammoInfo and ammoName then
ammoInfo = previousByName[ammoName]
end
if ammoInfo then
local button = getglobal(parent.name .. count)
button.id = ammoInfo.id
button.icon = ammoInfo.icon
button.isspell = nil
button.ammoname = ammoInfo.ammo
button.ammobrol = ammoInfo.brol
button.ammoqual = ammoInfo.quality
button.ammolvl = ammoInfo.lvl
button.ammotype = ammoInfo.type
button.ammobag = ammoInfo.bag
button.ammoslot = ammoInfo.slot
button.ammoid = ammoInfo.id
button.ammolink = ammoInfo.link
button.ammocount = ammoInfo.count
zButtonAmmo_AssignButtonFromAmmoInfo(button, ammoInfo)
zButtonAmmo_UpdateButton(button)
button:Show()
@@ -439,6 +461,7 @@ function zButtonAmmo_SetButtons(parent, ammoList)
else
parent:Show()
end
zButtonAmmo_LastCacheSignature = zButtonAmmo_GetCacheSignature()
return count - 1
end
@@ -553,21 +576,6 @@ local function zButtonAmmo_GetEquippedAmmoName()
return ammoLink
end
local function zButtonAmmo_IsDebugEnabled()
local saved = zButtonAmmo_GetSaved()
return saved["debug"]
end
local function zButtonAmmo_LogInit(msg)
if not zButtonAmmo_IsDebugEnabled() then
return
end
if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
MTH_ZH_Print("[AMMO INIT] " .. tostring(msg), "debug")
end
MTH_ZH_Print("[AMMO INIT] " .. tostring(msg), "debug")
end
local zButtonAmmo_EquipFromButton
local function zButtonAmmo_DeferredStartupSync()
@@ -590,26 +598,11 @@ local function zButtonAmmo_DeferredStartupSync()
syncFrame:SetScript("OnUpdate", nil)
local equippedNow = zButtonAmmo_GetEquippedAmmoName()
local saved = zButtonAmmo_GetSaved()
zButtonAmmo_LogInit("deferred sync equippedNow=" .. tostring(equippedNow) .. " saved.lastEquipped=" .. tostring(saved and saved["lastEquipped"]))
zButtonAmmo_RebuildCache()
if equippedNow and (not saved["lastEquipped"] or saved["lastEquipped"] == "") then
zButtonAmmo_SaveEquippedAmmo(equippedNow)
zButtonAmmo_LogInit("deferred sync seeded lastEquipped=" .. tostring(equippedNow))
return
end
if saved["lastEquipped"] and equippedNow and saved["lastEquipped"] ~= equippedNow and zButtonAmmo_Cache[saved["lastEquipped"]] then
local restored = false
for i = 1, zButtonAmmo.count do
local child = getglobal("zButtonAmmo" .. i)
if child and child.ammoname == saved["lastEquipped"] then
restored = zButtonAmmo_EquipFromButton(child)
break
end
end
zButtonAmmo_LogInit("deferred sync restore attempt target=" .. tostring(saved["lastEquipped"]) .. " ok=" .. tostring(restored))
end
end)
end
@@ -678,13 +671,10 @@ end
function zButtonAmmo_OnEvent()
if event == "VARIABLES_LOADED" then
zButtonAmmo_LogInit("VARIABLES_LOADED fired")
if not zButtonAmmo then
zButtonAmmo_LogInit("abort: zButtonAmmo frame missing")
return
end
if UnitClass("player") ~= ZHUNTER_HUNTER then
zButtonAmmo_LogInit("abort: non-hunter")
zButtonAmmo:UnregisterAllEvents()
zButtonAmmo:Hide()
return
@@ -696,13 +686,7 @@ function zButtonAmmo_OnEvent()
zButtonAmmoAdjustment:RegisterEvent("UNIT_INVENTORY_CHANGED")
zButtonAmmoAdjustment:RegisterEvent("BAG_UPDATE")
zButtonAmmoAdjustment:SetScript("OnEvent", zButtonAmmoAdjustment_OnEvent)
if zButtonAmmo_IsDebugEnabled() then
MTH_ZH_Print("[AMMO] zButtonAmmoAdjustment frame created and events registered", "debug")
end
zButtonAmmo_SetupSizeAndPosition()
local saved = zButtonAmmo_GetSaved()
zButtonAmmo_LogInit("post-init saved.lastEquipped=" .. tostring(saved and saved["lastEquipped"]))
zButtonAmmo_LogInit("post-init equippedNow=" .. tostring(zButtonAmmo_GetEquippedAmmoName()))
zButtonAmmo_DeferredStartupSync()
end
end
@@ -714,9 +698,6 @@ function zButtonAmmo_SaveEquippedAmmo(ammoname)
return
end
saved["lastEquipped"] = ammoname
if zButtonAmmo_IsDebugEnabled() then
MTH_ZH_Print("[AMMO] Saved equipped ammo to persistent storage: " .. ammoname, "debug")
end
end
function zButtonAmmo_LoadLastEquippedAmmo()
@@ -760,84 +741,8 @@ function zButtonAmmo_CreateButtons()
-- Try to restore the last equipped ammo from saved variables
local lastEquipped = zButtonAmmo_LoadLastEquippedAmmo()
local equippedAmmoNameAtInit = zButtonAmmo_GetEquippedAmmoName()
zButtonAmmo_LogInit("CreateButtons saved.lastEquipped=" .. tostring(lastEquipped) .. " equippedNow=" .. tostring(equippedAmmoNameAtInit))
if lastEquipped and zButtonAmmo_Cache[lastEquipped] then
if zButtonAmmo_IsDebugEnabled() then
MTH_ZH_Print("[AMMO] Restoring last equipped ammo from save: " .. lastEquipped, "debug")
end
-- Set the parent button directly from ammo cache data
local ammoInfo = zButtonAmmo_Cache[lastEquipped]
zButtonAmmo.ammoname = lastEquipped
zButtonAmmo.ammoid = ammoInfo["id"]
zButtonAmmo.icon = ammoInfo["icon"]
zButtonAmmo.isspell = nil
zButtonAmmo.ammobrol = ammoInfo["brol"]
zButtonAmmo.ammoqual = ammoInfo["quality"]
zButtonAmmo.ammolvl = ammoInfo["lvl"]
zButtonAmmo.ammotype = ammoInfo["type"]
zButtonAmmo.ammobag = ammoInfo["bag"]
zButtonAmmo.ammoslot = ammoInfo["slot"]
zButtonAmmo.ammolink = ammoInfo["link"]
zButtonAmmo_UpdateButton(zButtonAmmo)
zButtonAmmo:Enable()
local equippedAmmoName = zButtonAmmo_GetEquippedAmmoName()
if equippedAmmoName ~= lastEquipped then
local restored = false
for i = 1, zButtonAmmo.count do
local child = getglobal("zButtonAmmo" .. i)
if child and child.ammoname == lastEquipped then
restored = zButtonAmmo_EquipFromButton(child)
break
end
end
if not restored then
restored = zButtonAmmo_EquipFromButton({
ammoname = lastEquipped,
ammobag = ammoInfo["bag"],
ammoslot = ammoInfo["slot"],
ammoid = ammoInfo["id"],
})
end
if restored then
zButtonAmmo_SaveEquippedAmmo(lastEquipped)
zButtonAmmo_LogInit("restored to saved ammo=" .. tostring(lastEquipped))
else
zButtonAmmo_LogInit("restore failed for saved ammo=" .. tostring(lastEquipped))
end
else
zButtonAmmo_LogInit("restore skipped: equipped already matches saved")
end
else
zButtonAmmo_LogInit("restore skipped: no saved lastEquipped in cache")
if equippedAmmoNameAtInit then
zButtonAmmo_SaveEquippedAmmo(equippedAmmoNameAtInit)
zButtonAmmo_LogInit("seeded lastEquipped from equippedNow=" .. tostring(equippedAmmoNameAtInit))
else
local bestAvailable = nil
for i = 1, table.getn(ammoList) do
local ammoName = ammoList[i]
if ammoName and zButtonAmmo_Cache[ammoName] then
bestAvailable = ammoName
end
end
if bestAvailable and zButtonAmmo_Cache[bestAvailable] then
local bestInfo = zButtonAmmo_Cache[bestAvailable]
local equippedBest = zButtonAmmo_EquipFromButton({
ammoname = bestAvailable,
ammobag = bestInfo["bag"],
ammoslot = bestInfo["slot"],
ammoid = bestInfo["id"],
})
if equippedBest then
zButtonAmmo_SaveEquippedAmmo(bestAvailable)
zButtonAmmo_LogInit("fallback equip bestAvailable=" .. tostring(bestAvailable))
else
zButtonAmmo_LogInit("fallback equip failed bestAvailable=" .. tostring(bestAvailable))
end
end
end
if equippedAmmoNameAtInit then
zButtonAmmo_SaveEquippedAmmo(equippedAmmoNameAtInit)
end
end
@@ -890,7 +795,6 @@ function zButtonAmmo_Reset()
saved["children"]["hideonclick"] = 1
saved["showammoname"] = 1
saved["lastEquipped"] = nil
saved["debug"] = false
end
function zButtonAmmoAdjustment_OnEvent()
@@ -901,8 +805,11 @@ function zButtonAmmoAdjustment_OnEvent()
if event == "UNIT_INVENTORY_CHANGED" or event == "BAG_UPDATE" then
local ammoList = zButtonAmmo_GetAmmoList()
if ZHunterMod_Ammo_Buttons ~= ammoList then
ZHunterMod_Ammo_Buttons = ammoList
local listChanged = (ZHunterMod_Ammo_Buttons ~= ammoList)
ZHunterMod_Ammo_Buttons = ammoList
zButtonAmmo_RebuildCache()
local cacheSignature = zButtonAmmo_GetCacheSignature()
if listChanged or cacheSignature ~= zButtonAmmo_LastCacheSignature then
zButtonAmmo_EnsureSpellOrder(ammoList)
local info = {}
local infoIndex = 1
@@ -915,8 +822,8 @@ function zButtonAmmoAdjustment_OnEvent()
end
zButtonAmmo.found = ZSpellButton_SetButtons(zButtonAmmo, info)
zButtonAmmo_SetupSizeAndPosition()
zButtonAmmo_LastCacheSignature = zButtonAmmo_GetCacheSignature()
end
zButtonAmmo_RebuildCache()
-- Update ammo counts for child buttons
for i=1, zButtonAmmo.count do
local button = getglobal("zButtonAmmo"..i)
@@ -1013,25 +920,8 @@ SlashCmdList["zButtonAmmo"] = function(msg)
zButtonAmmo:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
elseif msg == "options" then
MTH_OpenOptions("Ammo")
elseif msg == "debug" then
-- Manually trigger ammo rescan with debug output
local currentAmmoList = ZHunterMod_Ammo_Buttons or zButtonAmmo_GetAmmoList()
zButtonAmmo_EnsureSpellOrder(currentAmmoList)
local saved = zButtonAmmo_GetSaved()
local info = {}
local infoIndex = 1
for i=1, table.getn(currentAmmoList) do
local ammoIndex = saved["spells"][i]
if saved["visible"][ammoIndex] ~= false then
info[infoIndex] = currentAmmoList[ammoIndex]
infoIndex = infoIndex + 1
end
end
zButtonAmmo.found = ZSpellButton_SetButtons(zButtonAmmo, info)
zButtonAmmo_UpdateButton(zButtonAmmo)
MTH_ZH_Print("Ammo button rescanned")
else
MTH_ZH_Print("Possible Commands: \"options\", \"reset\", \"debug\"")
MTH_ZH_Print("Possible Commands: \"options\", \"reset\"")
end
end
+49 -1
View File
@@ -99,6 +99,43 @@ local function zButtonAspect_ApplyRuntimeSettings()
zButtonAspect.hideonclick = saved["children"] and saved["children"]["hideonclick"] and true or false
end
local function zButtonAspect_IsKnownAspectSpellId(spellId)
if not spellId then
return false
end
local spellName = GetSpellName(spellId, "spell")
if not spellName or spellName == "" then
return false
end
for i = 1, table.getn(ZHunterMod_Aspect_Spells) do
if ZHunterMod_Aspect_Spells[i] == spellName then
return true
end
end
return false
end
local function zButtonAspect_EnsureValidParentId()
if not (zButtonAspect and zButtonAspect.count) then
return
end
if zButtonAspect_IsKnownAspectSpellId(zButtonAspect.id) then
return
end
for i = 1, zButtonAspect.count do
local child = getglobal(zButtonAspect.name .. i)
if child and child.id and zButtonAspect_IsKnownAspectSpellId(child.id) then
zButtonAspect.id = child.id
zButtonAspect.isspell = 1
ZSpellButton_UpdateButton(zButtonAspect)
ZSpellButton_UpdateCooldown(zButtonAspect)
return
end
end
end
function zButtonAspect_OnLoad()
this:RegisterEvent("VARIABLES_LOADED")
end
@@ -117,6 +154,9 @@ function zButtonAspect_OnEvent()
zButtonAspectAdjustment = CreateFrame("Frame", "zButtonAspectAdjustment")
zButtonAspectAdjustment:RegisterEvent("PLAYER_AURAS_CHANGED")
zButtonAspectAdjustment:RegisterEvent("PLAYER_ENTERING_WORLD")
zButtonAspectAdjustment:RegisterEvent("SPELLS_CHANGED")
zButtonAspectAdjustment:RegisterEvent("CHARACTER_POINTS_CHANGED")
zButtonAspectAdjustment:RegisterEvent("LEARNED_SPELL_IN_TAB")
zButtonAspectAdjustment:SetScript("OnEvent", zButtonAspectAdjustment_OnEvent)
zButtonAspect_Tooltip = CreateFrame("GameTooltip", "zButtonAspect_Tooltip", nil, "GameTooltipTemplate")
zButtonAspect_SetupSizeAndPosition()
@@ -144,6 +184,7 @@ function zButtonAspect_CreateButtons()
end
zButtonAspect.found = ZSpellButton_SetButtons(zButtonAspect, info)
zButtonAspect_ApplyRuntimeSettings()
zButtonAspect_EnsureValidParentId()
end
function zButtonAspect_SetupSizeAndPosition()
@@ -193,7 +234,14 @@ function zButtonAspectAdjustment_OnEvent()
if not zButtonAspect or not zButtonAspect.count then
return
end
if event == "PLAYER_AURAS_CHANGED" or event == "PLAYER_ENTERING_WORLD" then
if event == "SPELLS_CHANGED" or event == "CHARACTER_POINTS_CHANGED" or event == "LEARNED_SPELL_IN_TAB" then
zButtonAspect_CreateButtons()
zButtonAspect_SetupSizeAndPosition()
zButtonAspect_EnsureValidParentId()
end
if event == "PLAYER_AURAS_CHANGED" or event == "PLAYER_ENTERING_WORLD"
or event == "SPELLS_CHANGED" or event == "CHARACTER_POINTS_CHANGED" or event == "LEARNED_SPELL_IN_TAB" then
zButtonAspect_EnsureValidParentId()
if not zButtonAspect1.id then
return
end
+145 -10
View File
@@ -42,6 +42,7 @@ ZHunterMod_Pet_Spells = {
}
local ZHUNTER_PET_MAX = table.getn(ZHunterMod_Pet_Spells)
local zButtonPet_SetButtons
local function zButtonPet_GetSaved()
local currentRoot = zButtonPet_GetRoot()
@@ -147,6 +148,7 @@ function zButtonPet_OnEvent()
zButtonPet:Hide()
return
end
zButtonPet.customSetButtons = zButtonPet_SetButtons
zButtonPet_CreateButtons()
zButtonPet.beforeclick = zButtonPetAdjustment_BeforeClick
zButtonPet.afterclick = zButtonPet_AfterClick
@@ -157,6 +159,7 @@ function zButtonPet_OnEvent()
zButtonPetAdjustment:RegisterEvent("PET_BAR_UPDATE")
zButtonPetAdjustment:RegisterEvent("PLAYER_ENTERING_WORLD")
zButtonPetAdjustment:RegisterEvent("SPELLS_CHANGED")
zButtonPetAdjustment:RegisterEvent("LEARNED_SPELL_IN_TAB")
zButtonPetAdjustment:SetScript("OnEvent", zButtonPetAdjustment_OnEvent)
zButtonPet_Tooltip = CreateFrame("GameTooltip", "zButtonPet_Tooltip", nil, "GameTooltipTemplate")
zButtonPet_SetupSizeAndPosition()
@@ -300,17 +303,110 @@ local function zButtonPet_FindSpellIdByName(spellName)
if not spellName or spellName == "" then
return nil
end
local maxSpells = tonumber((_G and _G["MAX_SPELLS"]) or nil) or 1024
for i = 1, maxSpells do
local current = GetSpellName(i, "spell")
if not current then
break
end
if current == spellName then
return i
local lookup = {}
local foundAny = nil
if type(GetNumSpellTabs) == "function" and type(GetSpellTabInfo) == "function" then
local numTabs = GetNumSpellTabs() or 0
for tabIndex = 1, numTabs do
local _, _, offset, numSpells = GetSpellTabInfo(tabIndex)
offset = tonumber(offset) or 0
numSpells = tonumber(numSpells) or 0
if numSpells > 0 then
for spellIndex = (offset + 1), (offset + numSpells) do
local spellNameAtIndex = GetSpellName(spellIndex, "spell")
if spellNameAtIndex then
lookup[spellNameAtIndex] = spellIndex
foundAny = 1
end
end
end
end
end
return nil
if not foundAny then
local maxSpells = tonumber((_G and _G["MAX_SPELLS"]) or nil) or 1024
local nilStreak = 0
for spellIndex = 1, maxSpells do
local spellNameAtIndex = GetSpellName(spellIndex, "spell")
if spellNameAtIndex then
lookup[spellNameAtIndex] = spellIndex
nilStreak = 0
else
nilStreak = nilStreak + 1
if nilStreak >= 30 then
break
end
end
end
end
if spellName == ZHUNTER_PET_POSITION then
if lookup[spellName] then
return lookup[spellName]
end
for currentName, currentId in lookup do
if string.find(currentName, "Take Position", 1, true)
or string.find(currentName, "Position", 1, true)
or string.find(currentName, "Stay", 1, true) then
return currentId
end
end
return nil
end
return lookup[spellName]
end
zButtonPet_SetButtons = function(parent, spells)
if not (parent and parent.count and parent.name and spells) then
return 0
end
local info = {}
for i = 1, table.getn(spells) do
local spellName = spells[i]
local spellId = zButtonPet_FindSpellIdByName(spellName)
if spellId then
table.insert(info, spellId)
end
end
for i = 1, parent.count do
local child = getglobal(parent.name..i)
if child then
child:Hide()
child.id = nil
child.icon = nil
child.isspell = nil
end
end
parent.id = nil
parent.isspell = nil
local foundCount = 0
for i = 1, table.getn(info) do
if i > parent.count then
break
end
local button = getglobal(parent.name..i)
if button then
button.id = info[i]
button.isspell = 1
ZSpellButton_UpdateButton(button)
button:Show()
if i == 1 then
parent.id = info[i]
parent.isspell = 1
ZSpellButton_UpdateButton(parent)
parent:Enable()
end
foundCount = foundCount + 1
end
end
return foundCount
end
function zButtonPetAdjustment_BeforeClick()
@@ -437,18 +533,57 @@ function zButtonPet_FeedPet()
end
local function zButtonPet_DebugVerify()
if not zButtonPet then
MTH_ZH_Print("zPet: button frame is not ready yet.")
return
end
zButtonPet_CreateButtons()
zButtonPet_RefreshParentSpell()
MTH_ZH_Print("zPet verify: expected spell availability")
for i = 1, table.getn(ZHunterMod_Pet_Spells) do
local spellName = ZHunterMod_Pet_Spells[i]
local spellId = zButtonPet_FindSpellIdByName(spellName)
if spellId then
MTH_ZH_Print(" + "..spellName.." (id "..spellId..")")
else
MTH_ZH_Print(" - "..spellName.." (missing)")
end
end
if zButtonPet.id then
local parentName = GetSpellName(zButtonPet.id, "spell") or "<unknown>"
MTH_ZH_Print("zPet parent: "..parentName.." (id "..zButtonPet.id..")")
else
MTH_ZH_Print("zPet parent: <none>")
end
for i = 1, (zButtonPet.count or 0) do
local button = getglobal("zButtonPet"..i)
if button and button.id then
local name = GetSpellName(button.id, "spell") or "<unknown>"
MTH_ZH_Print(" slot "..i..": "..name.." (id "..button.id..")")
end
end
end
SLASH_zButtonPet1 = "/ZPet"
SlashCmdList["zButtonPet"] = function(msg)
if MTH_ZH_HandleDisabledSlash and MTH_ZH_HandleDisabledSlash("Pet button is disabled while module 'zhunter' is disabled.") then
return
end
msg = (msg and string.lower(msg)) or ""
if msg == "reset" then
zButtonPet_Reset()
zButtonPet:ClearAllPoints()
zButtonPet:SetPoint("CENTER", UIParent, "CENTER", 0, 60)
elseif msg == "options" then
MTH_OpenOptions("Pet")
elseif msg == "verify" then
zButtonPet_DebugVerify()
else
MTH_ZH_Print("Possible Commands: \"options\", \"reset\"")
MTH_ZH_Print("Possible Commands: \"options\", \"reset\", \"verify\"")
end
end
+717
View File
@@ -0,0 +1,717 @@
local function zButtonRanged_GetRoot()
return MTH_ZH_GetSavedRoot()
end
local root = zButtonRanged_GetRoot()
if not root["zButtonRanged"] then
root["zButtonRanged"] = {}
root["zButtonRanged"]["spells"] = {}
root["zButtonRanged"]["visible"] = {}
root["zButtonRanged"]["rows"] = 1
root["zButtonRanged"]["horizontal"] = nil
root["zButtonRanged"]["vertical"] = nil
root["zButtonRanged"]["firstbutton"] = "RIGHT"
root["zButtonRanged"]["enabled"] = false
root["zButtonRanged"]["tooltip"] = 1
root["zButtonRanged"]["parent"] = {}
root["zButtonRanged"]["parent"]["size"] = 36
root["zButtonRanged"]["parent"]["hide"] = nil
root["zButtonRanged"]["parent"]["circle"] = 1
root["zButtonRanged"]["children"] = {}
root["zButtonRanged"]["children"]["size"] = 36
root["zButtonRanged"]["children"]["hideonclick"] = 1
end
ZHunterMod_Ranged_Weapons = ZHunterMod_Ranged_Weapons or {}
local ZHUNTER_RANGED_MAX_COUNT = 80
local zButtonRanged_Cache = {}
local zButtonRanged_TooltipWarmed = false
local function zButtonRanged_GetKnownItemSpeed(itemId)
local idNum = tonumber(itemId)
if not idNum then
return nil
end
local items = _G["MTH_DS_Items"] or MTH_DS_AmmoItems
local item = items and items[idNum]
local speedVal = item and tonumber(item.speed)
if speedVal and speedVal > 0 then
return speedVal
end
return nil
end
local function zButtonRanged_GetSaved()
local currentRoot = zButtonRanged_GetRoot()
if not currentRoot["zButtonRanged"] then
currentRoot["zButtonRanged"] = {}
end
return currentRoot["zButtonRanged"]
end
local function zButtonRanged_GetColorGradient(perc)
perc = perc > 1 and 1 or perc
perc = perc < 0 and 0 or perc
local r1, g1, b1, r2, g2, b2
if perc <= 0.5 then
perc = perc * 2
r1, g1, b1 = 1, 0, 0
r2, g2, b2 = 1, 1, 0
else
perc = perc * 2 - 1
r1, g1, b1 = 1, 1, 0
r2, g2, b2 = 0, 1, 0
end
local r = r1 + (r2 - r1) * perc
local g = g1 + (g2 - g1) * perc
local b = b1 + (b2 - b1) * perc
return r, g, b
end
local function zButtonRanged_EnsureDurabilityText(button)
if button and not button.rangedDurabilityText then
button.rangedDurabilityText = button:CreateFontString(nil, "OVERLAY")
button.rangedDurabilityText:SetPoint("BOTTOMRIGHT", button)
button.rangedDurabilityText:SetFont("Fonts\\ARIALN.ttf", 13, "OUTLINE")
end
return button and button.rangedDurabilityText
end
local function zButtonRanged_EnsureSpeedText(button)
if button and not button.rangedSpeedText then
button.rangedSpeedText = button:CreateFontString(nil, "OVERLAY")
button.rangedSpeedText:SetPoint("TOPLEFT", button, "TOPLEFT", 1, -1)
button.rangedSpeedText:SetFont("Fonts\\ARIALN.ttf", 9, "OUTLINE")
end
return button and button.rangedSpeedText
end
local function zButtonRanged_IsRangedItem(subtype, equipLoc)
local subtypeText = tostring(subtype or "")
if subtypeText == tostring(MTH_WEAPON_BOWS or "Bows") then return true end
if subtypeText == tostring(MTH_WEAPON_GUNS or "Guns") then return true end
if subtypeText == tostring(MTH_WEAPON_CROSSBOWS or "Crossbows") then return true end
if subtypeText == "Thrown" then return true end
if equipLoc == "INVTYPE_RANGED" or equipLoc == "INVTYPE_RANGEDRIGHT" or equipLoc == "INVTYPE_THROWN" then
return true
end
return false
end
local function zButtonRanged_RebuildCache()
zButtonRanged_Cache = {}
for bag = 0, 4 do
for slot = 1, GetContainerNumSlots(bag) do
local link = GetContainerItemLink(bag, slot)
if link then
local _, _, id = string.find(link, "Hitem:((%d+).-)")
if id then
local itemNameResolved, itemLink, itemQuality, itemReqLevel, _, itemSubtype, _, itemEquipLoc, itemIcon = GetItemInfo(id)
local _, _, linkName = string.find(link, "%[(.+)%]")
local itemName = itemNameResolved or linkName
if itemName and zButtonRanged_IsRangedItem(itemSubtype, itemEquipLoc) then
local _, itemCount = GetContainerItemInfo(bag, slot)
local knownSpeed = zButtonRanged_GetKnownItemSpeed(id)
local rangedInfo = zButtonRanged_Cache[itemName]
if not rangedInfo then
rangedInfo = {
name = itemName,
quality = itemQuality,
reqLevel = itemReqLevel,
subtype = itemSubtype,
equipLoc = itemEquipLoc,
bag = bag,
slot = slot,
id = id,
link = link,
icon = itemIcon,
speed = knownSpeed,
count = 0,
}
zButtonRanged_Cache[itemName] = rangedInfo
end
if rangedInfo.speed == nil and knownSpeed ~= nil then
rangedInfo.speed = knownSpeed
end
rangedInfo.count = (rangedInfo.count or 0) + (itemCount or 0)
end
end
end
end
end
end
local function zButtonRanged_GetOrderedWeapons()
local names = {}
for weaponName, weaponInfo in pairs(zButtonRanged_Cache) do
if weaponName and weaponInfo and (tonumber(weaponInfo.count) or 0) > 0 then
table.insert(names, weaponName)
end
end
table.sort(names, function(a, b)
local infoA = zButtonRanged_Cache[a] or {}
local infoB = zButtonRanged_Cache[b] or {}
local lvlA = tonumber(infoA.reqLevel) or 0
local lvlB = tonumber(infoB.reqLevel) or 0
if lvlA ~= lvlB then
return lvlA < lvlB
end
local qualityA = tonumber(infoA.quality) or 0
local qualityB = tonumber(infoB.quality) or 0
if qualityA ~= qualityB then
return qualityA < qualityB
end
return tostring(a) < tostring(b)
end)
return names
end
local function zButtonRanged_EnsureSpellOrder(weapons)
local saved = zButtonRanged_GetSaved()
if not saved["spells"] then
saved["spells"] = {}
end
if not saved["visible"] then
saved["visible"] = {}
end
local maxWeapons = table.getn(weapons or {})
local needsReset = false
for i = 1, maxWeapons do
local index = saved["spells"][i]
if not tonumber(index) or index < 1 or index > maxWeapons then
needsReset = true
break
end
end
if needsReset or table.getn(saved["spells"]) ~= maxWeapons then
saved["spells"] = {}
for i = 1, maxWeapons do
saved["spells"][i] = i
end
end
for i = 1, maxWeapons do
if saved["visible"][i] == nil then
saved["visible"][i] = 1
end
end
end
local function zButtonRanged_AssignButtonFromInfo(button, weaponInfo)
if not (button and weaponInfo) then
return false
end
button.id = weaponInfo.id
button.icon = weaponInfo.icon
button.isspell = nil
button.ammoname = weaponInfo.name
button.ammobag = weaponInfo.bag
button.ammoslot = weaponInfo.slot
button.ammoid = weaponInfo.id
button.ammolink = weaponInfo.link
button.ammocount = weaponInfo.count
button.rangedType = weaponInfo.subtype
button.rangedReqLevel = weaponInfo.reqLevel
button.rangedQuality = weaponInfo.quality
button.rangedSpeed = weaponInfo.speed
return true
end
local function zButtonRanged_ApplyRuntimeSettings()
if not zButtonRanged then
return
end
local saved = zButtonRanged_GetSaved()
zButtonRanged.tooltip = saved["tooltip"] and true or false
zButtonRanged.hideonclick = saved["children"] and saved["children"]["hideonclick"] and true or false
end
local function zButtonRanged_UpdateDurabilityText(button)
local text = zButtonRanged_EnsureDurabilityText(button)
if not text then
return
end
if button ~= zButtonRanged then
text:SetText("")
return
end
if type(GetInventoryItemDurability) ~= "function" then
text:SetText("")
return
end
local cur, max = nil, nil
local okPlayer, cPlayer, mPlayer = pcall(GetInventoryItemDurability, "player", 18)
if okPlayer then
cur, max = cPlayer, mPlayer
else
local okSlot, cSlot, mSlot = pcall(GetInventoryItemDurability, 18)
if okSlot then
cur, max = cSlot, mSlot
end
end
cur = tonumber(cur)
max = tonumber(max)
if not cur or not max or max <= 0 then
text:SetText("")
return
end
local perc = math.floor(((cur / max) * 100) + 0.5)
if perc >= 100 then
text:SetText("")
return
end
local r, g, b = zButtonRanged_GetColorGradient(cur / max)
text:SetTextColor(r, g, b)
text:SetText(tostring(perc) .. "%")
end
local function zButtonRanged_UpdateSpeedText(button)
local text = zButtonRanged_EnsureSpeedText(button)
if not text then
return
end
local speedVal = tonumber(button and button.rangedSpeed)
if not speedVal then
text:SetText("")
return
end
text:SetText(string.format("%.2f", speedVal))
end
local function zButtonRanged_UpdateParentFromEquipped()
if not zButtonRanged then
return false
end
local equippedLink = GetInventoryItemLink("player", 18)
if not equippedLink then
return false
end
local _, _, linkName = string.find(equippedLink, "%[(.+)%]")
local _, _, itemId = string.find(equippedLink, "item:(%d+)")
if not itemId then
local _, _, altId = string.find(equippedLink, "Hitem:((%d+).-)")
itemId = altId
end
local itemName, _, itemQuality, itemReqLevel, _, itemSubtype, _, itemEquipLoc, itemIcon = GetItemInfo(itemId)
itemName = itemName or linkName
if not itemName then
return false
end
if (itemSubtype or itemEquipLoc) and not zButtonRanged_IsRangedItem(itemSubtype, itemEquipLoc) then
return false
end
local cacheInfo = zButtonRanged_Cache[itemName]
local info = {
name = itemName,
quality = itemQuality,
reqLevel = itemReqLevel,
subtype = itemSubtype,
equipLoc = itemEquipLoc,
bag = cacheInfo and cacheInfo.bag or nil,
slot = cacheInfo and cacheInfo.slot or nil,
id = itemId,
link = equippedLink,
icon = itemIcon or GetInventoryItemTexture("player", 18),
speed = (cacheInfo and cacheInfo.speed) or zButtonRanged_GetKnownItemSpeed(itemId),
count = cacheInfo and cacheInfo.count or 1,
}
if not info.icon then
info.icon = GetInventoryItemTexture("player", 18)
end
zButtonRanged_AssignButtonFromInfo(zButtonRanged, info)
zButtonRanged:Enable()
zButtonRanged:Show()
return true
end
local function zButtonRanged_SetButtons(parent, weaponNames)
if not (parent and parent.count) then
return 0
end
for i = 1, parent.count do
local child = getglobal(parent.name .. i)
if child then
child:Hide()
child.id = nil
child.icon = nil
child.isspell = nil
child.ammoname = nil
child.ammobag = nil
child.ammoslot = nil
end
end
local found = 0
for i = 1, table.getn(weaponNames or {}) do
if found >= parent.count then
break
end
local weaponName = weaponNames[i]
local weaponInfo = weaponName and zButtonRanged_Cache[weaponName] or nil
if weaponInfo and weaponInfo.id then
found = found + 1
local child = getglobal(parent.name .. found)
if child then
zButtonRanged_AssignButtonFromInfo(child, weaponInfo)
zButtonRanged_UpdateButton(child)
child:Show()
end
end
end
local hasEquipped = zButtonRanged_UpdateParentFromEquipped()
if not hasEquipped and found > 0 then
local first = getglobal(parent.name .. 1)
if first then
zButtonRanged_AssignButtonFromInfo(parent, {
name = first.ammoname,
quality = first.rangedQuality,
reqLevel = first.rangedReqLevel,
subtype = first.rangedType,
equipLoc = nil,
bag = first.ammobag,
slot = first.ammoslot,
id = first.ammoid or first.id,
link = first.ammolink,
icon = first.icon,
speed = first.rangedSpeed,
count = first.ammocount,
})
zButtonRanged_UpdateButton(parent)
parent:Enable()
parent:Show()
end
end
if found <= 0 and not hasEquipped then
parent.id = nil
parent.icon = nil
parent.ammoname = nil
parent:Hide()
else
parent:Show()
end
return found
end
function zButtonRanged_UpdateButton(button)
if not button then
button = this
end
if not (button and button.icontexture) then
return
end
if not button.id then
button.icontexture:Hide()
zButtonRanged_UpdateSpeedText(button)
zButtonRanged_UpdateDurabilityText(button)
return
end
button.icontexture:SetTexture(button.icon)
button.icontexture:Show()
zButtonRanged_UpdateSpeedText(button)
zButtonRanged_UpdateDurabilityText(button)
end
local function zButtonRanged_OnEnter(button)
if not button then
button = this
end
if not button then
return
end
if not (zButtonRanged and zButtonRanged.tooltip) then
return
end
GameTooltip:SetOwner(button, "ANCHOR_TOPLEFT")
if button == zButtonRanged then
if not GameTooltip:SetInventoryItem("player", 18) and button.ammobag and button.ammoslot then
GameTooltip:SetBagItem(button.ammobag, button.ammoslot)
end
elseif button.ammobag and button.ammoslot then
GameTooltip:SetBagItem(button.ammobag, button.ammoslot)
elseif button.ammolink then
GameTooltip:SetHyperlink(button.ammolink)
end
GameTooltip:Show()
end
local function zButtonRanged_PrewarmTooltipOnce()
if zButtonRanged_TooltipWarmed then
return
end
zButtonRanged_TooltipWarmed = true
if not GameTooltip then
return
end
GameTooltip:SetOwner(UIParent, "ANCHOR_NONE")
GameTooltip:ClearLines()
if zButtonRanged and zButtonRanged.ammolink then
GameTooltip:SetHyperlink(zButtonRanged.ammolink)
elseif zButtonRanged and zButtonRanged.ammobag and zButtonRanged.ammoslot then
GameTooltip:SetBagItem(zButtonRanged.ammobag, zButtonRanged.ammoslot)
else
GameTooltip:SetInventoryItem("player", 18)
end
GameTooltip:Hide()
end
local function zButtonRanged_EquipFromButton(button)
if not (button and button.ammobag and button.ammoslot) then
return false
end
PickupContainerItem(button.ammobag, button.ammoslot)
if CursorHasItem() then
EquipCursorItem(18)
end
if CursorHasItem() then
if ClearCursor then ClearCursor() end
return false
end
zButtonRanged_UpdateParentFromEquipped()
zButtonRanged_UpdateButton(zButtonRanged)
return true
end
local function zButtonRanged_BeforeClick(button)
if not button then
return false
end
if button.isspell then
return false
end
zButtonRanged_EquipFromButton(button)
return true
end
local function zButtonRanged_RefreshButtonsFromState()
if not zButtonRanged then
return
end
local saved = zButtonRanged_GetSaved()
zButtonRanged_RebuildCache()
local weapons = zButtonRanged_GetOrderedWeapons()
ZHunterMod_Ranged_Weapons = weapons
zButtonRanged_EnsureSpellOrder(weapons)
local info = {}
local infoIndex = 1
for i = 1, table.getn(weapons) do
local weaponIndex = saved["spells"][i]
if weaponIndex and saved["visible"][weaponIndex] ~= false then
info[infoIndex] = weapons[weaponIndex]
infoIndex = infoIndex + 1
end
end
zButtonRanged.found = ZSpellButton_SetButtons(zButtonRanged, info)
zButtonRanged_ApplyRuntimeSettings()
end
local function zButtonRanged_EnsureConfig()
local saved = zButtonRanged_GetSaved()
saved["count"] = nil
if saved["enabled"] == nil then
saved["enabled"] = false
end
if saved["tooltip"] == nil then
saved["tooltip"] = 1
end
if not saved["children"] then
saved["children"] = {}
end
if saved["children"]["hideonclick"] == nil then
saved["children"]["hideonclick"] = 1
end
if not saved["spells"] then
saved["spells"] = {}
end
if not saved["visible"] then
saved["visible"] = {}
end
if not saved["parent"] then
saved["parent"] = {}
end
if not saved["children"]["size"] then
saved["children"]["size"] = 36
end
if not saved["parent"]["size"] then
saved["parent"]["size"] = 36
end
if saved["parent"]["circle"] == nil then
saved["parent"]["circle"] = 1
end
if not saved["rows"] or saved["rows"] < 1 then
saved["rows"] = 1
end
if not saved["firstbutton"] then
saved["firstbutton"] = "RIGHT"
end
end
function zButtonRanged_OnLoad()
this:RegisterEvent("VARIABLES_LOADED")
end
function zButtonRanged_OnEvent()
if event == "VARIABLES_LOADED" then
if not zButtonRanged then
return
end
if UnitClass("player") ~= ZHUNTER_HUNTER then
zButtonRanged:UnregisterAllEvents()
zButtonRanged:Hide()
return
end
zButtonRanged.customSetButtons = zButtonRanged_SetButtons
zButtonRanged.customUpdateButton = zButtonRanged_UpdateButton
zButtonRanged.beforeclick = zButtonRanged_BeforeClick
zButtonRanged_CreateButtons()
zButtonRangedAdjustment = CreateFrame("Frame", "zButtonRangedAdjustment")
zButtonRangedAdjustment:RegisterEvent("UNIT_INVENTORY_CHANGED")
zButtonRangedAdjustment:RegisterEvent("BAG_UPDATE")
zButtonRangedAdjustment:RegisterEvent("PLAYER_ENTERING_WORLD")
zButtonRangedAdjustment:SetScript("OnEvent", zButtonRangedAdjustment_OnEvent)
zButtonRanged_SetupSizeAndPosition()
end
end
function zButtonRanged_CreateButtons()
zButtonRanged_EnsureConfig()
if not zButtonRanged.children then
ZSpellButton_CreateChildren(zButtonRanged, "zButtonRanged", ZHUNTER_RANGED_MAX_COUNT)
else
zButtonRanged.count = ZHUNTER_RANGED_MAX_COUNT
end
zButtonRanged:SetScript("OnEnter", function()
zButtonRanged_OnEnter(this)
end)
for i = 1, zButtonRanged.count do
local child = getglobal("zButtonRanged" .. i)
if child then
child:SetScript("OnEnter", function()
zButtonRanged_OnEnter(this)
end)
end
end
zButtonRanged_RefreshButtonsFromState()
end
function zButtonRanged_SetupSizeAndPosition()
local saved = zButtonRanged_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then
if zButtonRanged and zButtonRanged.Hide then
zButtonRanged:Hide()
end
return
end
local displayCount = zButtonRanged.found or 0
if displayCount < 0 then
displayCount = 0
end
ZSpellButton_SetSize(zButtonRanged, saved["parent"]["size"])
ZSpellButton_SetSize(zButtonRanged, saved["children"]["size"], 1)
ZSpellButton_SetExpandDirection(zButtonRanged, saved["firstbutton"])
ZSpellButton_ArrangeChildren(zButtonRanged, saved["rows"], displayCount, saved["horizontal"], saved["vertical"])
zButtonRanged_UpdateButton(zButtonRanged)
end
function zButtonRanged_Reset()
local currentRoot = zButtonRanged_GetRoot()
currentRoot["zButtonRanged"] = {}
local saved = zButtonRanged_GetSaved()
saved["spells"] = {}
saved["visible"] = {}
saved["rows"] = 1
saved["horizontal"] = nil
saved["vertical"] = nil
saved["firstbutton"] = "RIGHT"
saved["enabled"] = false
saved["tooltip"] = 1
saved["parent"] = {}
saved["parent"]["size"] = 36
saved["parent"]["hide"] = nil
saved["parent"]["circle"] = 1
saved["children"] = {}
saved["children"]["size"] = 36
saved["children"]["hideonclick"] = 1
zButtonRanged_EnsureConfig()
end
function zButtonRangedAdjustment_OnEvent()
if not zButtonRanged then
return
end
if event == "UNIT_INVENTORY_CHANGED" and arg1 and arg1 ~= "player" then
return
end
zButtonRanged_RefreshButtonsFromState()
zButtonRanged_SetupSizeAndPosition()
if event == "PLAYER_ENTERING_WORLD" then
zButtonRanged_PrewarmTooltipOnce()
end
if GameTooltip:IsOwned(zButtonRanged) then
zButtonRanged_OnEnter(zButtonRanged)
end
end
function zButtonRanged_KeyBinding(index)
if MTH_ZH_IsModuleEnabled and not MTH_ZH_IsModuleEnabled() then
return
end
local button
if index then
button = getglobal("zButtonRanged" .. index)
else
button = zButtonRanged
end
if button then
zButtonRanged_EquipFromButton(button)
if zButtonRanged.hideonclick then
if type(ZSpellButton_SetChildrenExpanded) == "function" then
ZSpellButton_SetChildrenExpanded(zButtonRanged, false)
elseif zButtonRanged.children then
zButtonRanged.children:Hide()
end
end
end
end
SLASH_zButtonRanged1 = "/ZRanged"
SlashCmdList["zButtonRanged"] = function(msg)
if MTH_ZH_HandleDisabledSlash and MTH_ZH_HandleDisabledSlash("Ranged button is disabled while module 'zhunter' is disabled.") then
return
end
if msg == "reset" then
zButtonRanged_Reset()
zButtonRanged:ClearAllPoints()
zButtonRanged:SetPoint("CENTER", UIParent, "CENTER", 120, 0)
zButtonRanged_RefreshButtonsFromState()
zButtonRanged_SetupSizeAndPosition()
elseif msg == "options" then
MTH_OpenOptions("Ranged")
else
MTH_ZH_Print("Possible Commands: \"reset\", \"options\"")
end
end
+14
View File
@@ -0,0 +1,14 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Frame name="zButtonRangedFrame">
</Frame>
<CheckButton name="zButtonRanged" inherits="ZSpellButtonTemplate">
<Anchors>
<Anchor point="CENTER" relativeTo="UIParent" relativePoint="CENTER">
<Offset>
<AbsDimension x="120" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
</Ui>
+1
View File
@@ -103,6 +103,7 @@ local function zButtonTrack_ApplyRuntimeSettings()
zButtonTrack.hideonclick = saved["children"] and saved["children"]["hideonclick"] and true or false
end
function zButtonTrack_OnLoad()
this:RegisterEvent("VARIABLES_LOADED")
end
+1
View File
@@ -96,6 +96,7 @@ local function zButtonTrap_ApplyRuntimeSettings()
zButtonTrap.hideonclick = saved["children"] and saved["children"]["hideonclick"] and true or false
end
function zButtonTrap_OnLoad()
this:RegisterEvent("VARIABLES_LOADED")
end