mirror of
https://codeberg.org/Duvelcorp/MetaHunt.git
synced 2026-09-27 01:56:04 +00:00
v1.1.0
This commit is contained in:
@@ -632,7 +632,7 @@ end
|
||||
function Engine:EnsureDefaults()
|
||||
local store = self:GetConfigStore()
|
||||
if store.enabled == nil then
|
||||
store.enabled = true
|
||||
store.enabled = false
|
||||
end
|
||||
if type(store.food) ~= "table" then
|
||||
store.food = {}
|
||||
@@ -647,13 +647,13 @@ function Engine:EnsureDefaults()
|
||||
store.petFood = {}
|
||||
end
|
||||
if store.food.enabled == nil then
|
||||
store.food.enabled = true
|
||||
store.food.enabled = false
|
||||
end
|
||||
if store.ammo.enabled == nil then
|
||||
store.ammo.enabled = true
|
||||
store.ammo.enabled = false
|
||||
end
|
||||
if store.projectiles.enabled == nil then
|
||||
store.projectiles.enabled = true
|
||||
store.projectiles.enabled = false
|
||||
end
|
||||
if store.petFood.enabled == nil then
|
||||
store.petFood.enabled = false
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
local MTH_AutoBuy = {
|
||||
name = "autobuy",
|
||||
enabled = false,
|
||||
version = "1.0.6",
|
||||
version = "1.1.0",
|
||||
events = {
|
||||
"VARIABLES_LOADED",
|
||||
"MERCHANT_SHOW",
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<!--
|
||||
MetaHunt Auto Quest Module Loader
|
||||
-->
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
||||
<Include file="module.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,987 @@
|
||||
------------------------------------------------------
|
||||
-- MetaHunt: Quest Automation Module
|
||||
-- SHIFT-rightclick automation for specific quest flows
|
||||
------------------------------------------------------
|
||||
|
||||
local MTH_AutoQuest = {
|
||||
name = "autoquest",
|
||||
enabled = false,
|
||||
version = "1.1.0",
|
||||
events = {
|
||||
"GOSSIP_SHOW",
|
||||
"QUEST_GREETING",
|
||||
"QUEST_DETAIL",
|
||||
"QUEST_PROGRESS",
|
||||
"QUEST_COMPLETE",
|
||||
},
|
||||
initialized = false,
|
||||
}
|
||||
|
||||
local QA_SCORPOK_QUEST_ID = 2586
|
||||
local QA_SCORPOK_QUEST_TITLE = "Salt of the Scorpok"
|
||||
local QA_SCORPOK_NPC_ID = 7505
|
||||
local QA_SCORPOK_NPC_NAME = "Bloodmage Drazial"
|
||||
local QA_SISSIES_QUEST_ID = 7342
|
||||
local QA_SISSIES_QUEST_TITLE = "Arrows Are For Sissies"
|
||||
local QA_SISSIES_NPC_ID = 14183
|
||||
local QA_SISSIES_NPC_NAME = "Artilleryman Sheldonore"
|
||||
local QA_ITEM_SCORPOK_PINCER_ID = 8393
|
||||
local QA_ITEM_BLASTED_BOAR_LUNG_ID = 8392
|
||||
local QA_ITEM_VULTURE_GIZZARD_ID = 8396
|
||||
local QA_ITEM_GROUND_SCORPOK_ASSAY_ID = 8412
|
||||
local QA_ITEM_SCORPOK_PINCER_NAME = "Scorpok Pincer"
|
||||
local QA_ITEM_BLASTED_BOAR_LUNG_NAME = "Blasted Boar Lung"
|
||||
local QA_ITEM_VULTURE_GIZZARD_NAME = "Vulture Gizzard"
|
||||
local QA_ITEM_GROUND_SCORPOK_ASSAY_NAME = "Ground Scorpok Assay"
|
||||
|
||||
local QA_DirectEventFrame = nil
|
||||
local QA_TooltipHooked = false
|
||||
local QA_TooltipPollFrame = nil
|
||||
local QA_TooltipRefreshFrame = nil
|
||||
|
||||
local function QA_Debug(message)
|
||||
return
|
||||
end
|
||||
|
||||
local function QA_CopyValue(value)
|
||||
if type(value) ~= "table" then
|
||||
return value
|
||||
end
|
||||
local copy = {}
|
||||
for key, entry in pairs(value) do
|
||||
copy[key] = QA_CopyValue(entry)
|
||||
end
|
||||
return copy
|
||||
end
|
||||
|
||||
local function QA_GetOptionsStore()
|
||||
if type(MTH_CharSavedVariables) ~= "table" then
|
||||
MTH_CharSavedVariables = {}
|
||||
end
|
||||
if type(MTH_CharSavedVariables.autoquest) ~= "table" then
|
||||
MTH_CharSavedVariables.autoquest = {}
|
||||
end
|
||||
local store = MTH_CharSavedVariables.autoquest
|
||||
|
||||
if store._migrated ~= true then
|
||||
if type(MTH_CharSavedVariables.questautomation) == "table" then
|
||||
local legacyStore = MTH_CharSavedVariables.questautomation
|
||||
if legacyStore.scorpokDrazial ~= nil and store.scorpokDrazial == nil then
|
||||
store.scorpokDrazial = legacyStore.scorpokDrazial and true or false
|
||||
end
|
||||
if legacyStore.scorpokTooltip ~= nil and store.scorpokTooltip == nil then
|
||||
store.scorpokTooltip = legacyStore.scorpokTooltip and true or false
|
||||
end
|
||||
end
|
||||
local legacyChar = nil
|
||||
local legacyAccount = nil
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
legacyChar = MTH:GetModuleCharSavedVariables("autoquest")
|
||||
if type(legacyChar) ~= "table" then
|
||||
legacyChar = MTH:GetModuleCharSavedVariables("questautomation")
|
||||
end
|
||||
end
|
||||
if MTH and MTH.GetModuleSavedVariables then
|
||||
legacyAccount = MTH:GetModuleSavedVariables("autoquest")
|
||||
if type(legacyAccount) ~= "table" then
|
||||
legacyAccount = MTH:GetModuleSavedVariables("questautomation")
|
||||
end
|
||||
end
|
||||
if type(legacyChar) == "table" and legacyChar.scorpokDrazial ~= nil and store.scorpokDrazial == nil then
|
||||
store.scorpokDrazial = legacyChar.scorpokDrazial and true or false
|
||||
elseif type(legacyAccount) == "table" and legacyAccount.scorpokDrazial ~= nil and store.scorpokDrazial == nil then
|
||||
store.scorpokDrazial = legacyAccount.scorpokDrazial and true or false
|
||||
elseif store.scorpokDrazial == nil and MTH and MTH.GetModuleCharSavedVariables then
|
||||
local autobuyStore = MTH:GetModuleCharSavedVariables("autobuy")
|
||||
if type(autobuyStore) == "table"
|
||||
and type(autobuyStore.questAutomation) == "table"
|
||||
and autobuyStore.questAutomation.scorpokDrazial ~= nil then
|
||||
store.scorpokDrazial = autobuyStore.questAutomation.scorpokDrazial and true or false
|
||||
end
|
||||
end
|
||||
store._migrated = true
|
||||
end
|
||||
|
||||
if store.scorpokDrazial == nil then
|
||||
store.scorpokDrazial = false
|
||||
end
|
||||
if store.arrowsForSissies == nil then
|
||||
store.arrowsForSissies = false
|
||||
end
|
||||
if store.scorpokTooltip == nil then
|
||||
store.scorpokTooltip = false
|
||||
end
|
||||
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
|
||||
if type(moduleStore) == "table" then
|
||||
moduleStore.scorpokDrazial = store.scorpokDrazial and true or false
|
||||
moduleStore.arrowsForSissies = store.arrowsForSissies and true or false
|
||||
moduleStore.scorpokTooltip = store.scorpokTooltip and true or false
|
||||
end
|
||||
end
|
||||
|
||||
return store
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:GetStore()
|
||||
return QA_GetOptionsStore()
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:SetScorpokDrazialEnabled(enabled)
|
||||
local store = QA_GetOptionsStore()
|
||||
store.scorpokDrazial = enabled and true or false
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
|
||||
if type(moduleStore) == "table" then
|
||||
moduleStore.scorpokDrazial = store.scorpokDrazial and true or false
|
||||
end
|
||||
end
|
||||
QA_Debug("option write: scorpokDrazial=" .. tostring(store.scorpokDrazial and true or false))
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:SetArrowsForSissiesEnabled(enabled)
|
||||
local store = QA_GetOptionsStore()
|
||||
store.arrowsForSissies = enabled and true or false
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
|
||||
if type(moduleStore) == "table" then
|
||||
moduleStore.arrowsForSissies = store.arrowsForSissies and true or false
|
||||
end
|
||||
end
|
||||
QA_Debug("option write: arrowsForSissies=" .. tostring(store.arrowsForSissies and true or false))
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:SetScorpokTooltipEnabled(enabled)
|
||||
local store = QA_GetOptionsStore()
|
||||
store.scorpokTooltip = enabled and true or false
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
|
||||
if type(moduleStore) == "table" then
|
||||
moduleStore.scorpokTooltip = store.scorpokTooltip and true or false
|
||||
end
|
||||
end
|
||||
QA_Debug("option write: scorpokTooltip=" .. tostring(store.scorpokTooltip and true or false))
|
||||
end
|
||||
|
||||
local function QA_IsScorpokAutomationEnabled()
|
||||
local store = QA_GetOptionsStore()
|
||||
return store and store.scorpokDrazial and true or false
|
||||
end
|
||||
|
||||
local function QA_IsArrowsForSissiesAutomationEnabled()
|
||||
local store = QA_GetOptionsStore()
|
||||
return store and store.arrowsForSissies and true or false
|
||||
end
|
||||
|
||||
local function QA_IsScorpokTooltipEnabled()
|
||||
local store = QA_GetOptionsStore()
|
||||
return store and store.scorpokTooltip and true or false
|
||||
end
|
||||
|
||||
local function QA_NormalizeText(value)
|
||||
local text = string.lower(tostring(value or ""))
|
||||
text = string.gsub(text, "[^%a%d]", "")
|
||||
return text
|
||||
end
|
||||
|
||||
local function QA_IsTitleMatch(title, expectedTitle)
|
||||
if type(title) ~= "string" or title == "" then
|
||||
return false
|
||||
end
|
||||
return QA_NormalizeText(title) == QA_NormalizeText(expectedTitle)
|
||||
end
|
||||
|
||||
local function QA_IsScorpokTitle(title)
|
||||
return QA_IsTitleMatch(title, QA_SCORPOK_QUEST_TITLE)
|
||||
end
|
||||
|
||||
local function QA_IsArrowsForSissiesTitle(title)
|
||||
return QA_IsTitleMatch(title, QA_SISSIES_QUEST_TITLE)
|
||||
end
|
||||
|
||||
local function QA_IsQuestContext(title, expectedQuestId, titleMatcher)
|
||||
if type(GetQuestID) == "function" then
|
||||
local questId = tonumber(GetQuestID())
|
||||
if questId and questId == expectedQuestId then
|
||||
return true
|
||||
end
|
||||
end
|
||||
if type(titleMatcher) == "function" then
|
||||
return titleMatcher(title)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function QA_IsScorpokQuestContext(title)
|
||||
return QA_IsQuestContext(title, QA_SCORPOK_QUEST_ID, QA_IsScorpokTitle)
|
||||
end
|
||||
|
||||
local function QA_IsArrowsForSissiesQuestContext(title)
|
||||
return QA_IsQuestContext(title, QA_SISSIES_QUEST_ID, QA_IsArrowsForSissiesTitle)
|
||||
end
|
||||
|
||||
local function QA_GetNpcIdFromGuid(guid)
|
||||
if type(guid) ~= "string" or guid == "" then
|
||||
return nil
|
||||
end
|
||||
|
||||
local _, _, _, _, _, npcId = string.find(guid, "^Creature%-%d+%-%d+%-%d+%-%d+%-(%d+)%-%x+$")
|
||||
if npcId then
|
||||
return tonumber(npcId)
|
||||
end
|
||||
|
||||
if string.sub(guid, 1, 2) == "0x" and string.len(guid) >= 12 then
|
||||
local hex = string.sub(guid, 9, 12)
|
||||
local parsed = tonumber(hex, 16)
|
||||
if parsed and parsed > 0 then
|
||||
return parsed
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function QA_ColorByThreshold(count, threshold)
|
||||
local value = math.floor(tonumber(count) or 0)
|
||||
if value <= 0 then
|
||||
return "|cffff0000" .. tostring(value) .. "|r"
|
||||
end
|
||||
local modFn = nil
|
||||
if type(rawget) == "function" and type(math) == "table" then
|
||||
modFn = rawget(math, "mod") or rawget(math, "fmod")
|
||||
elseif type(math) == "table" then
|
||||
modFn = math.fmod
|
||||
end
|
||||
if threshold > 0 and type(modFn) == "function" and modFn(value, threshold) == 0 then
|
||||
return "|cff00ff00" .. tostring(value) .. "|r"
|
||||
end
|
||||
return "|cffffa500" .. tostring(value) .. "|r"
|
||||
end
|
||||
|
||||
local function QA_ColorAssay(count)
|
||||
local value = math.floor(tonumber(count) or 0)
|
||||
if value > 0 then
|
||||
return "|cff66ccff" .. tostring(value) .. "|r"
|
||||
end
|
||||
return tostring(value)
|
||||
end
|
||||
|
||||
local function QA_MatchesItem(itemId, itemName, expectedId, expectedName)
|
||||
if expectedId and tonumber(itemId) == tonumber(expectedId) then
|
||||
return true
|
||||
end
|
||||
if type(itemName) == "string" and type(expectedName) == "string" and QA_NormalizeText(itemName) == QA_NormalizeText(expectedName) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function QA_CountItemInBags(expectedId, expectedName)
|
||||
local getContainerNumSlots = _G and _G["GetContainerNumSlots"] or nil
|
||||
local getContainerItemLink = _G and _G["GetContainerItemLink"] or nil
|
||||
local getContainerItemInfo = _G and _G["GetContainerItemInfo"] or nil
|
||||
local getItemInfo = _G and _G["GetItemInfo"] or nil
|
||||
if type(getContainerNumSlots) ~= "function" or type(getContainerItemLink) ~= "function" then
|
||||
return 0
|
||||
end
|
||||
|
||||
local total = 0
|
||||
for bag = 0, 4 do
|
||||
local slots = math.floor(tonumber(getContainerNumSlots(bag)) or 0)
|
||||
for slot = 1, slots do
|
||||
local link = getContainerItemLink(bag, slot)
|
||||
if type(link) == "string" and link ~= "" then
|
||||
local itemId = tonumber(string.match(link, "item:(%d+)"))
|
||||
local itemName = nil
|
||||
if type(getItemInfo) == "function" then
|
||||
itemName = getItemInfo(link)
|
||||
end
|
||||
if QA_MatchesItem(itemId, itemName, expectedId, expectedName) then
|
||||
local texture, stackCount = nil, nil
|
||||
if type(getContainerItemInfo) == "function" then
|
||||
texture, stackCount = getContainerItemInfo(bag, slot)
|
||||
end
|
||||
total = total + math.floor(tonumber(stackCount) or 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return total
|
||||
end
|
||||
|
||||
local function QA_TooltipTrace(message, force)
|
||||
return
|
||||
end
|
||||
|
||||
local function QA_GetTooltipNpc(tooltip)
|
||||
if not tooltip or type(tooltip.GetUnit) ~= "function" then
|
||||
return nil, nil, nil, nil
|
||||
end
|
||||
local ok, unitA, unitB = pcall(function()
|
||||
return tooltip:GetUnit()
|
||||
end)
|
||||
local unit = nil
|
||||
if ok then
|
||||
if type(unitB) == "string" and unitB ~= "" then
|
||||
unit = unitB
|
||||
elseif type(unitA) == "string" and unitA ~= "" then
|
||||
unit = unitA
|
||||
end
|
||||
end
|
||||
if (type(unit) ~= "string" or unit == "") and type(UnitExists) == "function" and UnitExists("mouseover") then
|
||||
unit = "mouseover"
|
||||
end
|
||||
if type(unit) ~= "string" or unit == "" then
|
||||
local left1 = (type(getglobal) == "function" and getglobal("GameTooltipTextLeft1")) or (_G and _G["GameTooltipTextLeft1"])
|
||||
local title = left1 and left1.GetText and left1:GetText() or nil
|
||||
if type(title) == "string" and title ~= "" then
|
||||
return nil, title, nil, title
|
||||
end
|
||||
return nil, nil, nil, nil
|
||||
end
|
||||
local guid = UnitGUID and UnitGUID(unit) or nil
|
||||
local npcId = QA_GetNpcIdFromGuid(guid)
|
||||
local name = UnitName and UnitName(unit) or nil
|
||||
local title = nil
|
||||
if (type(name) ~= "string" or name == "") then
|
||||
local left1 = (type(getglobal) == "function" and getglobal("GameTooltipTextLeft1")) or (_G and _G["GameTooltipTextLeft1"])
|
||||
title = left1 and left1.GetText and left1:GetText() or nil
|
||||
if type(title) == "string" and title ~= "" then
|
||||
name = title
|
||||
end
|
||||
end
|
||||
return npcId, name, unit, title
|
||||
end
|
||||
|
||||
local function QA_TooltipAlreadyExtended(tooltip)
|
||||
if not tooltip or type(tooltip.NumLines) ~= "function" then
|
||||
return false
|
||||
end
|
||||
local lines = math.floor(tonumber(tooltip:NumLines()) or 0)
|
||||
for i = 1, lines do
|
||||
local line = (type(getglobal) == "function" and getglobal("GameTooltipTextLeft" .. tostring(i))) or (_G and _G["GameTooltipTextLeft" .. tostring(i)])
|
||||
local text = line and line.GetText and line:GetText() or nil
|
||||
if type(text) == "string" and QA_NormalizeText(text) == QA_NormalizeText("Quest Automation") then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function QA_IsTooltipDrazial(tooltip)
|
||||
local npcId, npcName = QA_GetTooltipNpc(tooltip)
|
||||
if tonumber(npcId) == QA_SCORPOK_NPC_ID then
|
||||
return true
|
||||
end
|
||||
if type(npcName) == "string" and npcName ~= "" and QA_NormalizeText(npcName) == QA_NormalizeText(QA_SCORPOK_NPC_NAME) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function QA_AppendDrazialTooltip(tooltip, sourceTag)
|
||||
sourceTag = tostring(sourceTag or "unknown")
|
||||
if not (MTH_AutoQuest and MTH_AutoQuest.enabled) then
|
||||
QA_TooltipTrace("skip: module disabled source=" .. sourceTag)
|
||||
return
|
||||
end
|
||||
if not QA_IsScorpokAutomationEnabled() or not QA_IsScorpokTooltipEnabled() then
|
||||
QA_TooltipTrace("skip: option disabled source=" .. sourceTag)
|
||||
return
|
||||
end
|
||||
local npcId, npcName, unitToken, title = QA_GetTooltipNpc(tooltip)
|
||||
local isMatch = tonumber(npcId) == QA_SCORPOK_NPC_ID
|
||||
if not isMatch and type(npcName) == "string" and npcName ~= "" and QA_NormalizeText(npcName) == QA_NormalizeText(QA_SCORPOK_NPC_NAME) then
|
||||
isMatch = true
|
||||
end
|
||||
if not isMatch then
|
||||
QA_TooltipTrace("skip: npc mismatch source=" .. sourceTag
|
||||
.. " unit=" .. tostring(unitToken)
|
||||
.. " id=" .. tostring(npcId)
|
||||
.. " name='" .. tostring(npcName or "") .. "'"
|
||||
.. " title='" .. tostring(title or "") .. "'")
|
||||
return
|
||||
end
|
||||
if QA_TooltipAlreadyExtended(tooltip) then
|
||||
QA_TooltipTrace("skip: already-extended source=" .. sourceTag)
|
||||
return
|
||||
end
|
||||
|
||||
local pincerCount = QA_CountItemInBags(QA_ITEM_SCORPOK_PINCER_ID, QA_ITEM_SCORPOK_PINCER_NAME)
|
||||
local gizzardCount = QA_CountItemInBags(QA_ITEM_VULTURE_GIZZARD_ID, QA_ITEM_VULTURE_GIZZARD_NAME)
|
||||
local lungCount = QA_CountItemInBags(QA_ITEM_BLASTED_BOAR_LUNG_ID, QA_ITEM_BLASTED_BOAR_LUNG_NAME)
|
||||
local assayCount = QA_CountItemInBags(QA_ITEM_GROUND_SCORPOK_ASSAY_ID, QA_ITEM_GROUND_SCORPOK_ASSAY_NAME)
|
||||
|
||||
tooltip:AddLine(" ")
|
||||
tooltip:AddLine("|cffffff00Quest Automation|r")
|
||||
tooltip:AddLine("Scorpok Pincer: " .. QA_ColorByThreshold(pincerCount, 3), 1, 1, 1)
|
||||
tooltip:AddLine("Vulture Gizzard: " .. QA_ColorByThreshold(gizzardCount, 2), 1, 1, 1)
|
||||
tooltip:AddLine("Blasted Boar Lung: " .. QA_ColorByThreshold(lungCount, 1), 1, 1, 1)
|
||||
tooltip:AddLine("Ground Scorpok Assay: " .. QA_ColorAssay(assayCount), 1, 1, 1)
|
||||
tooltip:AddLine("Spam SHIFT-click!", 0.7, 0.9, 1)
|
||||
tooltip:AddLine("Recipes: 3x Pincer, 2x Gizzard, 1x Lung", 0.7, 0.7, 0.7)
|
||||
tooltip:Show()
|
||||
QA_TooltipTrace("added: source=" .. sourceTag
|
||||
.. " id=" .. tostring(npcId)
|
||||
.. " name='" .. tostring(npcName or "") .. "'", true)
|
||||
end
|
||||
|
||||
local function QA_EnsureTooltipHook()
|
||||
if QA_TooltipHooked then
|
||||
return
|
||||
end
|
||||
if not GameTooltip then
|
||||
return
|
||||
end
|
||||
|
||||
local hasGetScript = type(GameTooltip.GetScript) == "function"
|
||||
local hasSetScript = type(GameTooltip.SetScript) == "function"
|
||||
local hasHookScript = type(GameTooltip.HookScript) == "function"
|
||||
|
||||
local onTooltipSetUnitExists = false
|
||||
local onShowExists = false
|
||||
if hasGetScript then
|
||||
local okSetUnit, existingSetUnit = pcall(function()
|
||||
return GameTooltip:GetScript("OnTooltipSetUnit")
|
||||
end)
|
||||
onTooltipSetUnitExists = okSetUnit and type(existingSetUnit) == "function"
|
||||
|
||||
local okShow, existingShow = pcall(function()
|
||||
return GameTooltip:GetScript("OnShow")
|
||||
end)
|
||||
onShowExists = okShow and type(existingShow) == "function"
|
||||
end
|
||||
|
||||
if hasHookScript and onTooltipSetUnitExists then
|
||||
pcall(function()
|
||||
GameTooltip:HookScript("OnTooltipSetUnit", function(self)
|
||||
QA_AppendDrazialTooltip(self, "hook:setunit")
|
||||
end)
|
||||
end)
|
||||
elseif hasSetScript and hasGetScript and onTooltipSetUnitExists then
|
||||
local okGetPrev, previous = pcall(function()
|
||||
return GameTooltip:GetScript("OnTooltipSetUnit")
|
||||
end)
|
||||
if okGetPrev then
|
||||
pcall(function()
|
||||
GameTooltip:SetScript("OnTooltipSetUnit", function(self)
|
||||
if type(previous) == "function" then
|
||||
previous(self)
|
||||
end
|
||||
QA_AppendDrazialTooltip(self, "script:setunit")
|
||||
end)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
if hasHookScript and onShowExists then
|
||||
pcall(function()
|
||||
GameTooltip:HookScript("OnShow", function(self)
|
||||
QA_AppendDrazialTooltip(self, "hook:show")
|
||||
end)
|
||||
end)
|
||||
elseif hasSetScript and hasGetScript and onShowExists then
|
||||
local okGetPrevShow, previousShow = pcall(function()
|
||||
return GameTooltip:GetScript("OnShow")
|
||||
end)
|
||||
if okGetPrevShow then
|
||||
pcall(function()
|
||||
GameTooltip:SetScript("OnShow", function(self)
|
||||
if type(previousShow) == "function" then
|
||||
previousShow(self)
|
||||
end
|
||||
QA_AppendDrazialTooltip(self, "script:show")
|
||||
end)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
QA_TooltipHooked = true
|
||||
end
|
||||
|
||||
local function QA_EnsureTooltipPoller()
|
||||
if QA_TooltipPollFrame then
|
||||
return
|
||||
end
|
||||
local frame = CreateFrame("Frame", "MTH_AutoQuestTooltipPollFrame")
|
||||
if not frame then
|
||||
return
|
||||
end
|
||||
frame._mthElapsed = 0
|
||||
frame:SetScript("OnUpdate", function(self, elapsed)
|
||||
self._mthElapsed = (self._mthElapsed or 0) + (elapsed or arg1 or 0)
|
||||
if self._mthElapsed < 0.20 then
|
||||
return
|
||||
end
|
||||
self._mthElapsed = 0
|
||||
if not (MTH_AutoQuest and MTH_AutoQuest.enabled) then
|
||||
return
|
||||
end
|
||||
if GameTooltip and type(GameTooltip.IsVisible) == "function" and GameTooltip:IsVisible() then
|
||||
QA_AppendDrazialTooltip(GameTooltip, "poll")
|
||||
end
|
||||
end)
|
||||
QA_TooltipPollFrame = frame
|
||||
end
|
||||
|
||||
local function QA_GetInteractedNpcId()
|
||||
local getGuid = _G and _G["UnitGUID"] or nil
|
||||
if type(getGuid) ~= "function" then
|
||||
return nil
|
||||
end
|
||||
local npcGuid = getGuid("npc")
|
||||
local npcId = QA_GetNpcIdFromGuid(npcGuid)
|
||||
if npcId then
|
||||
return npcId
|
||||
end
|
||||
return QA_GetNpcIdFromGuid(getGuid("target"))
|
||||
end
|
||||
|
||||
local function QA_GetInteractedNpcName()
|
||||
local getName = _G and _G["UnitName"] or nil
|
||||
if type(getName) ~= "function" then
|
||||
return nil
|
||||
end
|
||||
local name = getName("npc")
|
||||
if type(name) == "string" and name ~= "" then
|
||||
return name
|
||||
end
|
||||
name = getName("target")
|
||||
if type(name) == "string" and name ~= "" then
|
||||
return name
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function QA_IsInteractedNpc(expectedNpcId, expectedNpcName)
|
||||
local npcId = QA_GetInteractedNpcId()
|
||||
if tonumber(npcId) == tonumber(expectedNpcId) then
|
||||
return true
|
||||
end
|
||||
local npcName = QA_GetInteractedNpcName()
|
||||
if type(npcName) == "string" and npcName ~= "" and QA_NormalizeText(npcName) == QA_NormalizeText(expectedNpcName) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function QA_IsScorpokNpc()
|
||||
return QA_IsInteractedNpc(QA_SCORPOK_NPC_ID, QA_SCORPOK_NPC_NAME)
|
||||
end
|
||||
|
||||
local function QA_IsArrowsForSissiesNpc()
|
||||
return QA_IsInteractedNpc(QA_SISSIES_NPC_ID, QA_SISSIES_NPC_NAME)
|
||||
end
|
||||
|
||||
local function QA_RefreshMouseoverTooltip()
|
||||
local tooltip = _G and _G["GameTooltip"] or GameTooltip
|
||||
if not tooltip then
|
||||
return
|
||||
end
|
||||
if type(UnitExists) == "function" and UnitExists("mouseover") and type(tooltip.SetUnit) == "function" then
|
||||
tooltip:SetUnit("mouseover")
|
||||
if type(tooltip.Show) == "function" then
|
||||
tooltip:Show()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function QA_RequestTooltipRefresh(delaySeconds)
|
||||
delaySeconds = tonumber(delaySeconds) or 0.10
|
||||
if not QA_TooltipRefreshFrame then
|
||||
QA_TooltipRefreshFrame = CreateFrame("Frame", "MTH_AutoQuestTooltipRefreshFrame")
|
||||
if not QA_TooltipRefreshFrame then
|
||||
return
|
||||
end
|
||||
QA_TooltipRefreshFrame:SetScript("OnUpdate", function(self, elapsed)
|
||||
local frameRef = self or this or QA_TooltipRefreshFrame
|
||||
if not frameRef then
|
||||
return
|
||||
end
|
||||
frameRef._elapsed = (frameRef._elapsed or 0) + (elapsed or arg1 or 0)
|
||||
if frameRef._elapsed < (frameRef._delay or 0.10) then
|
||||
return
|
||||
end
|
||||
frameRef._elapsed = 0
|
||||
frameRef._delay = 0
|
||||
frameRef:SetScript("OnUpdate", nil)
|
||||
QA_RefreshMouseoverTooltip()
|
||||
end)
|
||||
end
|
||||
QA_TooltipRefreshFrame._delay = delaySeconds
|
||||
QA_TooltipRefreshFrame._elapsed = 0
|
||||
QA_TooltipRefreshFrame:SetScript("OnUpdate", QA_TooltipRefreshFrame:GetScript("OnUpdate"))
|
||||
end
|
||||
|
||||
local QA_PROFILE_SCORPOK = {
|
||||
key = "scorpokDrazial",
|
||||
label = "Scorpok",
|
||||
optionCheck = QA_IsScorpokAutomationEnabled,
|
||||
npcCheck = QA_IsScorpokNpc,
|
||||
titleCheck = QA_IsScorpokTitle,
|
||||
questContextCheck = QA_IsScorpokQuestContext,
|
||||
lastActionField = "_scorpokLastActionAt",
|
||||
refreshTooltipOnComplete = true,
|
||||
}
|
||||
|
||||
local QA_PROFILE_SISSIES = {
|
||||
key = "arrowsForSissies",
|
||||
label = "ArrowsForSissies",
|
||||
optionCheck = QA_IsArrowsForSissiesAutomationEnabled,
|
||||
npcCheck = QA_IsArrowsForSissiesNpc,
|
||||
titleCheck = QA_IsArrowsForSissiesTitle,
|
||||
questContextCheck = QA_IsArrowsForSissiesQuestContext,
|
||||
lastActionField = "_sissiesLastActionAt",
|
||||
refreshTooltipOnComplete = false,
|
||||
}
|
||||
|
||||
local QA_LastActionAt = {}
|
||||
|
||||
local function QA_GetLastActionAt(profile)
|
||||
local key = type(profile) == "table" and tostring(profile.lastActionField or "") or ""
|
||||
if key == "" then
|
||||
return 0
|
||||
end
|
||||
return tonumber(QA_LastActionAt[key]) or 0
|
||||
end
|
||||
|
||||
local function QA_SetLastActionAt(profile, value)
|
||||
local key = type(profile) == "table" and tostring(profile.lastActionField or "") or ""
|
||||
if key == "" then
|
||||
return
|
||||
end
|
||||
QA_LastActionAt[key] = tonumber(value) or 0
|
||||
end
|
||||
|
||||
local function QA_CanRunProfile(profile)
|
||||
if type(profile) ~= "table" then
|
||||
return false
|
||||
end
|
||||
if type(profile.optionCheck) ~= "function" or not profile.optionCheck() then
|
||||
QA_Debug("[" .. tostring(profile.label or "AutoQuest") .. "] skip: option disabled")
|
||||
return false
|
||||
end
|
||||
if type(IsShiftKeyDown) ~= "function" or not IsShiftKeyDown() then
|
||||
QA_Debug("[" .. tostring(profile.label or "AutoQuest") .. "] skip: SHIFT not held")
|
||||
return false
|
||||
end
|
||||
local npcOk = type(profile.npcCheck) == "function" and profile.npcCheck() or false
|
||||
if not npcOk then
|
||||
QA_Debug("[" .. tostring(profile.label or "AutoQuest") .. "] skip: NPC mismatch (id=" .. tostring(QA_GetInteractedNpcId()) .. ", name='" .. tostring(QA_GetInteractedNpcName() or "") .. "')")
|
||||
end
|
||||
return npcOk
|
||||
end
|
||||
|
||||
local function QA_FindGossipQuestIndex(rawEntries, count, profile)
|
||||
if type(rawEntries) ~= "table" or tonumber(count) == nil or tonumber(count) <= 0 then
|
||||
return nil
|
||||
end
|
||||
if type(profile) ~= "table" or type(profile.titleCheck) ~= "function" then
|
||||
return nil
|
||||
end
|
||||
local entryCount = math.floor(tonumber(count) or 0)
|
||||
local tupleSize = math.floor(table.getn(rawEntries) / entryCount)
|
||||
if tupleSize < 1 then
|
||||
tupleSize = 1
|
||||
end
|
||||
for i = 1, entryCount do
|
||||
local title = tostring(rawEntries[((i - 1) * tupleSize) + 1] or "")
|
||||
if profile.titleCheck(title) then
|
||||
return i
|
||||
end
|
||||
end
|
||||
if entryCount == 1 and type(profile.npcCheck) == "function" and profile.npcCheck() then
|
||||
QA_Debug("[" .. tostring(profile.label or "AutoQuest") .. "] gossip fallback: single quest entry -> selecting index 1")
|
||||
return 1
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function QA_FindQuestGreetingIndex(isActive, profile)
|
||||
local getCount = isActive and _G and _G["GetNumActiveQuests"] or _G and _G["GetNumAvailableQuests"]
|
||||
local getTitle = isActive and _G and _G["GetActiveTitle"] or _G and _G["GetAvailableTitle"]
|
||||
if type(getCount) ~= "function" or type(getTitle) ~= "function" or type(profile) ~= "table" or type(profile.titleCheck) ~= "function" then
|
||||
return nil
|
||||
end
|
||||
local count = math.floor(tonumber(getCount()) or 0)
|
||||
if count <= 0 then
|
||||
return nil
|
||||
end
|
||||
for i = 1, count do
|
||||
local title = tostring(getTitle(i) or "")
|
||||
if profile.titleCheck(title) then
|
||||
return i
|
||||
end
|
||||
end
|
||||
if count == 1 and type(profile.npcCheck) == "function" and profile.npcCheck() then
|
||||
QA_Debug("[" .. tostring(profile.label or "AutoQuest") .. "] quest greeting fallback: single quest entry -> selecting index 1")
|
||||
return 1
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function QA_GetFrameText(frame)
|
||||
if type(frame) ~= "table" then
|
||||
return ""
|
||||
end
|
||||
if type(frame.GetText) == "function" then
|
||||
return tostring(frame:GetText() or "")
|
||||
end
|
||||
if type(frame.GetName) == "function" then
|
||||
local name = frame:GetName()
|
||||
if type(name) == "string" and name ~= "" then
|
||||
local textRegion = _G and _G[name .. "Text"] or nil
|
||||
if textRegion and type(textRegion.GetText) == "function" then
|
||||
return tostring(textRegion:GetText() or "")
|
||||
end
|
||||
end
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
local function QA_ClickGossipTitleButtonFallback(profile)
|
||||
if type(profile) ~= "table" or type(profile.titleCheck) ~= "function" then
|
||||
return false
|
||||
end
|
||||
for i = 1, 40 do
|
||||
local button = _G and _G["GossipTitleButton" .. tostring(i)] or nil
|
||||
if button then
|
||||
local visible = true
|
||||
if type(button.IsVisible) == "function" then
|
||||
visible = button:IsVisible() and true or false
|
||||
end
|
||||
if visible then
|
||||
local title = QA_GetFrameText(button)
|
||||
if profile.titleCheck(title) then
|
||||
QA_Debug("action: GossipTitleButton" .. tostring(i) .. " click title='" .. tostring(title) .. "'")
|
||||
if type(button.Click) == "function" then
|
||||
button:Click()
|
||||
return true
|
||||
end
|
||||
local onClick = type(button.GetScript) == "function" and button:GetScript("OnClick") or nil
|
||||
if type(onClick) == "function" then
|
||||
onClick(button)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function QA_RunProfileAutomation(eventName, profile)
|
||||
if type(profile) ~= "table" then
|
||||
return
|
||||
end
|
||||
QA_Debug("[" .. tostring(profile.label or "AutoQuest") .. "] event=" .. tostring(eventName))
|
||||
if not QA_CanRunProfile(profile) then
|
||||
return
|
||||
end
|
||||
|
||||
local getTimeFn = _G and _G["GetTime"] or nil
|
||||
if eventName == "GOSSIP_SHOW" and type(getTimeFn) == "function" then
|
||||
local now = tonumber(getTimeFn()) or 0
|
||||
local last = QA_GetLastActionAt(profile)
|
||||
if (now - last) < 0.05 then
|
||||
QA_Debug("skip: throttled dt=" .. tostring(now - last))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if eventName == "QUEST_GREETING" then
|
||||
local selectAvailableQuest = _G and _G["SelectAvailableQuest"] or nil
|
||||
local selectActiveQuest = _G and _G["SelectActiveQuest"] or nil
|
||||
local availableIndex = QA_FindQuestGreetingIndex(false, profile)
|
||||
if availableIndex and type(selectAvailableQuest) == "function" then
|
||||
QA_Debug("action: SelectAvailableQuest (compat) index=" .. tostring(availableIndex))
|
||||
selectAvailableQuest()
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
return
|
||||
end
|
||||
local activeIndex = QA_FindQuestGreetingIndex(true, profile)
|
||||
if activeIndex and type(selectActiveQuest) == "function" then
|
||||
QA_Debug("action: SelectActiveQuest (compat) index=" .. tostring(activeIndex))
|
||||
selectActiveQuest()
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
return
|
||||
end
|
||||
for i = 1, 40 do
|
||||
local button = _G and _G["QuestTitleButton" .. tostring(i)] or nil
|
||||
if button and (type(button.IsVisible) ~= "function" or button:IsVisible()) then
|
||||
local title = QA_GetFrameText(button)
|
||||
if profile.titleCheck(title) then
|
||||
QA_Debug("action: QuestTitleButton" .. tostring(i) .. " click title='" .. tostring(title) .. "'")
|
||||
if type(button.Click) == "function" then
|
||||
button:Click()
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
QA_Debug("quest greeting: no action taken")
|
||||
return
|
||||
end
|
||||
|
||||
if eventName == "GOSSIP_SHOW" then
|
||||
local getNumGossipAvailableQuests = _G and _G["GetNumGossipAvailableQuests"] or nil
|
||||
local getGossipAvailableQuests = _G and _G["GetGossipAvailableQuests"] or nil
|
||||
local selectGossipAvailableQuest = _G and _G["SelectGossipAvailableQuest"] or nil
|
||||
QA_Debug("api available: numAvail=" .. tostring(type(getNumGossipAvailableQuests) == "function")
|
||||
.. " getAvail=" .. tostring(type(getGossipAvailableQuests) == "function")
|
||||
.. " selAvail=" .. tostring(type(selectGossipAvailableQuest) == "function"))
|
||||
if type(getNumGossipAvailableQuests) == "function" and type(getGossipAvailableQuests) == "function" and type(selectGossipAvailableQuest) == "function" then
|
||||
local availableCount = math.floor(tonumber(getNumGossipAvailableQuests()) or 0)
|
||||
QA_Debug("gossip available count=" .. tostring(availableCount))
|
||||
if availableCount > 0 then
|
||||
local availableIndex = QA_FindGossipQuestIndex({ getGossipAvailableQuests() }, availableCount, profile)
|
||||
if availableIndex then
|
||||
QA_Debug("action: SelectGossipAvailableQuest index=" .. tostring(availableIndex))
|
||||
selectGossipAvailableQuest(availableIndex)
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
return
|
||||
end
|
||||
QA_Debug("gossip available: no Scorpok match")
|
||||
end
|
||||
end
|
||||
local getNumGossipActiveQuests = _G and _G["GetNumGossipActiveQuests"] or nil
|
||||
local getGossipActiveQuests = _G and _G["GetGossipActiveQuests"] or nil
|
||||
local selectGossipActiveQuest = _G and _G["SelectGossipActiveQuest"] or nil
|
||||
QA_Debug("api active: numActive=" .. tostring(type(getNumGossipActiveQuests) == "function")
|
||||
.. " getActive=" .. tostring(type(getGossipActiveQuests) == "function")
|
||||
.. " selActive=" .. tostring(type(selectGossipActiveQuest) == "function"))
|
||||
if type(getNumGossipActiveQuests) == "function" and type(getGossipActiveQuests) == "function" and type(selectGossipActiveQuest) == "function" then
|
||||
local activeCount = math.floor(tonumber(getNumGossipActiveQuests()) or 0)
|
||||
QA_Debug("gossip active count=" .. tostring(activeCount))
|
||||
if activeCount > 0 then
|
||||
local activeIndex = QA_FindGossipQuestIndex({ getGossipActiveQuests() }, activeCount, profile)
|
||||
if activeIndex then
|
||||
QA_Debug("action: SelectGossipActiveQuest index=" .. tostring(activeIndex))
|
||||
selectGossipActiveQuest(activeIndex)
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
return
|
||||
end
|
||||
QA_Debug("gossip active: no Scorpok match")
|
||||
end
|
||||
end
|
||||
if QA_ClickGossipTitleButtonFallback(profile) then
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
return
|
||||
end
|
||||
QA_Debug("gossip: no action taken")
|
||||
return
|
||||
end
|
||||
|
||||
local title = type(GetTitleText) == "function" and tostring(GetTitleText() or "") or ""
|
||||
QA_Debug("quest frame title='" .. tostring(title) .. "'")
|
||||
if type(profile.questContextCheck) ~= "function" or not profile.questContextCheck(title) then
|
||||
QA_Debug("skip: quest context mismatch")
|
||||
return
|
||||
end
|
||||
|
||||
if eventName == "QUEST_DETAIL" then
|
||||
if type(AcceptQuest) == "function" then
|
||||
QA_Debug("action: AcceptQuest")
|
||||
AcceptQuest()
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
end
|
||||
elseif eventName == "QUEST_PROGRESS" then
|
||||
if type(CompleteQuest) == "function" then
|
||||
if type(IsQuestCompletable) ~= "function" or IsQuestCompletable() then
|
||||
QA_Debug("action: CompleteQuest")
|
||||
CompleteQuest()
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
else
|
||||
QA_Debug("skip: quest not completable yet")
|
||||
end
|
||||
end
|
||||
elseif eventName == "QUEST_COMPLETE" then
|
||||
if type(GetQuestReward) == "function" then
|
||||
local choices = type(GetNumQuestChoices) == "function" and math.floor(tonumber(GetNumQuestChoices()) or 0) or 0
|
||||
if choices <= 1 then
|
||||
QA_Debug("action: GetQuestReward(1)")
|
||||
GetQuestReward(1)
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
if profile.refreshTooltipOnComplete then
|
||||
QA_RequestTooltipRefresh(0.10)
|
||||
end
|
||||
else
|
||||
QA_Debug("skip: multiple reward choices=" .. tostring(choices))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function QA_SetDirectEventFrameActive(active)
|
||||
if not QA_DirectEventFrame then
|
||||
return
|
||||
end
|
||||
if active then
|
||||
QA_DirectEventFrame:RegisterEvent("GOSSIP_SHOW")
|
||||
QA_DirectEventFrame:RegisterEvent("QUEST_GREETING")
|
||||
QA_DirectEventFrame:RegisterEvent("QUEST_DETAIL")
|
||||
QA_DirectEventFrame:RegisterEvent("QUEST_PROGRESS")
|
||||
QA_DirectEventFrame:RegisterEvent("QUEST_COMPLETE")
|
||||
else
|
||||
QA_DirectEventFrame:UnregisterAllEvents()
|
||||
end
|
||||
end
|
||||
|
||||
local function QA_EnsureDirectEventFrame(moduleRef)
|
||||
if QA_DirectEventFrame then
|
||||
return QA_DirectEventFrame
|
||||
end
|
||||
local frame = CreateFrame("Frame", "MTH_AutoQuestEventFrame")
|
||||
if not frame then
|
||||
QA_Debug("direct frame create failed")
|
||||
return nil
|
||||
end
|
||||
frame:SetScript("OnEvent", function(_, eventName)
|
||||
eventName = eventName or event
|
||||
if not (moduleRef and moduleRef.enabled) then
|
||||
return
|
||||
end
|
||||
QA_Debug("directEvent=" .. tostring(eventName))
|
||||
QA_RunProfileAutomation(eventName, QA_PROFILE_SCORPOK)
|
||||
QA_RunProfileAutomation(eventName, QA_PROFILE_SISSIES)
|
||||
end)
|
||||
QA_DirectEventFrame = frame
|
||||
return frame
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:init()
|
||||
local store = QA_GetOptionsStore()
|
||||
self.initialized = true
|
||||
QA_EnsureDirectEventFrame(self)
|
||||
QA_SetDirectEventFrameActive(self.enabled and true or false)
|
||||
QA_Debug("init: module active=" .. tostring(self.enabled and true or false)
|
||||
.. ", option scorpokDrazial=" .. tostring(store and store.scorpokDrazial and true or false)
|
||||
.. ", option arrowsForSissies=" .. tostring(store and store.arrowsForSissies and true or false)
|
||||
.. ", option scorpokTooltip=" .. tostring(store and store.scorpokTooltip and true or false))
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:setEnabled(enabled)
|
||||
self.enabled = enabled and true or false
|
||||
QA_SetDirectEventFrameActive(self.enabled and true or false)
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:onEvent(eventName)
|
||||
if eventName == "GOSSIP_SHOW"
|
||||
or eventName == "QUEST_GREETING"
|
||||
or eventName == "QUEST_DETAIL"
|
||||
or eventName == "QUEST_PROGRESS"
|
||||
or eventName == "QUEST_COMPLETE" then
|
||||
QA_Debug("onEvent=" .. tostring(eventName))
|
||||
QA_RunProfileAutomation(eventName, QA_PROFILE_SCORPOK)
|
||||
QA_RunProfileAutomation(eventName, QA_PROFILE_SISSIES)
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:cleanup()
|
||||
QA_SetDirectEventFrameActive(false)
|
||||
end
|
||||
|
||||
MTH:RegisterModule("autoquest", MTH_AutoQuest)
|
||||
@@ -43,8 +43,9 @@ function MTH_ChronometerHunterInstallData(engine)
|
||||
engine:AddTimer(engine.EVENT, BS["Frost Trap Aura"], 30, 0, 0, 0, { gr = 1, cr = "CYAN", a = 1, d = { tn = BS["Clever Traps"], tb = 0.15, tp = 1 }, xn = BS["Frost Trap"] })
|
||||
engine:AddTimer(engine.EVENT, BS["Immolation Trap Effect"], 15, 1, 0, 1, { gr = 1, cr = "ORANGE", a = 1, xn = BS["Immolation Trap"] })
|
||||
engine:AddTimer(engine.EVENT, BS["Improved Concussive Shot"], 3, 1, 0, 0, { a = 1, cr = "BLUE", xn = BS["Concussive Shot"] })
|
||||
engine:AddTimer(engine.EVENT, BS["Improved Wing Clip"], 5, 1, 0, 0, { a = 1, cr = "YELLOW", xn = BS["Wing Clip"] })
|
||||
engine:AddTimer(engine.EVENT, BS["Improved Wing Clip"], 5, 1, 0, 0, { a = 1, cr = "MAROON", xn = BS["Wing Clip"] })
|
||||
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["Entrapment"], 5, 1, 0, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\Spell_Nature_StrangleVines" })
|
||||
engine:AddTimer(engine.EVENT, BS["Quick Shots"], 12, 0, 1, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\Ability_Warrior_InnerRage" })
|
||||
engine:AddTimer(engine.EVENT, BS["Wing Clip"], 10, 1, 0, 1, { a = 1, cr = "YELLOW" })
|
||||
engine:AddTimer(engine.EVENT, BS["Scorpid Poison"], 10, 1, 0, 0, { gr = 3, cr = "PURPLE", a = 1, dn = 1 })
|
||||
|
||||
@@ -59,6 +59,45 @@ Chronometer.dataSetup = {}
|
||||
local latins = { I = 1, II = 2, III = 3, IV = 4, V = 5, VI = 6, VII = 7, VIII = 8, IX = 9, X = 10, XI = 11, XII = 12, XIII = 13, XIV = 14 }
|
||||
local BAR_GROUP = "MTHChronometer"
|
||||
local PARSER_OWNER = "MTHChronometerHunter"
|
||||
local MTH_CHRON_TRACE_ENABLED = false
|
||||
|
||||
local function MTH_CHRON_Trace(msg)
|
||||
if not MTH_CHRON_TRACE_ENABLED then
|
||||
return
|
||||
end
|
||||
if MTH and MTH.Print then
|
||||
MTH:Print("[CHRONTRACE] " .. tostring(msg), "debug")
|
||||
elseif DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("[CHRONTRACE] " .. tostring(msg))
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_CHRON_FormatBarPosition(profile)
|
||||
local bp = profile and profile.barposition
|
||||
if type(bp) ~= "table" then
|
||||
return "<none>"
|
||||
end
|
||||
return tostring(bp.point or "nil")
|
||||
.. "/" .. tostring(bp.relativePoint or "nil")
|
||||
.. " @(" .. tostring(bp.x) .. "," .. tostring(bp.y) .. ")"
|
||||
end
|
||||
|
||||
local function MTH_CHRON_DescribePoint(frame)
|
||||
if not (frame and frame.GetPoint) then
|
||||
return "<no-frame>"
|
||||
end
|
||||
local point, relTo, relPoint, x, y = frame:GetPoint()
|
||||
local relName = "nil"
|
||||
if type(relTo) == "table" and relTo.GetName then
|
||||
relName = tostring(relTo:GetName() or "<anon>")
|
||||
elseif relTo then
|
||||
relName = tostring(relTo)
|
||||
end
|
||||
return tostring(point or "nil")
|
||||
.. "->" .. relName
|
||||
.. ":" .. tostring(relPoint or "nil")
|
||||
.. " @(" .. tostring(x) .. "," .. tostring(y) .. ")"
|
||||
end
|
||||
|
||||
local COLOR_NAME_MAP = {
|
||||
white = { 1.0, 1.0, 1.0 },
|
||||
@@ -156,22 +195,67 @@ end
|
||||
|
||||
local function ensureProfile()
|
||||
if not MTH or not MTH.GetModuleCharSavedVariables then
|
||||
MTH_CHRON_Trace("ensureProfile fallback defaults (no MTH store)")
|
||||
return shallowCopy(DEFAULTS)
|
||||
end
|
||||
|
||||
local store = MTH:GetModuleCharSavedVariables("chronometer")
|
||||
if type(store) ~= "table" then
|
||||
MTH_CHRON_Trace("ensureProfile fallback defaults (invalid store)")
|
||||
return shallowCopy(DEFAULTS)
|
||||
end
|
||||
if type(store.profile) ~= "table"
|
||||
and type(MTH_CharSavedVariables) == "table"
|
||||
and type(MTH_CharSavedVariables.chronometer) == "table"
|
||||
then
|
||||
local legacyChar = MTH_CharSavedVariables.chronometer
|
||||
if type(legacyChar.profile) == "table" then
|
||||
store.profile = deepCopyValue(legacyChar.profile)
|
||||
MTH_CHRON_Trace("ensureProfile migrated legacy MTH_CharSavedVariables.chronometer.profile")
|
||||
elseif type(legacyChar.barposition) == "table" then
|
||||
store.profile = { barposition = deepCopyValue(legacyChar.barposition) }
|
||||
MTH_CHRON_Trace("ensureProfile migrated legacy MTH_CharSavedVariables.chronometer.barposition")
|
||||
end
|
||||
end
|
||||
if type(store.profile) ~= "table"
|
||||
and type(MTH_SavedVariables) == "table"
|
||||
and type(MTH_SavedVariables.chronometer) == "table"
|
||||
then
|
||||
local legacyAccount = MTH_SavedVariables.chronometer
|
||||
if type(legacyAccount.profile) == "table" then
|
||||
store.profile = deepCopyValue(legacyAccount.profile)
|
||||
MTH_CHRON_Trace("ensureProfile migrated legacy MTH_SavedVariables.chronometer.profile")
|
||||
elseif type(legacyAccount.barposition) == "table" then
|
||||
store.profile = { barposition = deepCopyValue(legacyAccount.barposition) }
|
||||
MTH_CHRON_Trace("ensureProfile migrated legacy MTH_SavedVariables.chronometer.barposition")
|
||||
end
|
||||
end
|
||||
if type(store.profile) ~= "table" and MTH.GetModuleSavedVariables then
|
||||
local accountStore = MTH:GetModuleSavedVariables("chronometer")
|
||||
if type(accountStore) == "table" and type(accountStore.profile) == "table" then
|
||||
store.profile = deepCopyValue(accountStore.profile)
|
||||
MTH_CHRON_Trace("ensureProfile copied account profile into char store")
|
||||
end
|
||||
end
|
||||
if type(store.profile) ~= "table" then
|
||||
store.profile = {}
|
||||
end
|
||||
if type(store.profile.barposition) ~= "table" and type(store.barposition) == "table" then
|
||||
store.profile.barposition = deepCopyValue(store.barposition)
|
||||
MTH_CHRON_Trace("ensureProfile migrated legacy char barposition -> profile.barposition")
|
||||
end
|
||||
if type(store.profile.barposition) ~= "table" and MTH.GetModuleSavedVariables then
|
||||
local accountStore = MTH:GetModuleSavedVariables("chronometer")
|
||||
if type(accountStore) == "table" then
|
||||
if type(accountStore.barposition) == "table" then
|
||||
store.profile.barposition = deepCopyValue(accountStore.barposition)
|
||||
MTH_CHRON_Trace("ensureProfile migrated legacy account barposition -> profile.barposition")
|
||||
elseif type(accountStore.profile) == "table" and type(accountStore.profile.barposition) == "table" then
|
||||
store.profile.barposition = deepCopyValue(accountStore.profile.barposition)
|
||||
MTH_CHRON_Trace("ensureProfile copied account profile.barposition -> char profile.barposition")
|
||||
end
|
||||
end
|
||||
end
|
||||
local profile = store.profile
|
||||
|
||||
for key, value in pairs(DEFAULTS) do
|
||||
@@ -198,9 +282,68 @@ local function ensureProfile()
|
||||
profile.disabledSpells.HUNTER = {}
|
||||
end
|
||||
|
||||
MTH_CHRON_Trace("ensureProfile result barposition=" .. MTH_CHRON_FormatBarPosition(profile))
|
||||
|
||||
return profile
|
||||
end
|
||||
|
||||
local function MTH_CHRON_PersistAnchorPosition(self, reason)
|
||||
if not (self and self.anchor and self.anchor.GetPoint) then
|
||||
return false
|
||||
end
|
||||
if type(self.profile) ~= "table" then
|
||||
return false
|
||||
end
|
||||
if type(self.profile.barposition) ~= "table" then
|
||||
self.profile.barposition = {}
|
||||
end
|
||||
local point, _, relPoint, x, y = self.anchor:GetPoint()
|
||||
x = tonumber(x)
|
||||
y = tonumber(y)
|
||||
if not (point and relPoint and x and y) then
|
||||
return false
|
||||
end
|
||||
x = math.floor(x + 0.5)
|
||||
y = math.floor(y + 0.5)
|
||||
self.profile.barposition.point = point
|
||||
self.profile.barposition.relativePoint = relPoint
|
||||
self.profile.barposition.x = x
|
||||
self.profile.barposition.y = y
|
||||
MTH_CHRON_Trace("persist-anchor reason=" .. tostring(reason or "")
|
||||
.. " profile=" .. MTH_CHRON_FormatBarPosition(self.profile))
|
||||
return true
|
||||
end
|
||||
|
||||
local function MTH_CHRON_RestoreAnchorFromProfile(self, reason)
|
||||
if not (self and self.anchor and self.anchor.ClearAllPoints and self.anchor.SetPoint) then
|
||||
return false
|
||||
end
|
||||
if type(self.profile) ~= "table" then
|
||||
return false
|
||||
end
|
||||
local bp = self.profile.barposition
|
||||
if type(bp) ~= "table" then
|
||||
return false
|
||||
end
|
||||
local px = tonumber(bp.x)
|
||||
local py = tonumber(bp.y)
|
||||
local ppoint = tostring(bp.point or "")
|
||||
local prelpoint = tostring(bp.relativePoint or "")
|
||||
if not (px and py and ppoint ~= "") then
|
||||
MTH_CHRON_Trace("restore-anchor skipped reason=" .. tostring(reason or "")
|
||||
.. " profile=" .. MTH_CHRON_FormatBarPosition(self.profile))
|
||||
return false
|
||||
end
|
||||
if prelpoint == "" then
|
||||
prelpoint = ppoint
|
||||
end
|
||||
self.anchor:ClearAllPoints()
|
||||
self.anchor:SetPoint(ppoint, UIParent, prelpoint, px, py)
|
||||
MTH_CHRON_Trace("restore-anchor applied reason=" .. tostring(reason or "")
|
||||
.. " frame=" .. MTH_CHRON_DescribePoint(self.anchor))
|
||||
return true
|
||||
end
|
||||
|
||||
local function MTH_CHRON_IsPersistedEnabled()
|
||||
if MTH and MTH.IsModuleEnabled then
|
||||
return MTH:IsModuleEnabled("chronometer", true) and true or false
|
||||
@@ -272,6 +415,70 @@ local function parseRankNumber(text)
|
||||
return 0
|
||||
end
|
||||
|
||||
local function resolvePlayerClassBucket(profile)
|
||||
profile = profile or {}
|
||||
local buckets = profile.disabledSpells
|
||||
if type(buckets) ~= "table" then
|
||||
return "HUNTER"
|
||||
end
|
||||
|
||||
local localizedClass, classToken = UnitClass("player")
|
||||
local candidates = {
|
||||
classToken,
|
||||
localizedClass,
|
||||
string.upper(tostring(classToken or "")),
|
||||
string.upper(tostring(localizedClass or "")),
|
||||
"HUNTER",
|
||||
}
|
||||
|
||||
for i = 1, table.getn(candidates) do
|
||||
local key = tostring(candidates[i] or "")
|
||||
if key ~= "" and type(buckets[key]) == "table" then
|
||||
return key
|
||||
end
|
||||
end
|
||||
|
||||
return tostring(classToken or localizedClass or "HUNTER")
|
||||
end
|
||||
|
||||
local function normalizeTimerName(name)
|
||||
local normalized = tostring(name or "")
|
||||
normalized = string.gsub(normalized, "^%s+", "")
|
||||
normalized = string.gsub(normalized, "%s+$", "")
|
||||
normalized = string.gsub(normalized, "%s+", " ")
|
||||
normalized = string.lower(normalized)
|
||||
return normalized
|
||||
end
|
||||
|
||||
local function isTimerDisabled(profile, timerClass, timerName)
|
||||
local disabledSpells = profile and profile.disabledSpells
|
||||
if type(disabledSpells) ~= "table" then
|
||||
return false, "no-disabled-table"
|
||||
end
|
||||
|
||||
local classBucket = disabledSpells[timerClass]
|
||||
if type(classBucket) ~= "table" then
|
||||
return false, "no-class-bucket"
|
||||
end
|
||||
|
||||
if classBucket[timerName] ~= nil then
|
||||
return true, "exact"
|
||||
end
|
||||
|
||||
local wanted = normalizeTimerName(timerName)
|
||||
if wanted == "" then
|
||||
return false, "empty-name"
|
||||
end
|
||||
|
||||
for key, value in pairs(classBucket) do
|
||||
if value ~= nil and normalizeTimerName(key) == wanted then
|
||||
return true, "normalized"
|
||||
end
|
||||
end
|
||||
|
||||
return false, "miss"
|
||||
end
|
||||
|
||||
local function getActionSpell(slot)
|
||||
if GetActionText(slot) or not HasAction(slot) then
|
||||
return nil, 0
|
||||
@@ -314,6 +521,7 @@ function Chronometer:MTH_Initialize()
|
||||
end
|
||||
|
||||
self.profile = ensureProfile()
|
||||
MTH_CHRON_Trace("MTH_Initialize profile=" .. MTH_CHRON_FormatBarPosition(self.profile))
|
||||
self.parser = ParserLib:GetInstance("1.1")
|
||||
|
||||
self.COLOR_MAP = {
|
||||
@@ -324,6 +532,7 @@ function Chronometer:MTH_Initialize()
|
||||
}
|
||||
|
||||
self.anchor = self:CreateAnchor("MetaHunt Chronometer", 0, 1, 0)
|
||||
MTH_CHRON_Trace("MTH_Initialize anchor-created point=" .. MTH_CHRON_DescribePoint(self.anchor))
|
||||
self:RegisterCandyBarGroup(BAR_GROUP)
|
||||
self:SetCandyBarGroupPoint(BAR_GROUP, "TOP", self.anchor, "BOTTOM", 0, 0)
|
||||
|
||||
@@ -332,16 +541,19 @@ end
|
||||
|
||||
function Chronometer:MTH_Enable()
|
||||
self._mth_explicitEnable = true
|
||||
MTH_CHRON_Trace("MTH_Enable called")
|
||||
self:MTH_Initialize()
|
||||
self:OnEnable()
|
||||
self._mth_explicitEnable = nil
|
||||
end
|
||||
|
||||
function Chronometer:MTH_Disable()
|
||||
MTH_CHRON_Trace("MTH_Disable called")
|
||||
self:OnDisable()
|
||||
end
|
||||
|
||||
function Chronometer:OnEnable()
|
||||
MTH_CHRON_Trace("OnEnable begin enabled=" .. tostring(self._mth_enabled and true or false))
|
||||
if self._mth_enabled then
|
||||
return
|
||||
end
|
||||
@@ -371,8 +583,13 @@ function Chronometer:OnEnable()
|
||||
self._mth_enabled = true
|
||||
|
||||
self.profile = ensureProfile()
|
||||
MTH_CHRON_Trace("OnEnable profile-after-ensure=" .. MTH_CHRON_FormatBarPosition(self.profile))
|
||||
self:SetCandyBarGroupGrowth(BAR_GROUP, self.profile.growup and true or false)
|
||||
self:SetCandyBarGroupVerticalSpacing(BAR_GROUP, self.profile.spacing or 0)
|
||||
if self.anchor then
|
||||
MTH_CHRON_Trace("OnEnable anchor-current-point=" .. MTH_CHRON_DescribePoint(self.anchor))
|
||||
end
|
||||
MTH_CHRON_RestoreAnchorFromProfile(self, "OnEnable")
|
||||
|
||||
self.groups = {}
|
||||
self.timers = {}
|
||||
@@ -450,16 +667,39 @@ function Chronometer:OnEnable()
|
||||
self:RegisterEvent("SPELLCAST_INTERRUPTED")
|
||||
self:RegisterEvent("SPELLCAST_START")
|
||||
self:RegisterEvent("SPELLCAST_STOP")
|
||||
self:RegisterEvent("UNIT_AURA")
|
||||
self:RegisterEvent("PLAYER_DEAD")
|
||||
self:RegisterEvent("VARIABLES_LOADED")
|
||||
self:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
self:RegisterEvent("PLAYER_LOGOUT")
|
||||
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_SELF_DAMAGE", function(event, info) self:SELF_DAMAGE(event, info) end)
|
||||
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF", function(event, info) self:SELF_DAMAGE(event, info) end)
|
||||
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_FAILED_LOCALPLAYER", function(event, info) self:SPELL_FAILED(event, info) end)
|
||||
end
|
||||
|
||||
function Chronometer:VARIABLES_LOADED()
|
||||
self.profile = ensureProfile()
|
||||
MTH_CHRON_RestoreAnchorFromProfile(self, "VARIABLES_LOADED")
|
||||
end
|
||||
|
||||
function Chronometer:PLAYER_ENTERING_WORLD()
|
||||
self.profile = ensureProfile()
|
||||
MTH_CHRON_RestoreAnchorFromProfile(self, "PLAYER_ENTERING_WORLD")
|
||||
end
|
||||
|
||||
function Chronometer:PLAYER_LOGOUT()
|
||||
MTH_CHRON_PersistAnchorPosition(self, "PLAYER_LOGOUT")
|
||||
end
|
||||
|
||||
function Chronometer:OnDisable()
|
||||
if not self._mth_enabled then
|
||||
return
|
||||
end
|
||||
MTH_CHRON_Trace("OnDisable begin profile=" .. MTH_CHRON_FormatBarPosition(self.profile))
|
||||
if self.anchor then
|
||||
MTH_CHRON_Trace("OnDisable anchor-point=" .. MTH_CHRON_DescribePoint(self.anchor))
|
||||
end
|
||||
MTH_CHRON_PersistAnchorPosition(self, "OnDisable")
|
||||
self._mth_enabled = false
|
||||
|
||||
if self.bars then
|
||||
@@ -563,9 +803,12 @@ function Chronometer:StartTimer(timer, name, target, rank, durmod)
|
||||
end
|
||||
end
|
||||
|
||||
local _, class = UnitClass("player")
|
||||
local timerClass = timer.x.cl == nil and class or timer.x.cl
|
||||
if self.profile.disabledSpells[timerClass] and self.profile.disabledSpells[timerClass][name] ~= nil then
|
||||
local timerClass = timer.x.cl
|
||||
if timerClass == nil then
|
||||
timerClass = resolvePlayerClassBucket(self.profile)
|
||||
end
|
||||
local blocked, reason = isTimerDisabled(self.profile, timerClass, name)
|
||||
if blocked then
|
||||
return
|
||||
end
|
||||
|
||||
@@ -958,11 +1201,22 @@ function Chronometer:CreateAnchor(text, r, g, b)
|
||||
|
||||
local px = tonumber(self.profile and self.profile.barposition and self.profile.barposition.x)
|
||||
local py = tonumber(self.profile and self.profile.barposition and self.profile.barposition.y)
|
||||
local ppoint = tostring(self.profile and self.profile.barposition and self.profile.barposition.point or "")
|
||||
local prelpoint = tostring(self.profile and self.profile.barposition and self.profile.barposition.relativePoint or "")
|
||||
MTH_CHRON_Trace("CreateAnchor saved-in profile=" .. MTH_CHRON_FormatBarPosition(self.profile))
|
||||
if px ~= nil and py ~= nil then
|
||||
if ppoint == "" then
|
||||
ppoint = "TOPLEFT"
|
||||
end
|
||||
if prelpoint == "" then
|
||||
prelpoint = ppoint
|
||||
end
|
||||
frame:ClearAllPoints()
|
||||
frame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", px, py)
|
||||
frame:SetPoint(ppoint, UIParent, prelpoint, px, py)
|
||||
MTH_CHRON_Trace("CreateAnchor restored point=" .. MTH_CHRON_DescribePoint(frame))
|
||||
else
|
||||
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 50)
|
||||
MTH_CHRON_Trace("CreateAnchor default point=" .. MTH_CHRON_DescribePoint(frame))
|
||||
end
|
||||
|
||||
frame:SetScript("OnDragStart", function(self)
|
||||
@@ -970,6 +1224,7 @@ function Chronometer:CreateAnchor(text, r, g, b)
|
||||
if not self or not self.StartMoving then
|
||||
return
|
||||
end
|
||||
MTH_CHRON_Trace("anchor drag-start point=" .. MTH_CHRON_DescribePoint(self))
|
||||
self:StartMoving()
|
||||
end)
|
||||
frame:SetScript("OnDragStop", function(self)
|
||||
@@ -995,8 +1250,12 @@ function Chronometer:CreateAnchor(text, r, g, b)
|
||||
self:SetPoint(point or "TOPLEFT", UIParent, point or "TOPLEFT", x, y)
|
||||
|
||||
if self.owner and self.owner.profile and type(self.owner.profile.barposition) == "table" then
|
||||
self.owner.profile.barposition.point = point or "TOPLEFT"
|
||||
self.owner.profile.barposition.relativePoint = point or "TOPLEFT"
|
||||
self.owner.profile.barposition.x = x
|
||||
self.owner.profile.barposition.y = y
|
||||
MTH_CHRON_Trace("anchor drag-stop saved profile=" .. MTH_CHRON_FormatBarPosition(self.owner.profile)
|
||||
.. " frame=" .. MTH_CHRON_DescribePoint(self))
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -1122,6 +1381,62 @@ function Chronometer:PLAYER_DEAD()
|
||||
end
|
||||
end
|
||||
|
||||
function Chronometer:UNIT_AURA(unit)
|
||||
local auraUnit = unit
|
||||
if (not auraUnit or auraUnit == "") and type(arg1) == "string" then
|
||||
auraUnit = arg1
|
||||
end
|
||||
if auraUnit ~= "pet" then
|
||||
return
|
||||
end
|
||||
if not (UnitExists and UnitExists("pet")) then
|
||||
return
|
||||
end
|
||||
|
||||
local feedSpell = BS and BS["Feed Pet"] or "Feed Pet"
|
||||
local timer = self.timers and self.timers[self.SPELL] and self.timers[self.SPELL][feedSpell]
|
||||
if not timer then
|
||||
return
|
||||
end
|
||||
|
||||
local hasFeedAura = false
|
||||
if type(UnitBuff) == "function" then
|
||||
for i = 1, 32 do
|
||||
local texture = UnitBuff("pet", i)
|
||||
if not texture then
|
||||
break
|
||||
end
|
||||
local tex = tostring(texture)
|
||||
if string.find(tex, "Ability_Hunter_BeastTraining", 1, true)
|
||||
or string.find(tex, "INV_Misc_Fork&Knife", 1, true)
|
||||
then
|
||||
hasFeedAura = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not hasFeedAura then
|
||||
return
|
||||
end
|
||||
|
||||
local petName = UnitName and UnitName("pet") or "none"
|
||||
if not petName or petName == "" then
|
||||
petName = "none"
|
||||
end
|
||||
|
||||
for i = 1, 20 do
|
||||
local bar = self.bars and self.bars[i]
|
||||
if bar and bar.id and bar.name == feedSpell then
|
||||
if bar.target == petName or bar.target == "none" then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:StartTimer(timer, feedSpell, petName)
|
||||
end
|
||||
|
||||
function Chronometer:UseAction(slot, clicked, onself)
|
||||
local name, rank = getActionSpell(slot)
|
||||
if name then
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
local MTH_ChronometerModule = {
|
||||
name = "chronometer",
|
||||
enabled = true,
|
||||
version = "1.0.6",
|
||||
version = "1.1.0",
|
||||
events = {},
|
||||
initialized = false,
|
||||
}
|
||||
|
||||
local MTH_CHRON_MODULE_TRACE_ENABLED = false
|
||||
|
||||
local function MTH_CHRON_ModuleTrace(msg)
|
||||
if not MTH_CHRON_MODULE_TRACE_ENABLED then
|
||||
return
|
||||
end
|
||||
if MTH and MTH.Print then
|
||||
MTH:Print("[CHRONTRACE] " .. tostring(msg), "debug")
|
||||
elseif DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("[CHRONTRACE] " .. tostring(msg))
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_CHRON_ApplyRuntimeEnabledState(enabled)
|
||||
MTH_CHRON_ModuleTrace("module apply runtime enabled=" .. tostring(enabled and true or false))
|
||||
if not MTH_ChronometerHunter then
|
||||
MTH_CHRON_ModuleTrace("module apply runtime skipped (engine unavailable)")
|
||||
return
|
||||
end
|
||||
if enabled then
|
||||
@@ -22,14 +37,18 @@ local function MTH_CHRON_ApplyRuntimeEnabledState(enabled)
|
||||
end
|
||||
|
||||
function MTH_ChronometerModule:init()
|
||||
MTH_CHRON_ModuleTrace("module init begin enabled=" .. tostring(self.enabled and true or false))
|
||||
if MTH_ChronometerHunter and MTH_ChronometerHunter.MTH_Initialize then
|
||||
MTH_ChronometerHunter:MTH_Initialize()
|
||||
end
|
||||
MTH_CHRON_ApplyRuntimeEnabledState(self.enabled and true or false)
|
||||
self.initialized = true
|
||||
MTH_CHRON_ModuleTrace("module init end initialized=true")
|
||||
end
|
||||
|
||||
function MTH_ChronometerModule:setEnabled(enabled)
|
||||
MTH_CHRON_ModuleTrace("module setEnabled enabled=" .. tostring(enabled and true or false)
|
||||
.. " initialized=" .. tostring(self.initialized and true or false))
|
||||
if not self.initialized then
|
||||
self:init()
|
||||
end
|
||||
@@ -37,6 +56,7 @@ function MTH_ChronometerModule:setEnabled(enabled)
|
||||
end
|
||||
|
||||
function MTH_ChronometerModule:cleanup()
|
||||
MTH_CHRON_ModuleTrace("module cleanup")
|
||||
if MTH_ChronometerHunter and MTH_ChronometerHunter.MTH_Disable then
|
||||
MTH_ChronometerHunter:MTH_Disable()
|
||||
end
|
||||
|
||||
+957
-101
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
local MTH_FeedOMatic = {
|
||||
name = "feedomatic",
|
||||
enabled = false,
|
||||
version = "1.0.6",
|
||||
version = "1.1.0",
|
||||
events = {
|
||||
"VARIABLES_LOADED",
|
||||
"MERCHANT_SHOW",
|
||||
@@ -38,7 +38,7 @@ function MTH_FeedOMatic_OnUpdate(elapsed)
|
||||
if not elapsed then
|
||||
return
|
||||
end
|
||||
if not (MTH and MTH.IsModuleEnabled and MTH:IsModuleEnabled("feedomatic", true)) then
|
||||
if not (MTH and MTH.IsModuleEnabled and MTH:IsModuleEnabled("feedomatic", false)) then
|
||||
return
|
||||
end
|
||||
if type(FOM_OnUpdate) == "function" then
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,320 @@
|
||||
<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/">
|
||||
<Script file="MTH_ICU.lua"/>
|
||||
<!-- The main ICU frame -->
|
||||
<Frame name="ICU_Frame">
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
ICU_OnLoad();
|
||||
</OnLoad>
|
||||
<OnEvent>
|
||||
ICU_OnEvent(event);
|
||||
</OnEvent>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
<!-- A button template, to be inherited by each button -->
|
||||
<Frame name="ICU_PopupButtonTemplate" virtual="true">
|
||||
<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
|
||||
<BackgroundInsets>
|
||||
<AbsInset left="5" right="5" top="5" bottom="5"/>
|
||||
</BackgroundInsets>
|
||||
<TileSize>
|
||||
<AbsValue val="16"/>
|
||||
</TileSize>
|
||||
<EdgeSize>
|
||||
<AbsValue val="16"/>
|
||||
</EdgeSize>
|
||||
</Backdrop>
|
||||
<Size>
|
||||
<AbsDimension x="30" y="28"/>
|
||||
</Size>
|
||||
<Layers>
|
||||
<Layer level="ARTWORK">
|
||||
<Texture name="$parentButtonPortraitIcon">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Texture>
|
||||
<Texture name="$parentButtonClassIcon">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentButtonPortraitIcon">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Texture>
|
||||
<Texture name="$parentButtonRankIcon">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="RIGHT" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Texture>
|
||||
</Layer>
|
||||
</Layers>
|
||||
<Frames>
|
||||
<Button name="$parentButton" frameStrata="ARTWORK">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<HighlightTexture file="Interface\QuestFrame\UI-QuestTitleHighlight" alphaMode="ADD" setAllPoints="true" hidden="true"/>
|
||||
<NormalText inherits="GameFontNormal">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentClassIcon">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</NormalText>
|
||||
<HighlightText inherits="GameFontHighlight">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentClassIcon">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</HighlightText>
|
||||
<DisabledText inherits="GameFontDisable">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentClassIcon">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</DisabledText>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
ICU_ButtonClick();
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</Button>
|
||||
<StatusBar name="$parentButtonBar" inherits="TextStatusBar" frameStrata="ARTWORK">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentButtonClassIcon">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<BarTexture file="Interface\TargetingFrame\UI-TargetingFrame-BarFill"/>
|
||||
<BarColor r="0" g="0.8" b="0" a="0.7" />
|
||||
<!--
|
||||
<Layers>
|
||||
<Layer level="OVERLAY">
|
||||
<FontString name="$parentLeftText" inherits="GameFontNormal" text="">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="10" y="1"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
<FontString name="$parentRightText" inherits="GameFontNormal" text="">
|
||||
<Anchors>
|
||||
<Anchor point="RIGHT" relativePoint="RIGHT">
|
||||
<Offset>
|
||||
<AbsDimension x="-10" y="1"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
</Layer>
|
||||
</Layers>
|
||||
!-->
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
this:SetMinMaxValues(0, 100);
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</StatusBar>
|
||||
<StatusBar name="$parentButtonBGBar" inherits="TextStatusBar" frameStrata="ARTWORK">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="TOP" relativeTo="$parentButtonBar">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<BarTexture file="Interface\TargetingFrame\UI-TargetingFrame-BarFill"/>
|
||||
<BarColor r="0" g="0.8" b="0" a="0.25"/>
|
||||
</StatusBar>
|
||||
</Frames>
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
this:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
|
||||
this:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
<!-- The popup menu -->
|
||||
<Frame name="ICU_Popup" toplevel="true" frameStrata="DIALOG" enableMouse="true" hidden="true" parent="UIParent">
|
||||
<Anchors>
|
||||
<Anchor point="TOPRIGHT" relativeTo="MinimapCluster" relativePoint="BOTTOMRIGHT"/>
|
||||
</Anchors>
|
||||
<!--
|
||||
<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
|
||||
<BackgroundInsets>
|
||||
<AbsInset left="5" right="5" top="5" bottom="5"/>
|
||||
</BackgroundInsets>
|
||||
<TileSize>
|
||||
<AbsValue val="16"/>
|
||||
</TileSize>
|
||||
<EdgeSize>
|
||||
<AbsValue val="16"/>
|
||||
</EdgeSize>
|
||||
</Backdrop>
|
||||
!-->
|
||||
<!-- Within the popup menu, the clickable buttons which to display text -->
|
||||
<Frames>
|
||||
<!-- Button 1 -->
|
||||
<Frame name="ICU_PopupButton1" inherits="ICU_PopupButtonTemplate" id="1" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-6"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 2 -->
|
||||
<Frame name="ICU_PopupButton2" inherits="ICU_PopupButtonTemplate" id="2" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton1" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 3 -->
|
||||
<Frame name="ICU_PopupButton3" inherits="ICU_PopupButtonTemplate" id="3" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton2" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 4 -->
|
||||
<Frame name="ICU_PopupButton4" inherits="ICU_PopupButtonTemplate" id="4" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton3" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 5 -->
|
||||
<Frame name="ICU_PopupButton5" inherits="ICU_PopupButtonTemplate" id="5" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton4" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 6 -->
|
||||
<Frame name="ICU_PopupButton6" inherits="ICU_PopupButtonTemplate" id="6" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton5" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 7 -->
|
||||
<Frame name="ICU_PopupButton7" inherits="ICU_PopupButtonTemplate" id="7" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton6" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 8 -->
|
||||
<Frame name="ICU_PopupButton8" inherits="ICU_PopupButtonTemplate" id="8" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton7" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 9 -->
|
||||
<Frame name="ICU_PopupButton9" inherits="ICU_PopupButtonTemplate" id="9" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton8" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 10 -->
|
||||
<Frame name="ICU_PopupButton10" inherits="ICU_PopupButtonTemplate" id="10" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton9" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
</Frames>
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
<!-- This makes the dialog look like a normal tooltip -->
|
||||
this:SetBackdropBorderColor( TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b );
|
||||
this:SetBackdropColor( TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b );
|
||||
</OnLoad>
|
||||
<OnUpdate>
|
||||
ICU_Popup_OnUpdate();
|
||||
</OnUpdate>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
<Frame name="ICU_UpdateFrame" hidden="true">
|
||||
<Scripts>
|
||||
<OnUpdate>
|
||||
ICU_MouseOverUpdate();
|
||||
</OnUpdate>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
</Ui>
|
||||
@@ -0,0 +1,8 @@
|
||||
<!--
|
||||
ICU Module Loader
|
||||
Loads ICU runtime and wraps it in the MetaHunt module system.
|
||||
-->
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
||||
<Include file="MTH_ICU.xml"/>
|
||||
<Include file="module.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,52 @@
|
||||
------------------------------------------------------
|
||||
-- MetaHunt: ICU Module Wrapper
|
||||
-- Safe wrapper for ICU minimap targeting utilities
|
||||
------------------------------------------------------
|
||||
|
||||
local MTH_ICU = {
|
||||
name = "icu",
|
||||
enabled = false,
|
||||
version = "1.1.0",
|
||||
events = {
|
||||
"VARIABLES_LOADED",
|
||||
},
|
||||
initialized = false,
|
||||
}
|
||||
|
||||
local function ICU_Log(message, severity)
|
||||
if type(MTH_Log) == "function" then
|
||||
MTH_Log("[ICU] " .. tostring(message or ""), severity)
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_ICU:init()
|
||||
self.initialized = true
|
||||
if type(ICU_SetEnabled) == "function" then
|
||||
ICU_SetEnabled(self.enabled and true or false)
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_ICU:setEnabled(enabled)
|
||||
if not self.initialized then
|
||||
self:init()
|
||||
end
|
||||
if type(ICU_SetEnabled) == "function" then
|
||||
ICU_SetEnabled(enabled and true or false)
|
||||
else
|
||||
ICU_Log("runtime not loaded; cannot change enabled state", "error")
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_ICU:onEvent(eventName)
|
||||
if eventName == "VARIABLES_LOADED" and type(ICU_SetEnabled) == "function" then
|
||||
ICU_SetEnabled(self.enabled and true or false)
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_ICU:cleanup()
|
||||
if type(ICU_SetEnabled) == "function" then
|
||||
ICU_SetEnabled(false)
|
||||
end
|
||||
end
|
||||
|
||||
MTH:RegisterModule("icu", MTH_ICU)
|
||||
@@ -7,7 +7,7 @@ MTH_SA_MANAGED_HOOKS = true
|
||||
local MTH_SmartAmmo = {
|
||||
name = "smartammo",
|
||||
enabled = true,
|
||||
version = "1.0.6",
|
||||
version = "1.1.0",
|
||||
events = {
|
||||
"VARIABLES_LOADED",
|
||||
"PLAYER_ENTERING_WORLD",
|
||||
|
||||
+240
-2
@@ -6,7 +6,7 @@
|
||||
local MTH_Tooltips = {
|
||||
name = "tooltips",
|
||||
enabled = true,
|
||||
version = "1.0.6",
|
||||
version = "1.1.0",
|
||||
events = {
|
||||
"UPDATE_MOUSEOVER_UNIT",
|
||||
"UNIT_NAME_UPDATE",
|
||||
@@ -115,6 +115,55 @@ local function MTH_TT_IsOwnPetTooltipsEnabled()
|
||||
return false
|
||||
end
|
||||
|
||||
local function MTH_TT_GetAutoQuestStore()
|
||||
if type(MTH_CharSavedVariables) ~= "table" then
|
||||
return nil
|
||||
end
|
||||
local store = MTH_CharSavedVariables.autoquest
|
||||
if type(store) ~= "table" then
|
||||
store = MTH_CharSavedVariables.questautomation
|
||||
end
|
||||
if type(store) ~= "table" then
|
||||
return nil
|
||||
end
|
||||
if store.scorpokDrazial == nil then
|
||||
store.scorpokDrazial = false
|
||||
end
|
||||
if store.scorpokTooltip == nil then
|
||||
store.scorpokTooltip = false
|
||||
end
|
||||
return store
|
||||
end
|
||||
|
||||
local function MTH_TT_IsScorpokAutomationEnabled()
|
||||
local store = MTH_TT_GetAutoQuestStore()
|
||||
if type(store) ~= "table" then
|
||||
return false
|
||||
end
|
||||
return store.scorpokDrazial and true or false
|
||||
end
|
||||
|
||||
local function MTH_TT_IsScorpokTooltipEnabled()
|
||||
local store = MTH_TT_GetAutoQuestStore()
|
||||
if type(store) ~= "table" then
|
||||
return false
|
||||
end
|
||||
return store.scorpokTooltip and true or false
|
||||
end
|
||||
|
||||
local function MTH_TT_IsAutoQuestModuleEnabled()
|
||||
if MTH and type(MTH.GetModule) == "function" then
|
||||
local module = MTH:GetModule("autoquest")
|
||||
if type(module) == "table" and module.enabled ~= nil then
|
||||
return module.enabled and true or false
|
||||
end
|
||||
end
|
||||
if MTH and type(MTH.IsModuleEnabled) == "function" then
|
||||
return MTH:IsModuleEnabled("autoquest", false) and true or false
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function MTH_TT_Loc(key, fallback)
|
||||
if MTH and MTH.GetLocalization then
|
||||
return MTH:GetLocalization(key, fallback)
|
||||
@@ -558,6 +607,191 @@ local function MTH_TT_ColorizeDigitsBlue(text)
|
||||
return string.gsub(source, "(%d+)", "|cff73bfff%1|r")
|
||||
end
|
||||
|
||||
local MTH_TT_SCORPOK_NPC_NAME = "Bloodmage Drazial"
|
||||
local MTH_TT_SCORPOK_TARGET_NPC_IDS = {
|
||||
[7505] = true,
|
||||
[5988] = true,
|
||||
[5982] = true,
|
||||
[5992] = true,
|
||||
[5993] = true,
|
||||
}
|
||||
local MTH_TT_SCORPOK_TARGET_NPC_NAMES = {
|
||||
[MTH_TT_NormalizeName("Bloodmage Drazial")] = true,
|
||||
[MTH_TT_NormalizeName("Scorpok Stinger")] = true,
|
||||
[MTH_TT_NormalizeName("Black Slayer")] = true,
|
||||
[MTH_TT_NormalizeName("Ashmane Boar")] = true,
|
||||
[MTH_TT_NormalizeName("Helboar")] = true,
|
||||
}
|
||||
local MTH_TT_ITEM_SCORPOK_PINCER_ID = 8393
|
||||
local MTH_TT_ITEM_VULTURE_GIZZARD_ID = 8396
|
||||
local MTH_TT_ITEM_BLASTED_BOAR_LUNG_ID = 8392
|
||||
local MTH_TT_ITEM_GROUND_SCORPOK_ASSAY_ID = 8412
|
||||
|
||||
local function MTH_TT_ParseNpcIdFromGuid(guid)
|
||||
if type(guid) ~= "string" or guid == "" then
|
||||
return nil
|
||||
end
|
||||
local _, _, _, _, _, npcId = string.find(guid, "^Creature%-%d+%-%d+%-%d+%-%d+%-(%d+)%-%x+$")
|
||||
if npcId then
|
||||
return tonumber(npcId)
|
||||
end
|
||||
if string.sub(guid, 1, 2) == "0x" and string.len(guid) >= 12 then
|
||||
local hex = string.sub(guid, 9, 12)
|
||||
local parsed = tonumber(hex, 16)
|
||||
if parsed and parsed > 0 then
|
||||
return parsed
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function MTH_TT_GetBagItemCount(itemId)
|
||||
local getContainerNumSlots = _G and _G["GetContainerNumSlots"] or nil
|
||||
local getContainerItemLink = _G and _G["GetContainerItemLink"] or nil
|
||||
local getContainerItemInfo = _G and _G["GetContainerItemInfo"] or nil
|
||||
if type(getContainerNumSlots) ~= "function" or type(getContainerItemLink) ~= "function" then
|
||||
return 0
|
||||
end
|
||||
local total = 0
|
||||
for bag = 0, 4 do
|
||||
local slots = math.floor(tonumber(getContainerNumSlots(bag)) or 0)
|
||||
for slot = 1, slots do
|
||||
local link = getContainerItemLink(bag, slot)
|
||||
if type(link) == "string" and link ~= "" then
|
||||
local _, _, foundText = string.find(link, "item:(%d+)")
|
||||
local found = tonumber(foundText)
|
||||
if found and tonumber(found) == tonumber(itemId) then
|
||||
local count = 1
|
||||
if type(getContainerItemInfo) == "function" then
|
||||
local _, stackCount = getContainerItemInfo(bag, slot)
|
||||
count = math.floor(tonumber(stackCount) or 1)
|
||||
end
|
||||
total = total + count
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return total
|
||||
end
|
||||
|
||||
local function MTH_TT_ColorCountByThreshold(value, threshold)
|
||||
local n = math.floor(tonumber(value) or 0)
|
||||
if n <= 0 then
|
||||
return "|cffff0000" .. tostring(n) .. "|r"
|
||||
end
|
||||
local modFn = nil
|
||||
if type(rawget) == "function" and type(math) == "table" then
|
||||
modFn = rawget(math, "mod") or rawget(math, "fmod")
|
||||
elseif type(math) == "table" then
|
||||
modFn = math.fmod
|
||||
end
|
||||
if threshold > 0 and type(modFn) == "function" and modFn(n, threshold) == 0 then
|
||||
return "|cff00ff00" .. tostring(n) .. "|r"
|
||||
end
|
||||
return "|cffffa500" .. tostring(n) .. "|r"
|
||||
end
|
||||
|
||||
local function MTH_TT_ColorAssayCount(value)
|
||||
local n = math.floor(tonumber(value) or 0)
|
||||
if n > 0 then
|
||||
return "|cff73bfff" .. tostring(n) .. "|r"
|
||||
end
|
||||
return tostring(n)
|
||||
end
|
||||
|
||||
local function MTH_TT_HasScorpokTooltipLine()
|
||||
if not GameTooltip or not GameTooltip.NumLines then return false end
|
||||
for i = 1, GameTooltip:NumLines() do
|
||||
local left = getglobal("GameTooltipTextLeft" .. i)
|
||||
if left and left.GetText then
|
||||
local text = tostring(left:GetText() or "")
|
||||
if string.find(text, "MTH Auto Quest", 1, true)
|
||||
or string.find(text, "Ground Scorpok Assay", 1, true) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function MTH_TT_IsScorpokTooltipZoneAllowed()
|
||||
local getRealZoneText = _G and _G["GetRealZoneText"] or nil
|
||||
local getZoneText = _G and _G["GetZoneText"] or nil
|
||||
local zoneName = ""
|
||||
if type(getRealZoneText) == "function" then
|
||||
zoneName = tostring(getRealZoneText() or "")
|
||||
end
|
||||
if zoneName == "" and type(getZoneText) == "function" then
|
||||
zoneName = tostring(getZoneText() or "")
|
||||
end
|
||||
if zoneName == "" then
|
||||
return true
|
||||
end
|
||||
return MTH_TT_NormalizeName(zoneName) == MTH_TT_NormalizeName("Blasted Lands")
|
||||
end
|
||||
|
||||
local function MTH_TT_AddScorpokTargetsTooltip(unit, unitName)
|
||||
if not MTH_TT_IsAutoQuestModuleEnabled() then
|
||||
return false
|
||||
end
|
||||
if not MTH_TT_IsScorpokAutomationEnabled() or not MTH_TT_IsScorpokTooltipEnabled() then
|
||||
return false
|
||||
end
|
||||
if not MTH_TT_IsScorpokTooltipZoneAllowed() then
|
||||
return false
|
||||
end
|
||||
if MTH_TT_HasScorpokTooltipLine() then
|
||||
return false
|
||||
end
|
||||
|
||||
local npcId = nil
|
||||
if type(UnitGUID) == "function" then
|
||||
npcId = MTH_TT_ParseNpcIdFromGuid(UnitGUID(unit))
|
||||
end
|
||||
local isDrazial = false
|
||||
if tonumber(npcId) == 7505 then
|
||||
isDrazial = true
|
||||
elseif MTH_TT_Lower(unitName) == MTH_TT_Lower(MTH_TT_SCORPOK_NPC_NAME) then
|
||||
isDrazial = true
|
||||
end
|
||||
local isTargetNpc = false
|
||||
if npcId and MTH_TT_SCORPOK_TARGET_NPC_IDS[tonumber(npcId)] then
|
||||
isTargetNpc = true
|
||||
end
|
||||
if not isTargetNpc then
|
||||
local normalizedName = MTH_TT_NormalizeName(unitName)
|
||||
isTargetNpc = MTH_TT_SCORPOK_TARGET_NPC_NAMES[normalizedName] and true or false
|
||||
if not isTargetNpc then
|
||||
isTargetNpc = MTH_TT_Lower(unitName) == MTH_TT_Lower(MTH_TT_SCORPOK_NPC_NAME)
|
||||
end
|
||||
end
|
||||
if not isTargetNpc then
|
||||
return false
|
||||
end
|
||||
|
||||
local pincer = MTH_TT_GetBagItemCount(MTH_TT_ITEM_SCORPOK_PINCER_ID)
|
||||
local gizzard = MTH_TT_GetBagItemCount(MTH_TT_ITEM_VULTURE_GIZZARD_ID)
|
||||
local lung = MTH_TT_GetBagItemCount(MTH_TT_ITEM_BLASTED_BOAR_LUNG_ID)
|
||||
local assayInBag = MTH_TT_GetBagItemCount(MTH_TT_ITEM_GROUND_SCORPOK_ASSAY_ID)
|
||||
local assaysToGet = math.floor(math.min((pincer / 3), (gizzard / 2), lung))
|
||||
|
||||
GameTooltip:AddLine(" ")
|
||||
GameTooltip:AddLine("|cffffff00MTH Auto Quest|r")
|
||||
GameTooltip:AddLine(" - Scorpok Pincer - " .. MTH_TT_ColorCountByThreshold(pincer, 3), 1, 1, 1)
|
||||
GameTooltip:AddLine(" - Vulture Gizzard - " .. MTH_TT_ColorCountByThreshold(gizzard, 2), 1, 1, 1)
|
||||
GameTooltip:AddLine(" - Blasted Boar Lung - " .. MTH_TT_ColorCountByThreshold(lung, 1), 1, 1, 1)
|
||||
local assaysToGetText = "|cff73bfff" .. tostring(assaysToGet) .. "|r"
|
||||
GameTooltip:AddLine(
|
||||
"Assays to get : " .. assaysToGetText .. " | Assays in bag : " .. MTH_TT_ColorAssayCount(assayInBag),
|
||||
1, 1, 1
|
||||
)
|
||||
if isDrazial then
|
||||
GameTooltip:AddLine("Spam SHIFT-click!", 0.7, 0.9, 1)
|
||||
end
|
||||
GameTooltip:AddLine("Recipes: 3x Pincer, 2x Gizzard, 1x Lung", 0.7, 0.7, 0.7)
|
||||
return true
|
||||
end
|
||||
|
||||
local function MTH_TT_AddOwnPetTooltipHint()
|
||||
if not (MTH_Tooltips and MTH_Tooltips.enabled) then
|
||||
return
|
||||
@@ -1251,7 +1485,8 @@ local function MTH_TT_AddTooltip(unit)
|
||||
local ammoVendorTooltipsEnabled = MTH_TT_IsAmmoVendorTooltipsEnabled()
|
||||
local vendorInfo = ammoVendorTooltipsEnabled and MTH_TT_FindVendorInfo(name) or nil
|
||||
local row = beastTooltipsEnabled and MTH_TT_FindBeastRow(name) or nil
|
||||
if not row and not vendorInfo then
|
||||
local scorpokAdded = MTH_TT_AddScorpokTargetsTooltip(unit, name)
|
||||
if not row and not vendorInfo and not scorpokAdded then
|
||||
state.lookupMiss = (state.lookupMiss or 0) + 1
|
||||
MTH_TT_StateSet("lookup-miss", name, normalized)
|
||||
MTH_TT_Log("lookup miss: unit='" .. tostring(name) .. "' normalized='" .. tostring(normalized) .. "'")
|
||||
@@ -1259,6 +1494,9 @@ local function MTH_TT_AddTooltip(unit)
|
||||
end
|
||||
|
||||
local addedAnything = nil
|
||||
if scorpokAdded then
|
||||
addedAnything = 1
|
||||
end
|
||||
|
||||
if vendorInfo and (vendorInfo.arrows or vendorInfo.bullets) and not MTH_TT_HasExistingVendorTooltipLine() then
|
||||
if vendorInfo.arrows and vendorInfo.bullets then
|
||||
|
||||
@@ -14,6 +14,71 @@ BINDING_HEADER_ZToysHeader = "ZToys Buttons"
|
||||
ZHunterModTooltip = CreateFrame("GameTooltip", "ZHunterModScan", nil, "GameTooltipTemplate")
|
||||
ZHunterModTooltipTextLeft1 = getglobal("ZHunterModScanTextLeft1")
|
||||
|
||||
MTH_ZH_TRACE_ENABLED = false
|
||||
|
||||
local function MTH_ZH_DescribePoint(frame)
|
||||
if not (frame and frame.GetPoint) then
|
||||
return "<no-frame>"
|
||||
end
|
||||
local point, relTo, relPoint, x, y = frame:GetPoint()
|
||||
local relName = "nil"
|
||||
if type(relTo) == "table" and relTo.GetName then
|
||||
relName = tostring(relTo:GetName() or "<anon>")
|
||||
elseif relTo then
|
||||
relName = tostring(relTo)
|
||||
end
|
||||
return tostring(point or "nil")
|
||||
.. "->" .. relName
|
||||
.. ":" .. tostring(relPoint or "nil")
|
||||
.. " @(" .. tostring(x) .. "," .. tostring(y) .. ")"
|
||||
end
|
||||
|
||||
function MTH_ZH_Trace(msg)
|
||||
if not MTH_ZH_TRACE_ENABLED then
|
||||
return
|
||||
end
|
||||
if MTH and MTH.Print then
|
||||
MTH:Print("[ZHTRACE] " .. tostring(msg), "debug")
|
||||
elseif DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("[ZHTRACE] " .. tostring(msg))
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_ZH_TraceButtonPoint(frame, reason)
|
||||
if not MTH_ZH_TRACE_ENABLED then
|
||||
return
|
||||
end
|
||||
if not frame then
|
||||
MTH_ZH_Trace("point " .. tostring(reason or "") .. " frame=nil")
|
||||
return
|
||||
end
|
||||
local name = frame.GetName and frame:GetName() or "<unnamed>"
|
||||
MTH_ZH_Trace("point " .. tostring(reason or "") .. " " .. tostring(name) .. " " .. MTH_ZH_DescribePoint(frame))
|
||||
end
|
||||
|
||||
function MTH_ZH_TraceAllButtonPoints(reason)
|
||||
if not MTH_ZH_TRACE_ENABLED then
|
||||
return
|
||||
end
|
||||
local names = {
|
||||
"zButtonAspect",
|
||||
"zButtonAmmo",
|
||||
"zButtonTrack",
|
||||
"zButtonTrap",
|
||||
"zButtonRanged",
|
||||
"zButtonPet",
|
||||
"zButtonMounts",
|
||||
"zButtonCompanions",
|
||||
"zButtonToys",
|
||||
}
|
||||
MTH_ZH_Trace("snapshot begin reason=" .. tostring(reason or ""))
|
||||
for i = 1, table.getn(names) do
|
||||
local frame = getglobal(names[i])
|
||||
MTH_ZH_TraceButtonPoint(frame, tostring(reason or "") .. ":" .. tostring(names[i]))
|
||||
end
|
||||
MTH_ZH_Trace("snapshot end reason=" .. tostring(reason or ""))
|
||||
end
|
||||
|
||||
function MTH_ZH_IsModuleEnabled()
|
||||
if not (MTH and MTH.IsModuleEnabled) then
|
||||
return true
|
||||
@@ -105,6 +170,7 @@ function MTH_ZH_HandleDisabledSlash(message, tableKey, fieldKey)
|
||||
end
|
||||
|
||||
function ZHunterMod_AlignButtons()
|
||||
MTH_ZH_TraceAllButtonPoints("AlignButtons:before")
|
||||
zButtonAmmo:ClearAllPoints()
|
||||
zButtonAmmo:SetPoint("TOP", zButtonAspect, "BOTTOM", 0, -15)
|
||||
zButtonTrack:ClearAllPoints()
|
||||
@@ -123,6 +189,7 @@ function ZHunterMod_AlignButtons()
|
||||
AutoStripDisplay:ClearAllPoints()
|
||||
AutoStripDisplay:SetPoint("TOP", zButtonToys, "BOTTOM", 0, -10)
|
||||
end
|
||||
MTH_ZH_TraceAllButtonPoints("AlignButtons:after")
|
||||
end
|
||||
|
||||
function ZMarkTarget()
|
||||
|
||||
@@ -377,6 +377,94 @@ function ZSpellButton_ApplyChildrenExpanded(parent)
|
||||
ZSpellButton_SetChildrenExpanded(parent, ZSpellButton_GetChildrenExpanded(parent))
|
||||
end
|
||||
|
||||
local function ZSpellButton_SaveParentPosition(parent)
|
||||
if not (parent and parent.GetPoint) then
|
||||
return
|
||||
end
|
||||
if type(MTH_ZH_GetSavedTable) ~= "function" then
|
||||
return
|
||||
end
|
||||
local key = parent.name
|
||||
if (type(key) ~= "string" or key == "") and parent.GetName then
|
||||
key = parent:GetName()
|
||||
end
|
||||
if type(key) ~= "string" or key == "" then
|
||||
return
|
||||
end
|
||||
|
||||
local saved = MTH_ZH_GetSavedTable(key)
|
||||
if type(saved) ~= "table" then
|
||||
return
|
||||
end
|
||||
if type(saved["parent"]) ~= "table" then
|
||||
saved["parent"] = {}
|
||||
end
|
||||
|
||||
local point, _, relPoint, x, y = parent:GetPoint()
|
||||
x = tonumber(x)
|
||||
y = tonumber(y)
|
||||
if not (point and relPoint and x and y) then
|
||||
return
|
||||
end
|
||||
|
||||
saved["parent"]["point"] = tostring(point)
|
||||
saved["parent"]["relativePoint"] = tostring(relPoint)
|
||||
saved["parent"]["x"] = math.floor(x + 0.5)
|
||||
saved["parent"]["y"] = math.floor(y + 0.5)
|
||||
if type(MTH_ZH_Trace) == "function" then
|
||||
MTH_ZH_Trace("persist-parent-position key=" .. tostring(key)
|
||||
.. " point=" .. tostring(saved["parent"]["point"])
|
||||
.. " rel=" .. tostring(saved["parent"]["relativePoint"])
|
||||
.. " x=" .. tostring(saved["parent"]["x"])
|
||||
.. " y=" .. tostring(saved["parent"]["y"]))
|
||||
end
|
||||
end
|
||||
|
||||
local function ZSpellButton_RestoreParentPosition(parent)
|
||||
if not (parent and parent.ClearAllPoints and parent.SetPoint) then
|
||||
return false
|
||||
end
|
||||
if type(MTH_ZH_GetSavedTable) ~= "function" then
|
||||
return false
|
||||
end
|
||||
local key = parent.name
|
||||
if (type(key) ~= "string" or key == "") and parent.GetName then
|
||||
key = parent:GetName()
|
||||
end
|
||||
if type(key) ~= "string" or key == "" then
|
||||
return false
|
||||
end
|
||||
|
||||
local saved = MTH_ZH_GetSavedTable(key)
|
||||
if type(saved) ~= "table" or type(saved["parent"]) ~= "table" then
|
||||
return false
|
||||
end
|
||||
|
||||
local parentSaved = saved["parent"]
|
||||
local px = tonumber(parentSaved["x"])
|
||||
local py = tonumber(parentSaved["y"])
|
||||
local point = parentSaved["point"]
|
||||
local relPoint = parentSaved["relativePoint"]
|
||||
if not (px and py and type(point) == "string" and point ~= "") then
|
||||
return false
|
||||
end
|
||||
|
||||
if type(relPoint) ~= "string" or relPoint == "" then
|
||||
relPoint = point
|
||||
end
|
||||
|
||||
parent:ClearAllPoints()
|
||||
parent:SetPoint(point, UIParent, relPoint, px, py)
|
||||
if type(MTH_ZH_Trace) == "function" then
|
||||
MTH_ZH_Trace("restore-parent-position key=" .. tostring(key)
|
||||
.. " point=" .. tostring(point)
|
||||
.. " rel=" .. tostring(relPoint)
|
||||
.. " x=" .. tostring(px)
|
||||
.. " y=" .. tostring(py))
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ZSpellButton_OnEnter()
|
||||
ZSpellButton_EnsureParentFlags(this.parent)
|
||||
if this.parent.tooltip then
|
||||
@@ -479,6 +567,46 @@ function ZSpellButtonParent_OnLoad()
|
||||
this.circle = getglobal(name.."Circle")
|
||||
-- Keep enabled so empty buttons can be moved on low-level characters.
|
||||
this:Enable()
|
||||
ZSpellButton_RestoreParentPosition(this)
|
||||
if this.SetScript then
|
||||
this:SetScript("OnDragStart", function(self)
|
||||
self = self or this
|
||||
if IsAltKeyDown() then
|
||||
if type(MTH_ZH_TraceButtonPoint) == "function" then
|
||||
MTH_ZH_TraceButtonPoint(self, "drag-start")
|
||||
end
|
||||
self:StartMoving()
|
||||
self.isMoving = true
|
||||
end
|
||||
end)
|
||||
this:SetScript("OnDragStop", function(self)
|
||||
self = self or this
|
||||
if not self then
|
||||
return
|
||||
end
|
||||
if self.StopMovingOrSizing then
|
||||
self:StopMovingOrSizing()
|
||||
end
|
||||
ZSpellButton_SaveParentPosition(self)
|
||||
self.isMoving = false
|
||||
if type(MTH_ZH_TraceButtonPoint) == "function" then
|
||||
MTH_ZH_TraceButtonPoint(self, "drag-stop")
|
||||
end
|
||||
end)
|
||||
this:SetScript("OnMouseUp", function(self)
|
||||
self = self or this
|
||||
if self and self.isMoving then
|
||||
if self.StopMovingOrSizing then
|
||||
self:StopMovingOrSizing()
|
||||
end
|
||||
ZSpellButton_SaveParentPosition(self)
|
||||
self.isMoving = false
|
||||
if type(MTH_ZH_TraceButtonPoint) == "function" then
|
||||
MTH_ZH_TraceButtonPoint(self, "mouse-up-stop")
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function ZSpellButtonParent_OnEvent()
|
||||
|
||||
@@ -8,7 +8,7 @@ MTH_ZH_MANAGED_HOOKS = true
|
||||
local MTH_ZHunter = {
|
||||
name = "zhunter",
|
||||
enabled = true,
|
||||
version = "1.0.6",
|
||||
version = "1.1.0",
|
||||
events = {
|
||||
"VARIABLES_LOADED",
|
||||
"PLAYER_ENTERING_WORLD",
|
||||
@@ -31,6 +31,12 @@ local function MTH_ZH_Log(msg)
|
||||
MTH:Print("[ZH MODULE] " .. tostring(msg), "debug")
|
||||
end
|
||||
|
||||
local function MTH_ZH_TraceLocal(msg)
|
||||
if type(MTH_ZH_Trace) == "function" then
|
||||
MTH_ZH_Trace(msg)
|
||||
end
|
||||
end
|
||||
|
||||
local MTH_ZH_PostLoginRestoreFrame = nil
|
||||
local MTH_ZH_BootstrapFrame = nil
|
||||
local MTH_ZH_SyncSavedVariables
|
||||
@@ -105,7 +111,6 @@ function MTH_ZH_OnDeferredInitComplete()
|
||||
return
|
||||
end
|
||||
MTH_ZH_SyncSavedVariables()
|
||||
MTH_ZH_ApplyDefaultWidgetSpawnLayoutOnce()
|
||||
MTH_ZH_RestoreRuntimeFeatureFlags()
|
||||
MTH_ZH_QueuePostLoginRestore("deferred-init")
|
||||
end
|
||||
@@ -132,6 +137,9 @@ MTH_ZH_QueuePostLoginRestore = function(tag)
|
||||
|
||||
MTH_ZH_SyncSavedVariables()
|
||||
MTH_ZH_RestoreRuntimeFeatureFlags()
|
||||
if type(MTH_ZH_TraceAllButtonPoints) == "function" then
|
||||
MTH_ZH_TraceAllButtonPoints("post-login-restore:" .. tostring(tag))
|
||||
end
|
||||
MTH_ZH_Log("post-login restore applied: " .. tostring(tag))
|
||||
end)
|
||||
end
|
||||
@@ -170,10 +178,17 @@ local function MTH_ZH_EnsureBootstrapRestoreFrame()
|
||||
end
|
||||
|
||||
MTH_ZH_ApplyEnabledRuntimeState = function(source)
|
||||
MTH_ZH_TraceLocal("apply-enabled-runtime-state source=" .. tostring(source or ""))
|
||||
if type(MTH_ZH_TraceAllButtonPoints) == "function" then
|
||||
MTH_ZH_TraceAllButtonPoints("apply-enabled:before:" .. tostring(source or ""))
|
||||
end
|
||||
MTH_ZH_SyncSavedVariables()
|
||||
MTH_ZH_SetButtonsVisible(true)
|
||||
MTH_ZH_SetAuxFramesVisible(true)
|
||||
MTH_ZH_RestoreRuntimeFeatureFlags()
|
||||
if type(MTH_ZH_TraceAllButtonPoints) == "function" then
|
||||
MTH_ZH_TraceAllButtonPoints("apply-enabled:after:" .. tostring(source or ""))
|
||||
end
|
||||
end
|
||||
|
||||
MTH_ZH_SyncSavedVariables = function()
|
||||
@@ -182,17 +197,22 @@ MTH_ZH_SyncSavedVariables = function()
|
||||
end
|
||||
|
||||
local moduleStore = MTH:GetModuleCharSavedVariables("zhunter")
|
||||
MTH_ZH_TraceLocal("sync-saved begin zhuntermod_saved=" .. tostring(type(ZHunterMod_Saved)))
|
||||
|
||||
if type(ZHunterMod_Saved) == "table" then
|
||||
if MTH_CharSavedVariables and MTH_CharSavedVariables.modules then
|
||||
MTH_CharSavedVariables.modules.zhunter = ZHunterMod_Saved
|
||||
MTH_ZH_TraceLocal("sync-saved wrote ZHunterMod_Saved -> MTH_CharSavedVariables.modules.zhunter")
|
||||
end
|
||||
elseif type(moduleStore) == "table" then
|
||||
ZHunterMod_Saved = moduleStore
|
||||
MTH_ZH_TraceLocal("sync-saved loaded moduleStore -> ZHunterMod_Saved")
|
||||
end
|
||||
MTH_ZH_TraceLocal("sync-saved end")
|
||||
end
|
||||
|
||||
MTH_ZH_SetButtonsVisible = function(visible)
|
||||
MTH_ZH_TraceLocal("set-buttons-visible visible=" .. tostring(visible and true or false))
|
||||
local buttonNames = {
|
||||
"zButtonAspect",
|
||||
"zButtonTrack",
|
||||
@@ -274,12 +294,18 @@ MTH_ZH_SetButtonsVisible = function(visible)
|
||||
for _, buttonName in ipairs(buttonNames) do
|
||||
local button = getglobal(buttonName)
|
||||
if button then
|
||||
if type(MTH_ZH_TraceButtonPoint) == "function" then
|
||||
MTH_ZH_TraceButtonPoint(button, "set-buttons-visible:before:" .. tostring(buttonName))
|
||||
end
|
||||
MTH_ZH_SetChildButtonsVisible(button, buttonName, visible)
|
||||
if visible then
|
||||
button:Show()
|
||||
else
|
||||
button:Hide()
|
||||
end
|
||||
if type(MTH_ZH_TraceButtonPoint) == "function" then
|
||||
MTH_ZH_TraceButtonPoint(button, "set-buttons-visible:after:" .. tostring(buttonName))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -358,6 +384,7 @@ function MTH_ZHunter:init()
|
||||
end
|
||||
|
||||
function MTH_ZHunter:setEnabled(enabled)
|
||||
MTH_ZH_TraceLocal("module setEnabled enabled=" .. tostring(enabled and true or false))
|
||||
MTH_ZH_SyncSavedVariables()
|
||||
if enabled then
|
||||
MTH_ZH_EnsureBootstrapRestoreFrame()
|
||||
@@ -366,8 +393,14 @@ function MTH_ZHunter:setEnabled(enabled)
|
||||
else
|
||||
MTH_ZH_ClearRuntimeFeatureFlags()
|
||||
MTH_ZH_SetAdjustmentHandlersActive(false)
|
||||
if type(MTH_ZH_TraceAllButtonPoints) == "function" then
|
||||
MTH_ZH_TraceAllButtonPoints("setEnabled:false:before-hide")
|
||||
end
|
||||
MTH_ZH_SetButtonsVisible(false)
|
||||
MTH_ZH_SetAuxFramesVisible(false)
|
||||
if type(MTH_ZH_TraceAllButtonPoints) == "function" then
|
||||
MTH_ZH_TraceAllButtonPoints("setEnabled:false:after-hide")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -30,13 +30,14 @@ local ZHUNTER_AMMO_MAX_COUNT = math.max(table.getn(MTH_AMMO_ARROWS or {}), table
|
||||
local zButtonAmmo_Cache = {}
|
||||
local zButtonAmmo_LastCacheSignature = nil
|
||||
local zButtonAmmo_LastRefreshAt = 0
|
||||
local zButtonAmmo_MinRefreshInterval = 0.20
|
||||
local zButtonAmmo_MinRefreshInterval = 0.50
|
||||
local zButtonAmmo_MinBagRefreshInterval = 0.75
|
||||
local zButtonAmmo_KnownAmmoTypes = nil
|
||||
local zButtonAmmo_AmmoBags = {}
|
||||
local zButtonAmmo_LastFullScanAt = 0
|
||||
local zButtonAmmo_MinUnknownBagScanInterval = 5.0
|
||||
local zButtonAmmo_EmptyScanStreak = 0
|
||||
local zButtonAmmo_LastEquippedAmmoSeen = nil
|
||||
local zButtonAmmo_GetKnownAmmoTypes
|
||||
|
||||
local function zButtonAmmo_BagHasAmmoNow(bagId)
|
||||
@@ -947,6 +948,14 @@ function zButtonAmmoAdjustment_OnEvent()
|
||||
|
||||
if event == "UNIT_INVENTORY_CHANGED" or event == "BAG_UPDATE" or event == "PLAYER_ALIVE" or event == "PLAYER_UNGHOST" then
|
||||
local now = GetTime and GetTime() or 0
|
||||
if event == "UNIT_INVENTORY_CHANGED" then
|
||||
local equippedNow = zButtonAmmo_GetEquippedAmmoName()
|
||||
if equippedNow == zButtonAmmo_LastEquippedAmmoSeen and now > 0 and zButtonAmmo_LastRefreshAt > 0 and (now - zButtonAmmo_LastRefreshAt) < 1.0 then
|
||||
zButtonAmmo_UpdateParentCountFast()
|
||||
return
|
||||
end
|
||||
zButtonAmmo_LastEquippedAmmoSeen = equippedNow
|
||||
end
|
||||
local bagIsAmmoRelated = false
|
||||
if event == "BAG_UPDATE" and arg1 ~= nil then
|
||||
local bagId = tonumber(arg1)
|
||||
@@ -1070,6 +1079,7 @@ function zButtonAmmoAdjustment_OnEvent()
|
||||
-- Save the currently equipped ammo for restoration on next reload
|
||||
if equippedAmmoName then
|
||||
zButtonAmmo_SaveEquippedAmmo(equippedAmmoName)
|
||||
zButtonAmmo_LastEquippedAmmoSeen = equippedAmmoName
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user