First version

This commit is contained in:
DuvelCorp
2026-02-24 23:00:59 +01:00
commit ee8328e903
125 changed files with 140652 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+8
View File
@@ -0,0 +1,8 @@
<!--
MetaHunt AutoBuy Module Loader
Standalone auto-buy foundation for pet food and ammo.
-->
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Include file="engine.lua"/>
<Include file="module.lua"/>
</Ui>
+161
View File
@@ -0,0 +1,161 @@
------------------------------------------------------
-- MetaHunt: AutoBuy Module
-- Standalone module shell for vendor auto-buy features.
------------------------------------------------------
local MTH_AutoBuy = {
name = "autobuy",
enabled = false,
version = "1.0.3",
events = {
"VARIABLES_LOADED",
"MERCHANT_SHOW",
"MERCHANT_UPDATE",
"MERCHANT_CLOSED",
},
initialized = false,
}
local function AB_Log(message, severity)
if type(MTH_Log) == "function" then
MTH_Log("[AutoBuy] " .. tostring(message or ""), severity)
end
end
local AB_Engine
local function AB_Trace(message)
return
end
local function AB_EnsureBridgeFrame(moduleRef)
if MTH_AutoBuy._bridgeFrame then
return MTH_AutoBuy._bridgeFrame
end
local frame = CreateFrame("Frame", "MTH_AutoBuyBridgeFrame")
if not frame then
AB_Log("failed to create bridge frame", "error")
return nil
end
frame:RegisterEvent("VARIABLES_LOADED")
frame:RegisterEvent("MERCHANT_SHOW")
frame:RegisterEvent("MERCHANT_UPDATE")
frame:RegisterEvent("MERCHANT_CLOSED")
frame:SetScript("OnEvent", function(_, eventName)
eventName = eventName or event
local engine = AB_Engine()
if not engine then
AB_Trace("bridge event=" .. tostring(eventName) .. " engine missing")
return
end
if eventName == "VARIABLES_LOADED" then
engine:Init()
local store = engine:EnsureDefaults()
AB_Trace("bridge VARIABLES_LOADED store.enabled=" .. tostring(store and store.enabled)
.. " projectiles.enabled=" .. tostring(store and store.projectiles and store.projectiles.enabled))
return
end
if eventName == "MERCHANT_SHOW" or eventName == "MERCHANT_UPDATE" then
AB_Trace("bridge " .. tostring(eventName) .. " -> engine")
engine:OnMerchantEvent(eventName)
elseif eventName == "MERCHANT_CLOSED" then
AB_Trace("bridge MERCHANT_CLOSED -> engine")
if engine.OnMerchantClosed then
engine:OnMerchantClosed()
end
end
end)
MTH_AutoBuy._bridgeFrame = frame
MTH_AutoBuy._bridgeActive = true
return frame
end
AB_Engine = function()
return MTH_AutoBuyEngine
end
function MTH_AutoBuy:init()
local engine = AB_Engine()
if not engine then
AB_Log("init failed: engine missing", "error")
AB_Trace("init failed: engine missing")
return
end
engine:Init()
AB_EnsureBridgeFrame(self)
self.initialized = true
AB_Trace("init done")
if self.enabled then
AB_Log("module initialized", "debug")
end
end
function MTH_AutoBuy:setEnabled(enabled)
if not self.initialized then
self:init()
end
local engine = AB_Engine()
if not engine then
AB_Trace("setEnabled ignored: engine missing")
return
end
local store = engine:EnsureDefaults()
store.enabled = enabled and true or false
AB_EnsureBridgeFrame(self)
AB_Trace("setEnabled store.enabled=" .. tostring(store.enabled))
end
function MTH_AutoBuy:onEvent(event)
local engine = AB_Engine()
if not engine then
AB_Log("onEvent ignored: engine missing, event=" .. tostring(event), "debug")
AB_Trace("engine missing, event=" .. tostring(event))
return
end
if self._bridgeActive and (event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" or event == "MERCHANT_CLOSED") then
return
end
AB_Log("onEvent event=" .. tostring(event) .. " module.enabled=" .. tostring(self.enabled), "debug")
if event == "VARIABLES_LOADED" then
engine:Init()
AB_EnsureBridgeFrame(self)
AB_Log("onEvent VARIABLES_LOADED -> engine init", "debug")
local store = engine:EnsureDefaults()
AB_Trace("VARIABLES_LOADED module.enabled=" .. tostring(self.enabled)
.. " store.enabled=" .. tostring(store and store.enabled)
.. " projectiles.enabled=" .. tostring(store and store.projectiles and store.projectiles.enabled))
return
end
if not self.enabled then
AB_Log("onEvent ignored: module disabled", "debug")
if event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" then
AB_Trace(tostring(event) .. " ignored: module disabled")
end
return
end
if event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" then
AB_Log("onEvent merchant event forwarded: " .. tostring(event), "debug")
AB_Trace("forwarding " .. tostring(event) .. " to engine")
engine:OnMerchantEvent(event)
elseif event == "MERCHANT_CLOSED" then
AB_Trace("forwarding MERCHANT_CLOSED to engine")
if engine.OnMerchantClosed then
engine:OnMerchantClosed()
end
end
end
function MTH_AutoBuy:cleanup()
AB_Log("module cleanup", "debug")
end
MTH:RegisterModule("autobuy", MTH_AutoBuy)
+78
View File
@@ -0,0 +1,78 @@
local BS = setmetatable({}, {
__index = function(_, key)
if MTH and MTH.LocalizeSpell then
return MTH:LocalizeSpell(key)
end
return key
end,
})
function MTH_ChronometerHunterInstallData(engine)
if not engine then
return
end
local _, class = UnitClass("player")
if class == "HUNTER" then
engine:AddGroup(1, true, "MAGENTA")
engine:AddGroup(2, false, "MAROON")
engine:AddGroup(3, false, "GREEN")
engine:AddTimer(engine.SPELL, BS["Bestial Wrath"], 18, 0, 1, 1, { cr = "RED" })
engine:AddTimer(engine.SPELL, BS["Concussive Shot"], 4, 1, 0, 0, { cr = "BLUE", ea = { [BS["Improved Concussive Shot"]] = 4 } })
engine:AddTimer(engine.SPELL, BS["Counterattack"], 5, 1, 0, 0, { cr = "ORANGE" })
engine:AddTimer(engine.SPELL, BS["Deterrence"], 10, 0, 1, 1, { cr = "ORANGE" })
engine:AddTimer(engine.SPELL, BS["Explosive Trap"], 60, 0, 0, 0, { gr = 1, cr = "ORANGE", rc = true, ea = { [BS["Explosive Trap Effect"]] = 60 } })
engine:AddTimer(engine.SPELL, BS["Freezing Trap"], 60, 0, 0, 0, { gr = 1, cr = "CYAN", rc = true, ea = { [BS["Freezing Trap Effect"]] = 60 } })
engine:AddTimer(engine.SPELL, BS["Frost Trap"], 60, 0, 0, 0, { gr = 1, cr = "CYAN", rc = true, ea = { [BS["Frost Trap Aura"]] = 60 } })
engine:AddTimer(engine.SPELL, BS["Flare"], 30, 0, 0, 0, { cr = "YELLOW", rc = true })
engine:AddTimer(engine.SPELL, BS["Hunter's Mark"], 120, 1, 0, 0, { cr = "RED", rc = true })
engine:AddTimer(engine.SPELL, BS["Immolation Trap"], 60, 0, 0, 0, { gr = 1, cr = "ORANGE", ea = { [BS["Immolation Trap Effect"]] = 60 } })
engine:AddTimer(engine.SPELL, BS["Rapid Fire"], 15, 0, 1, 1, { cr = "RED" })
engine:AddTimer(engine.SPELL, BS["Scare Beast"], 10, 1, 0, 0, { cr = "BLUE", rc = true, d = { rs = 5 } })
engine:AddTimer(engine.SPELL, BS["Scatter Shot"], 4, 1, 0, 0, { cr = "MAROON" })
engine:AddTimer(engine.SPELL, BS["Scorpid Sting"], 20, 1, 0, 0, { gr = 2, cr = "PURPLE", rc = true })
engine:AddTimer(engine.SPELL, BS["Serpent Sting"], 15, 1, 0, 0, { gr = 2, cr = "GREEN", rc = true })
engine:AddTimer(engine.SPELL, BS["Viper Sting"], 8, 1, 0, 0, { gr = 2, cr = "CYAN", rc = true })
engine:AddTimer(engine.SPELL, BS["Wing Clip"], 10, 1, 0, 0, { cr = "YELLOW", rc = true, ea = { [BS["Improved Wing Clip"]] = 10 } })
engine:AddTimer(engine.SPELL, BS["Wyvern Sting"], 12, 1, 0, 0, { gr = 2, cr = "MAROON", rc = true })
engine:AddTimer(engine.SPELL, BS["Feed Pet"], 20, 0, 0, 0, { cr = "MAROON" })
engine:AddTimer(engine.EVENT, BS["Explosive Trap Effect"], 20, 1, 0, 1, { gr = 1, cr = "ORANGE", a = 1, xn = BS["Explosive Trap"] })
engine:AddTimer(engine.EVENT, BS["Freezing Trap Effect"], 10, 1, 0, 1, { gr = 1, cr = "CYAN", a = 1, d = { rs = 5, tn = BS["Clever Traps"], tb = 0.15, tp = 1 }, xn = BS["Freezing Trap"] })
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["Piercing Shot"], 8, 1, 0, 1, { a = 1, cr = "PURPLE", tx = "Interface\\Icons\\Ability_Hunter_DisarmingShot" })
engine:AddTimer(engine.EVENT, BS["Quick Shots"], 12, 0, 1, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\Ability_Hunter_Quickshot" })
engine:AddTimer(engine.EVENT, BS["Scorpid Poison"], 10, 1, 0, 0, { gr = 3, cr = "PURPLE", a = 1, dn = 1 })
end
local _, race = UnitRace("player")
if race == "Dwarf" then
engine:AddTimer(engine.SPELL, BS["Stoneform"], 8, 0, 1, 1, { cl = "RACIAL" })
elseif race == "Human" then
engine:AddTimer(engine.SPELL, BS["Perception"], 20, 0, 1, 1, { cl = "RACIAL" })
elseif race == "Orc" then
engine:AddTimer(engine.SPELL, BS["Blood Fury"], 15, 0, 1, 1, { cl = "RACIAL" })
elseif race == "Tauren" then
engine:AddTimer(engine.SPELL, BS["War Stomp"], 2, 0, 0, 0, { cl = "RACIAL" })
elseif race == "Troll" then
engine:AddTimer(engine.SPELL, BS["Berserking"], 10, 0, 1, 1, { cl = "RACIAL" })
elseif race == "Scourge" then
engine:AddTimer(engine.SPELL, BS["Will of the Forsaken"], 5, 0, 1, 1, { cl = "RACIAL" })
end
if class == "PALADIN" or class == "WARRIOR" or class == "ROGUE" or class == "SHAMAN" then
engine:AddTimer(engine.EVENT, BS["Holy Strength"], 15, 0, 1, 1, { cr = "YELLOW", a = 1, cl = "COMMON" })
end
engine:AddTimer(engine.EVENT, BS["Unstable Power"], 20, 0, 1, 1, { a = 1, cr = "CYAN", cl = "COMMON" })
engine:AddTimer(engine.EVENT, BS["Ephemeral Power"], 15, 0, 1, 1, { a = 1, cr = "CYAN", cl = "COMMON" })
engine:AddTimer(engine.EVENT, BS["Mind Quickening"], 20, 0, 1, 1, { a = 1, cr = "CYAN", cl = "COMMON", xn = BS["Critical Mass"] })
end
if MTH_ChronometerHunter and MTH_ChronometerHunter.dataSetup then
table.insert(MTH_ChronometerHunter.dataSetup, MTH_ChronometerHunterInstallData)
end
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,973 @@
--[[
Name: AceEvent-2.0
Revision: $Rev: 17803 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceEvent-2.0
SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0
Description: Mixin to allow for event handling, scheduling, and inter-addon
communication.
Dependencies: AceLibrary, AceOO-2.0
]]
local MAJOR_VERSION = "AceEvent-2.0"
local MINOR_VERSION = "$Revision: 17803 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
local Mixin = AceOO.Mixin
local AceEvent = Mixin {
"RegisterEvent",
"RegisterAllEvents",
"UnregisterEvent",
"UnregisterAllEvents",
"TriggerEvent",
"ScheduleEvent",
"ScheduleRepeatingEvent",
"CancelScheduledEvent",
"CancelAllScheduledEvents",
"IsEventRegistered",
"IsEventScheduled",
"RegisterBucketEvent",
"UnregisterBucketEvent",
"UnregisterAllBucketEvents",
"IsBucketEventRegistered",
}
local table_setn
do
local version = GetBuildInfo()
if string.find(version, "^2%.") then
-- 2.0.0
table_setn = function() end
else
table_setn = table.setn
end
end
local weakKey = {__mode="k"}
local new, del
do
local list = setmetatable({}, weakKey)
function new()
local t = next(list)
if t then
list[t] = nil
return t
else
return {}
end
end
function del(t)
setmetatable(t, nil)
for k in pairs(t) do
t[k] = nil
end
list[t] = true
end
end
local FAKE_NIL
local RATE
local eventsWhichHappenOnce = {
PLAYER_LOGIN = true,
AceEvent_FullyInitialized = true,
VARIABLES_LOADED = true,
PLAYER_LOGOUT = true,
}
local registeringFromAceEvent
function AceEvent:RegisterEvent(event, method, once)
AceEvent:argCheck(event, 2, "string")
if self == AceEvent and not registeringFromAceEvent then
AceEvent:argCheck(method, 3, "function")
self = method
else
AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number")
if type(method) == "boolean" or type(method) == "number" then
AceEvent:argCheck(once, 4, "nil")
once, method = method, event
end
end
AceEvent:argCheck(once, 4, "number", "boolean", "nil")
if eventsWhichHappenOnce[event] then
once = true
end
local throttleRate
if type(once) == "number" then
throttleRate, once = once
end
if not method then
method = event
end
if type(method) == "string" and type(self[method]) ~= "function" then
AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
else
assert(type(method) == "function" or type(method) == "string")
end
local AceEvent_registry = AceEvent.registry
if not AceEvent_registry[event] then
AceEvent_registry[event] = new()
AceEvent.frame:RegisterEvent(event)
end
local remember = true
if AceEvent_registry[event][self] then
remember = false
end
AceEvent_registry[event][self] = method
local AceEvent_onceRegistry = AceEvent.onceRegistry
if once then
if not AceEvent_onceRegistry then
AceEvent.onceRegistry = new()
AceEvent_onceRegistry = AceEvent.onceRegistry
end
if not AceEvent_onceRegistry[event] then
AceEvent_onceRegistry[event] = new()
end
AceEvent_onceRegistry[event][self] = true
else
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
AceEvent_onceRegistry[event][self] = nil
if not next(AceEvent_onceRegistry[event]) then
AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
end
end
end
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
if throttleRate then
if not AceEvent_throttleRegistry then
AceEvent.throttleRegistry = new()
AceEvent_throttleRegistry = AceEvent.throttleRegistry
end
if not AceEvent_throttleRegistry[event] then
AceEvent_throttleRegistry[event] = new()
end
if AceEvent_throttleRegistry[event][self] then
AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
end
AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey)
local t = AceEvent_throttleRegistry[event][self]
t[RATE] = throttleRate
else
if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then
if AceEvent_throttleRegistry[event][self] then
AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
end
if not next(AceEvent_throttleRegistry[event]) then
AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
end
end
end
if remember then
AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event)
end
end
local ALL_EVENTS
function AceEvent:RegisterAllEvents(method)
if self == AceEvent then
AceEvent:argCheck(method, 1, "function")
self = method
else
AceEvent:argCheck(method, 1, "string", "function")
if type(method) == "string" and type(self[method]) ~= "function" then
AceEvent:error("Cannot register all events to method %q, it does not exist", method)
end
end
local AceEvent_registry = AceEvent.registry
if not AceEvent_registry[ALL_EVENTS] then
AceEvent_registry[ALL_EVENTS] = new()
AceEvent.frame:RegisterAllEvents()
end
AceEvent_registry[ALL_EVENTS][self] = method
end
local _G = getfenv(0)
local memstack, timestack = {}, {}
local memdiff, timediff
function AceEvent:TriggerEvent(event, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
AceEvent:argCheck(event, 2, "string")
local AceEvent_registry = AceEvent.registry
if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then
return
end
local _G_event = _G.event
_G.event = event
local lastEvent = AceEvent.currentEvent
AceEvent.currentEvent = event
local AceEvent_onceRegistry = AceEvent.onceRegistry
local AceEvent_debugTable = AceEvent.debugTable
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
local tmp = new()
for obj, method in pairs(AceEvent_onceRegistry[event]) do
tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil
end
local obj = next(tmp)
while obj do
local mem, time
if AceEvent_debugTable then
if not AceEvent_debugTable[event] then
AceEvent_debugTable[event] = new()
end
if not AceEvent_debugTable[event][obj] then
AceEvent_debugTable[event][obj] = new()
AceEvent_debugTable[event][obj].mem = 0
AceEvent_debugTable[event][obj].time = 0
AceEvent_debugTable[event][obj].count = 0
end
if memdiff then
table.insert(memstack, memdiff)
table.insert(timestack, timediff)
end
memdiff, timediff = 0, 0
mem, time = gcinfo(), GetTime()
end
local method = tmp[obj]
AceEvent.UnregisterEvent(obj, event)
if type(method) == "string" then
local obj_method = obj[method]
if obj_method then
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
elseif method then -- function
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
if AceEvent_debugTable then
local dmem, dtime = memdiff, timediff
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
memdiff, timediff = table.remove(memstack), table.remove(timestack)
if memdiff then
memdiff = memdiff + mem + dmem
timediff = timediff + time + dtime
end
end
tmp[obj] = nil
obj = next(tmp)
end
del(tmp)
end
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event]
if AceEvent_registry[event] then
local tmp = new()
for obj, method in pairs(AceEvent_registry[event]) do
tmp[obj] = method
end
local obj = next(tmp)
while obj do
local method = tmp[obj]
local continue = false
if throttleTable and throttleTable[obj] then
local a1 = a1
if a1 == nil then
a1 = FAKE_NIL
end
if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then
throttleTable[obj][a1] = GetTime()
else
continue = true
end
end
if not continue then
local mem, time
if AceEvent_debugTable then
if not AceEvent_debugTable[event] then
AceEvent_debugTable[event] = new()
end
if not AceEvent_debugTable[event][obj] then
AceEvent_debugTable[event][obj] = new()
AceEvent_debugTable[event][obj].mem = 0
AceEvent_debugTable[event][obj].time = 0
AceEvent_debugTable[event][obj].count = 0
end
if memdiff then
table.insert(memstack, memdiff)
table.insert(timestack, timediff)
end
memdiff, timediff = 0, 0
mem, time = gcinfo(), GetTime()
end
if type(method) == "string" then
local obj_method = obj[method]
if obj_method then
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
elseif method then -- function
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
if AceEvent_debugTable then
local dmem, dtime = memdiff, timediff
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
memdiff, timediff = table.remove(memstack), table.remove(timestack)
if memdiff then
memdiff = memdiff + mem + dmem
timediff = timediff + time + dtime
end
end
end
tmp[obj] = nil
obj = next(tmp)
end
del(tmp)
end
if AceEvent_registry[ALL_EVENTS] then
local tmp = new()
for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do
tmp[obj] = method
end
local obj = next(tmp)
while obj do
local method = tmp[obj]
local mem, time
if AceEvent_debugTable then
if not AceEvent_debugTable[event] then
AceEvent_debugTable[event] = new()
end
if not AceEvent_debugTable[event][obj] then
AceEvent_debugTable[event][obj] = new()
AceEvent_debugTable[event][obj].mem = 0
AceEvent_debugTable[event][obj].time = 0
AceEvent_debugTable[event][obj].count = 0
end
if memdiff then
table.insert(memstack, memdiff)
table.insert(timestack, timediff)
end
memdiff, timediff = 0, 0
mem, time = gcinfo(), GetTime()
end
if type(method) == "string" then
local obj_method = obj[method]
if obj_method then
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
elseif method then -- function
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
if AceEvent_debugTable then
local dmem, dtime = memdiff, timediff
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
memdiff, timediff = table.remove(memstack), table.remove(timestack)
if memdiff then
memdiff = memdiff + mem + dmem
timediff = timediff + time + dtime
end
end
tmp[obj] = nil
obj = next(tmp)
end
del(tmp)
end
_G.event = _G_event
AceEvent.currentEvent = lastEvent
end
-- local accessors
local getn = table.getn
local tinsert = table.insert
local tremove = table.remove
local floor = math.floor
local GetTime = GetTime
local next = next
local pairs = pairs
local unpack = unpack
local delayRegistry
local tmp = {}
local function OnUpdate()
local t = GetTime()
for k,v in pairs(delayRegistry) do
tmp[k] = true
end
for k in pairs(tmp) do
local v = delayRegistry[k]
if v then
local v_time = v.time
if not v_time then
delayRegistry[k] = del(v)
elseif v_time <= t then
local v_repeatDelay = v.repeatDelay
if v_repeatDelay then
-- use the event time, not the current time, else timing inaccuracies add up over time
v.time = v_time + v_repeatDelay
end
local event = v.event
local mem, time
if AceEvent_debugTable then
mem, time = gcinfo(), GetTime()
end
if type(event) == "function" then
event(unpack(v))
else
AceEvent:TriggerEvent(event, unpack(v))
end
if AceEvent_debugTable then
mem, time = gcinfo() - mem, GetTime() - time
v.mem = v.mem + mem
v.timeSpent = v.timeSpent + time
v.count = v.count + 1
end
if not v_repeatDelay then
local x = delayRegistry[k]
if x and x.time == v_time then -- check if it was manually reset
delayRegistry[k] = del(v)
end
end
end
end
end
for k in pairs(tmp) do
tmp[k] = nil
end
if not next(delayRegistry) then
AceEvent.frame:Hide()
end
end
local function ScheduleEvent(self, repeating, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
local id
if type(event) == "string" or type(event) == "table" then
if type(event) == "table" then
if not delayRegistry or not delayRegistry[event] then
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
end
end
if type(delay) ~= "number" then
id, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
AceEvent:argCheck(delay, 4, "number")
self:CancelScheduledEvent(id)
end
else
AceEvent:argCheck(event, 2, "string", "function")
AceEvent:argCheck(delay, 3, "number")
end
if not delayRegistry then
AceEvent.delayRegistry = new()
delayRegistry = AceEvent.delayRegistry
AceEvent.frame:SetScript("OnUpdate", OnUpdate)
end
local t
if type(id) == "table" then
for k in pairs(id) do
id[k] = nil
end
t = id
else
t = new()
end
t[1] = a1
t[2] = a2
t[3] = a3
t[4] = a4
t[5] = a5
t[6] = a6
t[7] = a7
t[8] = a8
t[9] = a9
t[10] = a10
t[11] = a11
t[12] = a12
t[13] = a13
t[14] = a14
t[15] = a15
t[16] = a16
t[17] = a17
t[18] = a18
t[19] = a19
t[20] = a20
table_setn(t, 20)
t.event = event
t.time = GetTime() + delay
t.self = self
t.id = id or t
t.repeatDelay = repeating and delay
if AceEvent_debugTable then
t.mem = 0
t.count = 0
t.timeSpent = 0
end
delayRegistry[t.id] = t
AceEvent.frame:Show()
return t.id
end
function AceEvent:ScheduleEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if type(event) == "string" or type(event) == "table" then
if type(event) == "table" then
if not delayRegistry or not delayRegistry[event] then
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
end
end
if type(delay) ~= "number" then
AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
AceEvent:argCheck(a1, 4, "number")
end
else
AceEvent:argCheck(event, 2, "string", "function")
AceEvent:argCheck(delay, 3, "number")
end
return ScheduleEvent(self, false, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
function AceEvent:ScheduleRepeatingEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if type(event) == "string" or type(event) == "table" then
if type(event) == "table" then
if not delayRegistry or not delayRegistry[event] then
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
end
end
if type(delay) ~= "number" then
AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
AceEvent:argCheck(a1, 4, "number")
end
else
AceEvent:argCheck(event, 2, "string", "function")
AceEvent:argCheck(delay, 3, "number")
end
return ScheduleEvent(self, true, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
function AceEvent:CancelScheduledEvent(t)
AceEvent:argCheck(t, 2, "string", "table")
if delayRegistry then
local v = delayRegistry[t]
if v then
delayRegistry[t] = del(v)
if not next(delayRegistry) then
AceEvent.frame:Hide()
end
return true
end
end
return false
end
function AceEvent:IsEventScheduled(t)
AceEvent:argCheck(t, 2, "string", "table")
if delayRegistry then
local v = delayRegistry[t]
if v then
return true, v.time - GetTime()
end
end
return false, nil
end
function AceEvent:UnregisterEvent(event)
AceEvent:argCheck(event, 2, "string")
local AceEvent_registry = AceEvent.registry
if AceEvent_registry[event] and AceEvent_registry[event][self] then
AceEvent_registry[event][self] = nil
local AceEvent_onceRegistry = AceEvent.onceRegistry
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then
AceEvent_onceRegistry[event][self] = nil
if not next(AceEvent_onceRegistry[event]) then
AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
end
end
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then
AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
if not next(AceEvent_throttleRegistry[event]) then
AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
end
end
if not next(AceEvent_registry[event]) then
AceEvent_registry[event] = del(AceEvent_registry[event])
if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
AceEvent.frame:UnregisterEvent(event)
end
end
else
if self == AceEvent then
error(string.format("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0.", event), 2)
else
AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self)
end
end
AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
end
function AceEvent:UnregisterAllEvents()
local AceEvent_registry = AceEvent.registry
if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
AceEvent_registry[ALL_EVENTS][self] = nil
if not next(AceEvent_registry[ALL_EVENTS]) then
del(AceEvent_registry[ALL_EVENTS])
AceEvent.frame:UnregisterAllEvents()
for k,v in pairs(AceEvent_registry) do
if k ~= ALL_EVENTS then
AceEvent.frame:RegisterEvent(k)
end
end
AceEvent_registry[event] = nil
end
end
local first = true
for event, data in pairs(AceEvent_registry) do
if first then
if AceEvent_registry.AceEvent_EventUnregistered then
event = "AceEvent_EventUnregistered"
else
first = false
end
end
local x = data[self]
data[self] = nil
if x and event ~= ALL_EVENTS then
if not next(data) then
del(data)
if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
AceEvent.frame:UnregisterEvent(event)
end
AceEvent_registry[event] = nil
end
AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
end
if first then
event = nil
end
end
if AceEvent.onceRegistry then
for event, data in pairs(AceEvent.onceRegistry) do
data[self] = nil
end
end
end
function AceEvent:CancelAllScheduledEvents()
if delayRegistry then
for k,v in pairs(delayRegistry) do
if v.self == self then
delayRegistry[k] = del(v)
end
end
if not next(delayRegistry) then
AceEvent.frame:Hide()
end
end
end
function AceEvent:IsEventRegistered(event)
AceEvent:argCheck(event, 2, "string")
local AceEvent_registry = AceEvent.registry
if self == AceEvent then
return AceEvent_registry[event] and next(AceEvent_registry[event]) and true or false
end
if AceEvent_registry[event] and AceEvent_registry[event][self] then
return true, AceEvent_registry[event][self]
end
return false, nil
end
local bucketfunc
function AceEvent:RegisterBucketEvent(event, delay, method)
AceEvent:argCheck(event, 2, "string", "table")
if type(event) == "table" then
for k,v in pairs(event) do
if type(k) ~= "number" then
AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.")
elseif type(v) ~= "string" then
AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.")
end
end
end
AceEvent:argCheck(delay, 3, "number")
if AceEvent == self then
AceEvent:argCheck(method, 4, "function")
self = method
else
if type(event) == "string" then
AceEvent:argCheck(method, 4, "string", "function", "nil")
if not method then
method = event
end
else
AceEvent:argCheck(method, 4, "string", "function")
end
if type(method) == "string" and type(self[method]) ~= "function" then
AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
end
end
if not AceEvent.buckets then
AceEvent.buckets = new()
end
if not AceEvent.buckets[event] then
AceEvent.buckets[event] = new()
end
if not AceEvent.buckets[event][self] then
AceEvent.buckets[event][self] = new()
AceEvent.buckets[event][self].current = new()
AceEvent.buckets[event][self].self = self
else
AceEvent.CancelScheduledEvent(self, AceEvent.buckets[event][self].id)
end
local bucket = AceEvent.buckets[event][self]
bucket.method = method
local func = function(arg1)
bucket.run = true
if arg1 then
bucket.current[arg1] = true
end
end
AceEvent.buckets[event][self].func = func
if type(event) == "string" then
AceEvent.RegisterEvent(self, event, func)
else
for _,v in ipairs(event) do
AceEvent.RegisterEvent(self, v, func)
end
end
if not bucketfunc then
bucketfunc = function(bucket)
local current = bucket.current
local method = bucket.method
local self = bucket.self
if bucket.run then
if type(method) == "string" then
self[method](self, current)
elseif method then -- function
method(current)
end
for k in pairs(current) do
current[k] = nil
k = nil
end
bucket.run = false
end
end
end
bucket.id = AceEvent.ScheduleRepeatingEvent(self, bucketfunc, delay, bucket)
end
function AceEvent:IsBucketEventRegistered(event)
AceEvent:argCheck(event, 2, "string", "table")
return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self]
end
function AceEvent:UnregisterBucketEvent(event)
AceEvent:argCheck(event, 2, "string", "table")
if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then
AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self)
end
local bucket = AceEvent.buckets[event][self]
if type(event) == "string" then
AceEvent.UnregisterEvent(self, event)
else
for _,v in ipairs(event) do
AceEvent.UnregisterEvent(self, v)
end
end
AceEvent:CancelScheduledEvent(bucket.id)
del(bucket.current)
AceEvent.buckets[event][self] = del(AceEvent.buckets[event][self])
if not next(AceEvent.buckets[event]) then
AceEvent.buckets[event] = del(AceEvent.buckets[event])
end
end
function AceEvent:UnregisterAllBucketEvents()
if not AceEvent.buckets or not next(AceEvent.buckets) then
return
end
for k,v in pairs(AceEvent.buckets) do
if v == self then
AceEvent.UnregisterBucketEvent(self, k)
k = nil
end
end
end
function AceEvent:OnEmbedDisable(target)
self.UnregisterAllEvents(target)
self.CancelAllScheduledEvents(target)
self.UnregisterAllBucketEvents(target)
end
function AceEvent:EnableDebugging()
if not self.debugTable then
self.debugTable = new()
if delayRegistry then
for k,v in pairs(self.delayRegistry) do
if not v.mem then
v.mem = 0
v.count = 0
v.timeSpent = 0
end
end
end
end
end
function AceEvent:IsFullyInitialized()
return self.postInit or false
end
function AceEvent:IsPostPlayerLogin()
return self.playerLogin or false
end
function AceEvent:activate(oldLib, oldDeactivate)
AceEvent = self
if oldLib then
self.onceRegistry = oldLib.onceRegistry
self.throttleRegistry = oldLib.throttleRegistry
self.delayRegistry = oldLib.delayRegistry
self.buckets = oldLib.buckets
self.registry = oldLib.registry
self.frame = oldLib.frame
self.debugTable = oldLib.debugTable
self.playerLogin = oldLib.pew or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage and true
self.postInit = oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
self.ALL_EVENTS = oldLib.ALL_EVENTS
self.FAKE_NIL = oldLib.FAKE_NIL
self.RATE = oldLib.RATE
end
if not self.registry then
self.registry = {}
end
if not self.frame then
self.frame = CreateFrame("Frame", "AceEvent20Frame")
end
if not self.ALL_EVENTS then
self.ALL_EVENTS = {}
end
if not self.FAKE_NIL then
self.FAKE_NIL = {}
end
if not self.RATE then
self.RATE = {}
end
ALL_EVENTS = self.ALL_EVENTS
FAKE_NIL = self.FAKE_NIL
RATE = self.RATE
local inPlw = false
local blacklist = {
UNIT_INVENTORY_CHANGED = true,
BAG_UPDATE = true,
ITEM_LOCK_CHANGED = true,
ACTIONBAR_SLOT_CHANGED = true,
}
self.frame:SetScript("OnEvent", function()
local event = event
if event == "PLAYER_ENTERING_WORLD" then
inPlw = false
elseif event == "PLAYER_LEAVING_WORLD" then
inPlw = true
end
if event and (not inPlw or not blacklist[event]) then
self:TriggerEvent(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
end
end)
if self.delayRegistry then
delayRegistry = self.delayRegistry
self.frame:SetScript("OnUpdate", OnUpdate)
end
self:UnregisterAllEvents()
self:CancelAllScheduledEvents()
registeringFromAceEvent = true
self:RegisterEvent("LOOT_OPENED", function()
SendAddonMessage("LOOT_OPENED", "", "RAID")
end)
registeringFromAceEvent = nil
if not self.playerLogin then
registeringFromAceEvent = true
self:RegisterEvent("PLAYER_LOGIN", function()
self.playerLogin = true
end, true)
registeringFromAceEvent = nil
end
if not self.postInit then
local isReload = true
local function func()
self.postInit = true
self:TriggerEvent("AceEvent_FullyInitialized")
if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then
self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
end
if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
self:UnregisterEvent("MEETINGSTONE_CHANGED")
end
if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then
self:UnregisterEvent("MINIMAP_ZONE_CHANGED")
end
if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then
self:UnregisterEvent("LANGUAGE_LIST_CHANGED")
end
end
registeringFromAceEvent = true
local f = function()
self.playerLogin = true
self:ScheduleEvent("AceEvent_FullyInitialized", func, 1)
end
self:RegisterEvent("MEETINGSTONE_CHANGED", f, true)
self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function()
self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.05)
end)
self:RegisterEvent("LANGUAGE_LIST_CHANGED", function()
if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
registeringFromAceEvent = true
self:UnregisterEvent("MEETINGSTONE_CHANGED")
self:RegisterEvent("MINIMAP_ZONE_CHANGED", f, true)
registeringFromAceEvent = nil
end
end)
self:ScheduleEvent("AceEvent_FullyInitialized", func, 10)
registeringFromAceEvent = nil
end
self.super.activate(self, oldLib, oldDeactivate)
if oldLib then
oldDeactivate(oldLib)
end
end
AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, AceEvent.activate)
AceEvent = AceLibrary(MAJOR_VERSION)
@@ -0,0 +1,569 @@
--[[
Name: AceHook-2.1
Revision: $Rev: 17638 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceHook-2.1
SVN: http://svn.wowace.com/root/trunk/Ace2/AceHook-2.1
Description: Mixin to allow for safe hooking of functions, methods, and scripts.
Dependencies: AceLibrary, AceOO-2.0
]]
local MAJOR_VERSION = "AceHook-2.1"
local MINOR_VERSION = "$Revision: 17638 $"
-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
--[[---------------------------------------------------------------------------------
Create the library object
----------------------------------------------------------------------------------]]
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
local AceHook = AceOO.Mixin {
"Hook",
"HookScript",
"SecureHook",
"Unhook",
"UnhookAll",
"HookReport",
"IsHooked",
}
--[[---------------------------------------------------------------------------------
Library Definitions
----------------------------------------------------------------------------------]]
local protFuncs = {
CameraOrSelectOrMoveStart = true, CameraOrSelectOrMoveStop = true,
TurnOrActionStart = true, TurnOrActionStop = true,
PitchUpStart = true, PitchUpStop = true,
PitchDownStart = true, PitchDownStop = true,
MoveBackwardStart = true, MoveBackwardStop = true,
MoveForwardStart = true, MoveForwardStop = true,
Jump = true, StrafeLeftStart = true,
StrafeLeftStop = true, StrafeRightStart = true,
StrafeRightStop = true, ToggleMouseMove = true,
ToggleRun = true, TurnLeftStart = true,
TurnLeftStop = true, TurnRightStart = true,
TurnRightStop = true,
}
local function issecurevariable(x)
if protFuncs[x] then
return 1
else
return nil
end
end
local _G = getfenv(0)
local function hooksecurefunc(arg1, arg2, arg3)
if type(arg1) == "string" then
arg1, arg2, arg3 = _G, arg1, arg2
end
local orig = arg1[arg2]
arg1[arg2] = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
local x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20 = orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
arg3(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
return x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20
end
end
local protectedScripts = {
OnClick = true,
}
local handlers, scripts, actives, registry
--[[---------------------------------------------------------------------------------
Private definitions (Not exposed)
----------------------------------------------------------------------------------]]
local new, del
do
local list = setmetatable({}, {__mode = "k"})
function new()
local t = next(list)
if not t then
return {}
end
list[t] = nil
return t
end
function del(t)
setmetatable(t, nil)
for k in pairs(t) do
t[k] = nil
end
list[t] = true
end
end
local function createFunctionHook(self, func, handler, orig, secure)
if not secure then
if type(handler) == "string" then
-- The handler is a method, need to self it
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
else
-- The handler is a function, just call it
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
end
else
-- secure hooks don't call the original method
if type(handler) == "string" then
-- The handler is a method, need to self it
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
else
-- The handler is a function, just call it
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
end
end
end
local function createMethodHook(self, object, method, handler, orig, secure, script)
if script then
if type(handler) == "string" then
local uid
uid = function()
if actives[uid] then
return self[handler](self, object)
else
return orig()
end
end
return uid
else
-- The handler is a function, just call it
local uid
uid = function()
if actives[uid] then
return handler(object)
else
return orig()
end
end
return uid
end
elseif not secure then
if type(handler) == "string" then
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
else
-- The handler is a function, just call it
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
end
else
-- secure hooks don't call the original method
if type(handler) == "string" then
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
else
-- The handler is a function, just call it
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
end
end
end
local function hookFunction(self, func, handler, secure)
local orig = _G[func]
if not orig or type(orig) ~= "function" then
AceHook:error("Attempt to hook a non-existant function %q", func)
end
if not handler then
handler = func
end
if registry[self][func] then
local uid = registry[self][func]
if actives[uid] then
-- We have an active hook from this source. Don't multi-hook
AceHook:error("%q already has an active hook from this source.", func)
end
if handlers[uid] == handler then
-- The hook is inactive, so reactivate it
actives[uid] = true
return
else
AceHook:error("There is a stale hook for %q can't hook or reactivate.", func)
end
end
if type(handler) == "string" then
if type(self[handler]) ~= "function" then
AceHook:error("Could not find the the handler %q when hooking function %q", handler, func)
end
elseif type(handler) ~= "function" then
AceHook:error("Could not find the handler you supplied when hooking %q", func)
end
local uid = createFunctionHook(self, func, handler, orig, secure)
registry[self][func] = uid
actives[uid] = true
handlers[uid] = handler
if not secure then
_G[func] = uid
self.hooks[func] = orig
else
hooksecurefunc(func, uid)
end
end
local function unhookFunction(self, func)
if not registry[self][func] then
AceHook:error("Tried to unhook %q which is not currently hooked.", func)
end
local uid = registry[self][func]
if actives[uid] then
-- See if we own the global function
if self.hooks[func] and _G[func] == uid then
_G[func] = self.hooks[func]
self.hooks[func] = nil
registry[self][func] = nil
handlers[uid] = nil
scripts[uid] = nil
actives[uid] = nil
-- Magically all-done
else
actives[uid] = nil
end
end
end
local function hookMethod(self, obj, method, handler, script, secure)
if not handler then
handler = method
end
if not obj or type(obj) ~= "table" then
AceHook:error("The object you supplied could not be found, or isn't a table.")
end
local uid = registry[self][obj] and registry[self][obj][method]
if uid then
if actives[uid] then
-- We have an active hook from this source. Don't multi-hook
AceHook:error("%q already has an active hook from this source.", method)
end
if handlers[uid] == handler then
-- The hook is inactive, reactivate it.
actives[uid] = true
return
else
AceHook:error("There is a stale hook for %q can't hook or reactivate.", method)
end
end
if type(handler) == "string" then
if type(self[handler]) ~= "function" then
AceHook:error("Could not find the handler %q you supplied when hooking method %q", handler, method)
end
elseif type(handler) ~= "function" then
AceHook:error("Could not find the handler you supplied when hooking method %q", method)
end
local orig
if script then
if not obj.GetScript then
AceHook:error("The object you supplied does not have a GetScript method.")
end
if not obj:HasScript(method) then
AceHook:error("The object you supplied doesn't allow the %q method.", method)
end
orig = obj:GetScript(method)
if type(orig) ~= "function" then
-- Sometimes there is not a original function for a script.
orig = function() end
end
else
orig = obj[method]
end
if not orig then
AceHook:error("Could not find the method or script %q you are trying to hook.", method)
end
if not registry[self][obj] then
registry[self][obj] = new()
end
if not self.hooks[obj] then
self.hooks[obj] = new()
end
local uid = createMethodHook(self, obj, method, handler, orig, secure, script)
registry[self][obj][method] = uid
actives[uid] = true
handlers[uid] = handler
scripts[uid] = script and true or nil
if script then
obj:SetScript(method, uid)
self.hooks[obj][method] = orig
elseif not secure then
obj[method] = uid
self.hooks[obj][method] = orig
else
hooksecurefunc(obj, method, uid)
end
end
local function unhookMethod(self, obj, method)
if not registry[self][obj] or not registry[self][obj][method] then
AceHook:error("Attempt to unhook a method %q that is not currently hooked.", method)
return
end
local uid = registry[self][obj][method]
if actives[uid] then
if scripts[uid] then -- If this is a script
if obj:GetScript(method) == uid then
-- We own the script. Revert to normal.
obj:SetScript(method, self.hooks[obj][method])
self.hooks[obj][method] = nil
registry[self][obj][method] = nil
handlers[uid] = nil
scripts[uid] = nil
actives[uid] = nil
else
actives[uid] = nil
end
else
if self.hooks[obj] and self.hooks[obj][method] and obj[method] == uid then
-- We own the method. Revert to normal.
obj[method] = self.hooks[obj][method]
self.hooks[obj][method] = nil
registry[self][obj][method] = nil
handlers[uid] = nil
actives[uid] = nil
else
actives[uid] = nil
end
end
end
if self.hooks[obj] and not next(self.hooks[obj]) then
self.hooks[obj] = del(self.hooks[obj])
end
if not next(registry[self][obj]) then
registry[self][obj] = del(registry[self][obj])
end
end
-- ("function" [, handler] [, hookSecure]) or (object, "method" [, handler] [, hookSecure])
function AceHook:Hook(object, method, handler, hookSecure)
if type(object) == "string" then
method, handler, hookSecure = object, method, handler
if handler == true then
handler, hookSecure = nil, true
end
if not hookSecure and issecurevariable(method) then
AceHook:error("Attempt to hook secure function %q. Use `SecureHook' or add `true' to the argument list to override.", method)
end
AceHook:argCheck(handler, 3, "function", "string", "nil")
AceHook:argCheck(hookSecure, 4, "boolean", "nil")
hookFunction(self, method, handler, false)
else
if handler == true then
handler, hookSecure = nil, true
end
if not hookSecure and issecurevariable(object, method) then
AceHook:error("Attempt to hook secure method %q. Use `SecureHook' or add `true' to the argument list to override.", method)
end
AceHook:argCheck(object, 2, "table")
AceHook:argCheck(method, 3, "string")
AceHook:argCheck(handler, 4, "function", "string", "nil")
AceHook:argCheck(hookSecure, 5, "boolean", "nil")
hookMethod(self, object, method, handler, false, false)
end
end
-- ("function", handler) or (object, "method", handler)
function AceHook:SecureHook(object, method, handler)
if type(object) == "string" then
method, handler = object, method
AceHook:argCheck(handler, 3, "function", "string", "nil")
hookFunction(self, method, handler, true)
else
AceHook:argCheck(object, 2, "table")
AceHook:argCheck(method, 3, "string")
AceHook:argCheck(handler, 4, "function", "string", "nil")
hookMethod(self, object, method, handler, false, true)
end
end
function AceHook:HookScript(frame, script, handler)
AceHook:argCheck(frame, 2, "table")
if not frame[0] or type(frame.IsFrameType) ~= "function" then
AceHook:error("Bad argument #2 to `HookScript'. Expected frame.")
end
AceHook:argCheck(script, 3, "string")
AceHook:argCheck(handler, 4, "function", "string", "nil")
hookMethod(self, frame, script, handler, true, false)
end
-- ("function") or (object, "method")
function AceHook:IsHooked(obj, method)
if type(obj) == "string" then
if registry[self][obj] and actives[registry[self][obj]] then
return true, handlers[registry[self][obj]]
end
else
AceHook:argCheck(obj, 2, "string", "table")
AceHook:argCheck(method, 3, "string")
if registry[self][obj] and registry[self][obj][method] and actives[registry[self][obj][method]] then
return true, handlers[registry[self][obj][method]]
end
end
return false, nil
end
-- ("function") or (object, "method")
function AceHook:Unhook(obj, method)
if type(obj) == "string" then
unhookFunction(self, obj)
else
AceHook:argCheck(obj, 2, "string", "table")
AceHook:argCheck(method, 3, "string")
unhookMethod(self, obj, method)
end
end
function AceHook:UnhookAll()
for key, value in pairs(registry[self]) do
if type(key) == "table" then
for method in pairs(value) do
self:Unhook(key, method)
end
else
self:Unhook(key)
end
end
end
function AceHook:HookReport()
DEFAULT_CHAT_FRAME:AddMessage("This is a list of all active hooks for this object:")
if not next(registry[self]) then
DEFAULT_CHAT_FRAME:AddMessage("No hooks")
end
for key, value in pairs(registry[self]) do
if type(value) == "table" then
for method, uid in pairs(value) do
DEFAULT_CHAT_FRAME:AddMessage(string.format("object: %s method: %q |cff%s|r%s", tostring(key), method, actives[uid] and "00ff00Active" or "ffff00Inactive", not self.hooks[key][method] and " |cff7f7fff-Secure-|r" or ""))
end
else
DEFAULT_CHAT_FRAME:AddMessage(string.format("function: %q |cff%s|r%s", tostring(key), actives[value] and "00ff00Active" or "ffff00Inactive", not self.hooks[key] and " |cff7f7fff-Secure-|r" or ""))
end
end
end
function AceHook:OnInstanceInit(object)
if not object.hooks then
object.hooks = new()
end
if not registry[object] then
registry[object] = new()
end
end
AceHook.OnManualEmbed = AceHook.OnInstanceInit
function AceHook:OnEmbedDisable(target)
self.UnhookAll(target)
end
local function activate(self, oldLib, oldDeactivate)
AceHook = self
self.handlers = oldLib and oldLib.handlers or {}
self.registry = oldLib and oldLib.registry or {}
self.scripts = oldLib and oldLib.scripts or {}
self.actives = oldLib and oldLib.actives or {}
handlers = self.handlers
registry = self.registry
scripts = self.scripts
actives = self.actives
AceHook.super.activate(self, oldLib, oldDeactivate)
if oldDeactivate then
oldDeactivate(oldLib)
end
end
AceLibrary:Register(AceHook, MAJOR_VERSION, MINOR_VERSION, activate)
@@ -0,0 +1,757 @@
--[[
Name: AceLibrary
Revision: $Rev: 17722 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Iriel (iriel@vigilance-committee.org)
Tekkub (tekkub@gmail.com)
Revision: $Rev: 17722 $
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceLibrary
SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary
Description: Versioning library to handle other library instances, upgrading,
and proper access.
It also provides a base for libraries to work off of, providing
proper error tools. It is handy because all the errors occur in the
file that called it, not in the library file itself.
Dependencies: None
]]
local ACELIBRARY_MAJOR = "AceLibrary"
local ACELIBRARY_MINOR = "$Revision: 17722 $"
if loadstring("return function(...) return ... end") and AceLibrary and AceLibrary:HasInstance(ACELIBRARY_MAJOR) then return end -- lua51 check
local table_setn
do
local version = GetBuildInfo()
if string.find(version, "^2%.") then
-- 2.0.0
table_setn = function() end
else
table_setn = table.setn
end
end
local string_gfind = string.gmatch or string.gfind
local _G = getfenv(0)
local previous = _G[ACELIBRARY_MAJOR]
if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
local function safecall(func,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
local success, err = pcall(func,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
if not success then geterrorhandler()(err) end
end
-- @table AceLibrary
-- @brief System to handle all versioning of libraries.
local AceLibrary = {}
local AceLibrary_mt = {}
setmetatable(AceLibrary, AceLibrary_mt)
local tmp
local function error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if type(self) ~= "table" then
_G.error(string.format("Bad argument #1 to `error' (table expected, got %s)", type(self)), 2)
end
if not tmp then
tmp = {}
else
for k in pairs(tmp) do tmp[k] = nil end
table_setn(tmp, 0)
end
table.insert(tmp, a1)
table.insert(tmp, a2)
table.insert(tmp, a3)
table.insert(tmp, a4)
table.insert(tmp, a5)
table.insert(tmp, a6)
table.insert(tmp, a7)
table.insert(tmp, a8)
table.insert(tmp, a9)
table.insert(tmp, a10)
table.insert(tmp, a11)
table.insert(tmp, a12)
table.insert(tmp, a13)
table.insert(tmp, a14)
table.insert(tmp, a15)
table.insert(tmp, a16)
table.insert(tmp, a17)
table.insert(tmp, a18)
table.insert(tmp, a19)
table.insert(tmp, a20)
local stack = debugstack()
if not message then
local _,_,second = string.find(stack, "\n(.-)\n")
message = "error raised! " .. second
else
for i = 1,table.getn(tmp) do
tmp[i] = tostring(tmp[i])
end
for i = 1,10 do
table.insert(tmp, "nil")
end
message = string.format(message, unpack(tmp))
end
if getmetatable(self) and getmetatable(self).__tostring then
message = string.format("%s: %s", tostring(self), message)
elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then
message = string.format("%s: %s", self:GetLibraryVersion(), message)
elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then
message = string.format("%s: %s", self.class:GetLibraryVersion(), message)
end
local first = string.gsub(stack, "\n.*", "")
local file = string.gsub(first, ".*\\(.*).lua:%d+: .*", "%1")
file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
local i = 0
for s in string_gfind(stack, "\n([^\n]*)") do
i = i + 1
if not string.find(s, file .. "%.lua:%d+:") then
file = string.gsub(s, "^.*\\(.*).lua:%d+: .*", "%1")
file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
break
end
end
local j = 0
for s in string_gfind(stack, "\n([^\n]*)") do
j = j + 1
if j > i and not string.find(s, file .. "%.lua:%d+:") then
_G.error(message, j + 1)
return
end
end
_G.error(message, 2)
return
end
local function assert(self, condition, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if not condition then
if not message then
local stack = debugstack()
local _,_,second = string.find(stack, "\n(.-)\n")
message = "assertion failed! " .. second
end
error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
return
end
return condition
end
local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5)
if type(num) ~= "number" then
error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num))
elseif type(kind) ~= "string" then
error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind))
end
local errored = false
arg = type(arg)
if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then
local _,_,func = string.find(debugstack(), "`argCheck'.-([`<].-['>])")
if not func then
_,_,func = string.find(debugstack(), "([`<].-['>])")
end
if kind5 then
error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg)
elseif kind4 then
error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg)
elseif kind3 then
error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg)
elseif kind2 then
error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg)
else
error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg)
end
end
end
local function pcall(self, func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = _G.pcall(func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if not a1 then
error(self, string.gsub(a2, ".-%.lua:%d-: ", ""))
else
return a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
end
end
local recurse = {}
local function addToPositions(t, major)
if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then
rawset(t, recurse, true)
AceLibrary.positions[t] = major
for k,v in pairs(t) do
if type(v) == "table" and not rawget(v, recurse) then
addToPositions(v, major)
end
if type(k) == "table" and not rawget(k, recurse) then
addToPositions(k, major)
end
end
local mt = getmetatable(t)
if mt and not rawget(mt, recurse) then
addToPositions(mt, major)
end
rawset(t, recurse, nil)
end
end
local function svnRevisionToNumber(text)
if type(text) == "string" then
if string.find(text, "^%$Revision: (%d+) %$$") then
return tonumber((string.gsub(text, "^%$Revision: (%d+) %$$", "%1")))
elseif string.find(text, "^%$Rev: (%d+) %$$") then
return tonumber((string.gsub(text, "^%$Rev: (%d+) %$$", "%1")))
elseif string.find(text, "^%$LastChangedRevision: (%d+) %$$") then
return tonumber((string.gsub(text, "^%$LastChangedRevision: (%d+) %$$", "%1")))
end
elseif type(text) == "number" then
return text
end
return nil
end
local crawlReplace
do
local recurse = {}
local function func(t, to, from)
if recurse[t] then
return
end
recurse[t] = true
local mt = getmetatable(t)
setmetatable(t, nil)
rawset(t, to, rawget(t, from))
rawset(t, from, nil)
for k,v in pairs(t) do
if v == from then
t[k] = to
elseif type(v) == "table" then
if not recurse[v] then
func(v, to, from)
end
end
if type(k) == "table" then
if not recurse[k] then
func(k, to, from)
end
end
end
setmetatable(t, mt)
if mt then
if mt == from then
setmetatable(t, to)
elseif not recurse[mt] then
func(mt, to, from)
end
end
end
function crawlReplace(t, to, from)
func(t, to, from)
for k in pairs(recurse) do
recurse[k] = nil
end
end
end
-- @function destroyTable
-- @brief remove all the contents of a table
-- @param t table to destroy
local function destroyTable(t)
setmetatable(t, nil)
for k,v in pairs(t) do t[k] = nil end
table_setn(t, 0)
end
local function isFrame(frame)
return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function"
end
local new, del
do
local tables = setmetatable({}, {__mode = "k"})
function new()
local t = next(tables)
if t then
tables[t] = nil
return t
else
return {}
end
end
function del(t, depth)
if depth and depth > 0 then
for k,v in pairs(t) do
if type(v) == "table" and not isFrame(v) then
del(v, depth - 1)
end
end
end
destroyTable(t)
tables[t] = true
end
end
-- @function copyTable
-- @brief Create a shallow copy of a table and return it.
-- @param from The table to copy from
-- @return A shallow copy of the table
local function copyTable(from)
local to = new()
for k,v in pairs(from) do to[k] = v end
table_setn(to, table.getn(from))
setmetatable(to, getmetatable(from))
return to
end
-- @function deepTransfer
-- @brief Fully transfer all data, keeping proper previous table
-- backreferences stable.
-- @param to The table with which data is to be injected into
-- @param from The table whose data will be injected into the first
-- @param saveFields If available, a shallow copy of the basic data is saved
-- in here.
-- @param list The account of table references
-- @param list2 The current status on which tables have been traversed.
local deepTransfer
do
-- @function examine
-- @brief Take account of all the table references to be shared
-- between the to and from tables.
-- @param to The table with which data is to be injected into
-- @param from The table whose data will be injected into the first
-- @param list An account of the table references
local function examine(to, from, list, major)
list[from] = to
for k,v in pairs(from) do
if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then
if from[k] == to[k] then
list[from[k]] = to[k]
elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then
list[from[k]] = from[k]
elseif not list[from[k]] then
examine(to[k], from[k], list, major)
end
end
end
return list
end
function deepTransfer(to, from, saveFields, major, list, list2)
setmetatable(to, nil)
local createdList
if not list then
createdList = true
list = new()
list2 = new()
examine(to, from, list, major)
end
list2[to] = to
for k,v in pairs(to) do
if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then
if saveFields then
saveFields[k] = v
end
to[k] = nil
elseif v ~= _G then
if saveFields then
saveFields[k] = copyTable(v)
end
end
end
for k in pairs(from) do
if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then
if not list2[to[k]] then
deepTransfer(to[k], from[k], nil, major, list, list2)
end
to[k] = list[to[k]] or list2[to[k]]
else
rawset(to, k, from[k])
end
end
table_setn(to, table.getn(from))
setmetatable(to, getmetatable(from))
local mt = getmetatable(to)
if mt then
if list[mt] then
setmetatable(to, list[mt])
elseif mt.__index and list[mt.__index] then
mt.__index = list[mt.__index]
end
end
destroyTable(from)
if createdList then
del(list)
del(list2)
end
end
end
-- @method TryToLoadStandalone
-- @brief Attempt to find and load a standalone version of the requested library
-- @param major A string representing the major version
-- @return If library is found, return values from the call to LoadAddOn are returned
-- If the library has been requested previously, nil is returned.
local function TryToLoadStandalone(major)
if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end
if AceLibrary.scannedlibs[major] then return end
AceLibrary.scannedlibs[major] = true
local name, _, _, enabled, loadable = GetAddOnInfo(major)
if loadable then
return LoadAddOn(name)
end
for i=1,GetNumAddOns() do
if GetAddOnMetadata(i, "X-AceLibrary-"..major) then
local name, _, _, enabled, loadable = GetAddOnInfo(i)
if loadable then
return LoadAddOn(name)
end
end
end
end
-- @method IsNewVersion
-- @brief Obtain whether the supplied version would be an upgrade to the
-- current version. This allows for bypass code in library
-- declaration.
-- @param major A string representing the major version
-- @param minor An integer or an svn revision string representing the minor version
-- @return whether the supplied version would be newer than what is
-- currently available.
function AceLibrary:IsNewVersion(major, minor)
argCheck(self, major, 2, "string")
TryToLoadStandalone(major)
if type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(string.format("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
end
end
argCheck(self, minor, 3, "number")
local data = self.libs[major]
if not data then
return true
end
return data.minor < minor
end
-- @method HasInstance
-- @brief Returns whether an instance exists. This allows for optional support of a library.
-- @param major A string representing the major version.
-- @param minor (optional) An integer or an svn revision string representing the minor version.
-- @return Whether an instance exists.
function AceLibrary:HasInstance(major, minor)
argCheck(self, major, 2, "string")
TryToLoadStandalone(major)
if minor then
if type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(string.format("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
end
end
argCheck(self, minor, 3, "number")
if not self.libs[major] then
return
end
return self.libs[major].minor == minor
end
return self.libs[major] and true
end
-- @method GetInstance
-- @brief Returns the library with the given major/minor version.
-- @param major A string representing the major version.
-- @param minor (optional) An integer or an svn revision string representing the minor version.
-- @return The library with the given major/minor version.
function AceLibrary:GetInstance(major, minor)
argCheck(self, major, 2, "string")
TryToLoadStandalone(major)
local data = self.libs[major]
if not data then
_G.error(string.format("Cannot find a library instance of %s.", major), 2)
return
end
if minor then
if type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(string.format("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
end
end
argCheck(self, minor, 2, "number")
if data.minor ~= minor then
_G.error(string.format("Cannot find a library instance of %s, minor version %d.", major, minor), 2)
return
end
end
return data.instance
end
-- Syntax sugar. AceLibrary("FooBar-1.0")
AceLibrary_mt.__call = AceLibrary.GetInstance
local donothing
local AceEvent
-- @method Register
-- @brief Registers a new version of a given library.
-- @param newInstance the library to register
-- @param major the major version of the library
-- @param minor the minor version of the library
-- @param activateFunc (optional) A function to be called when the library is
-- fully activated. Takes the arguments
-- (newInstance [, oldInstance, oldDeactivateFunc]). If
-- oldInstance is given, you should probably call
-- oldDeactivateFunc(oldInstance).
-- @param deactivateFunc (optional) A function to be called by a newer library's
-- activateFunc.
-- @param externalFunc (optional) A function to be called whenever a new
-- library is registered.
function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc)
argCheck(self, newInstance, 2, "table")
argCheck(self, major, 3, "string")
if type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(string.format("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
end
end
argCheck(self, minor, 4, "number")
if math.floor(minor) ~= minor or minor < 0 then
error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor)
end
argCheck(self, activateFunc, 5, "function", "nil")
argCheck(self, deactivateFunc, 6, "function", "nil")
argCheck(self, externalFunc, 7, "function", "nil")
if not deactivateFunc then
if not donothing then
donothing = function() end
end
deactivateFunc = donothing
end
local data = self.libs[major]
if not data then
-- This is new
local instance = copyTable(newInstance)
crawlReplace(instance, instance, newInstance)
destroyTable(newInstance)
if AceLibrary == newInstance then
self = instance
AceLibrary = instance
end
self.libs[major] = {
instance = instance,
minor = minor,
deactivateFunc = deactivateFunc,
externalFunc = externalFunc,
}
rawset(instance, 'GetLibraryVersion', function(self)
return major, minor
end)
if not rawget(instance, 'error') then
rawset(instance, 'error', error)
end
if not rawget(instance, 'assert') then
rawset(instance, 'assert', assert)
end
if not rawget(instance, 'argCheck') then
rawset(instance, 'argCheck', argCheck)
end
if not rawget(instance, 'pcall') then
rawset(instance, 'pcall', pcall)
end
addToPositions(instance, major)
if activateFunc then
safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil
end
if externalFunc then
for k,data in pairs(self.libs) do
if k ~= major then
safecall(externalFunc, instance, k, data.instance)
end
end
end
for k,data in pairs(self.libs) do
if k ~= major and data.externalFunc then
safecall(data.externalFunc, data.instance, major, instance)
end
end
if major == "AceEvent-2.0" then
AceEvent = instance
end
if AceEvent then
AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance)
end
return instance
end
local instance = data.instance
if minor <= data.minor then
-- This one is already obsolete, raise an error.
_G.error(string.format("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end", major, data.minor, minor, major, minor), 2)
return
end
-- This is an update
local oldInstance = new()
addToPositions(newInstance, major)
local isAceLibrary = (AceLibrary == newInstance)
local old_error, old_assert, old_argCheck, old_pcall
if isAceLibrary then
self = instance
AceLibrary = instance
old_error = instance.error
old_assert = instance.assert
old_argCheck = instance.argCheck
old_pcall = instance.pcall
self.error = error
self.assert = assert
self.argCheck = argCheck
self.pcall = pcall
end
deepTransfer(instance, newInstance, oldInstance, major)
crawlReplace(instance, instance, newInstance)
local oldDeactivateFunc = data.deactivateFunc
data.minor = minor
data.deactivateFunc = deactivateFunc
data.externalFunc = externalFunc
rawset(instance, 'GetLibraryVersion', function(self)
return major, minor
end)
if not rawget(instance, 'error') then
rawset(instance, 'error', error)
end
if not rawget(instance, 'assert') then
rawset(instance, 'assert', assert)
end
if not rawget(instance, 'argCheck') then
rawset(instance, 'argCheck', argCheck)
end
if not rawget(instance, 'pcall') then
rawset(instance, 'pcall', pcall)
end
if isAceLibrary then
for _,v in pairs(self.libs) do
local i = type(v) == "table" and v.instance
if type(i) == "table" then
if not rawget(i, 'error') or i.error == old_error then
rawset(i, 'error', error)
end
if not rawget(i, 'assert') or i.assert == old_assert then
rawset(i, 'assert', assert)
end
if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then
rawset(i, 'argCheck', argCheck)
end
if not rawget(i, 'pcall') or i.pcall == old_pcall then
rawset(i, 'pcall', pcall)
end
end
end
end
if activateFunc then
safecall(activateFunc, instance, oldInstance, oldDeactivateFunc)
else
safecall(oldDeactivateFunc, oldInstance)
end
del(oldInstance)
if externalFunc then
for k,data in pairs(self.libs) do
if k ~= major then
safecall(externalFunc, instance, k, data.instance)
end
end
end
return instance
end
local iter
function AceLibrary:IterateLibraries()
if not iter then
local function iter(t, k)
k = next(t, k)
if not k then
return nil
else
return k, t[k].instance
end
end
end
return iter, self.libs, nil
end
-- @function Activate
-- @brief The activateFunc for AceLibrary itself. Called when
-- AceLibrary properly registers.
-- @param self Reference to AceLibrary
-- @param oldLib (optional) Reference to an old version of AceLibrary
-- @param oldDeactivate (optional) Function to deactivate the old lib
local function activate(self, oldLib, oldDeactivate)
if not self.libs then
if oldLib then
self.libs = oldLib.libs
self.scannedlibs = oldLib.scannedlibs
end
if not self.libs then
self.libs = {}
end
if not self.scannedlibs then
self.scannedlibs = {}
end
end
if not self.positions then
if oldLib then
self.positions = oldLib.positions
end
if not self.positions then
self.positions = setmetatable({}, { __mode = "k" })
end
end
-- Expose the library in the global environment
_G[ACELIBRARY_MAJOR] = self
if oldDeactivate then
oldDeactivate(oldLib)
end
end
if not previous then
previous = AceLibrary
end
if not previous.libs then
previous.libs = {}
end
AceLibrary.libs = previous.libs
if not previous.positions then
previous.positions = setmetatable({}, { __mode = "k" })
end
AceLibrary.positions = previous.positions
AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,32 @@
-- Add a function to fix some global strings.
if GetLocale() == "koKR" then
function FixGlobalString(pName, str)
-- wrong global strings
-- "%1$s|1이;가; %3$s에게 %2$s|1을;를; 사용했습니다." <- "%s|1이;가; %3$s에게 %2$s|1을;를; 사용했습니다."
if (pName == "OPEN_LOCK_OTHER")
or (pName == "SIMPLEPERFORMOTHEROTHER")
or (pName == "SPELLPERFORMGOOTHERTARGETTED")
or (pName == "PERIODICAURADAMAGEOTHEROTHER")
or (pName == "PERIODICAURADAMAGESELFOTHER")
or (pName == "SIMPLECASTOTHEROTHER")
or (pName == "SIMPLECASTOTHERSELF")
or (pName == "SIMPLEPERFORMOTHERSELF")
or (pName == "SPELLDURABILITYDAMAGEALLOTHERSELF")
or (pName == "SPELLDURABILITYDAMAGEOTHERSELF")
or (pName == "SPELLMISSOTHEROTHER") then
str = string.gsub(str, "%%s", "%%1%$s"); -- by creep7
elseif (pName == "COMBATLOG_HONORGAIN") then
str = "%1$s|1이;가; 죽었습니다. 계급: %2$s (예상 명예 점수: %3$d)"; -- by creep7
end
--problematic strings
-- %s의
return string.gsub(str, "(%%%d?$?s)(의)", "%1% %2") -- by mundi4
end
else
function FixGlobalString(pName, str)
--problematic strings
-- %s's
return str
end
end
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,215 @@
if GetLocale() == "enUS" then
if not ParserLibOptimizer then
ParserLibOptimizer = {
AURAADDEDOTHERHARMFUL = "afflict",
AURAADDEDOTHERHELPFUL = "gain",
AURAADDEDSELFHARMFUL = "afflict",
AURAADDEDSELFHELPFUL = "gain",
AURAAPPLICATIONADDEDOTHERHARMFUL = "afflict",
AURAAPPLICATIONADDEDOTHERHELPFUL = "gain",
AURAAPPLICATIONADDEDSELFHARMFUL = "afflict",
AURAAPPLICATIONADDEDSELFHELPFUL = "gain",
AURADISPELOTHER = "remove",
AURADISPELSELF = "remove",
AURAREMOVEDOTHER = "fade",
AURAREMOVEDSELF = "fade",
COMBATHITCRITOTHEROTHER = "crit",
COMBATHITCRITOTHERSELF = "crit",
COMBATHITCRITSELFOTHER = "crit",
COMBATHITCRITSELFSELF = "crit",
COMBATHITCRITSCHOOLOTHEROTHER = "crit",
COMBATHITCRITSCHOOLOTHERSELF = "crit",
COMBATHITCRITSCHOOLSELFOTHER = "crit",
COMBATHITCRITSCHOOLSELFSELF = "crit",
COMBATHITOTHEROTHER = "hit",
COMBATHITOTHERSELF = "hit",
COMBATHITSELFOTHER = "hit",
COMBATHITSELFSELF = "hit",
COMBATHITSCHOOLOTHEROTHER = "hit",
COMBATHITSCHOOLOTHERSELF = "hit",
COMBATHITSCHOOLSELFOTHER = "hit",
COMBATHITSCHOOLSELFSELF = "hit",
DAMAGESHIELDOTHEROTHER = "reflect",
DAMAGESHIELDOTHERSELF = "reflect",
DAMAGESHIELDSELFOTHER = "reflect",
DISPELFAILEDOTHEROTHER = "fail",
DISPELFAILEDOTHERSELF = "fail",
DISPELFAILEDSELFOTHER = "fail",
DISPELFAILEDSELFSELF = "fail",
HEALEDCRITOTHEROTHER = "crit",
HEALEDCRITOTHERSELF = "crit",
HEALEDCRITSELFOTHER = "crit",
HEALEDCRITSELFSELF = "crit",
HEALEDOTHEROTHER = "heal",
HEALEDOTHERSELF = "heal",
HEALEDSELFOTHER = "heal",
HEALEDSELFSELF = "heal",
IMMUNESPELLOTHEROTHER = "immune",
IMMUNESPELLSELFOTHER = "immune",
IMMUNESPELLOTHERSELF = "immune",
IMMUNESPELLSELFSELF = "immune",
ITEMENCHANTMENTADDOTHEROTHER = "cast",
ITEMENCHANTMENTADDOTHERSELF = "cast",
ITEMENCHANTMENTADDSELFOTHER = "cast",
ITEMENCHANTMENTADDSELFSELF = "cast",
MISSEDOTHEROTHER = "miss",
MISSEDOTHERSELF = "miss",
MISSEDSELFOTHER = "miss",
MISSEDSELFSELF = "miss",
OPEN_LOCK_OTHER = "perform",
OPEN_LOCK_SELF = "perform",
PARTYKILLOTHER = "slain",
PERIODICAURADAMAGEOTHEROTHER = "suffer",
PERIODICAURADAMAGEOTHERSELF = "suffer",
PERIODICAURADAMAGESELFOTHER = "suffer",
PERIODICAURADAMAGESELFSELF = "suffer",
PERIODICAURAHEALOTHEROTHER = "gain",
PERIODICAURAHEALOTHERSELF = "gain",
PERIODICAURAHEALSELFOTHER = "gain",
PERIODICAURAHEALSELFSELF = "gain",
POWERGAINOTHEROTHER = "gain",
POWERGAINOTHERSELF = "gain",
POWERGAINSELFSELF = "gain",
POWERGAINSELFOTHER = "gain",
PROCRESISTOTHEROTHER = "resist",
PROCRESISTOTHERSELF = "resist",
PROCRESISTSELFOTHER = "resist",
PROCRESISTSELFSELF = "resist",
SIMPLECASTOTHEROTHER = "cast",
SIMPLECASTOTHERSELF = "cast",
SIMPLECASTSELFOTHER = "cast",
SIMPLECASTSELFSELF = "cast",
SIMPLEPERFORMOTHEROTHER = "perform",
SIMPLEPERFORMOTHERSELF = "perform",
SIMPLEPERFORMSELFOTHER = "perform",
SIMPLEPERFORMSELFSELF = "perform",
SPELLBLOCKEDOTHEROTHER = "block",
SPELLBLOCKEDOTHERSELF = "block",
SPELLBLOCKEDSELFOTHER = "block",
SPELLBLOCKEDSELFSELF = "block",
SPELLCASTOTHERSTART = "begin",
SPELLCASTSELFSTART = "begin",
SPELLDEFLECTEDOTHEROTHER = "deflect",
SPELLDEFLECTEDOTHERSELF = "deflect",
SPELLDEFLECTEDSELFOTHER = "deflect",
SPELLDEFLECTEDSELFSELF = "deflect",
SPELLDODGEDOTHEROTHER = "dodge",
SPELLDODGEDOTHERSELF = "dodge",
SPELLDODGEDSELFOTHER = "dodge",
SPELLEVADEDOTHEROTHER = "evade",
SPELLEVADEDOTHERSELF = "evade",
SPELLEVADEDSELFOTHER = "evade",
SPELLEVADEDSELFSELF = "evade",
SPELLEXTRAATTACKSOTHER = "extra",
SPELLEXTRAATTACKSOTHER_SINGULAR = "extra",
SPELLEXTRAATTACKSSELF = "extra",
SPELLEXTRAATTACKSSELF_SINGULAR = "extra",
SPELLFAILCASTSELF = "fail",
SPELLFAILPERFORMSELF = "fail",
SPELLIMMUNEOTHEROTHER = "immune",
SPELLIMMUNEOTHERSELF = "immune",
SPELLIMMUNESELFOTHER = "immune",
SPELLIMMUNESELFSELF = "immune",
SPELLINTERRUPTOTHEROTHER = "interrupt",
SPELLINTERRUPTOTHERSELF = "interrupt",
SPELLINTERRUPTSELFOTHER = "interrupt",
SPELLLOGABSORBOTHEROTHER = "absorb",
SPELLLOGABSORBOTHERSELF = "absorb",
SPELLLOGABSORBSELFOTHER = "absorb",
SPELLLOGABSORBSELFSELF = "absorb",
SPELLLOGCRITOTHEROTHER = "crit",
SPELLLOGCRITOTHERSELF = "crit",
SPELLLOGCRITSCHOOLOTHEROTHER = "crit",
SPELLLOGCRITSCHOOLOTHERSELF = "crit",
SPELLLOGCRITSCHOOLSELFOTHER = "crit",
SPELLLOGCRITSCHOOLSELFSELF = "crit",
SPELLLOGCRITSELFOTHER = "crit",
SPELLLOGOTHEROTHER = "hit",
SPELLLOGOTHERSELF = "hit",
SPELLLOGOTHERSELF = "hit",
SPELLLOGSCHOOLOTHEROTHER = "hit",
SPELLLOGSCHOOLOTHERSELF = "hit",
SPELLLOGSCHOOLSELFOTHER = "hit",
SPELLLOGSCHOOLSELFSELF = "hit",
SPELLLOGSELFOTHER = "hit",
SPELLMISSOTHEROTHER = "miss",
SPELLMISSOTHERSELF = "miss",
SPELLMISSSELFOTHER = "miss",
SPELLPARRIEDOTHEROTHER = "parr",
SPELLPARRIEDOTHERSELF = "parr",
SPELLPARRIEDSELFOTHER = "parr",
SPELLPERFORMOTHERSTART = "begin",
SPELLPERFORMSELFSTART = "begin",
SPELLPOWERDRAINOTHEROTHER = "drain",
SPELLPOWERDRAINOTHERSELF = "drain",
SPELLPOWERDRAINSELFOTHER = "drain",
SPELLPOWERLEECHOTHEROTHER = "drain",
SPELLPOWERLEECHOTHERSELF = "drain",
SPELLPOWERLEECHSELFOTHER = "drain",
SPELLREFLECTOTHEROTHER = "reflect",
SPELLREFLECTOTHERSELF = "reflect",
SPELLREFLECTSELFOTHER = "reflect",
SPELLREFLECTSELFSELF = "reflect",
SPELLRESISTOTHEROTHER = "resist",
SPELLRESISTOTHERSELF = "resist",
SPELLRESISTSELFOTHER = "resist",
SPELLRESISTSELFSELF = "resist",
SPELLSPLITDAMAGESELFOTHER = "cause",
SPELLSPLITDAMAGEOTHEROTHER = "cause",
SPELLSPLITDAMAGEOTHERSELF = "cause",
SPELLTERSEPERFORM_OTHER = "perform",
SPELLTERSEPERFORM_SELF = "perform",
SPELLTERSE_OTHER = "cast",
SPELLTERSE_SELF = "cast",
VSABSORBOTHEROTHER = "absorb",
VSABSORBOTHERSELF = "absorb",
VSABSORBSELFOTHER = "absorb",
VSBLOCKOTHEROTHER = "block",
VSBLOCKOTHERSELF = "block",
VSBLOCKSELFOTHER = "block",
VSBLOCKSELFSELF = "block",
VSDEFLECTOTHEROTHER = "deflect",
VSDEFLECTOTHERSELF = "deflect",
VSDEFLECTSELFOTHER = "deflect",
VSDEFLECTSELFSELF = "deflect",
VSDODGEOTHEROTHER = "dodge",
VSDODGEOTHERSELF = "dodge",
VSDODGESELFOTHER = "dodge",
VSDODGESELFSELF = "dodge",
VSENVIRONMENTALDAMAGE_FALLING_OTHER = "fall",
VSENVIRONMENTALDAMAGE_FALLING_SELF = "fall",
VSENVIRONMENTALDAMAGE_FIRE_OTHER = "fire",
VSENVIRONMENTALDAMAGE_FIRE_SELF = "fire",
VSENVIRONMENTALDAMAGE_LAVA_OTHER = "lava",
VSENVIRONMENTALDAMAGE_LAVA_SELF = "lava",
VSEVADEOTHEROTHER = "evade",
VSEVADEOTHERSELF = "evade",
VSEVADESELFOTHER = "evade",
VSEVADESELFSELF = "evade",
VSIMMUNEOTHEROTHER = "immune",
VSIMMUNEOTHERSELF = "immune",
VSIMMUNESELFOTHER = "immune",
VSPARRYOTHEROTHER = "parr",
VSPARRYOTHERSELF = "parr",
VSPARRYSELFOTHER = "parr",
VSRESISTOTHEROTHER = "resist",
VSRESISTOTHERSELF = "resist",
VSRESISTSELFOTHER = "resist",
VSRESISTSELFSELF = "resist",
VSENVIRONMENTALDAMAGE_FATIGUE_OTHER = "exhaust",
VSENVIRONMENTALDAMAGE_FIRE_OTHER = "fire",
VSENVIRONMENTALDAMAGE_SLIME_OTHER = "slime",
VSENVIRONMENTALDAMAGE_SLIME_SELF = "slime",
VSENVIRONMENTALDAMAGE_DROWNING_OTHER = "drown",
UNITDIESSELF = "die",
UNITDIESOTHER = "die",
UNITDESTROYEDOTHER = "destroy",
}
end
end
@@ -0,0 +1 @@
The newest documentation can be found at http://www.wowace.com/index.php/ParserLib
+17
View File
@@ -0,0 +1,17 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Include file="libs\AceLibrary\AceLibrary.lua"/>
<Include file="libs\AceOO-2.0\AceOO-2.0.lua"/>
<Include file="libs\AceEvent-2.0\AceEvent-2.0.lua"/>
<Include file="libs\AceHook-2.1\AceHook-2.1.lua"/>
<Include file="libs\AceAddon-2.0\AceAddon-2.0.lua"/>
<Include file="libs\CandyBar-2.0\CandyBar-2.0.lua"/>
<Include file="libs\ParserLib\FixGlobalString.lua"/>
<Include file="libs\ParserLib\ParserLib.lua"/>
<Include file="libs\ParserLib\optimizer-enUS.lua"/>
<Include file="engine.lua"/>
<Include file="data-hunter.lua"/>
<Include file="module.lua"/>
</Ui>
+45
View File
@@ -0,0 +1,45 @@
local MTH_ChronometerModule = {
name = "chronometer",
enabled = true,
version = "1.0.3",
events = {},
initialized = false,
}
local function MTH_CHRON_ApplyRuntimeEnabledState(enabled)
if not MTH_ChronometerHunter then
return
end
if enabled then
if MTH_ChronometerHunter.MTH_Enable then
MTH_ChronometerHunter:MTH_Enable()
end
else
if MTH_ChronometerHunter.MTH_Disable then
MTH_ChronometerHunter:MTH_Disable()
end
end
end
function MTH_ChronometerModule:init()
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
end
function MTH_ChronometerModule:setEnabled(enabled)
if not self.initialized then
self:init()
end
MTH_CHRON_ApplyRuntimeEnabledState(enabled and true or false)
end
function MTH_ChronometerModule:cleanup()
if MTH_ChronometerHunter and MTH_ChronometerHunter.MTH_Disable then
MTH_ChronometerHunter:MTH_Disable()
end
end
MTH:RegisterModule("chronometer", MTH_ChronometerModule)
+5
View File
@@ -0,0 +1,5 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Binding name="FEEDOMATIC" header="FEEDOMATIC">
FOM_Feed();
</Binding>
</Ui>
File diff suppressed because it is too large Load Diff
+86
View File
@@ -0,0 +1,86 @@
FOM_Emotes = {
["any"] = {
"Yum!",
"Mmm, good stuff.",
},
["male"] = {
"Good boy!",
},
["female"] = {
"Good girl!",
},
["Zesty Clam Meat"] = {
"Mmm, zesty!",
},
["Heaven Peach"] = {
"Movin' to the country...",
},
["Mystery Meat"] = {
"Tastes like chicken.",
},
["Dragonbreath Chili"] = {
"Yow, spicy!",
},
["Bat"] = {
"Squeak-squeak snack attack!",
},
["Bear"] = {
"One paw for me, one paw for the bear.",
},
["Boar"] = {
"Good piggy!"
},
["Carrion Bird"] = {
"A gourmet meal... by scavenger standards.",
},
["Cat"] = {
"Nice kitty!",
},
["Crab"] = {
"Crabby no more!",
},
["Crocolisk"] = {
"Easy there, chompy friend.",
},
["Gorilla"] = {
"Big buddy deserves a big bite.",
},
["Hyena"] = {
"Good dog!",
},
["Owl"] = {
"Whoo's a hungry hunter helper?",
},
["Raptor"] = {
"Tiny arms, huge appetite.",
},
["Scorpid"] = {
"No stinging the cook, deal?",
},
["Spider"] = {
"Eight legs, zero table manners.",
},
["Tallstrider"] = {
"Long neck, longer lunch break.",
},
["Turtle"] = {
"Slow and steady wins the snacks.",
},
["Wind Serpent"] = {
"Lightning in the sky, snacks on the ground.",
},
["Wolf"] = {
"Good dog!",
},
["Foxes"] = {
"Clever fox, clever snack choice.",
},
["Serpents (Cobra)"] = {
"No hissing with your mouth full.",
},
};
+238
View File
@@ -0,0 +1,238 @@
FOM_Foods = {
[FOM_DIET_FUNGUS] = {
4607, -- Delicious Cave Mold
8948, -- Dried King Bolete
4604, -- Forest Mushroom Cap
4608, -- Raw Black Truffle
4605, -- Red-speckled Mushroom
3448, -- Senggin Root
4606, -- Spongy Morel
},
[FOM_DIET_FISH] = {
13889, -- Raw Whitescale Salmon
19996, -- Harvest Fish
13933, -- Lobster Stew
13888, -- Darkclaw Lobster
13935, -- Baked Salmon
13546, -- Bloodbelly Fish
6290, -- Brilliant Smallfish
4593, -- Bristle Whisker Catfish
5503, -- Clam Meat
16971, -- Clamlette Surprise
2682, -- Cooked Crab Claw
13927, -- Cooked Glossy Mightfish
2675, -- Crawler Claw
13930, -- Filet of Redgill
5476, -- Fillet of Frenzy
4655, -- Giant Clam Meat
6038, -- Giant Clam Scorcho
13928, -- Grilled Squid
13929, -- Hot Smoked Bass
13893, -- Large Raw Mightfish
4592, -- Longjaw Mud Snapper
8364, -- Mithril Head Trout
13932, -- Poached Sunscale Salmon
5095, -- Rainbow Fin Albacore
6291, -- Raw Brilliant Smallfish
6308, -- Raw Bristle Whisker Catfish
13754, -- Raw Glossy Mightfish
6317, -- Raw Loch Frenzy
6289, -- Raw Longjaw Mud Snapper
8365, -- Raw Mithril Head Trout
6361, -- Raw Rainbow Fin Albacore
13758, -- Raw Redgill
6362, -- Raw Rockscale Cod
6303, -- Raw Slitherskin Mackerel
8959, -- Raw Spinefin Halibut
4603, -- Raw Spotted Yellowtail
13756, -- Raw Summer Bass
13760, -- Raw Sunscale Salmon
4594, -- Rockscale Cod
787, -- Slitherskin Mackerel
5468, -- Soft Frenzy Flesh
15924, -- Soft-shelled Clam Meat
12216, -- Spiced Chili Crab
8957, -- Spinefin Halibut
6887, -- Spotted Yellowtail
5504, -- Tangy Clam Meat
12206, -- Tender Crab Meat
13755, -- Winter Squid
7974, -- Zesty Clam Meat
},
[FOM_DIET_MEAT] = {
21235, -- Winter Veil Roast
19995, -- Harvest Boar
4457, -- Barbecued Buzzard Wing
3173, -- Bear Meat
2888, -- Beer Basted Boar Ribs
3730, -- Big Bear Meat
3726, -- Big Bear Steak
3220, -- Blood Sausage
2677, -- Boar Ribs
3404, -- Buzzard Wing
12213, -- Carrion Surprise
2679, -- Charred Wolf Meat
769, -- Chunk of Boar Meat
2673, -- Coyote Meat
2684, -- Coyote Steak
1081, -- Crisp Spider Meat
12224, -- Crispy Bat Wing
5479, -- Crispy Lizard Tail
2924, -- Crocolisk Meat
3662, -- Crocolisk Steak
4599, -- Cured Ham Steak
17119, -- Deeprun Rat Kabob
5478, -- Dig Rat Stew
5051, -- Dig Rat
12217, -- Dragonbreath Chili
2687, -- Dry Pork Ribs
9681, -- Grilled King Crawler Legs
2287, -- Haunch of Meat
12204, -- Heavy Kodo Meat
3727, -- Hot Lion Chops
13851, -- Hot Wolf Ribs
12212, -- Jungle Stew
5472, -- Kaldorei Spider Kabob
5467, -- Kodo Meat
5480, -- Lean Venison
1015, -- Lean Wolf Flank
12209, -- Lean Wolf Steak
3731, -- Lion Meat
12223, -- Meaty Bat Wing
3770, -- Mutton Chop
12037, -- Mystery Meat
4739, -- Plainstrider Meat
12184, -- Raptor Flesh
13759, -- Raw Nightfin Snapper
12203, -- Red Wolf Meat
12210, -- Roast Raptor
2681, -- Roasted Boar Meat
5474, -- Roasted Kodo Meat
8952, -- Roasted Quail
1017, -- Seasoned Wolf Kabob
5465, -- Small Spider Leg
6890, -- Smoked Bear Meat
3729, -- Soothing Turtle Bisque
2680, -- Spiced Wolf Meat
17222, -- Spider Sausage
5471, -- Stag Meat
5469, -- Strider Meat
5477, -- Strider Stew
2672, -- Stringy Wolf Meat
2685, -- Succulent Pork Ribs
3728, -- Tasty Lion Steak
3667, -- Tender Crocolisk Meat
12208, -- Tender Wolf Meat
18045, -- Tender Wolf Steak
5470, -- Thunder Lizard Tail
12202, -- Tiger Meat
117, -- Tough Jerky
3712, -- Turtle Meat
12205, -- White Spider Meat
3771, -- Wild Hog Shank
},
[FOM_DIET_BREAD] = {
1113, -- Conjured Bread
5349, -- Conjured Muffin
1487, -- Conjured Pumpernickel
1114, -- Conjured Rye
8075, -- Conjured Sourdough
8076, -- Conjured Sweet Roll
22895, -- Conjured Cinnamon Roll
83004, -- Conjured Mana Orange
19696, -- Harvest Bread
21254, -- Winter Veil Cookie
2683, -- Crab Cake
4541, -- Freshly Baked Bread
17197, -- Gingerbread Cookie
3666, -- Gooey Spider Cake
8950, -- Homemade Cherry Pie
4542, -- Moist Cornbread
4544, -- Mulgore Spice Bread
4601, -- Soft Banana Bread
4540, -- Tough Hunk of Bread
16169, -- Wild Ricecake
},
[FOM_DIET_CHEESE] = {
8932, -- Alterac Swiss
414, -- Dalaran Sharp
2070, -- Darnassian Bleu
422, -- Dwarven Mild
3927, -- Fine Aged Cheddar
1707, -- Stormwind Brie
},
[FOM_DIET_FRUIT] = {
19994, -- Harvest Fruit
8953, -- Deep Fried Plantains
4539, -- Goldenbark Apple
16168, -- Heaven Peach
4602, -- Moon Harvest Pumpkin
4536, -- Shiny Red Apple
4538, -- Snapvine Watermelon
4537, -- Tel'Abim Banana
11950, -- Windblossom Berries
},
[FOM_DIET_BONUS] = {
-- eat for 10 sec to get "well fed" sta/spi bonus
2888, -- Beer Basted Boar Ribs
11584, -- Cactus Apple Surprise
7807, -- Candy Bar
7808, -- Chocolate Square
12224, -- Crispy Bat Wing
17197, -- Gingerbread Cookie
6888, -- Herb Baked Egg
5472, -- Kaldorei Spider Kabob
7806, -- Lollipop
5474, -- Roasted Kodo Meat
2680, -- Spiced Wolf Meat
3220, -- Blood Sausage
5525, -- Boiled Clams
2684, -- Coyote Steak
2683, -- Crab Cake
3662, -- Crocolisk Steak
2687, -- Dry Pork Ribs
5476, -- Fillet of Frenzy
724, -- Goretusk Liver Pie
5477, -- Strider Stew
3726, -- Big Bear Steak
5479, -- Crispy Lizard Tail
3664, -- Crocolisk Gumbo
3665, -- Curiously Tasty Omelet
5527, -- Goblin Deviled Clams
3666, -- Gooey Spider Cake
3727, -- Hot Lion Chops
5480, -- Lean Venison
12209, -- Lean Wolf Steak
3663, -- Murloc Fin Soup
1082, -- Redridge Goulash
1017, -- Seasoned Wolf Kabob
4457, -- Barbecued Buzzard Wing
12213, -- Carrion Surprise
6038, -- Giant Clam Scorcho
13851, -- Hot Wolf Ribs
12212, -- Jungle Stew
12214, -- Mystery Stew
12210, -- Roast Raptor
3729, -- Soothing Turtle Bisque
3728, -- Tasty Lion Steak
16971, -- Clamlette Surprise
12215, -- Heavy Kodo Stew
12218, -- Monster Omelet
12216, -- Spiced Chili Crab
17222, -- Spider Sausage
18045, -- Tender Wolf Steak
-- restores both health and mana
2682, -- Cooked Crab Claw
3448, -- Senggin Root
-- bonus effect with no 10 sec requirement
12217, -- Dragonbreath Chili
13927, -- Cooked Glossy Mightfish
13928, -- Grilled Squid
13929, -- Hot Smoked Bass
13932, -- Poached Sunscale Salmon
13931, -- Nightfin Soup
13934, -- Mightfish Steak
11950, -- Windblossom Berries
18254, -- Runn Tum Tuber Surprise
},
};
+174
View File
@@ -0,0 +1,174 @@
------------------------------------------------------
-- GFWTable.lua
-- Utilities for manipulating tables
------------------------------------------------------
GFWTABLE_THIS_VERSION = 6;
------------------------------------------------------
-- Mean: returns the mean value of a table of numbers
function GFWTable_temp_Mean(aTable)
if (aTable == nil or table.getn(aTable) == 0) then
return nil;
end
return GFWTable.Sum(aTable) / table.getn(aTable);
end
-- Sum: returns the sum of a table of numbers
function GFWTable_temp_Sum(aTable)
if (aTable == nil or table.getn(aTable) == 0) then
return nil;
end
local sum = 0;
for i=1, table.getn(aTable) do
if (tonumber(aTable[i])) then
sum = sum + aTable[i];
end
end
return sum;
end
-- Median: returns the median value (most useful in a table of numbers, but usable in any sorted table)
function GFWTable_temp_Median(aTable)
if (aTable == nil or table.getn(aTable) == 0) then
return nil;
end
if (table.getn(aTable) == 1) then
return aTable[1];
end
local sortedTable = GFWTable.Copy(aTable); -- leave the original table in whatever order it's in
table.sort(sortedTable);
local count = table.getn(sortedTable);
local median;
if (math.mod(count, 2) == 0) then -- even table size
local middleIndex1 = count / 2;
local middleIndex2 = middleIndex1 + 1;
median = (sortedTable[middleIndex1] + sortedTable[middleIndex2]) / 2; --average the two middle values
else -- the table size is odd
local trueMiddleIndex = (count + 1) / 2; -- calculate the middle index
median = sortedTable[trueMiddleIndex];
end
return median;
end
-- Merge: returns the union of two tables (without repeated elements)
function GFWTable_temp_Merge(table1, table2)
local newTable = { };
if (table1) then
for i=1, table.getn(table1) do
table.insert(newTable, table1[i]);
end
end
if (table2) then
for i=1, table.getn(table2) do
if (GFWTable.IndexOf(newTable, table2[i]) == 0) then
table.insert(newTable, table2[i]);
end
end
end
return newTable;
end
-- Diff: returns the difference of two tables (those elements which occur in either but not both)
function GFWTable_temp_Diff(table1, table2)
local newTable = { };
if (table1 == nil) then
table1 = {};
end
if (table2 == nil) then
table2 = {};
end
for i=1, table.getn(table1) do
if (GFWTable.IndexOf(table2, table1[i]) == 0) then
table.insert(newTable, table1[i]);
end
end
for i=1, table.getn(table2) do
if (GFWTable.IndexOf(table1, table2[i]) == 0) then
table.insert(newTable, table2[i]);
end
end
return newTable;
end
-- Subtract: returns a table containing those items in table1 not present in table2
function GFWTable_temp_Subtract(table1, table2)
local newTable = { };
if (table1 == nil or table.getn(table1) == 0) then return newTable; end
if (table2 == nil or table.getn(table2) == 0) then return table1; end
for i=1, table.getn(table1) do
if (GFWTable.IndexOf(table2, table1[i]) == 0) then
table.insert(newTable, table1[i]);
end
end
return newTable;
end
-- IndexOf: returns the index (1-based) of an item in a table
function GFWTable_temp_IndexOf(aTable, item)
return GFWTable.KeyOf(aTable, item) or 0;
end
-- KeyOf: returns the key to an item in a table with numeric or non-numeric keys, or nil if not found
function GFWTable_temp_KeyOf(aTable, item)
if (aTable == nil or type(aTable) ~= "table") then
return nil; -- caller probably won't expect this, causing traceable error in their code
end
for key, value in pairs(aTable) do
if (item == value) then
return key;
end
end
return nil;
end
-- Copy: copies one table's elements into a new table (useful if you want to change them while preserving the first table).
-- Not a deep copy.
function GFWTable_temp_Copy(aTable)
local newTable = { };
for i=1, table.getn(aTable) do
newTable[i] = aTable[i];
end
return newTable;
end
-- Count: returns number of items in a table regardless of whether it has numeric indices.
function GFWTable_temp_Count(aTable)
if (aTable == nil or type(aTable) ~= "table") then
return nil; -- caller probably won't expect this, causing traceable error in their code
end
local count = 0;
for key, value in pairs(aTable) do
count = count + 1;
end
return count;
end
------------------------------------------------------
-- load only if not already loaded
------------------------------------------------------
if (GFWTable == nil) then
GFWTable = {};
end
local G = GFWTable;
if (G.Version == nil or (tonumber(G.Version) ~= nil and G.Version < GFWTABLE_THIS_VERSION)) then
-- Functions
G.Mean = GFWTable_temp_Mean;
G.Sum = GFWTable_temp_Sum;
G.Median = GFWTable_temp_Median;
G.Merge = GFWTable_temp_Merge;
G.Diff = GFWTable_temp_Diff;
G.Subtract = GFWTable_temp_Subtract;
G.IndexOf = GFWTable_temp_IndexOf;
G.KeyOf = GFWTable_temp_KeyOf;
G.Copy = GFWTable_temp_Copy;
G.Count = GFWTable_temp_Count;
-- Set version number
G.Version = GFWTABLE_THIS_VERSION;
end
+202
View File
@@ -0,0 +1,202 @@
------------------------------------------------------
-- GFWUtils.lua
-- Useful utility / debug functions
------------------------------------------------------
GFWUTILS_THIS_VERSION = 8;
------------------------------------------------------
-- Shortcuts for common text color codes
function GFWUtils_temp_HiliteText(text)
if (text == nil) then return nil; end
return HIGHLIGHT_FONT_COLOR_CODE..text..FONT_COLOR_CODE_CLOSE;
end
function GFWUtils_temp_RedText(text)
if (text == nil) then return nil; end
return RED_FONT_COLOR_CODE..text..FONT_COLOR_CODE_CLOSE;
end
function GFWUtils_temp_GrayText(text)
if (text == nil) then return nil; end
return GRAY_FONT_COLOR_CODE..text..FONT_COLOR_CODE_CLOSE;
end
function GFWUtils_temp_LightYellowText(text)
if (text == nil) then return nil; end
return LIGHTYELLOW_FONT_COLOR_CODE..text..FONT_COLOR_CODE_CLOSE;
end
-- Prints a message to the chat frame
function GFWUtils_temp_Print(message, r, g, b)
if MTH and MTH.Print then
MTH:Print(message)
else
DEFAULT_CHAT_FRAME:AddMessage(message, (r or GFW_FONT_COLOR.r), (g or GFW_FONT_COLOR.g), (b or GFW_FONT_COLOR.b));
end
end
-- Prints a message to the chat frame once per interval (seconds) or once per session if interval is nil
function GFWUtils_temp_PrintOnce(message, interval, r, g, b)
if (GFWUtils.PrintOnceCache == nil) then
GFWUtils.PrintOnceCache = {};
end
if (interval == nil and GFWUtils.PrintOnceCache[message]) then
return;
end
if (interval and GFWUtils.PrintOnceCache[message] and GetTime() - GFWUtils.PrintOnceCache[message] < interval) then
return;
end
if MTH and MTH.Print then
MTH:Print(message)
else
DEFAULT_CHAT_FRAME:AddMessage(message, (r or GFW_FONT_COLOR.r), (g or GFW_FONT_COLOR.g), (b or GFW_FONT_COLOR.b));
end
GFWUtils.PrintOnceCache[message] = GetTime();
end
-- Prints a message to the chat frame only if Debug is set
function GFWUtils_temp_DebugLog(message)
if (GFWUtils.Debug) then
if MTH and MTH.Print then
MTH:Print(message, "debug")
else
DEFAULT_CHAT_FRAME:AddMessage(message, GFW_DEBUG_COLOR.r, GFW_DEBUG_COLOR.g, GFW_DEBUG_COLOR.b);
end
end
end
-- Prints a message in yellow to the floating messages frame
function GFWUtils_temp_Note(message)
UIErrorsFrame:AddMessage(message, 1.0, 1.0, 0.0, 1.0, UIERRORS_HOLD_TIME);
end
-- Converts string.format to a string.find pattern: "%s hits %s for %d." to "(.+) hits (.+) for (%d+)"
-- based on Recap by Gello
function GFWUtils_temp_FormatToPattern(formatString)
local patternString = formatString;
patternString = string.gsub(patternString, "%%%d+%$([diouXxfgbcsq])", "%%%1"); -- reordering specifiers (e.g. %2$s) stripped
patternString = string.gsub(patternString, "([%$%(%)%.%[%]%*%+%-%?%^])", "%%%1"); -- convert regex special characters
patternString = string.gsub(patternString, "%%c", "(.)"); -- %c to (.)
patternString = string.gsub(patternString, "%%s", "(.+)"); -- %s to (.+)
patternString = string.gsub(patternString, "%%[du]", "(%%d+)"); -- %d to (%d+)
patternString = string.gsub(patternString, "%%([gf])", "(%%d+%%.*%%d*)"); -- %g or %f to (%d+%.*%d*)
return patternString;
end
-- Splits a string into a table of strings separated by 'separator'.
-- e.g. Split(aString, ", ") is the reverse of table.concat(aTable, ", ")
function GFWUtils_temp_Split(aString, separator)
if (aString == nil) then return nil; end
local t = {};
local function helper(segment)
table.insert(t, segment);
end
helper((string.gsub(aString, "(.-)"..separator, helper)));
return t;
end
-- Capitalizes the first letter of each word in aString.
function GFWUtils_temp_TitleCase(aString)
if (aString == nil) then return nil; end
local function capWords(first, rest)
return string.upper(first)..string.lower(rest);
end
return string.gsub(aString, "(%w)([%w_']*)", capWords);
end
-- Splits a cash amount into gold, siver, and copper
function GFWUtils_temp_GSC(money)
if (money == nil) then money = 0; end
local g = math.floor(money / 10000);
local s = math.floor((money - (g*10000)) / 100);
local c = math.floor(money - (g*10000) - (s*100));
return g,s,c;
end
-- Formats money text by color for gold, silver, copper
-- discards copper for amounts greater than 1g unless second arg evaluates true
-- based on Auctioneer
function GFWUtils_temp_TextGSC(money, noRound)
local GSC_GOLD="ffd100";
local GSC_SILVER="e6e6e6";
local GSC_COPPER="c8602c";
local GSC_START="|cff%s%d%s|r";
local GSC_PART=" |cff%s%02d%s|r";
local GSC_NONE="|cffa0a0a0none|r";
local g, s, c = GFWUtils.GSC(money);
local gsc = "";
if (g > 0) then
gsc = format(GSC_START, GSC_GOLD, g, "g");
if (s > 0) then
gsc = gsc..format(GSC_PART, GSC_SILVER, s, "s");
if (noRound and c > 0) then
gsc = gsc..format(GSC_PART, GSC_COPPER, c, "c");
end
end
elseif (s > 0) then
gsc = format(GSC_START, GSC_SILVER, s, "s");
if (c > 0) then
gsc = gsc..format(GSC_PART, GSC_COPPER, c, "c");
end
elseif (c > 0) then
gsc = gsc..format(GSC_START, GSC_COPPER, c, "c");
else
gsc = GSC_NONE;
end
return gsc;
end
function GFWUtils_temp_ItemLink(linkInfo)
local sName, sLink, iQuality, iLevel, sType, sSubType, iCount = GetItemInfo(linkInfo);
if (sName) then
local _, _, _, color = GetItemQualityColor(iQuality);
local linkFormat = "%s|H%s|h[%s]|h|r";
return string.format(linkFormat, color, sLink, sName);
else
return nil;
end
end
------------------------------------------------------
-- load only if not already loaded
------------------------------------------------------
if (GFWUtils == nil) then
GFWUtils = {};
end
local G = GFWUtils;
if (G.Version == nil or (tonumber(G.Version) ~= nil and G.Version < GFWUTILS_THIS_VERSION)) then
-- Constants
GFW_FONT_COLOR = {r=0.25, g=1.0, b=1.0};
GFW_DEBUG_COLOR = {r=1.0, g=0.75, b=0.25};
G.Debug = false;
-- Functions
G.Hilite = GFWUtils_temp_HiliteText;
G.Red = GFWUtils_temp_RedText;
G.Gray = GFWUtils_temp_GrayText;
G.LtY = GFWUtils_temp_LightYellowText;
G.Print = GFWUtils_temp_Print;
G.PrintOnce = GFWUtils_temp_PrintOnce;
G.DebugLog = GFWUtils_temp_DebugLog;
G.Note = GFWUtils_temp_Note;
G.FormatToPattern = GFWUtils_temp_FormatToPattern;
G.Split = GFWUtils_temp_Split;
G.TitleCase = GFWUtils_temp_TitleCase;
G.GSC = GFWUtils_temp_GSC;
G.TextGSC = GFWUtils_temp_TextGSC;
G.ItemLink = GFWUtils_temp_ItemLink;
-- Set version number
G.Version = GFWUTILS_THIS_VERSION;
end
+12
View File
@@ -0,0 +1,12 @@
## Interface: 11200
## Version: 11200.2
## Title: Fizzwidget Feed-O-Matic
## Author: Gazmik Fizzwidget
## Notes: Helps a Hunter keep his pets well fed (and the food in his inventory under control)
## SavedVariables: FOM_Config, FOM_FoodQuality, FOM_AddedFoods, FOM_RemovedFoods, FOM_Cooking, FOM_QuestFood, FOM_LocaleInfo
GFWUtils.lua
GFWTable.lua
localization.lua
FeedOMatic_Emotes.lua
FeedOMatic_Foods.lua
FeedOMatic.lua
+5
View File
@@ -0,0 +1,5 @@
<Addon name="Fizzwidget Feed-O-Matic" author="Gazmik Fizzwidget" email="gazmik@fizzwidget.com" url="http://fizzwidget.com/huntershelper/">
<Description>Helps a Hunter keep his pets well fed (and the food in his inventory under control).</Description>
<CurrentVersion ver="11200.2" />
<UpdateFile url="http://fizzwidget.com/UpdateUI.xml" />
</Addon>
+18
View File
@@ -0,0 +1,18 @@
<!--
FeedOMatic Module Loader
Loads all FeedOMatic addon code and wraps it in the MTH module system
-->
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<!-- Load original FeedOMatic addon files -->
<Include file="GFWUtils.lua"/>
<Include file="GFWTable.lua"/>
<Include file="localization.lua"/>
<Include file="FeedOMatic_Emotes.lua"/>
<Include file="FeedOMatic_Foods.lua"/>
<Include file="FeedOMatic.lua"/>
<Include file="runtime.xml"/>
<Include file="UpdateUI.xml"/>
<!-- Load ModuleHunt wrapper -->
<Include file="module.lua"/>
</Ui>
+304
View File
@@ -0,0 +1,304 @@
-----------------------------------------------------
-- localization.lua
-- English strings by default, localizations override with their own.
------------------------------------------------------
-- Key bindings
BINDING_HEADER_FEEDOMATIC = "Fizzwidget Feed-O-Matic";
BINDING_NAME_FEEDOMATIC = "Feed Pet";
-- Diet names. These should be the all-lowercase versions of the six diets returned from GetPetFoodTypes(). (Want to get them all nice and quick for your localization? Go tame a bear... they eat anything.)
-- THESE STRINGS MUST BE LOCALIZED for Feed-O-Matic to work properly in other locales.
FOM_DIET_MEAT = "meat";
FOM_DIET_FISH = "fish";
FOM_DIET_BREAD = "bread";
FOM_DIET_CHEESE = "cheese";
FOM_DIET_FRUIT = "fruit";
FOM_DIET_FUNGUS = "fungus";
-- If the player has a buff whose icon name contains "Ability_Mount" and whose name contains one of these substrings, we assume the player is mounted. We have to use this rather oblique way to check for mounted because some other buffs use the Ability_Mount_* icons. If these aren't localized, we may not recognize when the player is mounted and still try to feed the pet.
FOM_MOUNT_NAME_SUBSTRINGS = { "kodo", "wolf", "raptor", "steed", "horse", "ram", "saber", "mechanostrider" };
-- It's not clear whether the 5th and 6th returns from GetItemInfo() are supposed to be localized... so we have localized keys for them just in case. If these aren't localized, we'll just needlessly search your ammo bags for food.
FOM_AMMO_POUCH = "Ammo Pouch";
FOM_QUIVER = "Quiver";
-- From here on down, the localized strings are just for readability... they don't affect whether Feed-O-Matic works.
-- Two special diets; one is used for tracking food that provides a bonus (or at least, that you don't want to have fed to your pet when the 'savebonus' option is on), and another that's used in the chat-line interface for listing all diets.
FOM_DIET_BONUS = "bonus";
FOM_DIET_ALL = "all";
-- Used in tooltips to indicate food quality.
FOM_QUALITY_UNKNOWN = "%s can eat this, but hasn't tried it yet.";
FOM_QUALITY_UNDER = "%s doesn't like this anymore.";
FOM_QUALITY_MIGHT = "%s might eat this.";
FOM_QUALITY_WILL = "%s will eat this.";
FOM_QUALITY_LIKE = "%s likes to eat this.";
FOM_QUALITY_LOVE = "%s loves to eat this.";
-- User-visible errors
FOM_ERROR_NO_PET = "You don't have a pet to feed.";
FOM_ERROR_PET_DEAD = "Your pet is dead.";
FOM_ERROR_NO_FEEDABLE_PET = "You don't have a feedable pet.";
FOM_ERROR_IN_COMBAT = "You can't feed your pet during combat.";
FOM_ERROR_FOOD_NOT_FOUND = "%s could not find %s in your pack.";
FOM_ERROR_NO_FOOD = "%s could not find any food in your pack.";
FOM_ERROR_NO_FOOD_NO_FALLBACK = "%s could not find any food in your pack that you haven't forbidden %s to eat.";
FOM_PRONOUN_MALE = "him";
FOM_PRONOUN_FEMALE = "her";
-- Feeding status messages
FOM_FEEDING_EAT_ANOTHER = "%s doesn't like that food and will try something else...";
FOM_FEEDING_FEED_ANOTHER = "needs to feed %s something else...";
FOM_FEEDING_EAT = "%s eats a %s from your pack.";
FOM_FEEDING_FEED = "feeds %s a %s. ";
FOM_PET_HUNGRY = "%s is hungry!";
FOM_PET_VERY_HUNGRY = "%s is very hungry!";
-- Beast family names
BAT = "Bat";
BEAR = "Bear";
BOAR = "Boar";
CARRION_BIRD = "Carrion Bird";
CAT = "Cat";
CRAB = "Crab";
CROCOLISK = "Crocolisk";
GORILLA = "Gorilla";
HYENA = "Hyena";
OWL = "Owl";
RAPTOR = "Raptor";
SCORPID = "Scorpid";
SPIDER = "Spider";
TALLSTRIDER = "Tallstrider";
TURTLE = "Turtle";
WIND_SERPENT = "Wind Serpent";
WOLF = "Wolf";
FOM_OPTIONS_HEADER = "Feed-O-Matic Options";
FOM_OPTIONS_GENERAL = "General options:";
FOM_OPTIONS_FOOD_CHOICE = "Avoid foods used in Cooking:";
FOM_OPTIONS_FEED_NOTIFY = "Notify when feeding:";
FOM_OPTIONS_WARNING = "Warn that your pet needs feeding:";
FOM_KEEPOPEN = "Try to keep at least";
FOM_KEEPOPEN_SLOTS = "slots open in your bags.";
FOM_KEEPOPEN_INFO = "(Will choose foods from smaller stacks when low on space, regardless of how well your pet likes them.)";
FOM_OptionsButtonText = {
["Tooltip"] = "Show your pet's opinion of foods in their tooltips",
["AvoidQuestFood"] = "Avoid foods needed for quests",
["AvoidBonusFood"] = "Avoid foods that have a bonus effect when eaten",
["PreferHigherQuality"] = "Prefer foods your pet likes more",
["Fallback"] = "Fall back to otherwise-avoided foods if out of others",
["SaveForCook_All"] = "all foods used in cooking",
["SaveForCook_Green"] = "only foods used in |cff3fbf3f\"easy\"|r or better recipes",
["SaveForCook_Yellow"] = "only foods used in |cffffff00\"medium\"|r or better recipes",
["SaveForCook_Orange"] = "only foods used in |cffff7f3f\"difficult\"|r recipes",
["SaveForCook_None"] = "Don't save foods used in cooking",
["IconWarning"] = "Flash icon",
["TextWarning"] = "Show text",
["AudioWarning"] = "Play sound",
["AudioWarningBell"] = "Generic bell sound instead of pet-specific",
["AlertEmote"] = "Via emote (seen by others)",
["AlertChat"] = "In the chat window (seen by you only)",
["AlertNone"] = "Don't notify",
["LevelContent"] = "when \"content\"",
["LevelUnhappy"] = "when \"unhappy\"",
["LevelOff"] = "Don't warn",
};
------------------------------------------------------
if (GetLocale() == "frFR") then
-- Diet names. These should be the all-lowercase versions of the six diets returned from GetPetFoodTypes(). (Want to get them all nice and quick for your localization? Go tame a bear... they eat anything.)
-- THESE STRINGS MUST BE LOCALIZED for Feed-O-Matic to work properly in other locales.
FOM_DIET_MEAT = "viande";
FOM_DIET_FISH = "poisson";
FOM_DIET_BREAD = "pain";
FOM_DIET_CHEESE = "fromage";
FOM_DIET_FRUIT = "fruit";
FOM_DIET_FUNGUS = "champignon";
-- If the player has a buff whose icon name contains "Ability_Mount" and whose name contains one of these substrings, we assume the player is mounted. We have to use this rather oblique way to check for mounted because some other buffs use the Ability_Mount_* icons. If these aren't localized, we may not recognize when the player is mounted and still try to feed the pet.
FOM_MOUNT_NAME_SUBSTRINGS = { "kodo", "loup", "raptor", "steed", "cheval", "bélier", "tigre", "mécanotrotteur", };
-- It's not clear whether the 5th and 6th returns from GetItemInfo() are supposed to be localized... so we have localized keys for them just in case. If these aren't localized, we'll just needlessly search your ammo bags for food.
FOM_AMMO_POUCH = "Giberne";
FOM_QUIVER = "Carquois";
-- From here on down, the localized strings are just for readability... they don't affect whether Feed-O-Matic works.
-- Two special diets; one is used for tracking food that provides a bonus (or at least, that you don't want to have fed to your pet when the 'savebonus' option is on), and another that's used in the chat-line interface for listing all diets.
FOM_DIET_BONUS = "bonus";
FOM_DIET_ALL = "tous";
-- Used in tooltips to indicate food quality.
FOM_QUALITY_UNKNOWN = "%s peut le manger, mais n'a jamais essayé.";
FOM_QUALITY_UNDER = "%s n'en mange plus désormais.";
FOM_QUALITY_MIGHT = "%s en mangera peut-être.";
FOM_QUALITY_WILL = "%s en mangera.";
FOM_QUALITY_LIKE = "%s aime en manger.";
FOM_QUALITY_LOVE = "%s adore en manger.";
-- User-visible errors
FOM_ERROR_NO_PET = "Vous n'avez pas de familier.";
FOM_ERROR_PET_DEAD = "Votre familier est mort.";
FOM_ERROR_NO_FEEDABLE_PET = "Vous n'avez pas de familier capable de manger.";
FOM_ERROR_FOOD_NOT_FOUND = "%s n'a pas trouvé de %s dans votre sac.";
FOM_ERROR_NO_FOOD = "%s n'a pas trouvé de nourriture dans votre sac.";
-- Feeding status messages
FOM_FEEDING_EAT_ANOTHER = "%s n'aime pas cette nourriture et va essayer autre chose..."
FOM_FEEDING_FEED_ANOTHER = "cherche autre chose à donner à %s...";
FOM_FEEDING_EAT = "%s mange un(e) %s.";
FOM_FEEDING_FEED = "donne à %s à manger un(e) %s. ";
-- Beast family names
BAT = "Chauve-souris";
BEAR = "Ours";
BOAR = "Sanglier";
CARRION_BIRD = "Charognard";
CAT = "Félin";
CRAB = "Crabe";
CROCOLISK = "Crocilisque";
GORILLA = "Gorille";
HYENA = "Hyène";
OWL = "Chouette";
RAPTOR = "Raptor";
SCORPID = "Scorpide";
SPIDER = "Araignée";
TALLSTRIDER = "Haut-trotteur";
TURTLE = "Tortue";
WIND_SERPENT = "Serpent des vents";
WOLF = "Loup";
FOM_PET_HUNGRY = "%s a faim!";
FOM_PET_VERY_HUNGRY = "%s a très faim!";
FOM_OPTIONS_HEADER = "Feed-O-Matic Options";
FOM_OPTIONS_GENERAL = "Options générales:";
FOM_OPTIONS_FOOD_CHOICE = "Eviter la nourriture utilisée en cuisine:";
FOM_OPTIONS_FEED_NOTIFY = "Prévenir lorsque votre familier est nourrit:";
FOM_OPTIONS_WARNING = "Avertir quand votre familier a besoin d'être nourrit:";
FOM_KEEPOPEN = "Essayer de garder au moins";
FOM_KEEPOPEN_SLOTS = "emplacements de sac libres";
FOM_KEEPOPEN_INFO = "(Le familier choisira la nourriture des piles les plus petites, sans tenir compte de ses préférences.)";
FOM_OptionsButtonText = {
["Tooltip"] = "Afficher l'avis de votre familier concernant la nourriture",
["AvoidQuestFood"] = "Eviter la nourriture utile dans les quêtes",
["AvoidBonusFood"] = "Eviter la nourriture donnant un bonus",
["PreferHigherQuality"] = "Privilégier la nourriture que votre familier préfère",
["Fallback"] = "Utiliser la nourriture évitée s'il n'y en a plus d'autres",
["SaveForCook_All"] = "Toutes nourritures utilisées pour la cuisine",
["SaveForCook_Green"] = "si elle est utilisée dans les recettes |cff3fbf3f\"faciles\"|r ou supérieures",
["SaveForCook_Yellow"] = "si elle est utilisée dans les recettes |cffffff00\"moyennes\"|r ou supérieures",
["SaveForCook_Orange"] = "si elle est utilisée dans les recettes |cffff7f3f\"difficiles\"|r",
["SaveForCook_None"] = "Ne pas éviter la nourriture utilisée en cuisine",
["IconWarning"] = "Clignoter l'icône",
["TextWarning"] = "Afficher un texte",
["AudioWarning"] = "Jouer un son",
["AudioWarningBell"] = "Un son de cloche au lieu du cri du familier",
["AlertEmote"] = "Via emote (visible par les autres)",
["AlertChat"] = "Dans la fenêtre de discussion (visible uniquement par vous)",
["AlertNone"] = "Ne pas prévenir",
["LevelContent"] = "quand \"content\"",
["LevelUnhappy"] = "quand \"mécontent\"",
["LevelOff"] = "Ne pas avertir",
};
end
------------------------------------------------------
if (GetLocale() == "deDE") then
-- Diet names. These should be the all-lowercase versions of the six diets returned from GetPetFoodTypes(). (Want to get them all nice and quick for your localization? Go tame a bear... they eat anything.)
-- THESE STRINGS MUST BE LOCALIZED for Feed-O-Matic to work properly in other locales.
FOM_DIET_MEAT = "fleisch";
FOM_DIET_FISH = "fisch";
FOM_DIET_BREAD = "brot";
FOM_DIET_CHEESE = "käse";
FOM_DIET_FRUIT = "obst";
-- FOM_DIET_FUNGUS = "fungus"; -- same as English (?), so we don't need to re-define it.
-- If the player has a buff whose icon name contains "Ability_Mount" and whose name contains one of these substrings, we assume the player is mounted. We have to use this rather oblique way to check for mounted because some other buffs use the Ability_Mount_* icons. If these aren't localized, we may not recognize when the player is mounted and still try to feed the pet.
-- FOM_MOUNT_NAME_SUBSTRINGS = { "kodo", "wolf", "raptor", "steed", "horse", "ram", "saber", "mechanostrider" };
-- It's not clear whether the 5th and 6th returns from GetItemInfo() are supposed to be localized... so we have localized keys for them just in case.
FOM_AMMO_POUCH = "Munitionsbeutel";
FOM_QUIVER = "Köcher";
-- From here on down, the localized strings are just for readability; they don't affect whether Feed-O-Matic works.
-- Two special diets; one is used for tracking food that provides a bonus (or at least, that you don't want to have fed to your pet when the 'savebonus' option is on), and another that's used in the chat-line interface for listing all diets.
-- FOM_DIET_BONUS = "bonus"; -- same as English(?), so we don't need to re-define it.
FOM_DIET_ALL = "alles";
-- Used in tooltips to indicate food quality.
FOM_QUALITY_UNKNOWN = "%s kann das fressen, hat es aber noch nicht probiert.";
FOM_QUALITY_UNDER = "%s mag das nicht mehr fressen.";
FOM_QUALITY_MIGHT = "%s mag das möglicherweise fressen.";
FOM_QUALITY_WILL = "%s mag das fressen.";
FOM_QUALITY_LIKE = "%s frisst das gerne.";
FOM_QUALITY_LOVE = "%s liebt es, das zu fressen.";
-- User-visible errors
FOM_ERROR_NO_PET = "Du hast kein Tier um es zu füttern.";
FOM_ERROR_PET_DEAD = "Dein Tier ist tot.";
FOM_ERROR_NO_FEEDABLE_PET = "Du hast kein Tier das man füttern kann.";
FOM_ERROR_FOOD_NOT_FOUND = "%s kann %s nicht in Deinem Rucksack finden.";
FOM_ERROR_NO_FOOD = "%s findet nichts zu fressen in Deinem Rucksack.";
-- Feeding status messages
FOM_FEEDING_EAT_ANOTHER = "%s mag dieses Futter nicht und probiert etwas anderes...";
FOM_FEEDING_FEED_ANOTHER = "sucht nach etwas anderem um %s zu füttern...";
FOM_FEEDING_EAT = "%s frisst ein %s aus Deinem Rucksack.";
FOM_FEEDING_FEED = "füttert %s ein %s. ";
-- Beast family names
BAT = "Fledermaus";
BEAR = "Bär";
BOAR = "Eber";
CARRION_BIRD = "Aasvogel";
CAT = "Katze";
CRAB = "Krebs";
CROCOLISK = "Krokilisk";
-- GORILLA = "Gorilla"; -- same as enUS
HYENA = "Hyäne";
OWL = "Eule";
-- RAPTOR = "Raptor"; -- same as enUS
SCORPID = "Skorpid";
SPIDER = "Spinne";
TALLSTRIDER = "Weitschreiter";
TURTLE = "Schildkröte";
WIND_SERPENT = "Windnatter";
-- WOLF = "Wolf"; -- same as enUS
end
------------------------------------------------------
if (GetLocale() == "koKR") then
-- Diet names. These should be the all-lowercase versions of the six diets returned from GetPetFoodTypes(). (Want to get them all nice and quick for your localization? Go tame a bear... they eat anything.)
-- THESE STRINGS MUST BE LOCALIZED for Feed-O-Matic to work properly in other locales.
-- FOM_DIET_MEAT = "meat";
-- FOM_DIET_FISH = "fish";
-- FOM_DIET_BREAD = "bread";
-- FOM_DIET_CHEESE = "cheese";
-- FOM_DIET_FRUIT = "fruit";
-- FOM_DIET_FUNGUS = "fungus";
-- If the player has a buff whose icon name contains "Ability_Mount" and whose name contains one of these substrings, we assume the player is mounted. We have to use this rather oblique way to check for mounted because some other buffs use the Ability_Mount_* icons.
-- FOM_MOUNT_NAME_SUBSTRINGS = { "kodo", "wolf", "raptor", "steed", "horse", "ram", "saber", "mechanostrider" };
-- It's not clear whether the 5th and 6th returns from GetItemInfo() are supposed to be localized... so we have localized keys for them just in case.
-- FOM_AMMO_POUCH = "Ammo Pouch";
FOM_QUIVER = "화살통";
end
+340
View File
@@ -0,0 +1,340 @@
------------------------------------------------------
-- MetaHunt: FeedOMatic Module Wrapper
-- Modern module abstraction for the FeedOMatic addon
------------------------------------------------------
local MTH_FeedOMatic = {
name = "feedomatic",
enabled = false,
version = "1.0.3",
events = {
"VARIABLES_LOADED",
"MERCHANT_SHOW",
"MERCHANT_UPDATE",
"MTH_PET_LIVE_STATE_CHANGED",
"PET_ATTACK_START",
"PET_ATTACK_STOP",
"PET_STABLE_SHOW",
"PET_STABLE_UPDATE",
"TRADE_SKILL_SHOW",
"TRADE_SKILL_UPDATE",
"CHAT_MSG_SPELL_TRADESKILLS",
"CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS",
"UI_ERROR_MESSAGE",
"PET_BAR_SHOWGRID",
"PET_BAR_UPDATE",
"PET_UI_UPDATE",
"UNIT_HAPPINESS",
"PLAYER_REGEN_ENABLED",
},
initialized = false,
variablesLoadedProcessed = false,
}
local MTH_PETL_HOOK_BOUNDARY_KEY = "pet-lifecycle-hooks"
local MTH_FeedOMatic_MerchantProbeFrame = nil
function MTH_FeedOMatic_OnUpdate(elapsed)
if not elapsed then
return
end
if not (MTH and MTH.IsModuleEnabled and MTH:IsModuleEnabled("feedomatic", true)) then
return
end
if type(FOM_OnUpdate) == "function" then
FOM_OnUpdate(elapsed)
end
end
local function MTH_FeedOMatic_GetRuntimeFrame()
return getglobal("Frame_GFW_FeedOMatic")
end
local function MTH_FeedOMatic_CaptureHookBoundary()
if not (MTH and MTH.CaptureHookBoundary) then
return
end
MTH:CaptureHookBoundary(MTH_PETL_HOOK_BOUNDARY_KEY, {
{ globalName = "PetAbandon", originalName = "MTH_PETL_Original_PetAbandon" },
})
end
local function MTH_FeedOMatic_RestoreHookBoundary()
if not (MTH and MTH.RestoreHookBoundary) then
return
end
MTH:RestoreHookBoundary(MTH_PETL_HOOK_BOUNDARY_KEY)
end
local function MTH_FeedOMatic_ApplyLegacyHooks()
local canTouchPetAbandon = true
if MTH and MTH.GetGlobalHookOwner then
local abandonOwner = MTH:GetGlobalHookOwner("PetAbandon")
if abandonOwner and abandonOwner ~= MTH_PETL_HOOK_BOUNDARY_KEY then
canTouchPetAbandon = false
end
end
local abandonHook = MTH_PetAbandonHook or FOM_PetAbandon
local abandonOriginal = MTH_PETL_Original_PetAbandon or FOM_Original_PetAbandon
if type(abandonHook) == "function" and type(abandonOriginal) == "function" then
if canTouchPetAbandon and (PetAbandon == abandonOriginal or PetAbandon == abandonHook) then
PetAbandon = abandonHook
end
end
end
local function MTH_FeedOMatic_CallLegacyOnEvent(evt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
if type(FOM_OnEvent) ~= "function" then
return
end
local frame = MTH_FeedOMatic_GetRuntimeFrame()
if not frame then
return
end
local oldThis = this
local oldEvent = event
local oldArg1, oldArg2, oldArg3, oldArg4, oldArg5 = arg1, arg2, arg3, arg4, arg5
local oldArg6, oldArg7, oldArg8, oldArg9 = arg6, arg7, arg8, arg9
this = frame
event = evt
arg1, arg2, arg3, arg4, arg5 = a1, a2, a3, a4, a5
arg6, arg7, arg8, arg9 = a6, a7, a8, a9
local ok = pcall(function()
FOM_OnEvent(evt, a1)
end)
this = oldThis
event = oldEvent
arg1, arg2, arg3, arg4, arg5 = oldArg1, oldArg2, oldArg3, oldArg4, oldArg5
arg6, arg7, arg8, arg9 = oldArg6, oldArg7, oldArg8, oldArg9
if not ok and MTH and MTH.DebugPrint then
MTH:DebugPrint("FeedOMatic legacy OnEvent call failed for event: " .. tostring(evt))
end
end
local function MTH_FeedOMatic_EnsureVariablesLoaded(module)
if not module or module.variablesLoadedProcessed then
return
end
MTH_FeedOMatic_CallLegacyOnEvent("VARIABLES_LOADED")
module.variablesLoadedProcessed = true
end
local function MTH_FeedOMatic_SyncSavedVariables()
if not MTH or not MTH.GetModuleSavedVariables then
return
end
local moduleStore = MTH:GetModuleSavedVariables("feedomatic")
if not moduleStore.legacy then
moduleStore.legacy = {}
end
if type(FOM_Config) == "table" then
moduleStore.legacy.FOM_Config = FOM_Config
elseif type(moduleStore.legacy.FOM_Config) == "table" then
FOM_Config = moduleStore.legacy.FOM_Config
end
if type(FOM_FoodQuality) == "table" then
moduleStore.legacy.FOM_FoodQuality = FOM_FoodQuality
elseif type(moduleStore.legacy.FOM_FoodQuality) == "table" then
FOM_FoodQuality = moduleStore.legacy.FOM_FoodQuality
end
if type(FOM_AddedFoods) == "table" then
moduleStore.legacy.FOM_AddedFoods = FOM_AddedFoods
elseif type(moduleStore.legacy.FOM_AddedFoods) == "table" then
FOM_AddedFoods = moduleStore.legacy.FOM_AddedFoods
end
if type(FOM_RemovedFoods) == "table" then
moduleStore.legacy.FOM_RemovedFoods = FOM_RemovedFoods
elseif type(moduleStore.legacy.FOM_RemovedFoods) == "table" then
FOM_RemovedFoods = moduleStore.legacy.FOM_RemovedFoods
end
if type(FOM_Cooking) == "table" then
moduleStore.legacy.FOM_Cooking = FOM_Cooking
elseif type(moduleStore.legacy.FOM_Cooking) == "table" then
FOM_Cooking = moduleStore.legacy.FOM_Cooking
end
if type(FOM_QuestFood) == "table" then
moduleStore.legacy.FOM_QuestFood = FOM_QuestFood
elseif type(moduleStore.legacy.FOM_QuestFood) == "table" then
FOM_QuestFood = moduleStore.legacy.FOM_QuestFood
end
if type(FOM_LocaleInfo) == "table" then
moduleStore.legacy.FOM_LocaleInfo = FOM_LocaleInfo
elseif type(moduleStore.legacy.FOM_LocaleInfo) == "table" then
FOM_LocaleInfo = moduleStore.legacy.FOM_LocaleInfo
end
end
local function MTH_FeedOMatic_Log(message, severity)
if type(MTH_Log) == "function" then
local logSeverity = severity or "debug"
MTH_Log("[FeedOMatic] " .. tostring(message or ""), logSeverity)
end
end
local function MTH_FeedOMatic_DebugMerchantScan(sourceEvent)
if type(MTH_GetMerchantFoodsByDiet) ~= "function" then
MTH_FeedOMatic_Log(tostring(sourceEvent) .. ": MTH_GetMerchantFoodsByDiet is not available yet")
return
end
local merchantFoods = MTH_GetMerchantFoodsByDiet()
local knownCount = 0
local unknownCount = 0
if type(merchantFoods) == "table" then
if type(merchantFoods.items) == "table" then
knownCount = table.getn(merchantFoods.items)
end
if type(merchantFoods.unknown) == "table" then
unknownCount = table.getn(merchantFoods.unknown)
end
end
local merchantName = UnitName("npc") or UnitName("target") or "unknown"
MTH_FeedOMatic_Log(tostring(sourceEvent) .. ": wrapper scan for " .. tostring(merchantName) .. " | known=" .. tostring(knownCount) .. " | unknown=" .. tostring(unknownCount))
if type(merchantFoods.byDiet) == "table" then
for dietName, rows in merchantFoods.byDiet do
local dietCount = 0
if type(rows) == "table" then
dietCount = table.getn(rows)
end
MTH_FeedOMatic_Log("diet " .. tostring(dietName) .. ": " .. tostring(dietCount) .. " item(s)", "debug")
if type(rows) == "table" then
for _, row in rows do
MTH_FeedOMatic_Log(" - [" .. tostring(row.id) .. "] " .. tostring(row.name) .. " (slot=" .. tostring(row.index) .. ")", "debug")
end
end
end
end
if unknownCount > 0 and type(merchantFoods.unknown) == "table" then
for _, row in merchantFoods.unknown do
MTH_FeedOMatic_Log("unknown map: [" .. tostring(row.id) .. "] " .. tostring(row.name) .. " (slot=" .. tostring(row.index) .. ")", "debug")
end
end
end
local function MTH_FeedOMatic_SetMerchantProbeEnabled(enabled)
if not MTH_FeedOMatic_MerchantProbeFrame then
MTH_FeedOMatic_MerchantProbeFrame = CreateFrame("Frame", "MTH_FeedOMatic_MerchantProbeFrame")
MTH_FeedOMatic_MerchantProbeFrame:SetScript("OnEvent", function()
local evt = event
if evt == "MERCHANT_SHOW" or evt == "MERCHANT_UPDATE" then
MTH_FeedOMatic_Log("probe event received: " .. tostring(evt), "debug")
MTH_FeedOMatic_DebugMerchantScan(evt)
end
end)
end
if enabled then
MTH_FeedOMatic_MerchantProbeFrame:RegisterEvent("MERCHANT_SHOW")
MTH_FeedOMatic_MerchantProbeFrame:RegisterEvent("MERCHANT_UPDATE")
MTH_FeedOMatic_Log("merchant probe enabled", "debug")
else
MTH_FeedOMatic_MerchantProbeFrame:UnregisterEvent("MERCHANT_SHOW")
MTH_FeedOMatic_MerchantProbeFrame:UnregisterEvent("MERCHANT_UPDATE")
end
end
function MTH_FeedOMatic:init()
-- FeedOMatic initializes via its VARIABLES_LOADED event
-- This is called after the core MTH framework is loaded
MTH_FEED_WRAPPER_MODE = true
MTH_FOM_WRAPPER_MODE = MTH_FEED_WRAPPER_MODE
MTH_FeedOMatic_SyncSavedVariables()
if not self.initialized and not getglobal("FOM_METAHUNT_ONLOAD_DONE") and FOM_OnLoad then
local frame = MTH_FeedOMatic_GetRuntimeFrame()
if frame then
local oldThis = this
this = frame
pcall(function()
FOM_OnLoad()
end)
this = oldThis
FOM_METAHUNT_ONLOAD_DONE = true
end
end
MTH_FeedOMatic_CaptureHookBoundary()
self.initialized = true
if self.enabled then
MTH_FeedOMatic_EnsureVariablesLoaded(self)
end
end
function MTH_FeedOMatic:setEnabled(enabled)
if enabled then
if not self.initialized then
self:init()
end
MTH_FeedOMatic_ApplyLegacyHooks()
MTH_FeedOMatic_CaptureHookBoundary()
MTH_FeedOMatic_SyncSavedVariables()
MTH_FeedOMatic_EnsureVariablesLoaded(self)
MTH_FeedOMatic_SetMerchantProbeEnabled(false)
if FOM_FeedButton then
FOM_FeedButton:Show()
end
else
-- Disable FeedOMatic functionality
MTH_FeedOMatic_RestoreHookBoundary()
if type(FOM_State) == "table" then
FOM_State.ShouldFeed = false
end
MTH_FeedOMatic_SetMerchantProbeEnabled(false)
if FOM_FeedButton then
FOM_FeedButton:Hide()
end
end
end
function MTH_FeedOMatic:onEvent(event, arg1, arg2, arg3, arg4, arg5)
if event == "VARIABLES_LOADED" then
MTH_FeedOMatic_EnsureVariablesLoaded(self)
return
end
if event == "MTH_PET_LIVE_STATE_CHANGED" then
MTH_FeedOMatic_CallLegacyOnEvent("PET_BAR_UPDATE")
MTH_FeedOMatic_CallLegacyOnEvent("PET_UI_UPDATE")
MTH_FeedOMatic_CallLegacyOnEvent("UNIT_HAPPINESS", "pet")
return
end
MTH_FeedOMatic_CallLegacyOnEvent(event, arg1, arg2, arg3, arg4, arg5)
end
function MTH_FeedOMatic:cleanup()
-- Cleanup code when module is unloaded
MTH_FeedOMatic_RestoreHookBoundary()
if type(FOM_State) == "table" then
FOM_State.ShouldFeed = false
end
MTH_FeedOMatic_SetMerchantProbeEnabled(false)
if FOM_FeedButton then
FOM_FeedButton:Hide();
end
end
-- Register with MTH
MTH:RegisterModule("feedomatic", MTH_FeedOMatic)
MTH_FOM_OnUpdate = MTH_FeedOMatic_OnUpdate
+87
View File
@@ -0,0 +1,87 @@
------------------------------------------------------
Fizzwidget Feed-O-Matic
by Gazmik Fizzwidget
http://fizzwidget.com
gazmik@fizzwidget.com
------------------------------------------------------
As my Hunter friends can readily attest, keeping a wild pet can be a full-time job. Why, just feeding the critter when he gets hungry can throw off your routine -- you've got to rummage around in your bags, find a piece of food, make sure it's appropriate for his diet, and check your aim before tossing it to him (lest you accidentally destroy a tasty morsel). So inconvenient! Not to mention potentially dangerous... you don't want to spend so long digging through your bags that you or your pet become someone else's snack.
Never fear, Gazmik Fizzwidget is here with a new gadget to automate all your pet-food-management tasks! My incredible Feed-O-Matic features state-of-the-art nutritional analyzers to make sure your pet's hunger is satisfied with a minimum of fuss, advanced selective logic to make your pet doesn't eat anything you have another use for, and a weight optimizer to make sure the food in your bags stays well organized! Just press the "Feed Now" button and it'll intelligently choose a food and accurately toss it to your pet. This is actually one of the first gizmos I started work on... but because I'm a perfectionist I haven't considered it ready for release until now.
------------------------------------------------------
INSTALLATION: Put this folder into your World Of Warcraft/Interface/AddOns folder and launch WoW.
USAGE:
Makes feeding your pet quick, easy, and fun:
- Bind a key to "Feed Pet", and Feed-O-Matic will automatically choose an appropriate food and give it to the pet whenever you press it.
- Can use an emote to notify you when it's feeding your pet, with custom randomized messages. See FeedOMatic_Emotes.lua to customize them to your characters!
Helps you manage all the pet food in your inventory:
- Keeps track of which foods your pet likes more, and prioritizes "better" foods when choosing what to feed the pet. Also remembers what foods your pet has "outgrown", and doesn't choose them in the future (unless you've switched to a pet who might have different tastes).
- If you're on a quest to collect several of a certain item which also happens to be something your pet likes to eat, Feed-O-Matic can avoid consuming it. (Unless you're carrying more than is needed for the quest or there's nothing else for your pet to eat.)
- Feed-O-Matic can keep track of what foods are used by the Cooking recipes you know and avoid choosing food you'd rather cook; this behavior can be customized based on the difficulty of the recipies (so, for example, you can either save all cookable food or only save the foods most likely to increase your Cooking skill).
- If you'd prefer to save the better food (that is, those which provide a "well fed" bonus or other effect when eaten) for yourself, Feed-O-Matic can also avoid it when looking for pet food.
- All other things being equal, Feed-O-Matic will try to pick foods from smaller stacks, making sure your food supply doesn't take up all your bag space. When your bags get close to full, Feed-O-Matic will start ignoring other criteria and always choosing the smallest stack so that you won't run out of inventory sooner.
CHAT COMMANDS:
`/feedomatic` (or `/fom` or `/feed`) - Show the Options window.
or:
`/feedomatic` (or `/fom` or `/feed`) <command>
where <command> can be any of the following:
`help` - Print this helplist.
`status` - Check current settings.
`reset` - Reset to default settings.
`feed` - Feed your pet (automatically finds an appropriate food).
`feed <item link>` - Feed your pet a specific food.
`add <diet> <item link>` - Add food to the list for a specific diet (meat, fish, fruit, etc).
`remove <diet> <item link>` - Remove food from the list.
`show <diet>` - Show food list for a specific diet (or for `all`).
CAVEATS, ETC.:
- Feed-O-Matic has a database of many known foods, but it's not guaranteed to be comprehensive. You can use the `add`, `remove`, and `show` commands noted above to manage these lists directly. (Please drop me a line if you find a food that should be on there, or discover that something on the list shouldn't be there.)
- Currently, Feed-O-Matic can only update its list of which foods you know how to cook when your Cooking window is open. (So if you read a new recipe, we won't know to preserve the ingredients until you open your Cooking window again.)
- Only works in English, French, and German (for now). Localizers interested in helping with other WoW client languages please contact gazmik@fizzwidget.com.
------------------------------------------------------
VERSION HISTORY
v. 12000.2 - 2006/10/27
- Now always prefers conjured foods if available when feeding a pet that can eat them. (This was supposed to have been the case before, but the implementation turned out to be unreliable.)
- Fixed some issues which could result in Feed-O-Matic feeding the pet a food you'd told it to avoid, even if the "fall back" option was turned off. Also, a clearer error message is given if "fall back" is off and we can't find any allowed foods.
- The various reminder options for when your pet needs feeding (flashing the happiness icon, text messages, sounds) are now suppressed while you or your pet is in combat or if your pet is dead.
- Feed-O-Matic posts its own error message if you attempt use it to feed your pet while in combat. (Instead of trying to feed the pet anyway, causing WoW itself to post an error message.)
- Added a number of items to the default foods list (including some holiday treats and the new level 55 mage-conjured bread).
v. 11200.1 - 2006/08/22
- Updated TOC to reflect compatibility with WoW patch 1.12.
- Updated use of WoW's UnitSex() function to match changes in its behavior from WoW patch 1.11... your pet's gender should be reported correctly again.
v. 11100.1 - 2006/06/20
- Updated TOC to reflect compatibility with WoW patch 1.11. (No actual changes were needed.)
- Added French localization by "Artaher Medivh".
v. 11000.4 - 2006/04/17
- Fixed some issues with the tooltip code shared across Fizzwidget addons; Feed-O-Matic's addition to item tooltips should now be able to show up in just about every place you can get an item tooltip.
v. 11000.3 - 2006/04/11
- Feed-O-Matic settings can now be edited via a new Options panel. Typing `/fom` alone shows this panel (the various configuration subcommands, e.g. `/fom alert`, etc., are still available), which controls all aspects of Feed-O-Matic's behavior except for its list of known foods (for now, you'll still need to use slash commands to edit that).
- Additional options are available for warning you that your pet needs feeding: besides flashing the default UI's pet happiness icon, Feed-O-Matic can now also alert you via text message or with the sounds of your pet begging for food. (If you don't like these species-specific pet noises, there's also an option to have a simple bell sound as reminder.)
- You can now click the default UI's pet happiness icon to invoke Feed-O-Matic's feeding function. (This makes three ways to feed your pet with Feed-O-Matic: click the icon, set up a key for Feed Pet in the standard Key Bindings menu, or type or macro `/fom feed`.) Right-click the icon to show the new Options panel.
- Fixed a bug where we could bloat the SavedVariables file when attempting to clean it up upon visiting a stable master. (Now we properly discard data from pets no longer in service.)
- Fixed a bug where we'd still keep trying to feed a food to the pet after finding out it's too low level.
v. 11000.2 - 2006/04/01
- Due to changes in WoW patch 1.10, it's no longer possible for UI addons to feed your pet automatically without direct input; the automatic feeding function is thus no longer available in Feed-O-Matic. You may still find Feed-O-Matic quite useful for its ability to automatically choose foods for your pet and feed them at the touch of a button -- the "Feed Pet" button (configurable in WoW's Key Bindings menu) and `/fom feed` chat/macro command still work just great.
- As an aid to those suffering auto-feed withdrawal, there's now an option for Feed-O-Matic to provide an extra reminder when your pet needs feeding (in case you find the icon next to your pet's health bar too subtle). This is accessed by the same `/fom level` command that previously controlled automatic feeding; when your pet's happiness falls below the specified level, the happiness icon will blink until you feed him enough to sate his hunger.
- Fixed a bug where an error panel could appear when attempting to feed the pet with the `fallback` option turned off and the only foods in your inventory being types you'd prefer to avoid.
- KNOWN BUG: The tooltip additions aren't showing up in all cases where they should. Another update to address this issue should be coming along soon.
v. 11000.1 - 2006/03/28
- Updated for compatibility with WoW patch 1.10. (Minor changes were needed.)
- Should no longer disconnect if you have feed emotes turned on and you try to feed your pet a Legendary item. (Probably not a bug many experienced, but still...)
- Minor improvements to utility code shared across Fizzwidget addons.
- KNOWN BUG: The tooltip additions aren't showing up in all cases where they should. Another update to address this issue should be coming along soon.
See http://fizzwidget.com/notes/feedomatic/ for older release notes.
+25
View File
@@ -0,0 +1,25 @@
<!--
FeedOMatic Runtime Frame Loader (MetaHunt)
Minimal runtime XML without legacy options window definitions.
-->
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\..\..\FrameXML\UI.xsd">
<Frame name="Frame_GFW_FeedOMatic">
<Scripts>
<OnUpdate>
if (MTH_FOM_OnUpdate) then
MTH_FOM_OnUpdate(arg1);
elseif (FOM_OnUpdate) then
FOM_OnUpdate(arg1);
end
</OnUpdate>
</Scripts>
</Frame>
<GameTooltip name="FOMTooltip" frameStrata="TOOLTIP" hidden="true" parent="UIParent" inherits="GameTooltipTemplate">
<Scripts>
<OnLoad>
this:SetOwner(UIParent, "ANCHOR_NONE");
</OnLoad>
</Scripts>
</GameTooltip>
</Ui>
+672
View File
@@ -0,0 +1,672 @@
local function MTHSmartAmmo_GetSaved()
return MTH_SA_GetSavedTable("MTHSmartAmmo")
end
local function MTHSmartAmmo_GetModuleStore()
if MTH and MTH.GetModuleCharSavedVariables then
return MTH:GetModuleCharSavedVariables("smartammo")
end
return nil
end
local function MTHSmartAmmo_IsSmartEnabled()
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" and moduleStore.smartEnabled ~= nil then
return moduleStore.smartEnabled and true or false
end
local saved = MTHSmartAmmo_GetSaved()
return saved["enabled"]
end
local function MTHSmartAmmo_IsReloadEnabled()
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" and moduleStore.reloadEnabled ~= nil then
return moduleStore.reloadEnabled and true or false
end
local saved = MTHSmartAmmo_GetSaved()
if saved["reload"] == nil then
return true
end
return saved["reload"] and true or false
end
local MTHSmartAmmo_InitializeHooks
MTHSmartAmmo_EnsureHooks = nil
function MTHSmartAmmo_SetSmartEnabled(enabled, silent)
local saved = MTHSmartAmmo_GetSaved()
if enabled then
saved["enabled"] = 1
if MTHSmartAmmo_InitializeHooks then
MTHSmartAmmo_InitializeHooks()
end
if MTHSmartAmmo_EnsureHooks then
MTHSmartAmmo_EnsureHooks("SetSmartEnabled")
end
if not silent and DEFAULT_CHAT_FRAME then
MTH_SA_Print("Smart Ammo Enabled.")
end
else
saved["enabled"] = false
if not silent and DEFAULT_CHAT_FRAME then
MTH_SA_Print("Smart Ammo Disabled.")
end
end
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" then
moduleStore.smartEnabled = enabled and true or false
end
end
function MTHSmartAmmo_GetSmartEnabled()
return MTHSmartAmmo_IsSmartEnabled() and true or false
end
function MTHSmartAmmo_SetReloadEnabled(enabled, silent)
local saved = MTHSmartAmmo_GetSaved()
if enabled then
saved["reload"] = 1
else
saved["reload"] = false
end
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" then
moduleStore.reloadEnabled = enabled and true or false
end
if not silent and DEFAULT_CHAT_FRAME then
MTH_SA_Print("Smart Ammo reload fallback " .. (enabled and "Enabled." or "Disabled."))
end
end
function MTHSmartAmmo_GetReloadEnabled()
return MTHSmartAmmo_IsReloadEnabled() and true or false
end
local function MTHSmartAmmo_Log(msg)
return
end
local MTHSmartAmmo_CastSpell_Hook
local MTHSmartAmmo_UseAction_Hook
local MTHSmartAmmo_CastSpellByName_Hook
local MTHSmartAmmo_HookEnsureElapsed = 0
local MTHSmartAmmo_InCastSpellHook = false
local MTHSmartAmmo_InUseActionHook = false
local MTHSmartAmmo_InCastSpellByNameHook = false
local MTHSmartAmmo_OriginalCastSpell = CastSpell
local MTHSmartAmmo_OriginalUseAction = UseAction
local MTHSmartAmmo_OriginalCastSpellByName = CastSpellByName
local function MTHSmartAmmo_AreHooksInstalled()
return CastSpell == MTHSmartAmmo_CastSpell_Hook,
UseAction == MTHSmartAmmo_UseAction_Hook,
CastSpellByName == MTHSmartAmmo_CastSpellByName_Hook
end
local function MTHSmartAmmo_ForceHookGlobals()
if type(MTHSmartAmmo_CastSpell_Hook) == "function" and CastSpell ~= MTHSmartAmmo_CastSpell_Hook then
MTH_SA_CastSpell = CastSpell
CastSpell = MTHSmartAmmo_CastSpell_Hook
end
if type(MTHSmartAmmo_UseAction_Hook) == "function" and UseAction ~= MTHSmartAmmo_UseAction_Hook then
MTH_SA_UseAction = UseAction
UseAction = MTHSmartAmmo_UseAction_Hook
end
if type(MTHSmartAmmo_CastSpellByName_Hook) == "function" and CastSpellByName ~= MTHSmartAmmo_CastSpellByName_Hook then
MTH_SA_CastSpellByName = CastSpellByName
CastSpellByName = MTHSmartAmmo_CastSpellByName_Hook
end
end
MTH_SA = {}
MTH_SA_List = {}
MTH_SA_LastCheck = 0
MTH_SA_Tooltip = CreateFrame("GameTooltip", "MTH_SA_Tooltip", nil, "GameTooltipTemplate")
MTH_SA_Tooltip:Hide()
local _, class = UnitClass("player")
if class ~= "HUNTER" then
return
end
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
MTH_SA_AutoShot = nil
MTH_SA_LastSpell = nil
MTH_SA_UpdateInterval = 0.1
MTH_SA_Quantity = 0
MTH_SA_LastFallbackAttempt = 0
MTH_SA_LastKnownEquippedName = nil
MTH_SA_LastFallbackNotice = { key = nil, time = 0 }
local function MTHSmartAmmo_RefreshAmmoButtonDisplay()
local createButtons = getglobal("zButtonAmmo_CreateButtons")
local setupSizeAndPosition = getglobal("zButtonAmmo_SetupSizeAndPosition")
local ammoButton = getglobal("zButtonAmmo")
if type(createButtons) == "function" and ammoButton then
createButtons()
if type(setupSizeAndPosition) == "function" then
setupSizeAndPosition()
end
end
end
local function MTHSmartAmmo_ShowFallbackWarning(previousAmmo, newAmmo)
if not previousAmmo or previousAmmo == "" or not newAmmo or newAmmo == "" then
return
end
if previousAmmo == newAmmo then
return
end
local now = GetTime() or 0
local key = tostring(previousAmmo) .. "=>" .. tostring(newAmmo)
if MTH_SA_LastFallbackNotice.key == key and (now - (MTH_SA_LastFallbackNotice.time or 0)) < 1.0 then
return
end
MTH_SA_LastFallbackNotice.key = key
MTH_SA_LastFallbackNotice.time = now
local warning = "YOU RAN OUT OF " .. tostring(previousAmmo) .. ", I EQUIPPED " .. tostring(newAmmo) .. " !"
if MTH_SA_Print then
MTH_SA_Print(warning)
elseif DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
DEFAULT_CHAT_FRAME:AddMessage(warning)
end
if RaidWarningFrame and RaidNotice_AddMessage and ChatTypeInfo and ChatTypeInfo["RAID_WARNING"] then
RaidNotice_AddMessage(RaidWarningFrame, warning, ChatTypeInfo["RAID_WARNING"])
elseif UIErrorsFrame and UIErrorsFrame.AddMessage then
UIErrorsFrame:AddMessage(warning, 1.0, 0.15, 0.15, 1.0)
end
end
local function MTHSmartAmmo_HandleFallbackResult(previousAmmo)
local checkFrame = CreateFrame("Frame")
if not checkFrame then
return
end
checkFrame.elapsed = 0
checkFrame:SetScript("OnUpdate", function()
this.elapsed = (this.elapsed or 0) + (arg1 or 0)
if this.elapsed < 0.2 then
return
end
local equippedNow = MTH_SA_GetEquippedAmmoName()
if equippedNow and equippedNow ~= "" then
MTH_SA_LastKnownEquippedName = equippedNow
end
MTHSmartAmmo_RefreshAmmoButtonDisplay()
MTHSmartAmmo_ShowFallbackWarning(previousAmmo, equippedNow)
this:SetScript("OnUpdate", nil)
this:Hide()
end)
end
local function MTHSmartAmmo_TryFallbackEquip(reason)
if not MTH_SA_IsModuleEnabled() then
return
end
if not MTHSmartAmmo_IsSmartEnabled() then
return
end
if not MTHSmartAmmo_IsReloadEnabled() then
return
end
if MTH_SA_GetEquippedAmmoName() then
return
end
local now = GetTime() or 0
if MTH_SA_LastFallbackAttempt and (now - MTH_SA_LastFallbackAttempt) < 0.5 then
return
end
MTH_SA_LastFallbackAttempt = now
local previousAmmo = MTH_SA_GetEquippedAmmoName() or MTH_SA_LastKnownEquippedName
MTHSmartAmmo_Log("Fallback equip attempt reason=" .. tostring(reason or "unknown"))
if MTH_SA_Check() or MTH_SA_FindAmmo() then
MTH_SA_EquipAmmo()
MTHSmartAmmo_HandleFallbackResult(previousAmmo)
end
end
local frame = CreateFrame("Frame")
frame:RegisterEvent("START_AUTOREPEAT_SPELL")
frame:RegisterEvent("STOP_AUTOREPEAT_SPELL")
frame:RegisterEvent("SPELLCAST_INTERRUPTED")
frame:RegisterEvent("SPELLCAST_FAILED")
frame:RegisterEvent("SPELLCAST_STOP")
frame:RegisterEvent("SPELLCAST_DELAYED")
frame:SetScript("OnEvent", function()
if event == "START_AUTOREPEAT_SPELL" then
if MTHSmartAmmo_EnsureHooks then
MTHSmartAmmo_EnsureHooks("EVENT:START_AUTOREPEAT_SPELL")
end
local castHook, actionHook, byNameHook = MTHSmartAmmo_AreHooksInstalled()
MTHSmartAmmo_Log("EVENT START_AUTOREPEAT_SPELL smart=" .. tostring(MTHSmartAmmo_IsSmartEnabled()) .. " module=" .. tostring(MTH_SA_IsModuleEnabled()) .. " hooks=" .. tostring(castHook) .. "/" .. tostring(actionHook) .. "/" .. tostring(byNameHook))
MTH_SA_AutoShot = 1
MTHSmartAmmo_TryFallbackEquip("START_AUTOREPEAT_SPELL")
elseif event == "STOP_AUTOREPEAT_SPELL" then
MTHSmartAmmo_Log("EVENT STOP_AUTOREPEAT_SPELL")
MTH_SA_AutoShot = nil
elseif event == "SPELLCAST_START" then
--DEFAULT_CHAT_FRAME:AddMessage("SPELLCAST_START ", 0, 1, 1)
elseif event == "SPELLCAST_STOP" or event == "SPELLCAST_FAILED" or event == "SPELLCAST_INTERRUPTED" or event == "SPELLCAST_DELAYED" then
local castHook, actionHook, byNameHook = MTHSmartAmmo_AreHooksInstalled()
MTHSmartAmmo_Log("EVENT " .. tostring(event) .. " waitJunk=" .. tostring(MTH_SA_IsWaitingSwapJunk) .. " waitGood=" .. tostring(MTH_SA_IsWaitingSwapGood) .. " lastSpell=" .. tostring(MTH_SA_LastSpell) .. " smart=" .. tostring(MTHSmartAmmo_IsSmartEnabled()) .. " module=" .. tostring(MTH_SA_IsModuleEnabled()) .. " hooks=" .. tostring(castHook) .. "/" .. tostring(actionHook) .. "/" .. tostring(byNameHook))
if MTH_SA_IsWaitingSwapJunk then
MTHSmartAmmo_Log("EVENT swap request -> JUNK equipped=" .. tostring(MTH_SA_GetEquippedAmmoName()) .. " current=" .. tostring(MTH_SA.curname))
MTH_SA_EquipAmmo(1)
elseif MTH_SA_IsWaitingSwapGood then
MTHSmartAmmo_Log("EVENT swap request -> GOOD equipped=" .. tostring(MTH_SA_GetEquippedAmmoName()) .. " current=" .. tostring(MTH_SA.curname))
MTH_SA_EquipAmmo()
end
MTHSmartAmmo_Log("EVENT clear pending flags")
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
MTH_SA_LastSpell = nil
end
end)
frame:SetScript("OnUpdate", function(self, elapsed)
MTHSmartAmmo_HookEnsureElapsed = MTHSmartAmmo_HookEnsureElapsed + (elapsed or 0)
if MTHSmartAmmo_HookEnsureElapsed >= 0.5 then
MTHSmartAmmo_HookEnsureElapsed = 0
if MTH_SA_IsModuleEnabled() then
MTHSmartAmmo_InitializeHooks()
end
end
MTH_SA_CountEquippedAmmo()
if MTH_SA_Quantity == 0 and not MTH_SA_IsWaitingSwapJunk and not MTH_SA_IsWaitingSwapGood then
MTHSmartAmmo_TryFallbackEquip("OnUpdate-quantity-zero")
end
if MTH_SA_AmmoLastSwitch and (GetTime()-MTH_SA_AmmoLastSwitch > 0.5) and (MTH_SA_IsWaitingSwapJunk or MTH_SA_IsWaitingSwapGood) then
MTHSmartAmmo_Log("OnUpdate pending swap elapsed>0.5 equipped=" .. tostring(MTH_SA_GetEquippedAmmoName()) .. " waitJunk=" .. tostring(MTH_SA_IsWaitingSwapJunk) .. " waitGood=" .. tostring(MTH_SA_IsWaitingSwapGood))
if MTH_SA_IsWaitingSwapJunk then
MTHSmartAmmo_Log("OnUpdate swap request -> JUNK")
MTH_SA_EquipAmmo(1)
elseif MTH_SA_IsWaitingSwapGood then
MTHSmartAmmo_Log("OnUpdate swap request -> GOOD")
MTH_SA_EquipAmmo()
end
MTHSmartAmmo_Log("OnUpdate clear pending flags")
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
MTH_SA_LastSpell = nil
end
end)
function MTH_SA_CountEquippedAmmo()
local ammo = GetInventoryItemCount("player", 0)
local equippedName = MTH_SA_GetEquippedAmmoName()
if equippedName and equippedName ~= "" then
MTH_SA_LastKnownEquippedName = equippedName
end
if not ammo then
MTH_SA_Quantity=0
return
elseif ammo ~= MTH_SA_Quantity then
MTH_SA_Quantity = ammo
end
end
function MTH_SA_GetEquippedWeaponAmmoType()
local itemlink = GetInventoryItemLink("player", 18)
if not itemlink then return end
local _, _, itemid = string.find(itemlink, "item:(%d+)")
if not itemid then return end
local _, _, _, _, _, wpntype = GetItemInfo(itemid)
if wpntype == MTH_WEAPON_BOWS or wpntype == MTH_WEAPON_CROSSBOWS then
return "Arrows"
elseif wpntype == MTH_WEAPON_GUNS then
return "Bullets"
end
end
function MTH_SA_GetEquippedAmmoName()
MTH_SA_Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
if MTH_SA_Tooltip:SetInventoryItem("player", 0) then
return MTH_SA_TooltipTextLeft1:GetText()
end
return nil
end
function MTH_SA_GetContainerItemName(bag, slot)
if not (bag and slot) then return nil end
local item = GetContainerItemLink(bag, slot)
local _, _, name = string.find(item or "", "%[(.+)%]")
return name
end
function MTH_SA_EquipAmmo(junk)
MTHSmartAmmo_Log("EquipAmmo enter junk=" .. tostring(junk) .. " equipped=" .. tostring(MTH_SA_GetEquippedAmmoName()) .. " cur=" .. tostring(MTH_SA.curname) .. " junk=" .. tostring(MTH_SA.junkname))
if not MTH_SA_AmmoLastSwitch then MTH_SA_AmmoLastSwitch = GetTime() end
if not (MTH_SA_Check() or MTH_SA_FindAmmo()) then
MTHSmartAmmo_Log("EquipAmmo abort: cache invalid and FindAmmo failed")
return
end
local bag, slot
if junk then
--DEFAULT_CHAT_FRAME:AddMessage("Time= " .. GetTime()-MTH_SA_AmmoLastSwitch , 0, 1, 1)
if GetTime()-MTH_SA_AmmoLastSwitch > 0.5 then
--DEFAULT_CHAT_FRAME:AddMessage("JUNK ! GetTime > 0.5 | Equipped=" .. MTH_SA_GetEquippedAmmoName() .. ' | Current=' .. MTH_SA.curname , 0, 1, 1)
else
--DEFAULT_CHAT_FRAME:AddMessage("JUNK ! GetTime <= 0.5 | Equipped=" .. MTH_SA_GetEquippedAmmoName() .. ' | Current=' .. MTH_SA.curname , 0, 1, 1)
end
if MTH_SA_GetEquippedAmmoName() ~= MTH_SA.curname and GetTime()-MTH_SA_AmmoLastSwitch > 0.5 then
if not MTH_SA_FindAmmo() then
MTHSmartAmmo_Log("EquipAmmo abort: AMMO NOT FOUND during junk swap")
return
end
end
bag, slot = MTH_SA.junkbag, MTH_SA.junkslot
MTHSmartAmmo_Log("Swap GOOD->JUNK bag=" .. tostring(bag) .. " slot=" .. tostring(slot) .. " cur=" .. tostring(MTH_SA.curname) .. " curSlot=" .. tostring(MTH_SA.curslot) .. " junk=" .. tostring(MTH_SA.junkname) .. " junkSlot=" .. tostring(MTH_SA.junkslot))
else
bag, slot = MTH_SA.curbag, MTH_SA.curslot
MTHSmartAmmo_Log("Swap JUNK->GOOD bag=" .. tostring(bag) .. " slot=" .. tostring(slot) .. " cur=" .. tostring(MTH_SA.curname) .. " curSlot=" .. tostring(MTH_SA.curslot) .. " junk=" .. tostring(MTH_SA.junkname) .. " junkSlot=" .. tostring(MTH_SA.junkslot))
end
--UseContainerItem(bag, slot)
PickupContainerItem(bag,slot)
EquipCursorItem(0)
MTHSmartAmmo_Log("EquipCursorItem applied bag=" .. tostring(bag) .. " slot=" .. tostring(slot))
if junk then
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = 1
else
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
end
MTHSmartAmmo_Log("Pending flags set waitJunk=" .. tostring(MTH_SA_IsWaitingSwapJunk) .. " waitGood=" .. tostring(MTH_SA_IsWaitingSwapGood))
--PickupInventoryItem(0)
--AutoEquipCursorItem()
--EquipCursorItem(0)
MTH_SA_AmmoLastSwitch = GetTime()
end
function MTH_SA_FindAmmo()
MTHSmartAmmo_Log("FindAmmo start")
MTH_SA = {}
MTH_SA_List = {}
local ammotype = MTH_SA_GetEquippedWeaponAmmoType()
if not ammotype then
MTHSmartAmmo_Log("FindAmmo abort: no ranged weapon ammo type")
return
end
local curammo = MTH_SA_GetEquippedAmmoName()
if not curammo and not MTHSmartAmmo_IsReloadEnabled() then
MTHSmartAmmo_Log("FindAmmo abort: no equipped ammo and reload disabled")
return
end
MTHSmartAmmo_Log("FindAmmo type=" .. tostring(ammotype) .. " equipped=" .. tostring(curammo))
local ammolist = (ammotype == "Bullets" and MTH_AMMO_BULLET_RANK) or MTH_AMMO_ARROW_RANK or {}
MTH_SA_List = ammolist
local item, value
local junkvalue = 999
local goodvalue
for bag=4, 0, -1 do
for slot=GetContainerNumSlots(bag), 1, -1 do
item = MTH_SA_GetContainerItemName(bag, slot)
if item then
--DEFAULT_CHAT_FRAME:AddMessage("item = " .. item .. " | value = " .. ammolist[item], 0, 1, 1)
value = ammolist[item]
if value then
if not goodvalue and item == curammo then
MTH_SA.curvalue = value
MTH_SA.curname = item
MTH_SA.curbag = bag
MTH_SA.curslot = slot
goodvalue = value
--DEFAULT_CHAT_FRAME:AddMessage("goodvalue A = " .. value , 0, 1, 1)
if junkvalue == 1 then
return 1
end
end
if value < junkvalue then
MTH_SA.junkvalue = item
MTH_SA.junkname = item
MTH_SA.junkbag = bag
MTH_SA.junkslot = slot
junkvalue = value
--DEFAULT_CHAT_FRAME:AddMessage("junkvalue A = " .. value , 0, 1, 1)
if not curammo then
MTH_SA.curvalue = value
MTH_SA.curname = item
MTH_SA.curbag = bag
MTH_SA.curslot = slot
goodvalue = value
--DEFAULT_CHAT_FRAME:AddMessage("goodvalue B = " .. value , 0, 1, 1)
end
if junkvalue == 1 and goodvalue then
return 1
end
end
end
end
end
end
if not goodvalue or junkvalue > goodvalue then
MTHSmartAmmo_Log("FindAmmo failed: goodvalue=" .. tostring(goodvalue) .. " junkvalue=" .. tostring(junkvalue))
MTH_SA.error = 1
return
end
MTHSmartAmmo_Log("FindAmmo selected cur=" .. tostring(MTH_SA.curname) .. " junk=" .. tostring(MTH_SA.junkname) .. " curValue=" .. tostring(MTH_SA.curvalue) .. " junkValue=" .. tostring(junkvalue))
return 1
end
function MTH_SA_Check()
if not MTH_SA.error and MTH_SA.curname and MTH_SA.junkname then
if MTH_SA.curname == MTH_SA_GetContainerItemName(MTH_SA.curbag, MTH_SA.curslot) and
MTH_SA.junkname == MTH_SA_GetContainerItemName(MTH_SA.junkbag, MTH_SA.junkslot) then
return 1
end
end
end
MTHSmartAmmo_CastSpell_Hook = function(spell, tab)
if MTHSmartAmmo_InCastSpellHook then
if MTHSmartAmmo_OriginalCastSpell then
return MTHSmartAmmo_OriginalCastSpell(spell, tab)
end
return
end
MTHSmartAmmo_InCastSpellHook = true
if MTHSmartAmmo_IsSmartEnabled() then
local name = GetSpellName(spell, tab)
MTH_SA_LastSpell = name
MTHSmartAmmo_Log("HOOK CastSpell name=" .. tostring(name))
if name and MTH_AMMO_JUNKSHOT_SET and MTH_AMMO_JUNKSHOT_SET[name] then
MTHSmartAmmo_Log("HOOK CastSpell junk-shot detected name=" .. tostring(name))
if MTH_SA_Check() or MTH_SA_FindAmmo() then
MTHSmartAmmo_Log("HOOK CastSpell pre-swap -> junk")
MTH_SA_EquipAmmo(1)
end
end
end
local result
local original = MTH_SA_CastSpell
if original == MTHSmartAmmo_CastSpell_Hook or original == nil then
original = MTHSmartAmmo_OriginalCastSpell
end
if original then
result = original(spell, tab)
end
MTHSmartAmmo_InCastSpellHook = false
return result
end
MTHSmartAmmo_UseAction_Hook = function(slot, checkCursor, onSelf)
if MTHSmartAmmo_InUseActionHook then
if MTHSmartAmmo_OriginalUseAction then
return MTHSmartAmmo_OriginalUseAction(slot, checkCursor, onSelf)
end
return
end
MTHSmartAmmo_InUseActionHook = true
if not GetActionText(slot) and MTHSmartAmmo_IsSmartEnabled() then
MTH_SA_Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
MTH_SA_Tooltip:SetAction(slot)
local name = MTH_SA_TooltipTextLeft1:GetText()
MTH_SA_LastSpell = name
MTHSmartAmmo_Log("HOOK UseAction slot=" .. tostring(slot) .. " name=" .. tostring(name))
if name and MTH_AMMO_JUNKSHOT_SET and MTH_AMMO_JUNKSHOT_SET[name] then
MTHSmartAmmo_Log("HOOK UseAction junk-shot detected name=" .. tostring(name))
if MTH_SA_Check() or MTH_SA_FindAmmo() then
MTHSmartAmmo_Log("HOOK UseAction pre-swap -> junk")
MTH_SA_EquipAmmo(1)
end
end
end
local result
local original = MTH_SA_UseAction
if original == MTHSmartAmmo_UseAction_Hook or original == nil then
original = MTHSmartAmmo_OriginalUseAction
end
if original then
result = original(slot, checkCursor, onSelf)
end
MTHSmartAmmo_InUseActionHook = false
return result
end
MTHSmartAmmo_CastSpellByName_Hook = function(spell, onSelf)
if MTHSmartAmmo_InCastSpellByNameHook then
if MTHSmartAmmo_OriginalCastSpellByName then
return MTHSmartAmmo_OriginalCastSpellByName(spell, onSelf)
end
return
end
MTHSmartAmmo_InCastSpellByNameHook = true
local _, _, name = string.find(spell or "", "([%w%'%s]+)")
MTH_SA_LastSpell = name
MTHSmartAmmo_Log("HOOK CastSpellByName name=" .. tostring(name))
if name and MTHSmartAmmo_IsSmartEnabled() and MTH_AMMO_JUNKSHOT_SET and MTH_AMMO_JUNKSHOT_SET[name] then
MTHSmartAmmo_Log("HOOK CastSpellByName junk-shot detected name=" .. tostring(name))
if MTH_SA_Check() or MTH_SA_FindAmmo() then
MTHSmartAmmo_Log("HOOK CastSpellByName pre-swap -> junk")
MTH_SA_EquipAmmo(1)
end
end
local result
local original = MTH_SA_CastSpellByName
if original == MTHSmartAmmo_CastSpellByName_Hook or original == nil then
original = MTHSmartAmmo_OriginalCastSpellByName
end
if original then
result = original(spell, onSelf)
end
MTHSmartAmmo_InCastSpellByNameHook = false
return result
end
-- Defer hooking until after tables are initialized
MTHSmartAmmo_InitializeHooks = function()
if not MTH_SA_IsModuleEnabled() then
MTHSmartAmmo_Log("InitializeHooks skip: module disabled")
return
end
if CastSpell ~= MTHSmartAmmo_CastSpell_Hook then
MTH_SA_CastSpell = CastSpell
CastSpell = MTHSmartAmmo_CastSpell_Hook
MTHSmartAmmo_Log("InitializeHooks: CastSpell hook installed")
end
if UseAction ~= MTHSmartAmmo_UseAction_Hook then
MTH_SA_UseAction = UseAction
UseAction = MTHSmartAmmo_UseAction_Hook
MTHSmartAmmo_Log("InitializeHooks: UseAction hook installed")
end
if CastSpellByName ~= MTHSmartAmmo_CastSpellByName_Hook then
MTH_SA_CastSpellByName = CastSpellByName
CastSpellByName = MTHSmartAmmo_CastSpellByName_Hook
MTHSmartAmmo_Log("InitializeHooks: CastSpellByName hook installed")
end
end
MTHSmartAmmo_EnsureHooks = function(reason)
if not MTH_SA_IsModuleEnabled() then
return false
end
if not MTHSmartAmmo_IsSmartEnabled() then
return false
end
if MTHSmartAmmo_InitializeHooks then
local ok, err = pcall(MTHSmartAmmo_InitializeHooks)
if not ok then end
end
local castHook, actionHook, byNameHook = MTHSmartAmmo_AreHooksInstalled()
if castHook and actionHook and byNameHook then
return true
end
MTHSmartAmmo_ForceHookGlobals()
castHook, actionHook, byNameHook = MTHSmartAmmo_AreHooksInstalled()
return castHook and actionHook and byNameHook
end
-- Initialize hooks on module load
if not MTH_SA_MANAGED_HOOKS then
MTHSmartAmmo_InitializeHooks()
end
SLASH_MTHSmartAmmo1 = "/smartammo"
SlashCmdList["MTHSmartAmmo"] = function(msg)
if not MTH_SA_IsModuleEnabled() then
MTH_SA_Print("Smart Ammo is disabled while module 'smartammo' is disabled.")
return
end
local saved = MTHSmartAmmo_GetSaved()
if msg == "status" then
local castHook, actionHook, byNameHook = MTHSmartAmmo_AreHooksInstalled()
MTH_SA_Print("Smart Ammo status: smart=" .. tostring(saved["enabled"] and true or false) .. ", module=" .. tostring(MTH_SA_IsModuleEnabled()) .. ", hooks=" .. tostring(castHook) .. "/" .. tostring(actionHook) .. "/" .. tostring(byNameHook))
return
end
if saved["enabled"] then
MTHSmartAmmo_SetSmartEnabled(nil)
else
MTHSmartAmmo_SetSmartEnabled(1)
end
end
+8
View File
@@ -0,0 +1,8 @@
<!--
SmartAmmo Module Loader
Owns Smart Ammo runtime and hooks as a standalone MetaHunt module
-->
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Include file="module.lua"/>
<Include file="engine.lua"/>
</Ui>
+171
View File
@@ -0,0 +1,171 @@
------------------------------------------------------
-- MetaHunt: SmartAmmo Module
------------------------------------------------------
MTH_SA_MANAGED_HOOKS = true
local MTH_SmartAmmo = {
name = "smartammo",
enabled = true,
version = "1.0.3",
events = {
"VARIABLES_LOADED",
"PLAYER_ENTERING_WORLD",
},
}
local MTH_SA_BOUNDARY_KEY = "smartammo.core"
function MTH_SA_GetSavedTable(tableName)
if not MTH or not MTH.GetModuleCharSavedVariables then
if type(_G[tableName]) ~= "table" then
_G[tableName] = {}
end
return _G[tableName]
end
local moduleStore = MTH:GetModuleCharSavedVariables("smartammo")
if type(moduleStore) ~= "table" then
moduleStore = {}
end
if not moduleStore.legacy then
moduleStore.legacy = {}
end
if type(moduleStore.legacy[tableName]) ~= "table" then
moduleStore.legacy[tableName] = {}
end
if type(_G[tableName]) == "table" then
local legacyTable = moduleStore.legacy[tableName]
if not next(legacyTable) then
for key, value in pairs(_G[tableName]) do
legacyTable[key] = value
end
end
end
_G[tableName] = moduleStore.legacy[tableName]
return moduleStore.legacy[tableName]
end
function MTH_SA_IsModuleEnabled()
if MTH and MTH.IsModuleEnabled then
return MTH:IsModuleEnabled("smartammo", true) and true or false
end
return true
end
function MTH_SA_Print(msg, severity)
if MTH and MTH.Print then
MTH:Print(tostring(msg), severity)
return
end
if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
DEFAULT_CHAT_FRAME:AddMessage(tostring(msg))
end
end
local function MTH_SA_ApplySavedState()
if type(MTHSmartAmmo_SetSmartEnabled) ~= "function" then
return
end
local saved = MTH_SA_GetSavedTable("MTHSmartAmmo")
local moduleStore = MTH and MTH.GetModuleCharSavedVariables and MTH:GetModuleCharSavedVariables("smartammo") or nil
if type(moduleStore) == "table" then
if moduleStore.smartEnabled ~= nil then
saved["enabled"] = moduleStore.smartEnabled and 1 or false
end
if moduleStore.reloadEnabled ~= nil then
saved["reload"] = moduleStore.reloadEnabled and 1 or false
end
end
if saved["enabled"] == nil then
saved["enabled"] = 1
if type(moduleStore) == "table" then
moduleStore.smartEnabled = true
end
end
if saved["reload"] == nil and type(moduleStore) == "table" then
moduleStore.reloadEnabled = saved["reload"] ~= false
end
MTHSmartAmmo_SetSmartEnabled(saved["enabled"] and 1 or nil, 1)
if type(MTHSmartAmmo_SetReloadEnabled) == "function" then
MTHSmartAmmo_SetReloadEnabled(saved["reload"] ~= false and 1 or nil, 1)
end
if type(MTHSmartAmmo_EnsureHooks) == "function" then
MTHSmartAmmo_EnsureHooks("module-apply")
end
if not (MTH and MTH.CaptureHookBoundary) then
return
end
local castHook = getglobal("MTHSmartAmmo_CastSpell_Hook")
local useActionHook = getglobal("MTHSmartAmmo_UseAction_Hook")
local castByNameHook = getglobal("MTHSmartAmmo_CastSpellByName_Hook")
if type(castHook) ~= "function" or type(useActionHook) ~= "function" or type(castByNameHook) ~= "function" then
return
end
if CastSpell ~= castHook or UseAction ~= useActionHook or CastSpellByName ~= castByNameHook then
return
end
MTH:CaptureHookBoundary(MTH_SA_BOUNDARY_KEY, {
{ globalName = "CastSpell", originalName = "MTH_SA_CastSpell" },
{ globalName = "UseAction", originalName = "MTH_SA_UseAction" },
{ globalName = "CastSpellByName", originalName = "MTH_SA_CastSpellByName" },
})
end
local function MTH_SA_RestoreHooks()
if MTH and MTH.RestoreHookBoundary and MTH:RestoreHookBoundary(MTH_SA_BOUNDARY_KEY) then
return
end
local castHook = getglobal("MTHSmartAmmo_CastSpell_Hook")
local useActionHook = getglobal("MTHSmartAmmo_UseAction_Hook")
local castByNameHook = getglobal("MTHSmartAmmo_CastSpellByName_Hook")
if CastSpell == castHook and type(MTH_SA_CastSpell) == "function" then
CastSpell = MTH_SA_CastSpell
end
if UseAction == useActionHook and type(MTH_SA_UseAction) == "function" then
UseAction = MTH_SA_UseAction
end
if CastSpellByName == castByNameHook and type(MTH_SA_CastSpellByName) == "function" then
CastSpellByName = MTH_SA_CastSpellByName
end
end
function MTH_SmartAmmo:init()
MTH_SA_GetSavedTable("MTHSmartAmmo")
if self.enabled then
MTH_SA_ApplySavedState()
end
end
function MTH_SmartAmmo:setEnabled(enabled)
if enabled then
MTH_SA_ApplySavedState()
else
MTH_SA_RestoreHooks()
end
end
function MTH_SmartAmmo:onEvent(evt)
if not self.enabled then
return
end
if evt == "VARIABLES_LOADED" or evt == "PLAYER_ENTERING_WORLD" then
MTH_SA_ApplySavedState()
end
end
function MTH_SmartAmmo:cleanup()
self:setEnabled(false)
end
MTH:RegisterModule("smartammo", MTH_SmartAmmo)
+7
View File
@@ -0,0 +1,7 @@
<!--
MetaHunt Tooltips Module Loader
Standalone tooltip augmentation using MetaHunt data only.
-->
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Include file="module.lua"/>
</Ui>
File diff suppressed because it is too large Load Diff
+67
View File
@@ -0,0 +1,67 @@
Version 2.0 ----> Metahunt integration :-)
Version 1.12.14
September 15 - 1.12.14
-Fixed some translation errors
September 12 - 1.12.13
-ZMarkTarget() should no longer lockup some clients
-Fixed some translations
September 9 - 1.12.12
-Should've fixed the AntiDaze lockup, once and for all!
September 8 - 1.12.11
-/zammo has been changed back to a toggle ability
-Added Tame Beast, Beast Training, and Beast Lore to the pet buttons
-Added the function /script ZMarkTarget()
-Altered saved variables for easier patch transitions hopefully (current spell order will be reset)
August 26 - 1.12.10
-Using the ZTrap Key Binding will now put your pet in passive mode as well
-More French translations
-Split up the localization files for ease of use
August 25 - 1.12.9
-ZTrap buttons will now fade when you enter combat
-Added /zhunter to remind you of all of the other slash commands
-You can drag food on the ZPet button to feed your pet
August 25 - 1.12.8
-Fixed an error if you only had 1 of the button spells
August 24 - 1.12.7
-Woops... fixed AntiDaze even further
August 24 - 1.12.6
-Fixed the lock up issue with the AntiDaze feature
August 23 - 1.12.5
-Might've fixed some lockup issues
-Made the buttons overlap the user interface
-More translations
August 23 - 1.12.4
-Added some more translations
-Possibly fixed some button load errors
August 22 - 1.12.3
-Updated for Patch 1.12
-Should've removed the error for ZPet (Although the button probably still won't work because I still don't have the translations. Let me know if theres an error on the English client)
-Added some German translations
August 21 - 1.12.2
-Fixed the aspect bar
August 21 - 1.12.1
-Fixed a problem with the number of buttons displayed
August 21 - 1.12.0
-Altered (and hopefully fixed) all of the spell buttons
-Fixed Smart Ammo to work with all ammo
-Added a Pet Spell action bar
-Added an Anti-Daze feature
-Added a feature to automatically change the frenzy timer based on the boss
-Added a /script IsPetDead() command
+98
View File
@@ -0,0 +1,98 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Binding name="ZAspect Main" header="ZAspectHeader">
zButtonAspect_KeyBinding()
</Binding>
<Binding name="ZAspect 1" header="ZAspectHeader">
zButtonAspect_KeyBinding(1)
</Binding>
<Binding name="ZAspect 2" header="ZAspectHeader">
zButtonAspect_KeyBinding(2)
</Binding>
<Binding name="ZAspect 3" header="ZAspectHeader">
zButtonAspect_KeyBinding(3)
</Binding>
<Binding name="ZAspect 4" header="ZAspectHeader">
zButtonAspect_KeyBinding(4)
</Binding>
<Binding name="ZAspect 5" header="ZAspectHeader">
zButtonAspect_KeyBinding(5)
</Binding>
<Binding name="ZAspect 6" header="ZAspectHeader">
zButtonAspect_KeyBinding(6)
</Binding>
<Binding name="ZTrack Main" header="ZTrackHeader">
zButtonTrack_KeyBinding()
</Binding>
<Binding name="ZTrack 1" header="ZTrackHeader">
zButtonTrack_KeyBinding(1)
</Binding>
<Binding name="ZTrack 2" header="ZTrackHeader">
zButtonTrack_KeyBinding(2)
</Binding>
<Binding name="ZTrack 3" header="ZTrackHeader">
zButtonTrack_KeyBinding(3)
</Binding>
<Binding name="ZTrack 4" header="ZTrackHeader">
zButtonTrack_KeyBinding(4)
</Binding>
<Binding name="ZTrack 5" header="ZTrackHeader">
zButtonTrack_KeyBinding(5)
</Binding>
<Binding name="ZTrack 6" header="ZTrackHeader">
zButtonTrack_KeyBinding(6)
</Binding>
<Binding name="ZTrack 7" header="ZTrackHeader">
zButtonTrack_KeyBinding(7)
</Binding>
<Binding name="ZTrack 8" header="ZTrackHeader">
zButtonTrack_KeyBinding(8)
</Binding>
<Binding name="ZTrack 9" header="ZTrackHeader">
zButtonTrack_KeyBinding(9)
</Binding>
<Binding name="ZTrack 10" header="ZTrackHeader">
zButtonTrack_KeyBinding(10)
</Binding>
<Binding name="ZTrack 11" header="ZTrackHeader">
zButtonTrack_KeyBinding(11)
</Binding>
<Binding name="ZTrap Main" header="ZTrapHeader">
zButtonTrap_KeyBinding()
</Binding>
<Binding name="ZTrap 1" header="ZTrapHeader">
zButtonTrap_KeyBinding(1)
</Binding>
<Binding name="ZTrap 2" header="ZTrapHeader">
zButtonTrap_KeyBinding(2)
</Binding>
<Binding name="ZTrap 3" header="ZTrapHeader">
zButtonTrap_KeyBinding(3)
</Binding>
<Binding name="ZTrap 4" header="ZTrapHeader">
zButtonTrap_KeyBinding(4)
</Binding>
<Binding name="ZTrap 5" header="ZTrapHeader">
zButtonTrap_KeyBinding(5)
</Binding>
<Binding name="ZPet Main" header="ZPetHeader">
zButtonPet_KeyBinding()
</Binding>
<Binding name="ZPet 1" header="ZPetHeader">
zButtonPet_KeyBinding(1)
</Binding>
<Binding name="ZPet 2" header="ZPetHeader">
zButtonPet_KeyBinding(2)
</Binding>
<Binding name="ZPet 3" header="ZPetHeader">
zButtonPet_KeyBinding(3)
</Binding>
<Binding name="ZPet 4" header="ZPetHeader">
zButtonPet_KeyBinding(4)
</Binding>
<Binding name="ZPet 5" header="ZPetHeader">
zButtonPet_KeyBinding(5)
</Binding>
<Binding name="ZPet 6" header="ZPetHeader">
zButtonPet_KeyBinding(6)
</Binding>
</Ui>
+237
View File
@@ -0,0 +1,237 @@
-- Deferred initialization for ZHunterMod
-- This file runs at the END after all frames are created and all Lua is parsed
-- Wrap ZSpellButton_CreateChildren to automatically initialize child buttons
local original_CreateChildren = ZSpellButton_CreateChildren
function ZSpellButton_CreateChildren(parent, name, count)
-- Call original function to create children
original_CreateChildren(parent, name, count)
-- Now initialize each child button's properties
if parent and name and count then
for i = 1, count do
local button = getglobal(name .. i)
if button then
local oldThis = this
local oldEvent = event
this = button
ZSpellButton_OnLoad()
this = oldThis
event = oldEvent
end
end
end
end
local function ZHunterMod_RunButtonInit(frame, onEventFunc)
if not (frame and onEventFunc) then
return
end
local oldThis = this
local oldEvent = event
this = frame
ZSpellButtonParent_OnLoad()
event = "VARIABLES_LOADED"
onEventFunc()
this = oldThis
event = oldEvent
end
local function ZHunterMod_LogDeferred(msg)
local deferredDebug = _G and _G["MTH_ZH_DEFERRED_DEBUG"]
if not (MTH and MTH.debug and deferredDebug) then
return
end
MTH_ZH_Print("[ZHUNTER] " .. tostring(msg), "error")
end
local function ZHunterMod_EnsureButtonFrame(buttonName)
local frame = getglobal(buttonName)
if frame then
return frame
end
if type(CreateFrame) ~= "function" then
return nil
end
local created = CreateFrame("CheckButton", buttonName, UIParent, "ZSpellButtonTemplate")
if created then
created:ClearAllPoints()
if buttonName == "zButtonAspect" then
created:SetPoint("CENTER", UIParent, "CENTER", -60, 0)
elseif buttonName == "zButtonAmmo" then
created:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
elseif buttonName == "zButtonTrack" then
created:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
elseif buttonName == "zButtonTrap" then
created:SetPoint("CENTER", UIParent, "CENTER", 60, 0)
elseif buttonName == "zButtonPet" then
created:SetPoint("CENTER", UIParent, "CENTER", 0, 60)
elseif buttonName == "zButtonMounts" then
created:SetPoint("TOP", UIParent, "TOP", 0, -410)
elseif buttonName == "zButtonCompanions" then
created:SetPoint("TOP", UIParent, "TOP", 0, -464)
elseif buttonName == "zButtonToys" then
created:SetPoint("TOP", UIParent, "TOP", 0, -518)
else
created:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
end
ZHunterMod_LogDeferred("DeferredInit: created missing frame " .. tostring(buttonName))
end
return created
end
function ZHunterMod_DeferredInit()
-- Check if frames were created
local pet = ZHunterMod_EnsureButtonFrame("zButtonPet")
local aspect = ZHunterMod_EnsureButtonFrame("zButtonAspect")
local track = ZHunterMod_EnsureButtonFrame("zButtonTrack")
local trap = ZHunterMod_EnsureButtonFrame("zButtonTrap")
local ammo = ZHunterMod_EnsureButtonFrame("zButtonAmmo")
local mounts = ZHunterMod_EnsureButtonFrame("zButtonMounts")
local companions = ZHunterMod_EnsureButtonFrame("zButtonCompanions")
local toys = ZHunterMod_EnsureButtonFrame("zButtonToys")
ZHunterMod_LogDeferred("DeferredInit: Pet=" .. tostring(pet ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Aspect=" .. tostring(aspect ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Track=" .. tostring(track ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Trap=" .. tostring(trap ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Ammo=" .. tostring(ammo ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Mounts=" .. tostring(mounts ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Companions=" .. tostring(companions ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Toys=" .. tostring(toys ~= nil))
-- Continue with all frames that exist; do not hard-abort when one optional frame is missing.
local missing = {}
if not pet then table.insert(missing, "Pet") end
if not aspect then table.insert(missing, "Aspect") end
if not track then table.insert(missing, "Track") end
if not trap then table.insert(missing, "Trap") end
if not ammo then table.insert(missing, "Ammo") end
if not mounts then table.insert(missing, "Mounts") end
if not companions then table.insert(missing, "Companions") end
if not toys then table.insert(missing, "Toys") end
if table.getn(missing) > 0 then
MTH_ZH_Print("[ZHUNTER] Warning: missing frames: " .. table.concat(missing, ", ") .. ". Continuing with available buttons.", "error")
end
if not (pet or aspect or track or trap or ammo or mounts or companions or toys) then
MTH_ZH_Print("zhunter buttons not created - check for addon conflicts!", "error")
return
end
-- Initialize each button by calling template OnLoad then button-specific OnEvent
-- We set up global 'this' and 'event' for the OnEvent functions (Lua 5.0 style)
local initialized = 0
local function ZHunterMod_SafeRunButtonInit(frame, onEventFunc, buttonTag)
if not (frame and onEventFunc) then
return false
end
local ok, err = pcall(ZHunterMod_RunButtonInit, frame, onEventFunc)
if not ok then
MTH_ZH_Print("[ZHUNTER] DeferredInit failed for " .. tostring(buttonTag) .. ": " .. tostring(err), "error")
return false
end
return true
end
if pet and zButtonPet_OnEvent then
if ZHunterMod_SafeRunButtonInit(pet, zButtonPet_OnEvent, "zButtonPet") then
initialized = initialized + 1
end
end
if aspect and zButtonAspect_OnEvent then
if ZHunterMod_SafeRunButtonInit(aspect, zButtonAspect_OnEvent, "zButtonAspect") then
initialized = initialized + 1
end
end
if track and zButtonTrack_OnEvent then
if ZHunterMod_SafeRunButtonInit(track, zButtonTrack_OnEvent, "zButtonTrack") then
initialized = initialized + 1
end
end
if trap and zButtonTrap_OnEvent then
if ZHunterMod_SafeRunButtonInit(trap, zButtonTrap_OnEvent, "zButtonTrap") then
initialized = initialized + 1
end
end
if ammo and zButtonAmmo_OnEvent then
if ZHunterMod_SafeRunButtonInit(ammo, zButtonAmmo_OnEvent, "zButtonAmmo") then
initialized = initialized + 1
end
end
if mounts and zButtonMounts_OnEvent then
if ZHunterMod_SafeRunButtonInit(mounts, zButtonMounts_OnEvent, "zButtonMounts") then
initialized = initialized + 1
end
end
if companions and zButtonCompanions_OnEvent then
if ZHunterMod_SafeRunButtonInit(companions, zButtonCompanions_OnEvent, "zButtonCompanions") then
initialized = initialized + 1
end
end
if toys and zButtonToys_OnEvent then
if ZHunterMod_SafeRunButtonInit(toys, zButtonToys_OnEvent, "zButtonToys") then
initialized = initialized + 1
end
end
if initialized <= 0 then
MTH_ZH_Print("zhunter buttons not created - check for addon conflicts!", "error")
return
end
if type(MTH_ZH_OnDeferredInitComplete) == "function" then
local ok, err = pcall(MTH_ZH_OnDeferredInitComplete)
if not ok and MTH_DebugFrame and MTH_DebugFrame.AddError then
MTH_ZH_Print("[ZHUNTER] DeferredInit callback error: " .. tostring(err), "error")
end
end
end
-- Smart initialization that handles both initial load and reload
local function TryInitialize()
-- Check if spell data is available (hunters get aspect of monkey at level 4)
-- If player is low level without spells, we still want to initialize
local _, _, _, numSpells = GetNumSpellTabs()
-- Only initialize if we have some basic game data ready
if numSpells and numSpells > 0 then
ZHunterMod_DeferredInit()
return true
end
return false
end
-- Try immediate initialization (works for /reload)
if not TryInitialize() then
-- If immediate init failed, we're on initial game load
-- Set up event-based initialization
local initFrame = CreateFrame("Frame")
initFrame:RegisterEvent("PLAYER_LOGIN")
initFrame:SetScript("OnEvent", function()
if event == "PLAYER_LOGIN" then
-- Delay slightly to ensure spell book is ready
local elapsed = 0
initFrame:SetScript("OnUpdate", function()
elapsed = elapsed + arg1
if elapsed >= 0.3 then
initFrame:SetScript("OnUpdate", nil)
ZHunterMod_DeferredInit()
-- Master options will be initialized on-demand
end
end)
end
end)
else
-- Immediate init succeeded, do not initialize master options here
-- It will be created on-demand when first opened
end
+325
View File
@@ -0,0 +1,325 @@
if not ZHunterMod_Saved then
ZHunterMod_Saved = {}
end
BINDING_HEADER_ZAspectHeader = "ZAspect Buttons"
BINDING_HEADER_ZTrackHeader = "ZTrack Buttons"
BINDING_HEADER_ZTrapHeader = "ZTrap Buttons"
BINDING_HEADER_ZPetHeader = "ZPet Buttons"
function ZHunterMod_AlignButtons()
zButtonTrack:ClearAllPoints()
zButtonTrack:SetPoint("TOP", zButtonAspect, "BOTTOM", 0, -15)
zButtonTrap:ClearAllPoints()
zButtonTrap:SetPoint("TOP", zButtonTrack, "BOTTOM", 0, -15)
if AutoStripDisplay then
AutoStripDisplay:ClearAllPoints()
AutoStripDisplay:SetPoint("TOP", zButtonTrap, "BOTTOM", 0, -10)
end
end
-- ////////////////////////////////////////////////////////////////
-- ENGLISH
-- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
ZHUNTER_MAGMADAR = "Magmadar"
ZHUNTER_FLAMEGORE = "Flamegore"
ZHUNTER_CHROMMAGUS = "Chrommagus"
ZHUNTER_HUHURAN = "Princess Huhuran"
ZHUNTER_GLUTH = "Gluth"
ZHUNTER_YOU = "You"
ZHUNTER_HUNTER = "Hunter"
ZHUNTER_BOWS = "Bows"
ZHUNTER_CROSSBOWS = "Crossbows"
ZHUNTER_GUNS = "Guns"
ZHUNTER_AFFLICTED_DAZED = "(.+) (.+) afflicted by Dazed"
ZHUNTER_BULLETS_LIGHT = "Light Shot"
ZHUNTER_BULLETS_CRAFTLIGHT = "Crafted Light Shot"
ZHUNTER_BULLETS_FLASH = "Flash Pellet"
ZHUNTER_BULLETS_HEAVY = "Heavy Shot"
ZHUNTER_BULLETS_PEBBLE = "Smooth Pebble"
ZHUNTER_BULLETS_CRAFTHEAVY = "Crafted Heavy Shot"
ZHUNTER_BULLETS_SOLID = "Solid Shot"
ZHUNTER_BULLETS_CRAFTSOLID = "Crafted Solid Shot"
ZHUNTER_BULLETS_EXPLODING = "Exploding Shot"
ZHUNTER_BULLETS_MITHRILSLUG = "Hi-impact Mithril Slugs"
ZHUNTER_BULLETS_ACCURATE = "Accurate Slugs"
ZHUNTER_BULLETS_GYROSHOT = "Mithril Gyro-Shot"
ZHUNTER_BULLETS_ICETHREADED = "Ice Threaded Bullet"
ZHUNTER_BULLETS_THORIUM = "Thorium Shells"
ZHUNTER_BULLETS_ROCKSHARD = "Rockshard Pellets"
ZHUNTER_BULLETS_CANNONBALL = "Miniature Cannon Balls"
ZHUNTER_ARROWS_ROUGH = "Rough Arrow"
ZHUNTER_ARROWS_SHARP = "Sharp Arrow"
ZHUNTER_ARROWS_RAZOR = "Razor Arrow"
ZHUNTER_ARROWS_FEATHER = "Feathered Arrow"
ZHUNTER_ARROWS_PRECISION = "Precision Arrow"
ZHUNTER_ARROWS_JAGGED = "Jagged Arrow"
ZHUNTER_ARROWS_ICETHREADED = "Ice Threaded Arrow"
ZHUNTER_ARROWS_THORIUM = "Thorium Headed Arrow"
ZHUNTER_ARROWS_DOOMSHOT = "Doomshot"
ZHUNTER_RAPIDFIRE = "Rapid Fire"
ZHUNTER_IMPROVEDHAWK = "Quick Shots"
ZHUNTER_BERSERKING = "Berserking"
ZHUNTER_AUTO = "Auto Shot"
ZHUNTER_AIMED = "Aimed Shot"
ZHUNTER_SERPENT = "Serpent Sting"
ZHUNTER_SCORPID = "Scorpid Sting"
ZHUNTER_VIPER = "Viper Sting"
ZHUNTER_ARCANE = "Arcane Shot"
ZHUNTER_CONCUSSIVE = "Concussive Shot"
ZHUNTER_DISTRACTING = "Distracting Shot"
ZHUNTER_VOLLEY = "Volley"
ZHUNTER_TRACK_HUMANOIDS = "Track Humanoids"
ZHUNTER_TRACK_HIDDEN = "Track Hidden"
ZHUNTER_TRACK_BEASTS = "Track Beasts"
ZHUNTER_TRACK_ELEMENTALS = "Track Elementals"
ZHUNTER_TRACK_DEMONS = "Track Demons"
ZHUNTER_TRACK_DRAGONKIN = "Track Dragonkin"
ZHUNTER_TRACK_UNDEAD = "Track Undead"
ZHUNTER_TRACK_GIANTS = "Track Giants"
ZHUNTER_TRACK_MINERALS = "Find Minerals"
ZHUNTER_TRACK_HERBS = "Find Herbs"
ZHUNTER_TRACK_TREASURE = "Find Treasure"
ZHUNTER_TRAP_FREEZING = "Freezing Trap"
ZHUNTER_TRAP_FROST = "Frost Trap"
ZHUNTER_TRAP_IMMOLATION = "Immolation Trap"
ZHUNTER_TRAP_EXPLOSIVE = "Explosive Trap"
ZHUNTER_ASPECT_HAWK = "Aspect of the Hawk"
ZHUNTER_ASPECT_MONKEY = "Aspect of the Monkey"
ZHUNTER_ASPECT_CHEETAH = "Aspect of the Cheetah"
ZHUNTER_ASPECT_BEAST = "Aspect of the Beast"
ZHUNTER_ASPECT_PACK = "Aspect of the Pack"
ZHUNTER_ASPECT_WILD = "Aspect of the Wild"
ZHUNTER_PET_EYES = "Eyes of the Beast"
ZHUNTER_PET_DISMISS = "Dismiss Pet"
ZHUNTER_PET_MEND = "Mend Pet"
ZHUNTER_PET_FEED = "Feed Pet"
ZHUNTER_PET_CALL = "Call Pet"
ZHUNTER_PET_REVIVE = "Revive Pet"
ZHUNTER_PET_LORE = "Beast Lore"
ZHUNTER_PET_TRAINING = "Beast Training"
ZHUNTER_PET_TAMING = "Tame Beast"
--------------------------------------------------------------------
-- Meta 09 Feb 2026
-- Twow spells addition
ZHUNTER_PET_POSITION = "Pet Command: Take Position"
ZHUNTER_ASPECT_WOLF = "Aspect of the Wolf"
ZHUNTER_ASPECT_VIPER = "Aspect of the Viper"
ZHUNTER_STEADY = "Steady Shot"
ZHUNTER_BAITED = "Baited Shot"
ZHUNTER_INTIMIDATION = "Intimidation"
ZHUNTER_KILLCOMMAND = "Kill Command"
ZHUNTER_CARVE = "Carve"
ZHUNTER_LACERATE = "Lacerate"
--------------------------------------------------------------------
-- ////////////////////////////////////////////////////////////////
-- FRENCH
-- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
-- � = \195\136 � = \195\168
-- � = \195\137 � = \195\169
-- � = \195\138 � = \195\170
-- � = \195\143 � = \195\175
-- � = \195\135 � = \195\167
if ( GetLocale() == "frFR" ) then
--ZHUNTER_MAGMADAR = "Magmadar"
--ZHUNTER_FLAMEGORE = "Flamegore"
--ZHUNTER_CHROMMAGUS = "Chrommagus"
--ZHUNTER_HUHURAN = "Princess Huhuran"
--ZHUNTER_GLUTH = "Gluth"
ZHUNTER_YOU = "Vous"
ZHUNTER_HUNTER = "Chasseur"
--ZHUNTER_BOWS = "Bows"
ZHUNTER_CROSSBOWS = "Arbal\195\168tes"
ZHUNTER_GUNS = "Armes\195\160feus"
--ZHUNTER_AFFLICTED_DAZED = "(.+) (.+) afflicted by Dazed"
ZHUNTER_BULLETS_LIGHT = "Balle l\195\169g\195\168re"
ZHUNTER_BULLETS_CRAFTLIGHT = "Balle l\195\169g\195\168re fabriqu\195\169e"
ZHUNTER_BULLETS_FLASH = "Bille d'\195\169clair"
ZHUNTER_BULLETS_HEAVY = "Balle lourde"
ZHUNTER_BULLETS_PEBBLE = "Caillou lisse"
ZHUNTER_BULLETS_CRAFTHEAVY = "Balle lourde fabriqu\195\169e"
ZHUNTER_BULLETS_SOLID = "Balle dure"
ZHUNTER_BULLETS_CRAFTSOLID = "Balle dure fabriqu\195\169e"
ZHUNTER_BULLETS_EXPLODING = "Balle explosive"
ZHUNTER_BULLETS_MITHRILSLUG = "Balle per\195\167antes en mithril"
ZHUNTER_BULLETS_ACCURATE = "Balles de pr\195\169cision"
ZHUNTER_BULLETS_GYROSHOT = "Balle gyroscopique en mithril"
ZHUNTER_BULLETS_ICETHREADED = "Balle de glace"
ZHUNTER_BULLETS_THORIUM = "Obus en thorium"
ZHUNTER_BULLETS_ROCKSHARD = "Balle de roche"
ZHUNTER_BULLETS_CANNONBALL = "Boulet de canon miniature"
ZHUNTER_ARROWS_ROUGH = "Fl\195\168che grossi\195\168re"
ZHUNTER_ARROWS_SHARP = "Fl\195\168che pointue"
ZHUNTER_ARROWS_RAZOR = "Fl\195\168che rasoir"
ZHUNTER_ARROWS_FEATHER = "Fl\195\168che \195\160 plumes"
ZHUNTER_ARROWS_PRECISION = "Fl\195\168che de pr\195\169cision"
ZHUNTER_ARROWS_JAGGED = "Fl\195\168che barbel\195\169e"
ZHUNTER_ARROWS_ICETHREADED = "Fl\195\168che de glace"
ZHUNTER_ARROWS_THORIUM = "Fl\195\168ches \195\160 pointe de thorium"
ZHUNTER_ARROWS_DOOMSHOT = "Tir maudit"
ZHUNTER_RAPIDFIRE = "Tir rapide"
--ZHUNTER_IMPROVEDHAWK = "Quick Shots"
--ZHUNTER_BERSERKING = "Berserking"
ZHUNTER_AUTO = "Tir automatique"
ZHUNTER_AIMED = "Vis\195\169e"
ZHUNTER_SERPENT = "Morsure de serpent"
ZHUNTER_SCORPID = "Piq\195\187re de scorpide"
ZHUNTER_VIPER = "Morsure de vip\195\168re"
ZHUNTER_ARCANE = "Tir des arcanes"
ZHUNTER_CONCUSSIVE = "Trait de choc"
ZHUNTER_DISTRACTING = "Trait provocateur"
ZHUNTER_TRACK_HUMANOIDS = "Pistage des humano\195\175des"
ZHUNTER_TRACK_HIDDEN = "Pistage des camoufl\195\169s"
ZHUNTER_TRACK_BEASTS = "Pistage des b\195\170tes"
ZHUNTER_TRACK_ELEMENTALS = "Pistage des \195\169l\195\169mentaires"
ZHUNTER_TRACK_DEMONS = "Pistage des d\195\169mons"
ZHUNTER_TRACK_DRAGONKIN = "Pistage des draconiens"
ZHUNTER_TRACK_UNDEAD = "Pistage des morts-vivants"
ZHUNTER_TRACK_GIANTS = "Pistage des g\195\169ants"
--ZHUNTER_TRACK_MINERALS = "Find Minerals"
--ZHUNTER_TRACK_HERBS = "Find Herbs"
--ZHUNTER_TRACK_TREASURE = "Find Treasure"
ZHUNTER_TRAP_FREEZING = "Pi\195\168ge givrant"
ZHUNTER_TRAP_FROST = "Pi\195\168ge de givre"
ZHUNTER_TRAP_IMMOLATION = "Pi\195\168ge d'Immolation"
ZHUNTER_TRAP_EXPLOSIVE = "Pi\195\168ge explosif"
ZHUNTER_ASPECT_HAWK = "Aspect du faucon"
ZHUNTER_ASPECT_MONKEY = "Aspect du singe"
ZHUNTER_ASPECT_CHEETAH = "Aspect du gu\195\169pard"
ZHUNTER_ASPECT_BEAST = "Aspect de la b\195\170te"
ZHUNTER_ASPECT_PACK = "Aspect de la meute"
ZHUNTER_ASPECT_WILD = "Aspect de la nature"
ZHUNTER_PET_EYES = "oeil de la b\195\170te"
--ZHUNTER_PET_DISMISS = "Dismiss Pet"
--ZHUNTER_PET_MEND = "Mend Pet"
--ZHUNTER_PET_FEED = "Feed Pet"
--ZHUNTER_PET_CALL = "Call Pet"
--ZHUNTER_PET_REVIVE = "Revive Pet"
end
-- ////////////////////////////////////////////////////////////////
-- GERMAN
-- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
-- � = /195/164
-- � = /195/188
-- � = /195/182
if ( GetLocale() == "deDE" ) then
ZHUNTER_MAGMADAR = "Magmadar"
ZHUNTER_FLAMEGORE = "Flammenmaul"
ZHUNTER_CHROMMAGUS = "Chrommagus"
ZHUNTER_HUHURAN = "Prinzessin Huhuran"
--ZHUNTER_GLUTH = "Gluth"
ZHUNTER_YOU = "Ihr"
ZHUNTER_HUNTER = "J\195\164ger"
ZHUNTER_BOWS = "B\195\182gen"
ZHUNTER_CROSSBOWS = "Armbr\195\188ste"
ZHUNTER_GUNS = "Schusswaffen"
ZHUNTER_AFFLICTED_DAZED = "(.+) (.+) ersch\195\188ttert"
ZHUNTER_BULLETS_LIGHT = "Leichtes Geschoss"
ZHUNTER_BULLETS_CRAFTLIGHT = "Gefertigtes leichtes Geschoss"
ZHUNTER_BULLETS_FLASH = "Blitzk\195\188gelchen"
ZHUNTER_BULLETS_HEAVY = "Schweres Geschoss"
ZHUNTER_BULLETS_PEBBLE = "Glatter Kiesel"
ZHUNTER_BULLETS_CRAFTHEAVY = "Gefertigtes schweres Geschoss"
ZHUNTER_BULLETS_SOLID = "Robustes Geschoss"
ZHUNTER_BULLETS_CRAFTSOLID = "Gefertigtes robustes Geschoss"
ZHUNTER_BULLETS_EXPLODING = "Explosivgeschoss"
ZHUNTER_BULLETS_MITHRILSLUG = "Stark einschlagende Mithrilpatronen"
ZHUNTER_BULLETS_ACCURATE = "Genaue Patronen"
ZHUNTER_BULLETS_GYROSHOT = "Gyro-Mithrilgeschoss"
ZHUNTER_BULLETS_ICETHREADED = "Eisgewirkte Kugel"
ZHUNTER_BULLETS_THORIUM = "Thoriumpatronen"
ZHUNTER_BULLETS_ROCKSHARD = "Felssplitterk\195\188gelchen"
ZHUNTER_BULLETS_CANNONBALL = "Miniaturkanonenkugeln"
ZHUNTER_ARROWS_ROUGH = "Rauer Pfeil"
ZHUNTER_ARROWS_SHARP = "Scharfer Pfeil"
ZHUNTER_ARROWS_RAZOR = "Schneidenpfeil"
ZHUNTER_ARROWS_FEATHER = "Gefiederter Pfeil"
ZHUNTER_ARROWS_PRECISION = "Pr\195\164zisionspfeil"
ZHUNTER_ARROWS_JAGGED = "Gezackter Pfeil"
ZHUNTER_ARROWS_ICETHREADED = "Eisgewirkter Pfeil"
ZHUNTER_ARROWS_THORIUM = "Thoriumpfeile"
ZHUNTER_ARROWS_DOOMSHOT = "Verdammnisgeschoss"
ZHUNTER_RAPIDFIRE = "Schnellfeuer"
ZHUNTER_IMPROVEDHAWK = "Schnelle Sch\195\188sse"
ZHUNTER_BERSERKING = "Berserker"
ZHUNTER_AUTO = "Autom. Schuss"
ZHUNTER_AIMED = "Gezielter Schuss"
ZHUNTER_SERPENT = "Schlangenbiss"
ZHUNTER_SCORPID = "Skorpidstich"
ZHUNTER_VIPER = "Vipernbiss"
ZHUNTER_ARCANE = "Arkaner Schuss"
ZHUNTER_CONCUSSIVE = "Ersch\195\188tternder Schuss"
ZHUNTER_DISTRACTING = "Ablenkender Schuss"
ZHUNTER_TRACK_HUMANOIDS = "Humanoide aufsp\195\188ren"
ZHUNTER_TRACK_HIDDEN = "Verborgenes aufsp\195\188ren"
ZHUNTER_TRACK_BEASTS = "Wildtiere aufsp\195\188ren"
ZHUNTER_TRACK_ELEMENTALS = "Elementare aufsp\195\188ren"
ZHUNTER_TRACK_DEMONS = "D\195\164monen aufsp\195\188ren"
ZHUNTER_TRACK_DRAGONKIN = "Drachkin aufsp\195\188ren"
ZHUNTER_TRACK_UNDEAD = "Untote aufsp\195\188ren"
ZHUNTER_TRACK_GIANTS = "Riesen aufsp\195\188ren"
ZHUNTER_TRACK_MINERALS = "Mineraliensuche"
ZHUNTER_TRACK_HERBS = "Kr\195\164utersuche"
ZHUNTER_TRACK_TREASURE = "Schatzsucher"
ZHUNTER_TRAP_FREEZING = "Eisk\195\164ltefalle"
ZHUNTER_TRAP_FROST = "Frostfalle"
ZHUNTER_TRAP_IMMOLATION = "Feuerbrandfalle"
ZHUNTER_TRAP_EXPLOSIVE = "Sprengfalle"
ZHUNTER_ASPECT_HAWK = "Aspekt des Falken"
ZHUNTER_ASPECT_MONKEY = "Aspekt des Affen"
ZHUNTER_ASPECT_CHEETAH = "Aspekt des Geparden"
ZHUNTER_ASPECT_BEAST = "Aspekt des Wildtiers"
ZHUNTER_ASPECT_PACK = "Aspekt des Rudels"
ZHUNTER_ASPECT_WILD = "Aspekt der Wildnis"
ZHUNTER_PET_EYES = "Augen des Wildtiers"
ZHUNTER_PET_DISMISS = "Tier freigeben"
ZHUNTER_PET_MEND = "Tier heilen"
ZHUNTER_PET_FEED = "Tier f\195\188ttern"
ZHUNTER_PET_CALL = "Tier rufen"
ZHUNTER_PET_REVIVE = "Tier wiederbeleben"
ZHUNTER_PET_TAMING = "Wildtier z\195\164hmen"
ZHUNTER_PET_TRAINING = "Wildtierausbildung"
ZHUNTER_PET_POSITION = "Pet Command: Take Position"
end
+149
View File
@@ -0,0 +1,149 @@
if not ZHunterMod_Saved then
ZHunterMod_Saved = {}
end
BINDING_HEADER_ZAspectHeader = "ZAspect Buttons"
BINDING_HEADER_ZTrackHeader = "ZTrack Buttons"
BINDING_HEADER_ZTrapHeader = "ZTrap Buttons"
BINDING_HEADER_ZPetHeader = "ZPet Buttons"
BINDING_HEADER_ZAmmoHeader = "ZAmmo Buttons"
BINDING_HEADER_ZMountsHeader = "ZMounts Buttons"
BINDING_HEADER_ZCompanionsHeader = "ZCompanions Buttons"
BINDING_HEADER_ZToysHeader = "ZToys Buttons"
ZHunterModTooltip = CreateFrame("GameTooltip", "ZHunterModTooltip", nil, "GameTooltipTemplate")
function MTH_ZH_IsModuleEnabled()
if not (MTH and MTH.IsModuleEnabled) then
return true
end
return MTH:IsModuleEnabled("zhunter", true)
end
function MTH_ZH_GetSavedRoot()
if type(ZHunterMod_Saved) ~= "table" then
ZHunterMod_Saved = {}
end
return ZHunterMod_Saved
end
function MTH_ZH_GetSavedTable(key)
local root = MTH_ZH_GetSavedRoot()
if type(key) ~= "string" or key == "" then
return root
end
if type(root[key]) ~= "table" then
root[key] = {}
end
return root[key]
end
local function MTH_ZH_MigrateButtonSavedKeys_Replace()
local root = MTH_ZH_GetSavedRoot()
if type(root) ~= "table" then
return
end
local mapping = {
{"ZHunterButtonAspect", "zButtonAspect"},
{"ZHunterButtonTrack", "zButtonTrack"},
{"ZHunterButtonTrap", "zButtonTrap"},
{"ZHunterButtonAmmo", "zButtonAmmo"},
{"ZHunterButtonPet", "zButtonPet"},
{"ZHunterButtonMounts", "zButtonMounts"},
{"ZHunterButtonCompanions", "zButtonCompanions"},
{"ZHunterButtonToys", "zButtonToys"},
}
for i = 1, table.getn(mapping) do
local oldKey = mapping[i][1]
local newKey = mapping[i][2]
if root[oldKey] ~= nil then
root[newKey] = root[oldKey]
root[oldKey] = nil
end
end
end
MTH_ZH_MigrateButtonSavedKeys_Replace()
function MTH_ZH_Print(message, severity)
if type(MTH_Log) == "function" then
MTH_Log(message, severity)
return
end
if MTH and MTH.Print then
MTH:Print(message, severity)
return
end
if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
DEFAULT_CHAT_FRAME:AddMessage("[MetaHunt] " .. tostring(message or ""), 1, 0.9, 0.3)
end
end
function MTH_ZH_HandleDisabledSlash(message, tableKey, fieldKey)
if MTH_ZH_IsModuleEnabled() then
return false
end
if type(tableKey) == "string" and tableKey ~= "" then
if fieldKey then
local tbl = MTH_ZH_GetSavedTable(tableKey)
tbl[fieldKey] = nil
else
local root = MTH_ZH_GetSavedRoot()
root[tableKey] = nil
end
end
if message then
MTH_ZH_Print(message)
end
return true
end
function ZHunterMod_AlignButtons()
zButtonAmmo:ClearAllPoints()
zButtonAmmo:SetPoint("TOP", zButtonAspect, "BOTTOM", 0, -15)
zButtonTrack:ClearAllPoints()
zButtonTrack:SetPoint("TOP", zButtonAmmo, "BOTTOM", 0, -15)
zButtonTrap:ClearAllPoints()
zButtonTrap:SetPoint("TOP", zButtonTrack, "BOTTOM", 0, -15)
zButtonPet:ClearAllPoints()
zButtonPet:SetPoint("TOP", zButtonTrap, "BOTTOM", 0, -15)
zButtonMounts:ClearAllPoints()
zButtonMounts:SetPoint("TOP", zButtonPet, "BOTTOM", 0, -15)
zButtonCompanions:ClearAllPoints()
zButtonCompanions:SetPoint("TOP", zButtonMounts, "BOTTOM", 0, -15)
zButtonToys:ClearAllPoints()
zButtonToys:SetPoint("TOP", zButtonCompanions, "BOTTOM", 0, -15)
if AutoStripDisplay then
AutoStripDisplay:ClearAllPoints()
AutoStripDisplay:SetPoint("TOP", zButtonToys, "BOTTOM", 0, -10)
end
end
function ZMarkTarget()
if not MTH_ZH_IsModuleEnabled() then
return
end
if not UnitExists("target") then return end
for i=1, 40 do
if not UnitDebuff("target", i) then break end
ZHunterModTooltip:SetOwner(UIParent, "ANCHOR_NONE")
ZHunterModTooltip:SetUnitDebuff("target", i)
local spell = ZHunterModTooltipTextLeft1:GetText()
if spell == ZHUNTER_HUNTERSMARK then
return
end
end
CastSpellByName(ZHUNTER_HUNTERSMARK)
return 1
end
SLASH_ZHunterMod1 = "/zhunter"
SlashCmdList["ZHunterMod"] = function(msg)
MTH_ZH_Print("Possible Slash Commands: \"/zammo\", \"/zaspect\", \"/ztrack\", \"/ztrap\", \"/zpet\", \"/zmounts\", \"/zcompanions\", \"/zminipets\", \"/ztoys\", \"/zstrip\", \"/zantidaze\"")
end
+508
View File
@@ -0,0 +1,508 @@
-- MAX_SPELLS = 1024
local function ZSpellButton_ApplySavedVisibility(parent, foundCount)
if not parent then
return
end
local shouldShow = true
if foundCount and tonumber(foundCount) then
if tonumber(foundCount) <= 0 then
shouldShow = false
end
end
if type(MTH_ZH_GetSavedTable) == "function" and parent.name then
local saved = MTH_ZH_GetSavedTable(parent.name)
if saved then
if saved["enabled"] == false or saved["enabled"] == 0 then
shouldShow = false
end
if saved["parent"] and saved["parent"]["hide"] then
shouldShow = false
end
end
end
if shouldShow then
parent:Show()
else
parent:Hide()
end
end
function ZSpellButton_SetButtons(parent, spells)
--DEFAULT_CHAT_FRAME:AddMessage(" Parent = "..parent.name, 0, 1, 1)
if not (parent and parent.count and parent.name and spells) then return end
parent.spells = spells
if type(parent.customSetButtons) == "function" then
local customFound = parent.customSetButtons(parent, spells)
ZSpellButton_ApplySavedVisibility(parent, customFound)
return customFound
end
if not GetSpellName(1, "spell") then
parent:RegisterEvent("SPELLS_CHANGED")
return -1
end
local spell, finished, temp
local info = {}
-- Find All Spell IDs
for i=1, MAX_SPELLS do
spell = GetSpellName(i, "spell")
if not spell or finished then
break
end
finished = 1
for i2=1, table.getn(spells) do
if not info[i2] then
finished = nil
if spells[i2] == spell then
temp = i
while spells[i2] == spell do
temp = temp + 1
spell = GetSpellName(temp, "spell")
end
info[i2] = (temp-1)
break
end
end
end
end
-- Hide All Children
for i=1, parent.count do
local child = getglobal(parent.name..i)
child:Hide()
child.id = nil
child.icon = nil
child.isspell = nil
end
local button
local count = 1
-- Set Children IDs
for i, v in info do
if count > parent.count then break end
button = getglobal(parent.name..count)
button.id = v
button.isspell=1
ZSpellButton_UpdateButton(button)
button:Show()
-- Set The Parent To The First Spell
if count == 1 then
parent.id = v
parent.isspell=1
ZSpellButton_UpdateButton(parent)
parent:Enable()
end
count = count + 1
end
local foundCount = count - 1
ZSpellButton_ApplySavedVisibility(parent, foundCount)
return foundCount
end
local function ZHunterMod_UpdateButtonCount(parent, found)
return
end
function ZSpellButton_SetExpandDirection(parent, direction)
local button = getglobal(parent.name.."1")
local offset = parent:GetWidth() / 36
local circleVisible = true
if type(MTH_ZH_GetSavedTable) == "function" and parent and parent.name then
local saved = MTH_ZH_GetSavedTable(parent.name)
if saved and saved["parent"] and saved["parent"]["circle"] ~= nil then
circleVisible = saved["parent"]["circle"] and true or false
end
end
if parent and parent.circle then
if circleVisible then
parent.circle:Show()
else
parent.circle:Hide()
end
end
if circleVisible then
offset = offset * 5
else
offset = offset * 3
end
button:ClearAllPoints()
if direction == "TOP" then
button:SetPoint("BOTTOM", parent, "TOP", 0, offset)
elseif direction == "BOTTOM" then
button:SetPoint("TOP", parent, "BOTTOM", 0, -1 * offset)
elseif direction == "LEFT" then
button:SetPoint("RIGHT", parent, "LEFT", -1 * offset, 0)
elseif direction == "RIGHT" then
button:SetPoint("LEFT", parent, "RIGHT", offset, 0)
end
end
function ZSpellButton_ArrangeChildren(parent, rows, count, horizontal, vertical)
if not (parent and parent.count and parent.name) then return end
local left, right, top, bottom = "LEFT", "RIGHT", "TOP", "BOTTOM"
local xoffset = parent:GetWidth() / 36
xoffset = xoffset * 3
local yoffset = -1 * xoffset
if horizontal then
left, right = "RIGHT", "LEFT"
xoffset = xoffset * -1
end
if vertical then
top, bottom = "BOTTOM", "TOP"
yoffset = yoffset * -1
end
if count > parent.count then
count = parent.count
end
local cols = ceil(count / rows)
local temp = 1
local button
for i=2, parent.count do
button = getglobal(parent.name..i)
if i > count then
button:Hide()
else
if button.id then
button:Show()
end
button:ClearAllPoints()
if temp >= cols then
button:SetPoint(top, getglobal(parent.name..(i-temp)), bottom, 0, yoffset)
temp = 1
else
button:SetPoint(left, getglobal(parent.name..(i-1)), right, xoffset, 0)
temp = temp + 1
end
end
end
end
function ZSpellButton_SetSize(parent, size, setChildren)
local bgscale = 64 / 36
local cdscale = 0.75 / 36
if setChildren then
local button
for i=1, parent.count do
button = getglobal(parent.name..i)
button:SetHeight(size)
button:SetWidth(size)
button.background:SetWidth(size * bgscale)
button.background:SetHeight(size * bgscale)
button.cooldown:SetModelScale(size * cdscale)
end
else
local cscale = 100/36
local cxscale = 20 / 36
local cyscale = -22 / 36
local circleVisible = true
if type(MTH_ZH_GetSavedTable) == "function" and parent and parent.name then
local saved = MTH_ZH_GetSavedTable(parent.name)
if saved and saved["parent"] and saved["parent"]["circle"] ~= nil then
circleVisible = saved["parent"]["circle"] and true or false
end
end
parent:SetHeight(size)
parent:SetWidth(size)
parent.background:SetWidth(size * bgscale)
parent.background:SetHeight(size * bgscale)
parent.cooldown:SetModelScale(size * cdscale)
parent.circle:SetWidth(size * cscale)
parent.circle:SetHeight(size * cscale)
parent.circle:SetPoint("CENTER", size * cxscale, size * cyscale)
if circleVisible then
parent.circle:Show()
else
parent.circle:Hide()
end
end
end
function ZSpellButton_UpdateButton(button)
local texture
if not button then
button = this
end
if not (button.id and button.icontexture) then
return
end
texture = button.icon or GetSpellTexture(button.id, "spell")
button.icontexture:SetTexture(texture)
button.icontexture:Show()
end
function ZSpellButton_UpdateCooldown(button)
if not button then
button = this
end
if not button.id or not button.isspell then return end
local start, duration, enable = GetSpellCooldown(button.id, "spell")
CooldownFrame_SetTimer(button.cooldown, start, duration, enable)
if not button.customcolor then
local r, g, b = 1.0, 1.0, 1.0
if enable ~= 1 then
r, g, b = 0.4, 0.4, 0.4
end
button.icontexture:SetVertexColor(r, g, b)
end
end
function ZSpellButton_CreateChildren(parent, name, count)
if not (parent and name and count) then return end
parent.children = CreateFrame("Frame", parent:GetName().."Children", UIParent)
parent.count = count
parent.name = name
local button
for i=1, count do
button = CreateFrame("CheckButton", parent.name..i, parent.children, "ZSpellButtonChildTemplate")
button.parent = parent
end
if type(ZSpellButton_ApplyChildrenExpanded) == "function" then
ZSpellButton_ApplyChildrenExpanded(parent)
end
end
function ZSpellButton_OnLoad()
this:RegisterEvent("SPELL_UPDATE_COOLDOWN")
this:RegisterForClicks("LeftButtonUp", "RightButtonUp")
local name = this:GetName()
this.icontexture = getglobal(name.."IconTexture")
this.cooldown = getglobal(name.."Cooldown")
this.background = getglobal(name.."Background")
end
function ZSpellButton_OnEvent()
if event == "SPELL_UPDATE_COOLDOWN" then
ZSpellButton_UpdateCooldown()
end
end
local function ZSpellButton_EnsureParentFlags(parent)
if not (parent and parent.name) then
return
end
local saved = MTH_ZH_GetSavedTable(parent.name)
if parent.tooltip == nil and saved["tooltip"] ~= nil then
parent.tooltip = saved["tooltip"] and true or false
end
if parent.hideonclick == nil and saved["children"] and saved["children"]["hideonclick"] ~= nil then
parent.hideonclick = saved["children"]["hideonclick"] and true or false
end
end
function ZSpellButton_GetChildrenExpanded(parent)
if not (parent and parent.name) then
return true
end
local saved = MTH_ZH_GetSavedTable(parent.name)
if not saved["children"] then
saved["children"] = {}
end
if saved["children"]["expanded"] == nil then
saved["children"]["expanded"] = 1
end
local expanded = saved["children"]["expanded"] ~= false and saved["children"]["expanded"] ~= 0
return expanded
end
function ZSpellButton_SetChildrenExpanded(parent, expanded)
if not (parent and parent.name) then
return
end
local saved = MTH_ZH_GetSavedTable(parent.name)
if not saved["children"] then
saved["children"] = {}
end
if expanded then
saved["children"]["expanded"] = 1
if parent.children then
parent.children:Show()
end
else
saved["children"]["expanded"] = 0
if parent.children then
parent.children:Hide()
end
end
end
function ZSpellButton_ApplyChildrenExpanded(parent)
if not (parent and parent.children) then
return
end
if ZSpellButton_GetChildrenExpanded(parent) then
parent.children:Show()
else
parent.children:Hide()
end
end
function ZSpellButton_OnEnter()
ZSpellButton_EnsureParentFlags(this.parent)
if this.parent.tooltip then
GameTooltip:SetOwner(this, "ANCHOR_TOPRIGHT")
if this.isspell then
GameTooltip:SetSpell(this.id, "spell")
else
GameTooltip:SetText(this.ammocount .. " x "..this.ammolink, 1, 1, 1)
--GameTooltip:AddLine("Q="..this.ammocount)
end
end
end
function ZSpellButton_OnClick()
ZSpellButton_EnsureParentFlags(this.parent)
this:SetChecked(0)
if type(this.parent.beforeclick) == "function" then
if this.parent.beforeclick(this) then
return
end
end
if this.isspell then
CastSpell(this.id, "spell")
else
PickupContainerItem(this.ammobag,this.ammoslot)
EquipCursorItem(0)
-- Update parent button immediately to show newly equipped ammo
if not this.isspell then
this.parent.id = this.ammoid
this.parent.icon = this.icon
this.parent.isspell = nil
this.parent.ammoname = this.ammoname
this.parent.ammobrol = this.ammobrol
this.parent.ammoqual = this.ammoqual
this.parent.ammolvl = this.ammolvl
this.parent.ammotype = this.ammotype
this.parent.ammobag = this.ammobag
this.parent.ammoslot = this.ammoslot
this.parent.ammoid = this.ammoid
this.parent.ammolink = this.ammolink
this.parent.ammocount = this.ammocount
if type(this.parent.customUpdateButton) == "function" then
this.parent.customUpdateButton(this.parent)
else
ZSpellButton_UpdateButton(this.parent)
end
end
end
if type(this.parent.afterclick) == "function" then
if this.parent.afterclick(this) then
return
end
end
if this.parent.hideonclick then
if type(ZSpellButton_SetChildrenExpanded) == "function" then
ZSpellButton_SetChildrenExpanded(this.parent, false)
elseif this.parent.children then
this.parent.children:Hide()
end
end
end
function ZSpellButtonParent_OnLoad()
this:RegisterEvent("SPELL_UPDATE_COOLDOWN")
this:RegisterEvent("LEARNED_SPELL_IN_TAB")
this:RegisterForDrag("LeftButton")
this:RegisterForClicks("LeftButtonUp", "RightButtonUp")
local name = this:GetName()
this.icontexture = getglobal(name.."IconTexture")
this.cooldown = getglobal(name.."Cooldown")
this.background = getglobal(name.."Background")
this.circle = getglobal(name.."Circle")
-- Keep enabled so empty buttons can be moved on low-level characters.
this:Enable()
end
function ZSpellButtonParent_OnEvent()
if event == "SPELL_UPDATE_COOLDOWN" then
ZSpellButton_UpdateCooldown()
elseif event == "LEARNED_SPELL_IN_TAB" then
if this.name and this.count and this.spells then
local found = ZSpellButton_SetButtons(this, this.spells)
ZHunterMod_UpdateButtonCount(this, found)
end
elseif event == "SPELLS_CHANGED" then
this.found = ZSpellButton_SetButtons(this, this.spells)
ZHunterMod_UpdateButtonCount(this, this.found)
if this.found == 0 then
this:Hide()
end
if this.found > -1 then
this:UnregisterEvent("SPELLS_CHANGED")
end
end
end
function ZSpellButtonParent_OnEnter(frame)
if not frame then
frame = this
end
ZSpellButton_EnsureParentFlags(frame)
if frame.tooltip and frame.id then
GameTooltip:SetOwner(frame, "ANCHOR_TOPLEFT")
local msg, rank
if frame.isspell then
msg, rank = GetSpellName(frame.id, "spell")
if string.len(rank) > 0 then
msg = msg.." ("..rank..")"
end
else
msg = frame.ammoname
end
GameTooltip:SetText(msg, 1, 1, 1)
GameTooltip:AddLine("Alt+Drag To Move This Button")
GameTooltip:Show()
end
end
function ZSpellButtonParent_OnClick()
ZSpellButton_EnsureParentFlags(this)
this:SetChecked(0)
if arg1 == "RightButton" then
local showChildren = not this.children:IsVisible()
if type(ZSpellButton_SetChildrenExpanded) == "function" then
ZSpellButton_SetChildrenExpanded(this, showChildren)
elseif showChildren then
this.children:Show()
else
this.children:Hide()
end
else
if type(this.beforeclick) == "function" then
if this.beforeclick(this) then
return
end
end
if this.isspell then
if not this.id then
return
end
CastSpell(this.id, "spell")
else
if not (this.ammobag and this.ammoslot) then
return
end
PickupContainerItem(this.ammobag,this.ammoslot)
EquipCursorItem(0)
end
if type(this.afterclick) == "function" then
if this.afterclick(this) then
return
end
end
if this.hideonclick then
if type(ZSpellButton_SetChildrenExpanded) == "function" then
ZSpellButton_SetChildrenExpanded(this, false)
elseif this.children then
this.children:Hide()
end
end
end
end
+124
View File
@@ -0,0 +1,124 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<CheckButton name="ZSpellButtonTemplate" toplevel="true" frameStrata="MEDIUM" movable="true" parent="UIParent" virtual="true">
<Size>
<AbsDimension x="36" y="36"/>
</Size>
<Layers>
<Layer level="BORDER">
<Texture name="$parentIconTexture" setAllPoints="true" hidden="true"/>
</Layer>
<Layer level="ARTWORK">
<Texture name="$parentBackground" file="Interface\Buttons\UI-Quickslot2">
<Size>
<AbsDimension x="64" y="64"/>
</Size>
<Anchors>
<Anchor point="CENTER">
<Offset>
<AbsDimension x="0" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Texture>
</Layer>
</Layers>
<Frames>
<Model name="$parentCooldown" inherits="CooldownFrameTemplate"/>
<Frame setAllPoints="true">
<Layers>
<Layer level="OVERLAY">
<Texture name="$parentCircle" file="Interface\Minimap\MiniMap-TrackingBorder">
<Size>
<AbsDimension x="100" y="100"/>
</Size>
<Anchors>
<Anchor point="CENTER">
<Offset>
<AbsDimension x="20" y="-22"/>
</Offset>
</Anchor>
</Anchors>
</Texture>
</Layer>
</Layers>
</Frame>
</Frames>
<Scripts>
<OnClick>
ZSpellButtonParent_OnClick()
</OnClick>
<OnEnter>
ZSpellButtonParent_OnEnter()
</OnEnter>
<OnLeave>
GameTooltip:Hide()
</OnLeave>
<OnMouseUp>
if ( this.isMoving ) then
this:StopMovingOrSizing()
this.isMoving = false
end
</OnMouseUp>
<OnDragStart>
if IsAltKeyDown() then
this:StartMoving()
this.isMoving = true
end
</OnDragStart>
<OnDragStop>
this:StopMovingOrSizing()
this.isMoving = false
</OnDragStop>
</Scripts>
<NormalTexture file=""/>
<PushedTexture file="Interface\Buttons\UI-Quickslot-Depress"/>
<HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD"/>
<CheckedTexture file="Interface\Buttons\CheckButtonHilight" alphaMode="ADD"/>
</CheckButton>
<CheckButton name="ZSpellButtonChildTemplate" toplevel="true" frameStrata="MEDIUM" movable="true" hidden="true" virtual="true">
<Size>
<AbsDimension x="36" y="36"/>
</Size>
<Layers>
<Layer level="BORDER">
<Texture name="$parentIconTexture" setAllPoints="true" hidden="true"/>
</Layer>
<Layer level="ARTWORK">
<Texture name="$parentBackground" file="Interface\Buttons\UI-Quickslot2">
<Size>
<AbsDimension x="64" y="64"/>
</Size>
<Anchors>
<Anchor point="CENTER">
<Offset>
<AbsDimension x="0" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Texture>
</Layer>
</Layers>
<Frames>
<Model name="$parentCooldown" inherits="CooldownFrameTemplate"/>
</Frames>
<Scripts>
<OnClick>
ZSpellButton_OnClick()
</OnClick>
<OnEnter>
ZSpellButton_OnEnter()
</OnEnter>
<OnLeave>
GameTooltip:Hide()
</OnLeave>
</Scripts>
<NormalTexture file=""/>
<PushedTexture file="Interface\Buttons\UI-Quickslot-Depress"/>
<HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD"/>
<CheckedTexture file="Interface\Buttons\CheckButtonHilight" alphaMode="ADD"/>
</CheckButton>
</Ui>
+50
View File
@@ -0,0 +1,50 @@
<!--
zhunter Module Loader
Loads all zhunter addon code and wraps it in the MTH module system
-->
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<!-- Load module wrapper first so module registration is always available -->
<Include file="module.lua"/>
<!-- Load localization first -->
<Include file="Localization.lua"/>
<!-- Load button template XML first (creates frame definitions) -->
<Include file="ZSpellButtonTemplate.xml"/>
<!-- Load individual button XMLs (creates all button frame instances) -->
<Include file="zButtonAspect.xml"/>
<Include file="zButtonTrack.xml"/>
<Include file="zButtonTrap.xml"/>
<Include file="zButtonAmmo.xml"/>
<Include file="zButtonPet.xml"/>
<Include file="zButtonMounts.xml"/>
<Include file="zButtonCompanions.xml"/>
<Include file="zButtonToys.xml"/>
<!-- Load main ZHunterMod.lua FIRST so ZHunterMod_Saved table exists before button files use it -->
<Include file="ZHunterMod.lua"/>
<!-- NOW load all Lua files (which use the frames created above) -->
<Include file="ZSpellButtonTemplate.lua"/>
<!-- Load individual button Lua files -->
<Include file="zButtonAspect.lua"/>
<Include file="zButtonTrack.lua"/>
<Include file="zButtonTrap.lua"/>
<Include file="zButtonAmmo.lua"/>
<Include file="zButtonPet.lua"/>
<Include file="zButtonMounts.lua"/>
<Include file="zButtonCompanions.lua"/>
<Include file="zButtonToys.lua"/>
<!-- Deferred initialization - runs LAST after all parsing is complete -->
<Include file="DeferredInit.lua"/>
</Ui>
+326
View File
@@ -0,0 +1,326 @@
------------------------------------------------------
-- MetaHunt: zhunter Module Wrapper
-- Modern module abstraction for the zhunter addon
------------------------------------------------------
MTH_ZH_MANAGED_HOOKS = true
local MTH_ZHunter = {
name = "zhunter",
enabled = true,
version = "1.0.3",
events = {
"VARIABLES_LOADED",
"PLAYER_ENTERING_WORLD",
"MTH_PET_LIVE_STATE_CHANGED",
},
features = {
aspect = true,
tracking = true,
traps = true,
ammo = true,
pet = true,
}
}
local function MTH_ZH_Log(msg)
if not (MTH and MTH.debug) then
return
end
MTH:Print("[ZH MODULE] " .. tostring(msg), "debug")
end
local MTH_ZH_PostLoginRestoreFrame = nil
local MTH_ZH_BootstrapFrame = nil
local MTH_ZH_SyncSavedVariables
local MTH_ZH_SetButtonsVisible
local MTH_ZH_SetAuxFramesVisible
local MTH_ZH_RestoreRuntimeFeatureFlags
local MTH_ZH_ApplyEnabledRuntimeState
local MTH_ZH_QueuePostLoginRestore
local function MTH_ZH_ApplyDefaultWidgetSpawnLayoutOnce()
local savedRoot = nil
if type(MTH_ZH_GetSavedRoot) == "function" then
savedRoot = MTH_ZH_GetSavedRoot()
elseif type(ZHunterMod_Saved) == "table" then
savedRoot = ZHunterMod_Saved
end
if type(savedRoot) ~= "table" then
return false
end
if savedRoot["_mth_widget_spawn_layout_v1"] then
return false
end
local orderedButtons = {
"zButtonAspect",
"zButtonAmmo",
"zButtonTrack",
"zButtonTrap",
"zButtonPet",
"zButtonMounts",
"zButtonCompanions",
"zButtonToys",
}
local startY = -140
local stepY = -54
local orderedCount = table.getn(orderedButtons)
for i = 1, orderedCount do
if not getglobal(orderedButtons[i]) then
MTH_ZH_Log("skipped one-time default widget spawn layout (missing frame: " .. tostring(orderedButtons[i]) .. ")")
return false
end
end
for i = 1, orderedCount do
local buttonName = orderedButtons[i]
local button = getglobal(buttonName)
if button then
button:ClearAllPoints()
button:SetPoint("TOP", UIParent, "TOP", 0, startY + ((i - 1) * stepY))
end
end
savedRoot["_mth_widget_spawn_layout_v1"] = 1
MTH_ZH_Log("applied one-time default widget spawn layout")
return true
end
function MTH_ZH_OnDeferredInitComplete()
if not (MTH and MTH.IsModuleEnabled and MTH:IsModuleEnabled("zhunter", true)) then
if MTH_ZH_SetButtonsVisible then
MTH_ZH_SetButtonsVisible(false)
end
if MTH_ZH_SetAuxFramesVisible then
MTH_ZH_SetAuxFramesVisible(false)
end
MTH_ZH_Log("deferred init applied disabled-state hide")
return
end
MTH_ZH_SyncSavedVariables()
MTH_ZH_ApplyDefaultWidgetSpawnLayoutOnce()
MTH_ZH_RestoreRuntimeFeatureFlags()
MTH_ZH_QueuePostLoginRestore("deferred-init")
end
MTH_ZH_QueuePostLoginRestore = function(tag)
if not MTH_ZH_PostLoginRestoreFrame then
MTH_ZH_PostLoginRestoreFrame = CreateFrame("Frame", "MTH_ZH_PostLoginRestoreFrame")
if not MTH_ZH_PostLoginRestoreFrame then
return
end
end
MTH_ZH_PostLoginRestoreFrame._mthElapsed = 0
MTH_ZH_PostLoginRestoreFrame:SetScript("OnUpdate", function()
this._mthElapsed = (this._mthElapsed or 0) + (arg1 or 0)
if this._mthElapsed < 0.2 then
return
end
this:SetScript("OnUpdate", nil)
if not (MTH and MTH.IsModuleEnabled and MTH:IsModuleEnabled("zhunter", true)) then
return
end
MTH_ZH_SyncSavedVariables()
MTH_ZH_RestoreRuntimeFeatureFlags()
MTH_ZH_Log("post-login restore applied: " .. tostring(tag))
end)
end
local function MTH_ZH_EnsureBootstrapRestoreFrame()
if MTH_ZH_BootstrapFrame then
return MTH_ZH_BootstrapFrame
end
MTH_ZH_BootstrapFrame = CreateFrame("Frame", "MTH_ZH_BootstrapRestoreFrame")
if not MTH_ZH_BootstrapFrame then
return nil
end
MTH_ZH_BootstrapFrame:RegisterEvent("VARIABLES_LOADED")
MTH_ZH_BootstrapFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
MTH_ZH_BootstrapFrame:SetScript("OnEvent", function()
if not (MTH and MTH.IsModuleEnabled and MTH:IsModuleEnabled("zhunter", true)) then
return
end
if event == "VARIABLES_LOADED" then
MTH_ZH_SyncSavedVariables()
return
end
if event == "PLAYER_ENTERING_WORLD" then
MTH_ZH_ApplyEnabledRuntimeState("bootstrap:" .. tostring(event))
MTH_ZH_QueuePostLoginRestore("bootstrap:" .. tostring(event))
this:UnregisterAllEvents()
this:SetScript("OnEvent", nil)
end
end)
return MTH_ZH_BootstrapFrame
end
MTH_ZH_ApplyEnabledRuntimeState = function(source)
MTH_ZH_SyncSavedVariables()
MTH_ZH_SetButtonsVisible(true)
MTH_ZH_SetAuxFramesVisible(true)
MTH_ZH_RestoreRuntimeFeatureFlags()
end
MTH_ZH_SyncSavedVariables = function()
if not MTH or not MTH.GetModuleCharSavedVariables then
return
end
local moduleStore = MTH:GetModuleCharSavedVariables("zhunter")
if type(ZHunterMod_Saved) == "table" then
if MTH_CharSavedVariables and MTH_CharSavedVariables.modules then
MTH_CharSavedVariables.modules.zhunter = ZHunterMod_Saved
end
elseif type(moduleStore) == "table" then
ZHunterMod_Saved = moduleStore
end
end
MTH_ZH_SetButtonsVisible = function(visible)
local buttonNames = {
"zButtonAspect",
"zButtonTrack",
"zButtonTrap",
"zButtonAmmo",
"zButtonPet",
"zButtonMounts",
"zButtonCompanions",
"zButtonToys",
}
local function MTH_ZH_SetChildButtonsVisible(parentButton, parentName, show)
if not parentButton then
return
end
local showChildren = false
if show then
if type(ZSpellButton_GetChildrenExpanded) == "function" then
showChildren = ZSpellButton_GetChildrenExpanded(parentButton)
else
showChildren = true
end
end
if parentButton.children then
if showChildren then
parentButton.children:Show()
else
parentButton.children:Hide()
end
end
if not parentButton.count then
return
end
local baseName = parentButton.name or parentName
if not baseName then
return
end
for index = 1, parentButton.count do
local child = getglobal(baseName .. index)
if child then
if showChildren then
if child.id then
child:Show()
else
child:Hide()
end
else
child:Hide()
end
end
end
end
for _, buttonName in ipairs(buttonNames) do
local button = getglobal(buttonName)
if button then
MTH_ZH_SetChildButtonsVisible(button, buttonName, visible)
if visible then
button:Show()
else
button:Hide()
end
end
end
end
MTH_ZH_SetAuxFramesVisible = function(visible)
return
end
local function MTH_ZH_ClearRuntimeFeatureFlags()
return
end
MTH_ZH_RestoreRuntimeFeatureFlags = function()
return
end
function MTH_ZHunter:init()
-- ZHunterMod initializes via the game events
-- Features: Aspect, Tracking, Trap, Ammo, Pet management buttons
MTH_ZH_SyncSavedVariables()
MTH_ZH_EnsureBootstrapRestoreFrame()
if self.enabled then
MTH_ZH_SyncSavedVariables()
end
end
function MTH_ZHunter:setEnabled(enabled)
MTH_ZH_SyncSavedVariables()
if enabled then
MTH_ZH_EnsureBootstrapRestoreFrame()
MTH_ZH_ApplyEnabledRuntimeState("setEnabled")
else
MTH_ZH_ClearRuntimeFeatureFlags()
MTH_ZH_SetButtonsVisible(false)
MTH_ZH_SetAuxFramesVisible(false)
end
end
function MTH_ZHunter:onEvent(evt, arg1, arg2)
if not self.enabled then
return
end
if evt == "MTH_PET_LIVE_STATE_CHANGED" then
if type(zButtonPet_RefreshLiveState) == "function" then
zButtonPet_RefreshLiveState(arg1, arg2)
end
return
end
if evt == "VARIABLES_LOADED" then
MTH_ZH_SyncSavedVariables()
MTH_ZH_RestoreRuntimeFeatureFlags()
return
end
if evt == "PLAYER_ENTERING_WORLD" then
MTH_ZH_ApplyEnabledRuntimeState("event:" .. tostring(evt))
MTH_ZH_QueuePostLoginRestore(evt)
end
end
function MTH_ZHunter:cleanup()
-- Cleanup code when module is unloaded
self:setEnabled(false)
end
-- Register with MTH
MTH:RegisterModule("zhunter", MTH_ZHunter)
File diff suppressed because it is too large Load Diff
+14
View File
@@ -0,0 +1,14 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Frame name="zButtonAmmoFrame">
</Frame>
<CheckButton name="zButtonAmmo" inherits="ZSpellButtonTemplate">
<Anchors>
<Anchor point="CENTER" relativeTo="UIParent" relativePoint="CENTER">
<Offset>
<AbsDimension x="0" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
</Ui>
+281
View File
@@ -0,0 +1,281 @@
local function zButtonAspect_GetRoot()
return MTH_ZH_GetSavedRoot()
end
local root = zButtonAspect_GetRoot()
if not root["zButtonAspect"] then
root["zButtonAspect"] = {}
root["zButtonAspect"]["spells"] = {1, 2, 3, 4, 5, 6, 7}
root["zButtonAspect"]["rows"] = 1
root["zButtonAspect"]["horizontal"] = nil
root["zButtonAspect"]["vertical"] = nil
root["zButtonAspect"]["firstbutton"] = "RIGHT"
root["zButtonAspect"]["enabled"] = 1
root["zButtonAspect"]["tooltip"] = 1
root["zButtonAspect"]["parent"] = {}
root["zButtonAspect"]["parent"]["size"] = 36
root["zButtonAspect"]["parent"]["hide"] = nil
root["zButtonAspect"]["parent"]["circle"] = 1
root["zButtonAspect"]["children"] = {}
root["zButtonAspect"]["children"]["size"] = 36
root["zButtonAspect"]["children"]["hideonclick"] = 1
end
ZHunterMod_Aspect_Spells = {
ZHUNTER_ASPECT_HAWK,
ZHUNTER_ASPECT_MONKEY,
ZHUNTER_ASPECT_WOLF,
ZHUNTER_ASPECT_CHEETAH,
ZHUNTER_ASPECT_PACK,
ZHUNTER_ASPECT_WILD,
ZHUNTER_ASPECT_BEAST
}
local ZHUNTER_ASPECT_MAX = table.getn(ZHunterMod_Aspect_Spells)
local function zButtonAspect_GetSaved()
local currentRoot = zButtonAspect_GetRoot()
if not currentRoot["zButtonAspect"] then
currentRoot["zButtonAspect"] = {}
end
return currentRoot["zButtonAspect"]
end
local function zButtonAspect_EnsureConfig()
local saved = zButtonAspect_GetSaved()
saved["count"] = nil
if saved["rows"] == nil then
saved["rows"] = 1
end
if saved["firstbutton"] == nil then
saved["firstbutton"] = "RIGHT"
end
if saved["enabled"] == nil then
saved["enabled"] = 1
end
if saved["tooltip"] == nil then
saved["tooltip"] = 1
end
if not saved["parent"] then
saved["parent"] = {}
end
if saved["parent"]["size"] == nil then
saved["parent"]["size"] = 36
end
if saved["parent"]["circle"] == nil then
saved["parent"]["circle"] = 1
end
if not saved["children"] then
saved["children"] = {}
end
if saved["children"]["size"] == nil then
saved["children"]["size"] = 36
end
if saved["children"]["hideonclick"] == nil then
saved["children"]["hideonclick"] = 1
end
if not saved["spells"] then
saved["spells"] = {}
end
if not saved["visible"] then
saved["visible"] = {}
end
for i = 1, ZHUNTER_ASPECT_MAX do
if not tonumber(saved["spells"][i]) then
saved["spells"][i] = i
end
if saved["visible"][i] == nil then
saved["visible"][i] = 1
end
end
end
local function zButtonAspect_ApplyRuntimeSettings()
if not zButtonAspect then
return
end
local saved = zButtonAspect_GetSaved()
zButtonAspect.tooltip = saved["tooltip"] and true or false
zButtonAspect.hideonclick = saved["children"] and saved["children"]["hideonclick"] and true or false
end
function zButtonAspect_OnLoad()
this:RegisterEvent("VARIABLES_LOADED")
end
function zButtonAspect_OnEvent()
if event == "VARIABLES_LOADED" then
if not zButtonAspect then
return
end
if UnitClass("player") ~= ZHUNTER_HUNTER then
zButtonAspect:UnregisterAllEvents()
zButtonAspect:Hide()
return
end
zButtonAspect_CreateButtons()
zButtonAspectAdjustment = CreateFrame("Frame", "zButtonAspectAdjustment")
zButtonAspectAdjustment:RegisterEvent("PLAYER_AURAS_CHANGED")
zButtonAspectAdjustment:RegisterEvent("PLAYER_ENTERING_WORLD")
zButtonAspectAdjustment:SetScript("OnEvent", zButtonAspectAdjustment_OnEvent)
zButtonAspect_Tooltip = CreateFrame("GameTooltip", "zButtonAspect_Tooltip", nil, "GameTooltipTemplate")
zButtonAspect_SetupSizeAndPosition()
end
end
function zButtonAspect_CreateButtons()
zButtonAspect_EnsureConfig()
local saved = zButtonAspect_GetSaved()
ZSpellButton_CreateChildren(zButtonAspect, "zButtonAspect", ZHUNTER_ASPECT_MAX)
local info = {}
local infoIndex = 1
for i=1, table.getn(ZHunterMod_Aspect_Spells) do
if not tonumber(saved["spells"][i]) then
info = ZHunterMod_Aspect_Spells
saved["spells"] = {1, 2, 3, 4, 5, 6, 7}
break
end
local spellIndex = saved["spells"][i]
if saved["visible"][spellIndex] ~= false then
info[infoIndex] = ZHunterMod_Aspect_Spells[spellIndex]
infoIndex = infoIndex + 1
end
end
zButtonAspect.found = ZSpellButton_SetButtons(zButtonAspect, info)
zButtonAspect_ApplyRuntimeSettings()
end
function zButtonAspect_SetupSizeAndPosition()
zButtonAspect_EnsureConfig()
local saved = zButtonAspect_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then
if zButtonAspect and zButtonAspect.Hide then
zButtonAspect:Hide()
end
return
end
local displayCount = zButtonAspect.found or ZHUNTER_ASPECT_MAX
if displayCount < 0 then
displayCount = 0
end
ZSpellButton_SetSize(zButtonAspect, saved["parent"]["size"])
ZSpellButton_SetSize(zButtonAspect, saved["children"]["size"], 1)
ZSpellButton_SetExpandDirection(zButtonAspect, saved["firstbutton"])
ZSpellButton_ArrangeChildren(zButtonAspect, saved["rows"],
displayCount, saved["horizontal"],
saved["vertical"])
end
function zButtonAspect_Reset()
local currentRoot = zButtonAspect_GetRoot()
currentRoot["zButtonAspect"] = {}
local saved = zButtonAspect_GetSaved()
saved["spells"] = {1, 2, 3, 4, 5, 6, 7}
saved["rows"] = 1
saved["horizontal"] = nil
saved["vertical"] = nil
saved["firstbutton"] = "RIGHT"
saved["enabled"] = 1
saved["tooltip"] = 1
saved["parent"] = {}
saved["parent"]["size"] = 36
saved["parent"]["hide"] = nil
saved["parent"]["circle"] = 1
saved["children"] = {}
saved["children"]["size"] = 36
saved["children"]["hideonclick"] = 1
saved["visible"] = {1, 1, 1, 1, 1, 1, 1}
zButtonAspect_EnsureConfig()
end
function zButtonAspectAdjustment_OnEvent()
if not zButtonAspect or not zButtonAspect.count then
return
end
if event == "PLAYER_AURAS_CHANGED" or event == "PLAYER_ENTERING_WORLD" then
if not zButtonAspect1.id then
return
end
local buttontextures = {}
local button
for i=1, zButtonAspect.count do
button = getglobal(zButtonAspect.name..i)
button.icon = nil
if button.id then
buttontextures[GetSpellTexture(button.id, "spell")] = button
end
end
local i = 1
local texture = GetSpellTexture(zButtonAspect1.id, "spell")
local buff = UnitBuff("player", i)
local spellname, buffname
zButtonAspect.id = zButtonAspect1.id
while buff do
if texture == buff and zButtonAspect2.id then
zButtonAspect.id = zButtonAspect2.id
end
if buttontextures[buff] then
zButtonAspect_Tooltip:SetOwner(this, "ANCHOR_NONE")
zButtonAspect_Tooltip:SetUnitBuff("player", i)
buffname = zButtonAspect_TooltipTextLeft1:GetText()
spellname = GetSpellName(buttontextures[buff].id, "spell")
if buffname == spellname then
buttontextures[buff].icon = "Interface\\Icons\\Spell_Nature_WispSplode"
end
end
i = i + 1
buff = UnitBuff("player", i)
end
ZSpellButton_UpdateButton(zButtonAspect)
ZSpellButton_UpdateCooldown(zButtonAspect)
for i=1, zButtonAspect.count do
button = getglobal(zButtonAspect.name..i)
if button.id then
ZSpellButton_UpdateButton(button)
end
end
if GameTooltip:IsOwned(zButtonAspect) then
ZSpellButtonParent_OnEnter(zButtonAspect)
end
end
end
function zButtonAspect_KeyBinding(index)
if MTH_ZH_IsModuleEnabled and not MTH_ZH_IsModuleEnabled() then
return
end
local button
if index then
button = getglobal("zButtonAspect"..index)
else
button = zButtonAspect
end
if button.id then
CastSpell(button.id, "spell")
if zButtonAspect.hideonclick then
if type(ZSpellButton_SetChildrenExpanded) == "function" then
ZSpellButton_SetChildrenExpanded(zButtonAspect, false)
elseif zButtonAspect.children then
zButtonAspect.children:Hide()
end
end
end
end
SLASH_zButtonAspect1 = "/ZAspect"
SlashCmdList["zButtonAspect"] = function(msg)
if MTH_ZH_HandleDisabledSlash and MTH_ZH_HandleDisabledSlash("Aspect button is disabled while module 'zhunter' is disabled.") then
return
end
if msg == "reset" then
zButtonAspect_Reset()
zButtonAspect:ClearAllPoints()
zButtonAspect:SetPoint("CENTER", UIParent, "CENTER", -60, 0)
elseif msg == "options" then
MTH_OpenOptions("Aspect")
else
MTH_ZH_Print("Possible Commands: \"options\", \"reset\"")
end
end
+14
View File
@@ -0,0 +1,14 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Frame name="zButtonAspectFrame">
</Frame>
<CheckButton name="zButtonAspect" inherits="ZSpellButtonTemplate">
<Anchors>
<Anchor point="CENTER" relativeTo="UIParent" relativePoint="CENTER">
<Offset>
<AbsDimension x="-60" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
</Ui>
+323
View File
@@ -0,0 +1,323 @@
local function zButtonCompanions_GetRoot()
return MTH_ZH_GetSavedRoot()
end
local root = zButtonCompanions_GetRoot()
if not root["zButtonCompanions"] then
root["zButtonCompanions"] = {}
root["zButtonCompanions"]["spells"] = {}
root["zButtonCompanions"]["rows"] = 1
root["zButtonCompanions"]["horizontal"] = nil
root["zButtonCompanions"]["vertical"] = nil
root["zButtonCompanions"]["firstbutton"] = "RIGHT"
root["zButtonCompanions"]["enabled"] = 0
root["zButtonCompanions"]["tooltip"] = 1
root["zButtonCompanions"]["parent"] = {}
root["zButtonCompanions"]["parent"]["size"] = 36
root["zButtonCompanions"]["parent"]["hide"] = nil
root["zButtonCompanions"]["parent"]["circle"] = 1
root["zButtonCompanions"]["children"] = {}
root["zButtonCompanions"]["children"]["size"] = 36
root["zButtonCompanions"]["children"]["hideonclick"] = 1
end
local ZHUNTER_COMPANIONS_BUTTON_MAX = 80
local function zButtonCompanions_GetSaved()
local currentRoot = zButtonCompanions_GetRoot()
if not currentRoot["zButtonCompanions"] then
currentRoot["zButtonCompanions"] = {}
end
return currentRoot["zButtonCompanions"]
end
local function zButtonCompanions_EnsureConfig()
local saved = zButtonCompanions_GetSaved()
saved["count"] = nil
if saved["enabled"] == nil then
saved["enabled"] = 0
end
if saved["tooltip"] == nil then
saved["tooltip"] = 1
end
if not saved["children"] then
saved["children"] = {}
end
if saved["children"]["hideonclick"] == nil then
saved["children"]["hideonclick"] = 1
end
if not saved["spells"] then
saved["spells"] = {}
end
if not saved["parent"] then
saved["parent"] = {}
end
if not saved["children"] then
saved["children"] = {}
end
if not saved["parent"]["size"] then
saved["parent"]["size"] = 36
end
if saved["parent"]["circle"] == nil then
saved["parent"]["circle"] = 1
end
if not saved["children"]["size"] then
saved["children"]["size"] = 36
end
if not saved["rows"] or saved["rows"] < 1 then
saved["rows"] = 1
end
if not saved["firstbutton"] then
saved["firstbutton"] = "RIGHT"
end
end
local function zButtonCompanions_ApplyRuntimeSettings()
if not zButtonCompanions then
return
end
local saved = zButtonCompanions_GetSaved()
zButtonCompanions.tooltip = saved["tooltip"] and true or false
zButtonCompanions.hideonclick = saved["children"] and saved["children"]["hideonclick"] and true or false
end
local function zButtonCompanions_NormalizeTabName(value)
local text = string.lower(tostring(value or ""))
text = string.gsub(text, "%s+", "")
text = string.gsub(text, "[^%a]", "")
while string.sub(text, 1, 1) == "z" and string.len(text) > 1 do
text = string.sub(text, 2)
end
return text
end
local function zButtonCompanions_FindTabBounds()
if type(GetNumSpellTabs) ~= "function" or type(GetSpellTabInfo) ~= "function" then
return nil, nil
end
local tabCount = GetNumSpellTabs() or 0
for tabIndex = 1, tabCount do
local tabName, _, tabOffset, tabEntries = GetSpellTabInfo(tabIndex)
local normalized = zButtonCompanions_NormalizeTabName(tabName)
if string.find(normalized, "companion", 1, true) or string.find(normalized, "minipet", 1, true) then
return tonumber(tabOffset) or 0, tonumber(tabEntries) or 0
end
end
return nil, nil
end
local function zButtonCompanions_CollectTabSpellIds()
local tabOffset, tabEntries = zButtonCompanions_FindTabBounds()
if not tabOffset or not tabEntries or tabEntries <= 0 then
return {}
end
local spellIds = {}
local bookType = BOOKTYPE_SPELL or "spell"
local maxIndex = tabOffset + tabEntries
for spellIndex = tabOffset + 1, maxIndex do
local spellName = GetSpellName(spellIndex, bookType)
if spellName and spellName ~= "" then
table.insert(spellIds, spellIndex)
end
end
return spellIds
end
local function zButtonCompanions_ApplySpellIds(spellIds)
if not zButtonCompanions then
return 0
end
local parent = zButtonCompanions
local childCount = parent.count or ZHUNTER_COMPANIONS_BUTTON_MAX
for i = 1, childCount do
local child = getglobal("zButtonCompanions" .. i)
if child then
child:Hide()
child.id = nil
child.icon = nil
child.isspell = nil
end
end
local found = 0
for i = 1, table.getn(spellIds) do
if found >= childCount then
break
end
local spellId = spellIds[i]
if spellId then
found = found + 1
local child = getglobal("zButtonCompanions" .. found)
if child then
child.id = spellId
child.isspell = 1
ZSpellButton_UpdateButton(child)
child:Show()
end
end
end
if found > 0 then
parent.id = spellIds[1]
parent.isspell = 1
ZSpellButton_UpdateButton(parent)
parent:Enable()
parent:Show()
else
parent.id = nil
parent:Hide()
end
return found
end
local function zButtonCompanions_RefreshSpells()
if not zButtonCompanions then
return 0
end
local saved = zButtonCompanions_GetSaved()
local spellIds = zButtonCompanions_CollectTabSpellIds()
local spellNames = {}
local bookType = BOOKTYPE_SPELL or "spell"
for i = 1, table.getn(spellIds) do
local n = GetSpellName(spellIds[i], bookType)
if n and n ~= "" then
table.insert(spellNames, n)
end
end
saved["spellIds"] = spellIds
saved["spells"] = spellNames
zButtonCompanions.spells = spellNames
zButtonCompanions.found = zButtonCompanions_ApplySpellIds(spellIds)
zButtonCompanions_ApplyRuntimeSettings()
return zButtonCompanions.found or 0
end
function zButtonCompanions_OnLoad()
this:RegisterEvent("VARIABLES_LOADED")
end
function zButtonCompanions_OnEvent()
if event == "VARIABLES_LOADED" then
if not zButtonCompanions then
return
end
if UnitClass("player") ~= ZHUNTER_HUNTER then
zButtonCompanions:UnregisterAllEvents()
zButtonCompanions:Hide()
return
end
zButtonCompanions_CreateButtons()
zButtonCompanionsAdjustment = CreateFrame("Frame", "zButtonCompanionsAdjustment")
zButtonCompanionsAdjustment:RegisterEvent("SPELLS_CHANGED")
zButtonCompanionsAdjustment:RegisterEvent("PLAYER_ENTERING_WORLD")
zButtonCompanionsAdjustment:SetScript("OnEvent", zButtonCompanionsAdjustment_OnEvent)
zButtonCompanions_SetupSizeAndPosition()
end
end
function zButtonCompanions_CreateButtons()
zButtonCompanions_EnsureConfig()
if not zButtonCompanions._mthChildrenCreated then
ZSpellButton_CreateChildren(zButtonCompanions, "zButtonCompanions", ZHUNTER_COMPANIONS_BUTTON_MAX)
zButtonCompanions._mthChildrenCreated = 1
end
zButtonCompanions_RefreshSpells()
end
function zButtonCompanions_SetupSizeAndPosition()
local saved = zButtonCompanions_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then
if zButtonCompanions and zButtonCompanions.Hide then
zButtonCompanions:Hide()
end
return
end
local displayCount = zButtonCompanions.found or 0
if displayCount < 0 then
displayCount = 0
end
ZSpellButton_SetSize(zButtonCompanions, saved["parent"]["size"])
ZSpellButton_SetSize(zButtonCompanions, saved["children"]["size"], 1)
ZSpellButton_SetExpandDirection(zButtonCompanions, saved["firstbutton"])
ZSpellButton_ArrangeChildren(zButtonCompanions, saved["rows"],
displayCount, saved["horizontal"],
saved["vertical"])
end
function zButtonCompanions_Reset()
local currentRoot = zButtonCompanions_GetRoot()
currentRoot["zButtonCompanions"] = {}
local saved = zButtonCompanions_GetSaved()
saved["spells"] = {}
saved["rows"] = 1
saved["horizontal"] = nil
saved["vertical"] = nil
saved["firstbutton"] = "RIGHT"
saved["enabled"] = 1
saved["tooltip"] = 1
saved["parent"] = {}
saved["parent"]["size"] = 36
saved["parent"]["hide"] = nil
saved["parent"]["circle"] = 1
saved["children"] = {}
saved["children"]["size"] = 36
saved["children"]["hideonclick"] = 1
zButtonCompanions_EnsureConfig()
end
function zButtonCompanionsAdjustment_OnEvent()
if not zButtonCompanions then
return
end
zButtonCompanions_RefreshSpells()
zButtonCompanions_SetupSizeAndPosition()
if GameTooltip:IsOwned(zButtonCompanions) then
ZSpellButtonParent_OnEnter(zButtonCompanions)
end
end
function zButtonCompanions_KeyBinding(index)
if MTH_ZH_IsModuleEnabled and not MTH_ZH_IsModuleEnabled() then
return
end
local button
if index then
button = getglobal("zButtonCompanions"..index)
else
button = zButtonCompanions
end
if button and button.id then
CastSpell(button.id, "spell")
if zButtonCompanions.hideonclick then
if type(ZSpellButton_SetChildrenExpanded) == "function" then
ZSpellButton_SetChildrenExpanded(zButtonCompanions, false)
elseif zButtonCompanions.children then
zButtonCompanions.children:Hide()
end
end
end
end
SLASH_zButtonCompanions1 = "/ZCompanions"
SLASH_zButtonCompanions2 = "/ZMinipets"
SlashCmdList["zButtonCompanions"] = function(msg)
if MTH_ZH_HandleDisabledSlash and MTH_ZH_HandleDisabledSlash("Companions button is disabled while module 'zhunter' is disabled.") then
return
end
if msg == "reset" then
zButtonCompanions_Reset()
zButtonCompanions:ClearAllPoints()
zButtonCompanions:SetPoint("TOP", UIParent, "TOP", 0, -464)
zButtonCompanions_RefreshSpells()
zButtonCompanions_SetupSizeAndPosition()
else
MTH_ZH_Print("Possible Commands: \"reset\"")
end
end
+14
View File
@@ -0,0 +1,14 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Frame name="zButtonCompanionsFrame">
</Frame>
<CheckButton name="zButtonCompanions" inherits="ZSpellButtonTemplate">
<Anchors>
<Anchor point="CENTER" relativeTo="UIParent" relativePoint="CENTER">
<Offset>
<AbsDimension x="0" y="-180"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
</Ui>
+322
View File
@@ -0,0 +1,322 @@
local function zButtonMounts_GetRoot()
return MTH_ZH_GetSavedRoot()
end
local root = zButtonMounts_GetRoot()
if not root["zButtonMounts"] then
root["zButtonMounts"] = {}
root["zButtonMounts"]["spells"] = {}
root["zButtonMounts"]["rows"] = 1
root["zButtonMounts"]["horizontal"] = nil
root["zButtonMounts"]["vertical"] = nil
root["zButtonMounts"]["firstbutton"] = "RIGHT"
root["zButtonMounts"]["enabled"] = 0
root["zButtonMounts"]["tooltip"] = 1
root["zButtonMounts"]["parent"] = {}
root["zButtonMounts"]["parent"]["size"] = 36
root["zButtonMounts"]["parent"]["hide"] = nil
root["zButtonMounts"]["parent"]["circle"] = 1
root["zButtonMounts"]["children"] = {}
root["zButtonMounts"]["children"]["size"] = 36
root["zButtonMounts"]["children"]["hideonclick"] = 1
end
local ZHUNTER_MOUNTS_BUTTON_MAX = 80
local function zButtonMounts_GetSaved()
local currentRoot = zButtonMounts_GetRoot()
if not currentRoot["zButtonMounts"] then
currentRoot["zButtonMounts"] = {}
end
return currentRoot["zButtonMounts"]
end
local function zButtonMounts_EnsureConfig()
local saved = zButtonMounts_GetSaved()
saved["count"] = nil
if saved["enabled"] == nil then
saved["enabled"] = 0
end
if saved["tooltip"] == nil then
saved["tooltip"] = 1
end
if not saved["children"] then
saved["children"] = {}
end
if saved["children"]["hideonclick"] == nil then
saved["children"]["hideonclick"] = 1
end
if not saved["spells"] then
saved["spells"] = {}
end
if not saved["parent"] then
saved["parent"] = {}
end
if not saved["children"] then
saved["children"] = {}
end
if not saved["parent"]["size"] then
saved["parent"]["size"] = 36
end
if saved["parent"]["circle"] == nil then
saved["parent"]["circle"] = 1
end
if not saved["children"]["size"] then
saved["children"]["size"] = 36
end
if not saved["rows"] or saved["rows"] < 1 then
saved["rows"] = 1
end
if not saved["firstbutton"] then
saved["firstbutton"] = "RIGHT"
end
end
local function zButtonMounts_ApplyRuntimeSettings()
if not zButtonMounts then
return
end
local saved = zButtonMounts_GetSaved()
zButtonMounts.tooltip = saved["tooltip"] and true or false
zButtonMounts.hideonclick = saved["children"] and saved["children"]["hideonclick"] and true or false
end
local function zButtonMounts_NormalizeTabName(value)
local text = string.lower(tostring(value or ""))
text = string.gsub(text, "%s+", "")
text = string.gsub(text, "[^%a]", "")
while string.sub(text, 1, 1) == "z" and string.len(text) > 1 do
text = string.sub(text, 2)
end
return text
end
local function zButtonMounts_FindTabBounds()
if type(GetNumSpellTabs) ~= "function" or type(GetSpellTabInfo) ~= "function" then
return nil, nil
end
local tabCount = GetNumSpellTabs() or 0
for tabIndex = 1, tabCount do
local tabName, _, tabOffset, tabEntries = GetSpellTabInfo(tabIndex)
local normalized = zButtonMounts_NormalizeTabName(tabName)
if string.find(normalized, "mount", 1, true) then
return tonumber(tabOffset) or 0, tonumber(tabEntries) or 0
end
end
return nil, nil
end
local function zButtonMounts_CollectTabSpellIds()
local tabOffset, tabEntries = zButtonMounts_FindTabBounds()
if not tabOffset or not tabEntries or tabEntries <= 0 then
return {}
end
local spellIds = {}
local bookType = BOOKTYPE_SPELL or "spell"
local maxIndex = tabOffset + tabEntries
for spellIndex = tabOffset + 1, maxIndex do
local spellName = GetSpellName(spellIndex, bookType)
if spellName and spellName ~= "" then
table.insert(spellIds, spellIndex)
end
end
return spellIds
end
local function zButtonMounts_ApplySpellIds(spellIds)
if not zButtonMounts then
return 0
end
local parent = zButtonMounts
local childCount = parent.count or ZHUNTER_MOUNTS_BUTTON_MAX
for i = 1, childCount do
local child = getglobal("zButtonMounts" .. i)
if child then
child:Hide()
child.id = nil
child.icon = nil
child.isspell = nil
end
end
local found = 0
for i = 1, table.getn(spellIds) do
if found >= childCount then
break
end
local spellId = spellIds[i]
if spellId then
found = found + 1
local child = getglobal("zButtonMounts" .. found)
if child then
child.id = spellId
child.isspell = 1
ZSpellButton_UpdateButton(child)
child:Show()
end
end
end
if found > 0 then
parent.id = spellIds[1]
parent.isspell = 1
ZSpellButton_UpdateButton(parent)
parent:Enable()
parent:Show()
else
parent.id = nil
parent:Hide()
end
return found
end
local function zButtonMounts_RefreshSpells()
if not zButtonMounts then
return 0
end
local saved = zButtonMounts_GetSaved()
local spellIds = zButtonMounts_CollectTabSpellIds()
local spellNames = {}
local bookType = BOOKTYPE_SPELL or "spell"
for i = 1, table.getn(spellIds) do
local n = GetSpellName(spellIds[i], bookType)
if n and n ~= "" then
table.insert(spellNames, n)
end
end
saved["spellIds"] = spellIds
saved["spells"] = spellNames
zButtonMounts.spells = spellNames
zButtonMounts.found = zButtonMounts_ApplySpellIds(spellIds)
zButtonMounts_ApplyRuntimeSettings()
return zButtonMounts.found or 0
end
function zButtonMounts_OnLoad()
this:RegisterEvent("VARIABLES_LOADED")
end
function zButtonMounts_OnEvent()
if event == "VARIABLES_LOADED" then
if not zButtonMounts then
return
end
if UnitClass("player") ~= ZHUNTER_HUNTER then
zButtonMounts:UnregisterAllEvents()
zButtonMounts:Hide()
return
end
zButtonMounts_CreateButtons()
zButtonMountsAdjustment = CreateFrame("Frame", "zButtonMountsAdjustment")
zButtonMountsAdjustment:RegisterEvent("SPELLS_CHANGED")
zButtonMountsAdjustment:RegisterEvent("PLAYER_ENTERING_WORLD")
zButtonMountsAdjustment:SetScript("OnEvent", zButtonMountsAdjustment_OnEvent)
zButtonMounts_SetupSizeAndPosition()
end
end
function zButtonMounts_CreateButtons()
zButtonMounts_EnsureConfig()
if not zButtonMounts._mthChildrenCreated then
ZSpellButton_CreateChildren(zButtonMounts, "zButtonMounts", ZHUNTER_MOUNTS_BUTTON_MAX)
zButtonMounts._mthChildrenCreated = 1
end
zButtonMounts_RefreshSpells()
end
function zButtonMounts_SetupSizeAndPosition()
local saved = zButtonMounts_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then
if zButtonMounts and zButtonMounts.Hide then
zButtonMounts:Hide()
end
return
end
local displayCount = zButtonMounts.found or 0
if displayCount < 0 then
displayCount = 0
end
ZSpellButton_SetSize(zButtonMounts, saved["parent"]["size"])
ZSpellButton_SetSize(zButtonMounts, saved["children"]["size"], 1)
ZSpellButton_SetExpandDirection(zButtonMounts, saved["firstbutton"])
ZSpellButton_ArrangeChildren(zButtonMounts, saved["rows"],
displayCount, saved["horizontal"],
saved["vertical"])
end
function zButtonMounts_Reset()
local currentRoot = zButtonMounts_GetRoot()
currentRoot["zButtonMounts"] = {}
local saved = zButtonMounts_GetSaved()
saved["spells"] = {}
saved["rows"] = 1
saved["horizontal"] = nil
saved["vertical"] = nil
saved["firstbutton"] = "RIGHT"
saved["enabled"] = 1
saved["tooltip"] = 1
saved["parent"] = {}
saved["parent"]["size"] = 36
saved["parent"]["hide"] = nil
saved["parent"]["circle"] = 1
saved["children"] = {}
saved["children"]["size"] = 36
saved["children"]["hideonclick"] = 1
zButtonMounts_EnsureConfig()
end
function zButtonMountsAdjustment_OnEvent()
if not zButtonMounts then
return
end
zButtonMounts_RefreshSpells()
zButtonMounts_SetupSizeAndPosition()
if GameTooltip:IsOwned(zButtonMounts) then
ZSpellButtonParent_OnEnter(zButtonMounts)
end
end
function zButtonMounts_KeyBinding(index)
if MTH_ZH_IsModuleEnabled and not MTH_ZH_IsModuleEnabled() then
return
end
local button
if index then
button = getglobal("zButtonMounts"..index)
else
button = zButtonMounts
end
if button and button.id then
CastSpell(button.id, "spell")
if zButtonMounts.hideonclick then
if type(ZSpellButton_SetChildrenExpanded) == "function" then
ZSpellButton_SetChildrenExpanded(zButtonMounts, false)
elseif zButtonMounts.children then
zButtonMounts.children:Hide()
end
end
end
end
SLASH_zButtonMounts1 = "/ZMounts"
SlashCmdList["zButtonMounts"] = function(msg)
if MTH_ZH_HandleDisabledSlash and MTH_ZH_HandleDisabledSlash("Mounts button is disabled while module 'zhunter' is disabled.") then
return
end
if msg == "reset" then
zButtonMounts_Reset()
zButtonMounts:ClearAllPoints()
zButtonMounts:SetPoint("TOP", UIParent, "TOP", 0, -410)
zButtonMounts_RefreshSpells()
zButtonMounts_SetupSizeAndPosition()
else
MTH_ZH_Print("Possible Commands: \"reset\"")
end
end
+14
View File
@@ -0,0 +1,14 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Frame name="zButtonMountsFrame">
</Frame>
<CheckButton name="zButtonMounts" inherits="ZSpellButtonTemplate">
<Anchors>
<Anchor point="CENTER" relativeTo="UIParent" relativePoint="CENTER">
<Offset>
<AbsDimension x="0" y="-120"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
</Ui>
+454
View File
@@ -0,0 +1,454 @@
local function zButtonPet_GetRoot()
return MTH_ZH_GetSavedRoot()
end
local root = zButtonPet_GetRoot()
-- Initialize with defaults only if not already configured
if not root["zButtonPet"] then
root["zButtonPet"] = {}
root["zButtonPet"]["pet"] = {}
root["zButtonPet"]["pet"]["happiness"] = nil
root["zButtonPet"]["pet"]["status"] = nil
root["zButtonPet"]["pet"]["dead"] = nil
root["zButtonPet"]["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
root["zButtonPet"]["rows"] = 1
root["zButtonPet"]["horizontal"] = nil
root["zButtonPet"]["vertical"] = nil
root["zButtonPet"]["firstbutton"] = "RIGHT"
root["zButtonPet"]["enabled"] = 1
root["zButtonPet"]["tooltip"] = 1
root["zButtonPet"]["parent"] = {}
root["zButtonPet"]["parent"]["size"] = 36
root["zButtonPet"]["parent"]["hide"] = nil
root["zButtonPet"]["parent"]["circle"] = 1
root["zButtonPet"]["children"] = {}
root["zButtonPet"]["children"]["size"] = 36
root["zButtonPet"]["children"]["hideonclick"] = 1
end
root["zButtonPet"]["food"] = {}
ZHunterMod_Pet_Spells = {
ZHUNTER_PET_EYES,
ZHUNTER_PET_DISMISS,
ZHUNTER_PET_MEND,
ZHUNTER_PET_FEED,
ZHUNTER_PET_CALL,
ZHUNTER_PET_REVIVE,
ZHUNTER_PET_LORE,
ZHUNTER_PET_TRAINING,
ZHUNTER_PET_TAMING,
ZHUNTER_PET_POSITION
}
local ZHUNTER_PET_MAX = table.getn(ZHunterMod_Pet_Spells)
local function zButtonPet_GetSaved()
local currentRoot = zButtonPet_GetRoot()
if not currentRoot["zButtonPet"] then
currentRoot["zButtonPet"] = {}
end
return currentRoot["zButtonPet"]
end
local function zButtonPet_EnsureConfig()
local saved = zButtonPet_GetSaved()
saved["count"] = nil
if not saved["pet"] then
saved["pet"] = {}
end
if saved["pet"]["happiness"] == nil then
saved["pet"]["happiness"] = nil
end
if saved["pet"]["status"] == nil then
saved["pet"]["status"] = nil
end
if saved["pet"]["dead"] == nil then
saved["pet"]["dead"] = nil
end
if not saved["parent"] then
saved["parent"] = {}
end
if saved["parent"]["size"] == nil then
saved["parent"]["size"] = 36
end
if saved["parent"]["hide"] == nil then
saved["parent"]["hide"] = nil
end
if saved["parent"]["circle"] == nil then
saved["parent"]["circle"] = 1
end
if saved["enabled"] == nil then
saved["enabled"] = 1
end
if saved["tooltip"] == nil then
saved["tooltip"] = 1
end
if saved["rows"] == nil then
saved["rows"] = 1
end
if saved["horizontal"] == nil then
saved["horizontal"] = nil
end
if saved["vertical"] == nil then
saved["vertical"] = nil
end
if saved["firstbutton"] == nil then
saved["firstbutton"] = "RIGHT"
end
if not saved["children"] then
saved["children"] = {}
end
if saved["children"]["size"] == nil then
saved["children"]["size"] = 36
end
if saved["children"]["hideonclick"] == nil then
saved["children"]["hideonclick"] = 1
end
if saved["food"] == nil then
saved["food"] = {}
end
if not saved["spells"] then
saved["spells"] = {}
end
if not saved["visible"] then
saved["visible"] = {}
end
for i = 1, ZHUNTER_PET_MAX do
if not tonumber(saved["spells"][i]) then
saved["spells"][i] = i
end
if saved["visible"][i] == nil then
saved["visible"][i] = 1
end
end
end
local function zButtonPet_ApplyRuntimeSettings()
if not zButtonPet then
return
end
local saved = zButtonPet_GetSaved()
zButtonPet.tooltip = saved["tooltip"] and true or false
zButtonPet.hideonclick = saved["children"] and saved["children"]["hideonclick"] and true or false
end
function zButtonPet_OnLoad()
this:RegisterEvent("VARIABLES_LOADED")
end
function zButtonPet_OnEvent()
if event == "VARIABLES_LOADED" then
if not zButtonPet then
return
end
if UnitClass("player") ~= ZHUNTER_HUNTER then
zButtonPet:UnregisterAllEvents()
zButtonPet:Hide()
return
end
zButtonPet_CreateButtons()
zButtonPet.beforeclick = zButtonPetAdjustment_BeforeClick
zButtonPet.afterclick = zButtonPet_AfterClick
zButtonPetAdjustment = CreateFrame("Frame", "zButtonPetAdjustment")
zButtonPetAdjustment:RegisterEvent("UNIT_HEALTH")
zButtonPetAdjustment:RegisterEvent("UNIT_HAPPINESS")
zButtonPetAdjustment:RegisterEvent("UNIT_PET")
zButtonPetAdjustment:RegisterEvent("PET_BAR_UPDATE")
zButtonPetAdjustment:RegisterEvent("PLAYER_ENTERING_WORLD")
zButtonPetAdjustment:RegisterEvent("SPELLS_CHANGED")
zButtonPetAdjustment:SetScript("OnEvent", zButtonPetAdjustment_OnEvent)
zButtonPet_Tooltip = CreateFrame("GameTooltip", "zButtonPet_Tooltip", nil, "GameTooltipTemplate")
zButtonPet_SetupSizeAndPosition()
zButtonPetAdjustment_OnEvent()
end
end
function zButtonPet_CreateButtons()
zButtonPet_EnsureConfig()
local saved = zButtonPet_GetSaved()
ZSpellButton_CreateChildren(zButtonPet, "zButtonPet", ZHUNTER_PET_MAX)
local info = {}
local infoIndex = 1
for i=1, table.getn(ZHunterMod_Pet_Spells) do
if not tonumber(saved["spells"][i]) then
info = ZHunterMod_Pet_Spells
saved["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
break
end
local spellIndex = saved["spells"][i]
if saved["visible"][spellIndex] ~= false then
info[infoIndex] = ZHunterMod_Pet_Spells[spellIndex]
infoIndex = infoIndex + 1
end
end
zButtonPet.found = ZSpellButton_SetButtons(zButtonPet, info)
zButtonPet_ApplyRuntimeSettings()
end
function zButtonPet_SetupSizeAndPosition()
local saved = zButtonPet_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then
if zButtonPet and zButtonPet.Hide then
zButtonPet:Hide()
end
return
end
local displayCount = zButtonPet.found or ZHUNTER_PET_MAX
if displayCount < 0 then
displayCount = 0
end
ZSpellButton_SetSize(zButtonPet, saved["parent"]["size"])
ZSpellButton_SetSize(zButtonPet, saved["children"]["size"], 1)
ZSpellButton_SetExpandDirection(zButtonPet, saved["firstbutton"])
ZSpellButton_ArrangeChildren(zButtonPet, saved["rows"],
displayCount, saved["horizontal"],
saved["vertical"])
end
function zButtonPet_Reset()
local currentRoot = zButtonPet_GetRoot()
currentRoot["zButtonPet"] = {}
local saved = zButtonPet_GetSaved()
saved["pet"] = {}
saved["pet"]["happiness"] = nil
saved["pet"]["status"] = nil
saved["pet"]["dead"] = nil
saved["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
saved["rows"] = 1
saved["horizontal"] = nil
saved["vertical"] = nil
saved["firstbutton"] = "RIGHT"
saved["enabled"] = 1
saved["tooltip"] = 1
saved["parent"] = {}
saved["parent"]["size"] = 36
saved["parent"]["hide"] = nil
saved["parent"]["circle"] = 1
saved["children"] = {}
saved["children"]["size"] = 36
saved["children"]["hideonclick"] = 1
saved["visible"] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
zButtonPet_EnsureConfig()
end
function IsPetDead()
local saved = zButtonPet_GetSaved()
return saved["pet"] and saved["pet"]["dead"]
end
local function zButtonPet_GetCorePetInfo()
if type(MTH_GetCurrentPetInfo) == "function" then
local info = MTH_GetCurrentPetInfo()
if type(info) == "table" then
return info
end
end
return nil
end
local function zButtonPet_RefreshSavedPetState(saved, corePetInfo)
local hasLivePet = false
if type(UnitExists) == "function" then
hasLivePet = UnitExists("pet") and true or false
elseif type(corePetInfo) == "table" and corePetInfo.liveExists ~= nil then
hasLivePet = corePetInfo.liveExists and true or false
end
if not hasLivePet then
saved["pet"]["status"] = nil
saved["pet"]["dead"] = nil
saved["pet"]["happiness"] = nil
return false
end
local currentHealth = (corePetInfo and tonumber(corePetInfo.health)) or (type(UnitHealth) == "function" and UnitHealth("pet")) or nil
local currentHealthMax = (corePetInfo and tonumber(corePetInfo.healthMax)) or (type(UnitHealthMax) == "function" and UnitHealthMax("pet")) or nil
local isDead = (corePetInfo and corePetInfo.dead) and true or false
if not isDead and type(UnitIsDead) == "function" then
isDead = UnitIsDead("pet") and true or false
end
if isDead then
saved["pet"]["dead"] = 1
else
saved["pet"]["dead"] = nil
end
local happiness = corePetInfo and corePetInfo.happiness or nil
if happiness == nil and type(GetPetHappiness) == "function" then
happiness = GetPetHappiness()
end
saved["pet"]["happiness"] = happiness
if isDead then
saved["pet"]["status"] = 1
elseif currentHealth and currentHealthMax and currentHealthMax > 0 then
if (currentHealth / currentHealthMax) > 0.75 then
saved["pet"]["status"] = 2
else
saved["pet"]["status"] = 1
end
else
saved["pet"]["status"] = 2
end
return true
end
local function zButtonPet_FindSpellIdByName(spellName)
if not spellName or spellName == "" then
return nil
end
local maxSpells = tonumber((_G and _G["MAX_SPELLS"]) or nil) or 1024
for i = 1, maxSpells do
local current = GetSpellName(i, "spell")
if not current then
break
end
if current == spellName then
return i
end
end
return nil
end
function zButtonPetAdjustment_BeforeClick()
if CursorHasItem() then
DropItemOnUnit("pet")
return 1
end
end
local function zButtonPet_RefreshParentSpell()
if not zButtonPet or not zButtonPet.count then
return
end
zButtonPet_EnsureConfig()
local saved = zButtonPet_GetSaved()
local corePetInfo = zButtonPet_GetCorePetInfo()
local hasCurrentPet = nil
local hasLivePet = nil
if type(corePetInfo) == "table" and corePetInfo.exists ~= nil then
hasCurrentPet = corePetInfo.exists and true or false
end
if type(corePetInfo) == "table" and corePetInfo.liveExists ~= nil then
hasLivePet = corePetInfo.liveExists and true or false
end
zButtonPet_RefreshSavedPetState(saved, corePetInfo)
local status, happiness, dead
local spells = {}
local name
local choice
for i=1, zButtonPet.count do
local button
button = getglobal(zButtonPet.name..i)
if button and button.id then
name = GetSpellName(button.id, "spell")
spells[name] = button
if not choice and (name == ZHUNTER_PET_DISMISS or name == ZHUNTER_PET_EYES or name == ZHUNTER_PET_POSITION) then
choice = button
end
end
end
status = saved["pet"]["status"]
happiness = saved["pet"]["happiness"]
dead = saved["pet"]["dead"]
local id = zButtonPet.id
name = nil
if hasCurrentPet == false and hasLivePet == false then
name = ZHUNTER_PET_TAMING
elseif not status then
name = ZHUNTER_PET_CALL
elseif dead then
name = ZHUNTER_PET_REVIVE
elseif status == 1 then
name = ZHUNTER_PET_MEND
elseif happiness ~= 3 then
name = ZHUNTER_PET_FEED
elseif choice then
id = choice.id
end
if name and spells[name] then
id = spells[name].id
elseif name then
local fallbackId = zButtonPet_FindSpellIdByName(name)
if fallbackId then
id = fallbackId
end
end
zButtonPet.id = id
ZSpellButton_UpdateButton(zButtonPet)
ZSpellButton_UpdateCooldown(zButtonPet)
if GameTooltip:IsOwned(zButtonPet) then
ZSpellButtonParent_OnEnter(zButtonPet)
end
end
function zButtonPet_AfterClick()
zButtonPet_RefreshParentSpell()
end
function zButtonPet_RefreshLiveState(_liveState, _source)
zButtonPet_RefreshParentSpell()
end
function zButtonPetAdjustment_OnEvent()
if not zButtonPet or not zButtonPet.count then
return
end
if (event == "UNIT_HEALTH" or event == "UNIT_HAPPINESS") and arg1 and arg1 ~= "pet" then
return
end
if event == "UNIT_PET" and arg1 and arg1 ~= "player" then
return
end
zButtonPet_RefreshParentSpell()
end
function zButtonPet_KeyBinding(index)
if MTH_ZH_IsModuleEnabled and not MTH_ZH_IsModuleEnabled() then
return
end
local button
if index then
button = getglobal("zButtonPet"..index)
else
button = zButtonPet
end
if button.id then
CastSpell(button.id, "spell")
if zButtonPet.hideonclick then
if type(ZSpellButton_SetChildrenExpanded) == "function" then
ZSpellButton_SetChildrenExpanded(zButtonPet, false)
elseif zButtonPet.children then
zButtonPet.children:Hide()
end
end
end
end
function zButtonPet_FeedPet()
end
SLASH_zButtonPet1 = "/ZPet"
SlashCmdList["zButtonPet"] = function(msg)
if MTH_ZH_HandleDisabledSlash and MTH_ZH_HandleDisabledSlash("Pet button is disabled while module 'zhunter' is disabled.") then
return
end
if msg == "reset" then
zButtonPet_Reset()
zButtonPet:ClearAllPoints()
zButtonPet:SetPoint("CENTER", UIParent, "CENTER", 0, 60)
elseif msg == "options" then
MTH_OpenOptions("Pet")
else
MTH_ZH_Print("Possible Commands: \"options\", \"reset\"")
end
end
+14
View File
@@ -0,0 +1,14 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Frame name="zButtonPetFrame">
</Frame>
<CheckButton name="zButtonPet" inherits="ZSpellButtonTemplate">
<Anchors>
<Anchor point="CENTER" relativeTo="UIParent" relativePoint="CENTER">
<Offset>
<AbsDimension x="0" y="60"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
</Ui>
+322
View File
@@ -0,0 +1,322 @@
local function zButtonToys_GetRoot()
return MTH_ZH_GetSavedRoot()
end
local root = zButtonToys_GetRoot()
if not root["zButtonToys"] then
root["zButtonToys"] = {}
root["zButtonToys"]["spells"] = {}
root["zButtonToys"]["rows"] = 1
root["zButtonToys"]["horizontal"] = nil
root["zButtonToys"]["vertical"] = nil
root["zButtonToys"]["firstbutton"] = "RIGHT"
root["zButtonToys"]["enabled"] = 0
root["zButtonToys"]["tooltip"] = 1
root["zButtonToys"]["parent"] = {}
root["zButtonToys"]["parent"]["size"] = 36
root["zButtonToys"]["parent"]["hide"] = nil
root["zButtonToys"]["parent"]["circle"] = 1
root["zButtonToys"]["children"] = {}
root["zButtonToys"]["children"]["size"] = 36
root["zButtonToys"]["children"]["hideonclick"] = 1
end
local ZHUNTER_TOYS_BUTTON_MAX = 80
local function zButtonToys_GetSaved()
local currentRoot = zButtonToys_GetRoot()
if not currentRoot["zButtonToys"] then
currentRoot["zButtonToys"] = {}
end
return currentRoot["zButtonToys"]
end
local function zButtonToys_EnsureConfig()
local saved = zButtonToys_GetSaved()
saved["count"] = nil
if saved["enabled"] == nil then
saved["enabled"] = 0
end
if saved["tooltip"] == nil then
saved["tooltip"] = 1
end
if not saved["children"] then
saved["children"] = {}
end
if saved["children"]["hideonclick"] == nil then
saved["children"]["hideonclick"] = 1
end
if not saved["spells"] then
saved["spells"] = {}
end
if not saved["parent"] then
saved["parent"] = {}
end
if not saved["children"] then
saved["children"] = {}
end
if not saved["parent"]["size"] then
saved["parent"]["size"] = 36
end
if saved["parent"]["circle"] == nil then
saved["parent"]["circle"] = 1
end
if not saved["children"]["size"] then
saved["children"]["size"] = 36
end
if not saved["rows"] or saved["rows"] < 1 then
saved["rows"] = 1
end
if not saved["firstbutton"] then
saved["firstbutton"] = "RIGHT"
end
end
local function zButtonToys_ApplyRuntimeSettings()
if not zButtonToys then
return
end
local saved = zButtonToys_GetSaved()
zButtonToys.tooltip = saved["tooltip"] and true or false
zButtonToys.hideonclick = saved["children"] and saved["children"]["hideonclick"] and true or false
end
local function zButtonToys_NormalizeTabName(value)
local text = string.lower(tostring(value or ""))
text = string.gsub(text, "%s+", "")
text = string.gsub(text, "[^%a]", "")
while string.sub(text, 1, 1) == "z" and string.len(text) > 1 do
text = string.sub(text, 2)
end
return text
end
local function zButtonToys_FindTabBounds()
if type(GetNumSpellTabs) ~= "function" or type(GetSpellTabInfo) ~= "function" then
return nil, nil
end
local tabCount = GetNumSpellTabs() or 0
for tabIndex = 1, tabCount do
local tabName, _, tabOffset, tabEntries = GetSpellTabInfo(tabIndex)
local normalized = zButtonToys_NormalizeTabName(tabName)
if string.find(normalized, "toy", 1, true) then
return tonumber(tabOffset) or 0, tonumber(tabEntries) or 0
end
end
return nil, nil
end
local function zButtonToys_CollectTabSpellIds()
local tabOffset, tabEntries = zButtonToys_FindTabBounds()
if not tabOffset or not tabEntries or tabEntries <= 0 then
return {}
end
local spellIds = {}
local bookType = BOOKTYPE_SPELL or "spell"
local maxIndex = tabOffset + tabEntries
for spellIndex = tabOffset + 1, maxIndex do
local spellName = GetSpellName(spellIndex, bookType)
if spellName and spellName ~= "" then
table.insert(spellIds, spellIndex)
end
end
return spellIds
end
local function zButtonToys_ApplySpellIds(spellIds)
if not zButtonToys then
return 0
end
local parent = zButtonToys
local childCount = parent.count or ZHUNTER_TOYS_BUTTON_MAX
for i = 1, childCount do
local child = getglobal("zButtonToys" .. i)
if child then
child:Hide()
child.id = nil
child.icon = nil
child.isspell = nil
end
end
local found = 0
for i = 1, table.getn(spellIds) do
if found >= childCount then
break
end
local spellId = spellIds[i]
if spellId then
found = found + 1
local child = getglobal("zButtonToys" .. found)
if child then
child.id = spellId
child.isspell = 1
ZSpellButton_UpdateButton(child)
child:Show()
end
end
end
if found > 0 then
parent.id = spellIds[1]
parent.isspell = 1
ZSpellButton_UpdateButton(parent)
parent:Enable()
parent:Show()
else
parent.id = nil
parent:Hide()
end
return found
end
local function zButtonToys_RefreshSpells()
if not zButtonToys then
return 0
end
local saved = zButtonToys_GetSaved()
local spellIds = zButtonToys_CollectTabSpellIds()
local spellNames = {}
local bookType = BOOKTYPE_SPELL or "spell"
for i = 1, table.getn(spellIds) do
local n = GetSpellName(spellIds[i], bookType)
if n and n ~= "" then
table.insert(spellNames, n)
end
end
saved["spellIds"] = spellIds
saved["spells"] = spellNames
zButtonToys.spells = spellNames
zButtonToys.found = zButtonToys_ApplySpellIds(spellIds)
zButtonToys_ApplyRuntimeSettings()
return zButtonToys.found or 0
end
function zButtonToys_OnLoad()
this:RegisterEvent("VARIABLES_LOADED")
end
function zButtonToys_OnEvent()
if event == "VARIABLES_LOADED" then
if not zButtonToys then
return
end
if UnitClass("player") ~= ZHUNTER_HUNTER then
zButtonToys:UnregisterAllEvents()
zButtonToys:Hide()
return
end
zButtonToys_CreateButtons()
zButtonToysAdjustment = CreateFrame("Frame", "zButtonToysAdjustment")
zButtonToysAdjustment:RegisterEvent("SPELLS_CHANGED")
zButtonToysAdjustment:RegisterEvent("PLAYER_ENTERING_WORLD")
zButtonToysAdjustment:SetScript("OnEvent", zButtonToysAdjustment_OnEvent)
zButtonToys_SetupSizeAndPosition()
end
end
function zButtonToys_CreateButtons()
zButtonToys_EnsureConfig()
if not zButtonToys._mthChildrenCreated then
ZSpellButton_CreateChildren(zButtonToys, "zButtonToys", ZHUNTER_TOYS_BUTTON_MAX)
zButtonToys._mthChildrenCreated = 1
end
zButtonToys_RefreshSpells()
end
function zButtonToys_SetupSizeAndPosition()
local saved = zButtonToys_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then
if zButtonToys and zButtonToys.Hide then
zButtonToys:Hide()
end
return
end
local displayCount = zButtonToys.found or 0
if displayCount < 0 then
displayCount = 0
end
ZSpellButton_SetSize(zButtonToys, saved["parent"]["size"])
ZSpellButton_SetSize(zButtonToys, saved["children"]["size"], 1)
ZSpellButton_SetExpandDirection(zButtonToys, saved["firstbutton"])
ZSpellButton_ArrangeChildren(zButtonToys, saved["rows"],
displayCount, saved["horizontal"],
saved["vertical"])
end
function zButtonToys_Reset()
local currentRoot = zButtonToys_GetRoot()
currentRoot["zButtonToys"] = {}
local saved = zButtonToys_GetSaved()
saved["spells"] = {}
saved["rows"] = 1
saved["horizontal"] = nil
saved["vertical"] = nil
saved["firstbutton"] = "RIGHT"
saved["enabled"] = 1
saved["tooltip"] = 1
saved["parent"] = {}
saved["parent"]["size"] = 36
saved["parent"]["hide"] = nil
saved["parent"]["circle"] = 1
saved["children"] = {}
saved["children"]["size"] = 36
saved["children"]["hideonclick"] = 1
zButtonToys_EnsureConfig()
end
function zButtonToysAdjustment_OnEvent()
if not zButtonToys then
return
end
zButtonToys_RefreshSpells()
zButtonToys_SetupSizeAndPosition()
if GameTooltip:IsOwned(zButtonToys) then
ZSpellButtonParent_OnEnter(zButtonToys)
end
end
function zButtonToys_KeyBinding(index)
if MTH_ZH_IsModuleEnabled and not MTH_ZH_IsModuleEnabled() then
return
end
local button
if index then
button = getglobal("zButtonToys"..index)
else
button = zButtonToys
end
if button and button.id then
CastSpell(button.id, "spell")
if zButtonToys.hideonclick then
if type(ZSpellButton_SetChildrenExpanded) == "function" then
ZSpellButton_SetChildrenExpanded(zButtonToys, false)
elseif zButtonToys.children then
zButtonToys.children:Hide()
end
end
end
end
SLASH_zButtonToys1 = "/ZToys"
SlashCmdList["zButtonToys"] = function(msg)
if MTH_ZH_HandleDisabledSlash and MTH_ZH_HandleDisabledSlash("Toys button is disabled while module 'zhunter' is disabled.") then
return
end
if msg == "reset" then
zButtonToys_Reset()
zButtonToys:ClearAllPoints()
zButtonToys:SetPoint("TOP", UIParent, "TOP", 0, -518)
zButtonToys_RefreshSpells()
zButtonToys_SetupSizeAndPosition()
else
MTH_ZH_Print("Possible Commands: \"reset\"")
end
end
+14
View File
@@ -0,0 +1,14 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Frame name="zButtonToysFrame">
</Frame>
<CheckButton name="zButtonToys" inherits="ZSpellButtonTemplate">
<Anchors>
<Anchor point="CENTER" relativeTo="UIParent" relativePoint="CENTER">
<Offset>
<AbsDimension x="0" y="-240"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
</Ui>
+260
View File
@@ -0,0 +1,260 @@
local function zButtonTrack_GetRoot()
return MTH_ZH_GetSavedRoot()
end
local root = zButtonTrack_GetRoot()
if not root["zButtonTrack"] then
root["zButtonTrack"] = {}
root["zButtonTrack"]["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
root["zButtonTrack"]["rows"] = 1
root["zButtonTrack"]["horizontal"] = nil
root["zButtonTrack"]["vertical"] = nil
root["zButtonTrack"]["firstbutton"] = "RIGHT"
root["zButtonTrack"]["enabled"] = 1
root["zButtonTrack"]["tooltip"] = 1
root["zButtonTrack"]["parent"] = {}
root["zButtonTrack"]["parent"]["size"] = 36
root["zButtonTrack"]["parent"]["hide"] = nil
root["zButtonTrack"]["parent"]["circle"] = 1
root["zButtonTrack"]["children"] = {}
root["zButtonTrack"]["children"]["size"] = 36
root["zButtonTrack"]["children"]["hideonclick"] = 1
end
ZHunterMod_Track_Spells = {
ZHUNTER_TRACK_HIDDEN,
ZHUNTER_TRACK_HUMANOIDS,
ZHUNTER_TRACK_UNDEAD,
ZHUNTER_TRACK_BEASTS,
ZHUNTER_TRACK_DEMONS,
ZHUNTER_TRACK_ELEMENTALS,
ZHUNTER_TRACK_DRAGONKIN,
ZHUNTER_TRACK_GIANTS,
ZHUNTER_TRACK_MINERALS,
ZHUNTER_TRACK_HERBS,
ZHUNTER_TRACK_TREASURE
}
local ZHUNTER_TRACK_MAX = table.getn(ZHunterMod_Track_Spells)
local function zButtonTrack_GetSaved()
local currentRoot = zButtonTrack_GetRoot()
if not currentRoot["zButtonTrack"] then
currentRoot["zButtonTrack"] = {}
end
return currentRoot["zButtonTrack"]
end
local function zButtonTrack_EnsureConfig()
local saved = zButtonTrack_GetSaved()
saved["count"] = nil
if saved["rows"] == nil then
saved["rows"] = 1
end
if saved["firstbutton"] == nil then
saved["firstbutton"] = "RIGHT"
end
if saved["enabled"] == nil then
saved["enabled"] = 1
end
if saved["tooltip"] == nil then
saved["tooltip"] = 1
end
if not saved["parent"] then
saved["parent"] = {}
end
if saved["parent"]["size"] == nil then
saved["parent"]["size"] = 36
end
if saved["parent"]["circle"] == nil then
saved["parent"]["circle"] = 1
end
if not saved["children"] then
saved["children"] = {}
end
if saved["children"]["size"] == nil then
saved["children"]["size"] = 36
end
if saved["children"]["hideonclick"] == nil then
saved["children"]["hideonclick"] = 1
end
if not saved["spells"] then
saved["spells"] = {}
end
if not saved["visible"] then
saved["visible"] = {}
end
for i = 1, ZHUNTER_TRACK_MAX do
if not tonumber(saved["spells"][i]) then
saved["spells"][i] = i
end
if saved["visible"][i] == nil then
saved["visible"][i] = 1
end
end
end
local function zButtonTrack_ApplyRuntimeSettings()
if not zButtonTrack then
return
end
local saved = zButtonTrack_GetSaved()
zButtonTrack.tooltip = saved["tooltip"] and true or false
zButtonTrack.hideonclick = saved["children"] and saved["children"]["hideonclick"] and true or false
end
function zButtonTrack_OnLoad()
this:RegisterEvent("VARIABLES_LOADED")
end
function zButtonTrack_OnEvent()
if event == "VARIABLES_LOADED" then
if not zButtonTrack then
return
end
if UnitClass("player") ~= ZHUNTER_HUNTER then
zButtonTrack:UnregisterAllEvents()
zButtonTrack:Hide()
return
end
zButtonTrack_CreateButtons()
zButtonTrackAdjustment = CreateFrame("Frame", "zButtonTrackAdjustment")
zButtonTrackAdjustment:RegisterEvent("PLAYER_AURAS_CHANGED")
zButtonTrackAdjustment:RegisterEvent("PLAYER_ENTERING_WORLD")
zButtonTrackAdjustment:RegisterEvent("SPELLS_CHANGED")
zButtonTrackAdjustment:RegisterEvent("CHARACTER_POINTS_CHANGED")
zButtonTrackAdjustment:SetScript("OnEvent", zButtonTrackAdjustment_OnEvent)
zButtonTrack_SetupSizeAndPosition()
end
end
function zButtonTrack_CreateButtons()
zButtonTrack_EnsureConfig()
local saved = zButtonTrack_GetSaved()
ZSpellButton_CreateChildren(zButtonTrack, "zButtonTrack", ZHUNTER_TRACK_MAX)
local info = {}
local infoIndex = 1
for i=1, table.getn(ZHunterMod_Track_Spells) do
if not tonumber(saved["spells"][i]) then
info = ZHunterMod_Track_Spells
saved["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
break
end
local spellIndex = saved["spells"][i]
if saved["visible"][spellIndex] ~= false then
info[infoIndex] = ZHunterMod_Track_Spells[spellIndex]
infoIndex = infoIndex + 1
end
end
zButtonTrack.found = ZSpellButton_SetButtons(zButtonTrack, info)
zButtonTrack_ApplyRuntimeSettings()
end
function zButtonTrack_SetupSizeAndPosition()
zButtonTrack_EnsureConfig()
local saved = zButtonTrack_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then
if zButtonTrack and zButtonTrack.Hide then
zButtonTrack:Hide()
end
return
end
local displayCount = zButtonTrack.found or ZHUNTER_TRACK_MAX
if displayCount < 0 then
displayCount = 0
end
ZSpellButton_SetSize(zButtonTrack, saved["parent"]["size"])
ZSpellButton_SetSize(zButtonTrack, saved["children"]["size"], 1)
ZSpellButton_SetExpandDirection(zButtonTrack, saved["firstbutton"])
ZSpellButton_ArrangeChildren(zButtonTrack, saved["rows"],
displayCount, saved["horizontal"],
saved["vertical"])
end
function zButtonTrack_Reset()
local currentRoot = zButtonTrack_GetRoot()
currentRoot["zButtonTrack"] = {}
local saved = zButtonTrack_GetSaved()
saved["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
saved["rows"] = 1
saved["horizontal"] = nil
saved["vertical"] = nil
saved["firstbutton"] = "RIGHT"
saved["enabled"] = 1
saved["tooltip"] = 1
saved["parent"] = {}
saved["parent"]["size"] = 36
saved["parent"]["hide"] = nil
saved["parent"]["circle"] = 1
saved["children"] = {}
saved["children"]["size"] = 36
saved["children"]["hideonclick"] = 1
saved["visible"] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
zButtonTrack_EnsureConfig()
end
function zButtonTrackAdjustment_OnEvent()
if not zButtonTrack or not zButtonTrack.count then
return
end
if event == "SPELLS_CHANGED" or event == "CHARACTER_POINTS_CHANGED" then
zButtonTrack_CreateButtons()
zButtonTrack_SetupSizeAndPosition()
end
if event == "PLAYER_AURAS_CHANGED" or event == "PLAYER_ENTERING_WORLD"
or event == "SPELLS_CHANGED" or event == "CHARACTER_POINTS_CHANGED" then
local i = 1
local texture = zButtonTrack1IconTexture:GetTexture()
local buff = GetTrackingTexture()
if texture == buff and zButtonTrack2.id then
zButtonTrack.id = zButtonTrack2.id
else
zButtonTrack.id = zButtonTrack1.id
end
ZSpellButton_UpdateButton(zButtonTrack)
ZSpellButton_UpdateCooldown(zButtonTrack)
if GameTooltip:IsOwned(zButtonTrack) then
ZSpellButtonParent_OnEnter(zButtonTrack)
end
end
end
function zButtonTrack_KeyBinding(index)
if MTH_ZH_IsModuleEnabled and not MTH_ZH_IsModuleEnabled() then
return
end
local button
if index then
button = getglobal("zButtonTrack"..index)
else
button = zButtonTrack
end
if button.id then
CastSpell(button.id, "spell")
if zButtonTrack.hideonclick then
if type(ZSpellButton_SetChildrenExpanded) == "function" then
ZSpellButton_SetChildrenExpanded(zButtonTrack, false)
elseif zButtonTrack.children then
zButtonTrack.children:Hide()
end
end
end
end
SLASH_zButtonTrack1 = "/ZTrack"
SlashCmdList["zButtonTrack"] = function(msg)
if MTH_ZH_HandleDisabledSlash and MTH_ZH_HandleDisabledSlash("Track button is disabled while module 'zhunter' is disabled.") then
return
end
if msg == "reset" then
zButtonTrack_Reset()
zButtonTrack:ClearAllPoints()
zButtonTrack:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
elseif msg == "options" then
MTH_OpenOptions("Track")
else
MTH_ZH_Print("Possible Commands: \"options\", \"reset\"")
end
end
+14
View File
@@ -0,0 +1,14 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Frame name="zButtonTrackFrame">
</Frame>
<CheckButton name="zButtonTrack" inherits="ZSpellButtonTemplate">
<Anchors>
<Anchor point="CENTER" relativeTo="UIParent" relativePoint="CENTER">
<Offset>
<AbsDimension x="0" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
</Ui>
+262
View File
@@ -0,0 +1,262 @@
local function zButtonTrap_GetRoot()
return MTH_ZH_GetSavedRoot()
end
local root = zButtonTrap_GetRoot()
if not root["zButtonTrap"] then
root["zButtonTrap"] = {}
root["zButtonTrap"]["spells"] = {1, 2, 3, 4}
root["zButtonTrap"]["rows"] = 1
root["zButtonTrap"]["horizontal"] = nil
root["zButtonTrap"]["vertical"] = nil
root["zButtonTrap"]["firstbutton"] = "RIGHT"
root["zButtonTrap"]["enabled"] = 1
root["zButtonTrap"]["tooltip"] = 1
root["zButtonTrap"]["parent"] = {}
root["zButtonTrap"]["parent"]["size"] = 36
root["zButtonTrap"]["parent"]["hide"] = nil
root["zButtonTrap"]["parent"]["circle"] = 1
root["zButtonTrap"]["children"] = {}
root["zButtonTrap"]["children"]["size"] = 36
root["zButtonTrap"]["children"]["hideonclick"] = 1
end
ZHunterMod_Trap_Spells = {
ZHUNTER_TRAP_FREEZING,
ZHUNTER_TRAP_FROST,
ZHUNTER_TRAP_IMMOLATION,
ZHUNTER_TRAP_EXPLOSIVE
}
local ZHUNTER_TRAP_MAX = table.getn(ZHunterMod_Trap_Spells)
local function zButtonTrap_GetSaved()
local currentRoot = zButtonTrap_GetRoot()
if not currentRoot["zButtonTrap"] then
currentRoot["zButtonTrap"] = {}
end
return currentRoot["zButtonTrap"]
end
local function zButtonTrap_EnsureConfig()
local saved = zButtonTrap_GetSaved()
saved["count"] = nil
if saved["rows"] == nil then
saved["rows"] = 1
end
if saved["firstbutton"] == nil then
saved["firstbutton"] = "RIGHT"
end
if saved["enabled"] == nil then
saved["enabled"] = 1
end
if saved["tooltip"] == nil then
saved["tooltip"] = 1
end
if not saved["parent"] then
saved["parent"] = {}
end
if saved["parent"]["size"] == nil then
saved["parent"]["size"] = 36
end
if saved["parent"]["circle"] == nil then
saved["parent"]["circle"] = 1
end
if not saved["children"] then
saved["children"] = {}
end
if saved["children"]["size"] == nil then
saved["children"]["size"] = 36
end
if saved["children"]["hideonclick"] == nil then
saved["children"]["hideonclick"] = 1
end
if not saved["spells"] then
saved["spells"] = {}
end
if not saved["visible"] then
saved["visible"] = {}
end
for i = 1, ZHUNTER_TRAP_MAX do
if not tonumber(saved["spells"][i]) then
saved["spells"][i] = i
end
if saved["visible"][i] == nil then
saved["visible"][i] = 1
end
end
end
local function zButtonTrap_ApplyRuntimeSettings()
if not zButtonTrap then
return
end
local saved = zButtonTrap_GetSaved()
zButtonTrap.tooltip = saved["tooltip"] and true or false
zButtonTrap.hideonclick = saved["children"] and saved["children"]["hideonclick"] and true or false
end
function zButtonTrap_OnLoad()
this:RegisterEvent("VARIABLES_LOADED")
end
function zButtonTrap_OnEvent()
if event == "VARIABLES_LOADED" then
if not zButtonTrap then
return
end
if UnitClass("player") ~= ZHUNTER_HUNTER then
zButtonTrap:UnregisterAllEvents()
zButtonTrap:Hide()
return
end
zButtonTrap_CreateButtons()
zButtonTrapAdjustment = CreateFrame("Frame", "zButtonTrapAdjustment")
zButtonTrapAdjustment:RegisterEvent("PLAYER_REGEN_ENABLED")
zButtonTrapAdjustment:RegisterEvent("PLAYER_REGEN_DISABLED")
zButtonTrapAdjustment:RegisterEvent("PLAYER_ENTERING_WORLD")
zButtonTrapAdjustment:RegisterEvent("SPELLS_CHANGED")
zButtonTrapAdjustment:RegisterEvent("CHARACTER_POINTS_CHANGED")
zButtonTrapAdjustment:SetScript("OnEvent", zButtonTrapAdjustment_OnEvent)
zButtonTrap_SetupSizeAndPosition()
end
end
function zButtonTrap_CreateButtons()
zButtonTrap_EnsureConfig()
local saved = zButtonTrap_GetSaved()
ZSpellButton_CreateChildren(zButtonTrap, "zButtonTrap", ZHUNTER_TRAP_MAX)
local info = {}
local infoIndex = 1
for i=1, table.getn(ZHunterMod_Trap_Spells) do
if not tonumber(saved["spells"][i]) then
info = ZHunterMod_Trap_Spells
saved["spells"] = {1, 2, 3, 4}
break
end
local spellIndex = saved["spells"][i]
if saved["visible"][spellIndex] ~= false then
info[infoIndex] = ZHunterMod_Trap_Spells[spellIndex]
infoIndex = infoIndex + 1
end
end
zButtonTrap.found = ZSpellButton_SetButtons(zButtonTrap, info)
zButtonTrap_ApplyRuntimeSettings()
end
function zButtonTrap_SetupSizeAndPosition()
zButtonTrap_EnsureConfig()
local saved = zButtonTrap_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then
if zButtonTrap and zButtonTrap.Hide then
zButtonTrap:Hide()
end
return
end
local displayCount = zButtonTrap.found or ZHUNTER_TRAP_MAX
if displayCount < 0 then
displayCount = 0
end
ZSpellButton_SetSize(zButtonTrap, saved["parent"]["size"])
ZSpellButton_SetSize(zButtonTrap, saved["children"]["size"], 1)
ZSpellButton_SetExpandDirection(zButtonTrap, saved["firstbutton"])
ZSpellButton_ArrangeChildren(zButtonTrap, saved["rows"],
displayCount, saved["horizontal"],
saved["vertical"])
end
function zButtonTrap_Reset()
local currentRoot = zButtonTrap_GetRoot()
currentRoot["zButtonTrap"] = {}
local saved = zButtonTrap_GetSaved()
saved["spells"] = {1, 2, 3, 4}
saved["rows"] = 1
saved["horizontal"] = nil
saved["vertical"] = nil
saved["firstbutton"] = "RIGHT"
saved["enabled"] = 1
saved["tooltip"] = 1
saved["parent"] = {}
saved["parent"]["size"] = 36
saved["parent"]["hide"] = nil
saved["parent"]["circle"] = 1
saved["children"] = {}
saved["children"]["size"] = 36
saved["children"]["hideonclick"] = 1
saved["visible"] = {1, 1, 1, 1}
zButtonTrap_EnsureConfig()
end
function zButtonTrapAdjustment_OnEvent()
if not zButtonTrap or not zButtonTrap.count then
return
end
if event == "SPELLS_CHANGED" or event == "CHARACTER_POINTS_CHANGED" then
zButtonTrap_CreateButtons()
zButtonTrap_SetupSizeAndPosition()
end
local nextbutton
local button
local combat = event == "PLAYER_REGEN_DISABLED"
for i=1, zButtonTrap.count do
button = getglobal(zButtonTrap.name..i)
button.customcolor = nil
if button.id then
if not nextbutton then
nextbutton = button
end
if combat then
button.icontexture:SetVertexColor(0.4, 0.4, 0.4)
button.customcolor = 1
else
button.icontexture:SetVertexColor(1.0, 1.0, 1.0)
end
end
end
zButtonTrap.id = nextbutton and nextbutton.id or zButtonTrap1.id
ZSpellButton_UpdateButton(zButtonTrap)
ZSpellButton_UpdateCooldown(zButtonTrap)
if GameTooltip:IsOwned(zButtonTrap) then
ZSpellButtonParent_OnEnter(zButtonTrap)
end
end
function zButtonTrap_KeyBinding(index)
if MTH_ZH_IsModuleEnabled and not MTH_ZH_IsModuleEnabled() then
return
end
local button
if index then
button = getglobal("zButtonTrap"..index)
else
button = zButtonTrap
end
if button.id then
CastSpell(button.id, "spell")
if zButtonTrap.hideonclick then
if type(ZSpellButton_SetChildrenExpanded) == "function" then
ZSpellButton_SetChildrenExpanded(zButtonTrap, false)
elseif zButtonTrap.children then
zButtonTrap.children:Hide()
end
end
end
end
SLASH_zButtonTrap1 = "/ZTrap"
SlashCmdList["zButtonTrap"] = function(msg)
if MTH_ZH_HandleDisabledSlash and MTH_ZH_HandleDisabledSlash("Trap button is disabled while module 'zhunter' is disabled.") then
return
end
if msg == "reset" then
zButtonTrap_Reset()
zButtonTrap:ClearAllPoints()
zButtonTrap:SetPoint("CENTER", UIParent, "CENTER", 60, 0)
elseif msg == "options" then
MTH_OpenOptions("Trap")
else
MTH_ZH_Print("Possible Commands: \"options\", \"reset\"")
end
end
+14
View File
@@ -0,0 +1,14 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Frame name="zButtonTrapFrame">
</Frame>
<CheckButton name="zButtonTrap" inherits="ZSpellButtonTemplate">
<Anchors>
<Anchor point="CENTER" relativeTo="UIParent" relativePoint="CENTER">
<Offset>
<AbsDimension x="60" y="0"/>
</Offset>
</Anchor>
</Anchors>
</CheckButton>
</Ui>