2 Commits
27 changed files with 301 additions and 120 deletions
+24 -2
View File
@@ -2,13 +2,35 @@
All notable changes to MetaHunt will be documented in this file. All notable changes to MetaHunt will be documented in this file.
## [1.4.1] - 2026-03-24
### Added
- **zTrack**: added `Find Trees` in tracking spells.
### Changed
- **Performance — MM Widget / ExpAmmo**: Replaced tooltip-based aura scanning (which triggered hidden tooltip rendering on every aura check) with direct texture/icon comparison via `UnitBuff`/`UnitDebuff`. Added a 150 ms throttle on `PLAYER_AURAS_CHANGED`, which fires 10–50+ times per second in combat. Lock and Load detection and ammo cycle recovery after `/reload` both updated to use the new zero-cost texture path.
- **Performance — event frame leaks**: Some addon features were registering WoW game events at load time and never unregistering them when the feature was disabled from the options, causing their `OnEvent` handlers to fire even with the option turned off. Fixed for: Auto-Strip (`PLAYER_REGEN_*`), Smart Ammo (`SPELLCAST_*`, `START/STOP_AUTOREPEAT_SPELL`), and some zButton frames (Pet, Mounts, Track, Trap, Toys). Events are now properly registered on enable and unregistered on disable.
- **Chronometer — trap effects from other hunters**: Trap effect bars (`Immolation Trap Effect`, `Explosive Trap Effect`, `Freezing Trap Effect`, `Frost Trap Aura`) were incorrectly appearing when another hunter's trap triggered on a mob you were also targeting. .
- **Version check broadcast interval**: Increased update notification broadcast cooldown from 10 minutes to 1 hour to reduce channel traffic now that the user base has grown.
- **Profile snapshot memory**: The auto `BuildSnapshot` (called on every `/reload` via `PLAYER_LOGOUT`) was deep-copying `feedomatic.legacy`, a large migration table mirroring `FOM_Cooking`, `FOM_QuestFood`, `FOM_AddedFoods` etc. These are runtime/operational blobs, not user configuration settings, and should never be included in a profile. Introduced `MTH_Profile_CopyModules` which skips `legacy` and `history` keys, reducing the snapshot allocation from ~1 MB to a few KB.
## [1.4.0] - 2026-03-23 ## [1.4.0] - 2026-03-23
### TWoW 1.18.1 "Nightmares of Ursol" support ### TWoW 1.18.1 "Nightmares of Ursol" support
### Added
- **Complete beast database overhaul**: The MTH beast datastore was reconstructed from scratch, based on a full (beasts) 1.18.1 extract from live DB, gladly provided by Twow staff (thanks @Haaxor!). The beast data should now be 100% accurate, and notably all spawn coordinates, respawn times and pet abilities learnable on all beasts in the world. - **Complete beast database overhaul**: The MTH beast datastore was reconstructed from scratch, based on a full (beasts) 1.18.1 extract from live DB, gladly provided by Twow staff (thanks @Haaxor!). The beast data should now be 100% accurate, and notably all spawn coordinates, respawn times and pet abilities learnable on all beasts in the world.
- The **Beast Lore** page of the Book now allows to filter the list by Zone. Additionaly, the beast inspector has been reformated and all meaningful beast's data is displayed nicely. - The **Beast Lore** page of the Book now allows to filter the list by Zone. Additionally, the beast inspector has been reformatted and all meaningful beast's data is displayed nicely.
- All new and missing **Beasts Models** have been (re)scanned from MPQ game files and are viewable in the Beast Lore page, and browsable in the Family Model viewer. - All new and missing **Beasts Models** have been (re)scanned from MPQ game files and are viewable in the Beast Lore page, and browsable in the Family Model viewer.
@@ -46,7 +68,7 @@ All notable changes to MetaHunt will be documented in this file.
### Fixed ### Fixed
- Fixed **Chronometer** bars appearing from nearby players' combat events (e.g. another hunter's traps or DoTs triggering your own bars). - Fixed **Chronometer** bars appearing from nearby players' combat events (e.g. another hunter's traps or DoTs triggering your own bars).
- Fixed the list in Families Book's page, that wasnt tall enough to display all famillies (wolves were hidden). - Fixed the list in Families Book's page, that wasn't tall enough to display all families (wolves were hidden).
## [1.3.0] - 2026-03-19 ## [1.3.0] - 2026-03-19
+1 -1
View File
@@ -1,5 +1,5 @@
## Interface: 11200 ## Interface: 11200
## Version: 1.4.0 ## Version: 1.4.1
## Title: MetaHunt - |cff00ff00Hunter ## Title: MetaHunt - |cff00ff00Hunter
## Author: Metasploit and his Copilot ;) ## Author: Metasploit and his Copilot ;)
## Notes: Unified addon suite for huntards making old addons compatible with TurtleWoW, and adding an arsenal of never seen Hunter's utilities. ## Notes: Unified addon suite for huntards making old addons compatible with TurtleWoW, and adding an arsenal of never seen Hunter's utilities.
+7 -4
View File
@@ -1,12 +1,12 @@
# MetaHunt # MetaHunt
MetaHunt is a Turtle WoW Hunter toolkit. MetaHunt is a Turtle WoW Hunter toolkit.
It is a modern modular addon that combines never-seen features, and improves/fixes a few old hunter add-ons. It is a modern modular addon compiling brand new features, and improving a few old hunter add-ons, that were broken on twow.
It provides a bunch useful tools for all huntards, wheter they are still levelling, lone-wolf, or HL raider. It provides a bunch of useful tools for all huntards, wheter they are still levelling, lone-wolf, or HL raider.
## Twow Data ## Twow Data
MetaHunt ships with large up-to-date datastores for all Turtle WOW data a hunter needs : MetaHunt ships with large Turtle WOW datastores :
- 100% accurate beasts' data, their locations, and the abilities they can learn you - 100% accurate beasts' data, their locations, and the abilities they can learn you
- All Pet families, their abilities and their diet - All Pet families, their abilities and their diet
@@ -31,7 +31,7 @@ MetaHunt ships with large up-to-date datastores for all Turtle WOW data a hunter
- Vendors : Shows if a vendor sells Arrows and/or Bullets. - Vendors : Shows if a vendor sells Arrows and/or Bullets.
- Your pet : Shows your pet's XP, loyalty, happiness and how much you fed it this session. - Your pet : Shows your pet's XP, loyalty, happiness and how much you fed it this session.
## zBouttons ## zButtons
Old zHunterMod addon on steroids. Fully compatible with Twow, and enhanced with new functionalities Old zHunterMod addon on steroids. Fully compatible with Twow, and enhanced with new functionalities
@@ -63,6 +63,9 @@ Define your own simple rules for auto buy ammo and pet food when you open a vend
Just spam SHIFT-click on the NPC to validate quests Scorpok and Thorium arrows. Additionally you can have an enhanced tooltip that display your actual Scorpok-related items when you mouseover the mobs involved. Just spam SHIFT-click on the NPC to validate quests Scorpok and Thorium arrows. Additionally you can have an enhanced tooltip that display your actual Scorpok-related items when you mouseover the mobs involved.
## Beast model Viewer
Display the model of all beasts in the world. Always know what you are going to tame exactly before running there ! You can also browse all skin models of the same pet family to find the best-looking pet according to your tastes.
## The Great Book of Huntards ## The Great Book of Huntards
+14 -2
View File
@@ -150,6 +150,10 @@ function AutoStrip_SetAutoStripToggle(enabled, silent)
if enabled then if enabled then
saved["autostrip"] = 1 saved["autostrip"] = 1
AutoStrip_On = 1 AutoStrip_On = 1
if AutoStrip_Frame then
AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_DISABLED")
AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_ENABLED")
end
if AutoStripDisplay and AutoStripDisplay:IsVisible() and AutoStripDisplayAutoCast then if AutoStripDisplay and AutoStripDisplay:IsVisible() and AutoStripDisplayAutoCast then
AutoStripDisplayAutoCast:Show() AutoStripDisplayAutoCast:Show()
end end
@@ -159,6 +163,10 @@ function AutoStrip_SetAutoStripToggle(enabled, silent)
else else
saved["autostrip"] = nil saved["autostrip"] = nil
AutoStrip_On = nil AutoStrip_On = nil
if AutoStrip_Frame then
AutoStrip_Frame:UnregisterEvent("PLAYER_REGEN_DISABLED")
AutoStrip_Frame:UnregisterEvent("PLAYER_REGEN_ENABLED")
end
if AutoStripDisplayAutoCast then if AutoStripDisplayAutoCast then
AutoStripDisplayAutoCast:Hide() AutoStripDisplayAutoCast:Hide()
end end
@@ -252,10 +260,12 @@ function AutoStrip_UnequipAll(weaponsOnly)
end end
local function AutoStrip_OnEvent() local function AutoStrip_OnEvent()
if AutoStrip_TraceEnabled then
AutoStrip_Trace("OnEvent evt=" .. tostring(event or "") AutoStrip_Trace("OnEvent evt=" .. tostring(event or "")
.. " runtime=" .. tostring(AutoStrip_On and 1 or 0) .. " runtime=" .. tostring(AutoStrip_On and 1 or 0)
.. " wasInCombat=" .. tostring(AutoStrip_WasInCombat and 1 or 0) .. " wasInCombat=" .. tostring(AutoStrip_WasInCombat and 1 or 0)
.. " playerInCombat=" .. tostring((type(UnitAffectingCombat) == "function" and UnitAffectingCombat("player")) and 1 or 0)) .. " playerInCombat=" .. tostring((type(UnitAffectingCombat) == "function" and UnitAffectingCombat("player")) and 1 or 0))
end
if event == "VARIABLES_LOADED" then if event == "VARIABLES_LOADED" then
local saved = AutoStrip_GetSaved() local saved = AutoStrip_GetSaved()
AutoStrip_Trace("VARIABLES_LOADED saved.autostrip=" .. tostring(saved["autostrip"] and 1 or 0) AutoStrip_Trace("VARIABLES_LOADED saved.autostrip=" .. tostring(saved["autostrip"] and 1 or 0)
@@ -318,9 +328,11 @@ end
AutoStrip_Frame = CreateFrame("Frame", "MTH_AutoStripEvent") AutoStrip_Frame = CreateFrame("Frame", "MTH_AutoStripEvent")
if AutoStrip_Frame then if AutoStrip_Frame then
-- PLAYER_REGEN_DISABLED / PLAYER_REGEN_ENABLED are intentionally NOT registered here.
-- They are registered only when the feature is enabled via AutoStrip_SetAutoStripToggle(true),
-- and unregistered when it is disabled. This prevents any combat event overhead when the
-- feature is off.
AutoStrip_Frame:RegisterEvent("VARIABLES_LOADED") AutoStrip_Frame:RegisterEvent("VARIABLES_LOADED")
AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_DISABLED")
AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_ENABLED")
AutoStrip_Frame:RegisterEvent("PLAYER_ENTERING_WORLD") AutoStrip_Frame:RegisterEvent("PLAYER_ENTERING_WORLD")
AutoStrip_Frame:RegisterEvent("PLAYER_LOGOUT") AutoStrip_Frame:RegisterEvent("PLAYER_LOGOUT")
AutoStrip_Frame:SetScript("OnEvent", AutoStrip_OnEvent) AutoStrip_Frame:SetScript("OnEvent", AutoStrip_OnEvent)
+1 -1
View File
@@ -1,5 +1,5 @@
MTH_CONST = MTH_CONST or {} MTH_CONST = MTH_CONST or {}
MTH_CONST.version = MTH_CONST.version or "1.4.0" MTH_CONST.version = MTH_CONST.version or "1.4.1"
MTH_CONST.WEAPON_TYPES = { MTH_CONST.WEAPON_TYPES = {
BOWS = "Bows", BOWS = "Bows",
+1 -1
View File
@@ -1,5 +1,5 @@
MTH = MTH or { MTH = MTH or {
version = "1.4.0", version = "1.4.1",
name = "MetaHunt", name = "MetaHunt",
modules = {}, modules = {},
config = {}, config = {},
+26 -2
View File
@@ -19,6 +19,30 @@ local function MTH_Profile_DeepCopy(orig)
return copy return copy
end end
-- Shallow-copy a module's saved data, skipping keys that hold large operational
-- blobs (e.g. feedomatic's "legacy" table which mirrors FOM_Cooking, FOM_QuestFood
-- etc.) — those are runtime migration artifacts, not user configuration settings.
local MTH_PROFILE_SKIP_KEYS = { legacy = true, history = true }
local function MTH_Profile_CopyModules(src)
if type(src) ~= "table" then return {} end
local out = {}
for modName, modData in src do
if type(modData) == "table" then
local modCopy = {}
for k, v in modData do
if not MTH_PROFILE_SKIP_KEYS[k] then
modCopy[MTH_Profile_DeepCopy(k)] = MTH_Profile_DeepCopy(v)
end
end
out[modName] = modCopy
else
out[modName] = modData
end
end
return out
end
local function MTH_Profile_EnsureStore() local function MTH_Profile_EnsureStore()
if type(MTH_SavedVariables) ~= "table" then if type(MTH_SavedVariables) ~= "table" then
MTH_SavedVariables = {} MTH_SavedVariables = {}
@@ -47,13 +71,13 @@ local function MTH_Profile_BuildSnapshot()
-- Account-wide module option values (e.g. feedomatic) -- Account-wide module option values (e.g. feedomatic)
snap.config = (type(MTH_SavedVariables) == "table" snap.config = (type(MTH_SavedVariables) == "table"
and type(MTH_SavedVariables.modules) == "table") and type(MTH_SavedVariables.modules) == "table")
and MTH_Profile_DeepCopy(MTH_SavedVariables.modules) and MTH_Profile_CopyModules(MTH_SavedVariables.modules)
or {} or {}
-- Per-character module option values (ICU, Chronometer, AutoBuy, SmartAmmo, etc.) -- Per-character module option values (ICU, Chronometer, AutoBuy, SmartAmmo, etc.)
snap.charConfig = (type(MTH_CharSavedVariables) == "table" snap.charConfig = (type(MTH_CharSavedVariables) == "table"
and type(MTH_CharSavedVariables.modules) == "table") and type(MTH_CharSavedVariables.modules) == "table")
and MTH_Profile_DeepCopy(MTH_CharSavedVariables.modules) and MTH_Profile_CopyModules(MTH_CharSavedVariables.modules)
or {} or {}
-- Per-character module enabled/disabled states -- Per-character module enabled/disabled states
+2 -2
View File
@@ -221,8 +221,8 @@ end
function VC:ResetPublishDelay() function VC:ResetPublishDelay()
local now = VC_GetTimeNow() local now = VC_GetTimeNow()
if self.lastPublishedAt and (now - self.lastPublishedAt) < 600 then if self.lastPublishedAt and (now - self.lastPublishedAt) < 3600 then
return -- 10-minute cooldown between publishes return -- 1-hour cooldown between publishes
end end
self.nextPublishAt = now + math.random(10, 20) self.nextPublishAt = now + math.random(10, 20)
end end
+1 -1
View File
@@ -6,7 +6,7 @@
local MTH_AutoBuy = { local MTH_AutoBuy = {
name = "autobuy", name = "autobuy",
enabled = false, enabled = false,
version = "1.4.0", version = "1.4.1",
events = { events = {
"VARIABLES_LOADED", "VARIABLES_LOADED",
"MERCHANT_SHOW", "MERCHANT_SHOW",
+1 -1
View File
@@ -6,7 +6,7 @@
local MTH_AutoQuest = { local MTH_AutoQuest = {
name = "autoquest", name = "autoquest",
enabled = false, enabled = false,
version = "1.4.0", version = "1.4.1",
events = { events = {
"GOSSIP_SHOW", "GOSSIP_SHOW",
"QUEST_GREETING", "QUEST_GREETING",
+7 -4
View File
@@ -40,10 +40,13 @@ function MTH_ChronometerHunterInstallData(engine)
engine:AddTimer(engine.SPELL, BS["Wyvern Sting"], 12, 1, 0, 0, { gr = 2, cr = "MAROON", rc = true }) 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.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"] }) -- Trap effects: no "a=1" here — primed by the SPELL timer's "ea" chain (cast hook sets timer.v
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"] }) -- and timer.t). Using "a=1" would trigger on any hunter's affliction message since
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"] }) -- CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS never embeds a caster name.
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["Explosive Trap Effect"], 20, 1, 0, 1, { gr = 1, cr = "ORANGE", xn = BS["Explosive Trap"] })
engine:AddTimer(engine.EVENT, BS["Freezing Trap Effect"], 10, 1, 0, 1, { gr = 1, cr = "CYAN", 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", 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", 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 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 = "MAROON", xn = BS["Wing Clip"] }) engine:AddTimer(engine.EVENT, BS["Improved Wing Clip"], 5, 1, 0, 0, { a = 1, cr = "MAROON", xn = BS["Wing Clip"] })
engine:AddTimer(engine.EVENT, BS["Lock and Load"], 10, 0, 1, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\ability_hunter_lockandload" }) -- 10s (tooltip confirmed; expires on Aimed Shot cast) engine:AddTimer(engine.EVENT, BS["Lock and Load"], 10, 0, 1, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\ability_hunter_lockandload" }) -- 10s (tooltip confirmed; expires on Aimed Shot cast)
+39 -6
View File
@@ -580,14 +580,18 @@ function Chronometer:OnEnable()
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_AURA_GONE_SELF", function(event, info) self:SPELL_FADE(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_AURA_GONE_SELF", function(event, info) self:SPELL_FADE(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_AURA_GONE_OTHER", function(event, info) self:SPELL_FADE(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_AURA_GONE_OTHER", function(event, info) self:SPELL_FADE(event, info) end)
-- Registered events:
-- SELF_BUFFS / SELF_DAMAGE → our own procs & self-damage (source == ParserLib_SELF confirmed)
-- CREATURE_DAMAGE → DOT ticks on creatures ("from your X" embeds source; filtered in SPELL_PERIODIC)
-- CREATURE_BUFFS → debuff APPLICATION on creatures ("X is afflicted by Y"; no source embedded).
-- Needed for non-ticking debuffs: Poisonous/Enchanted Ammunition, Piercing Shot.
-- Foreign-bar risk is mitigated in SPELL_PERIODIC by requiring victim == target
-- when source is nil and no confirmed cast record exists.
-- FRIENDLYPLAYER_*, HOSTILEPLAYER_* are other players' events → intentionally NOT registered.
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end)
local enableRoM = false local enableRoM = false
for _, timer in pairs(self.timers[self.SPELL] or {}) do for _, timer in pairs(self.timers[self.SPELL] or {}) do
@@ -1274,11 +1278,20 @@ end
function Chronometer:SPELL_PERIODIC(event, info) function Chronometer:SPELL_PERIODIC(event, info)
local aura, rank, unit, isgain local aura, rank, unit, isgain
-- Ignore events not caused by the player (e.g. other players' DOTs/traps nearby) -- Primary filter: explicit non-self source → always ignore (other player's confirmed event)
if info.source and info.source ~= ParserLib_SELF then return end if info.source and info.source ~= ParserLib_SELF then return end
-- Secondary filter: creature/friendly periodic events do NOT embed a caster name,
-- so info.source is nil even for other players' effects. Track whether this event
-- was provably ours (SELF_BUFFS / SELF_DAMAGE events give source == ParserLib_SELF).
local sourceIsConfirmedSelf = (info.source == ParserLib_SELF)
if info.type == "buff" then if info.type == "buff" then
isgain = 1 isgain = 1
-- Buff gained by someone other than self with no source confirmation → another player's proc
if not sourceIsConfirmedSelf and info.victim ~= nil and info.victim ~= ParserLib_SELF then
return
end
elseif info.type == "debuff" then elseif info.type == "debuff" then
isgain = nil isgain = nil
elseif not info.isDOT then elseif not info.isDOT then
@@ -1306,7 +1319,27 @@ function Chronometer:SPELL_PERIODIC(event, info)
if timer.k.t then if timer.k.t then
if not unit then unit = UnitName("player") end if not unit then unit = UnitName("player") end
if timer.k.s then if timer.k.s then
if timer.t and timer.t ~= unit then return end -- Selforselect: four-tier confirmation.
-- 1. Confirmed cast record (timer.t set by CastSpell hook): require target match.
-- 2. Confirmed self source (SELF_BUFFS / SELF_DAMAGE events, source == SELF): accept.
-- 3. Cast-window confirmed (timer.v fresh, timer.t nil): untargeted spells like traps
-- where the caster is known but the trigger victim cannot be predicted in advance.
-- Accept unconditionally — the mob that walked into the trap may not be our target.
-- 4. Source unconfirmed AND no cast record (CREATURE_BUFFS affliction messages never
-- embed a caster name): fall back to target-check. This lets non-ticking debuffs
-- (Poisonous Ammo, Enchanted Ammo, Piercing Shot…) show when applied to our current
-- target, while blocking the same debuff on a mob we are NOT targeting (i.e. another
-- player's debuff on a different dummy).
if timer.t then
if timer.t ~= unit then return end
elseif sourceIsConfirmedSelf then
-- source confirmed → accept unconditionally
elseif timer.v and timer.v > GetTime() then
-- cast-window confirmed, timer.t nil → untargeted cast (e.g. trap placed on ground)
-- victim unknown at cast time; accept whatever mob triggered it
elseif not UnitExists("target") or unit ~= UnitName("target") then
return
end
else else
if not UnitExists("target") or unit ~= UnitName("target") then return end if not UnitExists("target") or unit ~= UnitName("target") then return end
end end
+1 -1
View File
@@ -1,7 +1,7 @@
local MTH_ChronometerModule = { local MTH_ChronometerModule = {
name = "chronometer", name = "chronometer",
enabled = true, enabled = true,
version = "1.4.0", version = "1.4.1",
events = {}, events = {},
initialized = false, initialized = false,
} }
+81 -46
View File
@@ -169,28 +169,66 @@ local function MTH_EA_GetLnLRemaining()
return nil return nil
end end
-- Scan all player auras (buffs then debuffs) for an active ammo state. -- ── Fast texture-based aura scanners (no tooltip, no pcall) ─────────────────
-- Returns the matching STATE_ORDER key, or nil if none found. -- UnitBuff("player", i) → icon texture path for buff slot i (nil = end)
local function MTH_EA_FindAmmoAura() -- UnitDebuff("player", i) → icon texture path for debuff slot i (nil = end)
-- Try buffs first -- We match by icon basename instead of buff name: zero rendering cost.
-- Known icon basenames (lower-case, no path prefix, no extension):
local MTH_EA_AMMO_TEX = {
[EXPLOSIVE] = "ability_searingarrow",
[POISONOUS] = "ability_poisonarrow",
[ENCHANTED] = "ability_theblackarrow",
}
local MTH_EA_LNL_TEX = "lockandload" -- matches "ability_hunter_lockandload"
local function MTH_EA_IconBasename(texturePath)
if not texturePath then return "" end
local s = string.lower(tostring(texturePath))
local _, _, base = string.find(s, "([^\\]+)$")
return base or s
end
-- Scan player buffs+debuffs for an active ammo state via texture comparison.
local function MTH_EA_FindAmmoStateByTexture()
for i = 1, 32 do for i = 1, 32 do
local name = MTH_EA_GetAuraName(false, i) local t = UnitBuff("player", i)
if not name then break end if not t then break end
for _, stateKey in ipairs(STATE_ORDER) do local base = MTH_EA_IconBasename(t)
if name == STATE_BUFF[stateKey] then return stateKey end for stateKey, frag in pairs(MTH_EA_AMMO_TEX) do
if base == frag then return stateKey end
end end
end end
-- Fall back to debuffs ("You are afflicted by" = player debuff)
for i = 1, 16 do for i = 1, 16 do
local name = MTH_EA_GetAuraName(true, i) local t = UnitDebuff("player", i)
if not name then break end if not t then break end
for _, stateKey in ipairs(STATE_ORDER) do local base = MTH_EA_IconBasename(t)
if name == STATE_BUFF[stateKey] then return stateKey end for stateKey, frag in pairs(MTH_EA_AMMO_TEX) do
if base == frag then return stateKey end
end end
end end
return nil return nil
end end
-- Returns true if LnL buff is currently on the player.
local function MTH_EA_HasLnLByTexture()
for i = 1, 32 do
local t = UnitBuff("player", i)
if not t then break end
if string.find(MTH_EA_IconBasename(t), MTH_EA_LNL_TEX, 1, true) then
return true
end
end
return false
end
-- Scan all player auras (buffs then debuffs) for an active ammo state.
-- Returns the matching STATE_ORDER key, or nil if none found.
-- (Delegates to the fast texture path; tooltip path kept for debug use only.)
local function MTH_EA_FindAmmoAura()
return MTH_EA_FindAmmoStateByTexture()
end
-- Restore cycle state from active auras (survives /reload within session). -- Restore cycle state from active auras (survives /reload within session).
local function MTH_EA_RecoverStateFromBuffs() local function MTH_EA_RecoverStateFromBuffs()
local stateKey = MTH_EA_FindAmmoAura() local stateKey = MTH_EA_FindAmmoAura()
@@ -234,6 +272,10 @@ end
-- Combat state flag (avoids needing InCombatLockdown, which doesn't exist in 1.12) -- Combat state flag (avoids needing InCombatLockdown, which doesn't exist in 1.12)
local inCombat = false local inCombat = false
-- Throttle for PLAYER_AURAS_CHANGED: even with the fast texture path this event
-- fires 10-50+/sec in combat, so cap processing at ~6/sec.
local MTH_EA_AurasChangedLastTime = 0
-- UI frame handles — declared here so MTH_EA_RefreshVisibility (and every -- UI frame handles — declared here so MTH_EA_RefreshVisibility (and every
-- function defined below) all close over the SAME locals. -- function defined below) all close over the SAME locals.
local strip = nil -- root drag frame (sized to 3×1 row) local strip = nil -- root drag frame (sized to 3×1 row)
@@ -834,47 +876,40 @@ frame:SetScript("OnEvent", function()
if event == "PLAYER_AURAS_CHANGED" then if event == "PLAYER_AURAS_CHANGED" then
if not MTH_EA_IsEnabled() then return end if not MTH_EA_IsEnabled() then return end
-- Pending LnL icon capture: buff is now on the unit, do the diff.
-- Throttle: cap processing at ~6/sec. Chat-message handlers cover all
-- real-time state transitions; this path is only for /reload recovery
-- and LnL sync, so a 150 ms gate is perfectly safe.
local now = GetTime()
if (now - MTH_EA_AurasChangedLastTime) < 0.15 then return end
MTH_EA_AurasChangedLastTime = now
-- Pending LnL icon capture (no-op stub; kept to avoid errors).
if lnlPendingCapture then if lnlPendingCapture then
MTH_EA_TryCaptureNewBuffIcon() MTH_EA_TryCaptureNewBuffIcon()
end end
-- ── LnL detection: always sync timer from tooltip ────────────────
-- PLAYER_AURAS_CHANGED fires for every buff change (unrelated to LnL), -- ── LnL sync: texture-based, zero tooltip cost ───────────────────
-- so we CANNOT just reset to DURATION on each fire. Instead we read -- We only SET active here (initial gain / missed chat message).
-- the actual remaining time from the game's own buff tooltip — this -- LOSS is authoritative from the AURA_GONE_SELF chat handler + OnUpdate
-- gives correct values for both initial proc AND mid-buff refresh. -- expiry, so we deliberately do NOT clear lnl.active when not found —
local lnlBuffIndex = nil -- AURAS_CHANGED fires for every unrelated buff change and a transient
for i = 1, 32 do -- miss during slot reordering would prematurely kill the timer.
local name = MTH_EA_GetAuraName(false, i) if MTH_EA_HasLnLByTexture() then
if not name then break end if not lnl.active then
if string.find(name, "Lock and Load", 1, true) then
lnlBuffIndex = i
break
end
end
if lnlBuffIndex then
local rem = MTH_EA_GetLnLRemaining()
if rem and rem > 0 then
-- Sync to game's real remaining time (handles refresh correctly too).
lnl.active = true lnl.active = true
lnl.expiresAt = GetTime() + rem lnl.expiresAt = now + lnl.DURATION
elseif not lnl.active then
-- Tooltip parse failed; first-gain fallback only.
lnl.active = true
lnl.expiresAt = GetTime() + lnl.DURATION
end end
-- If already active and parse failed: leave expiresAt as-is.
lnlPendingCapture = false lnlPendingCapture = false
end end
-- NOTE: do NOT set lnl.active=false here when the buff is not found.
-- AURAS_CHANGED fires for every unrelated buff change and the tooltip -- ── Recovery: resync ammo state after /reload ─────────────────────
-- scan can transiently miss LnL during slot reordering.
-- Loss is handled by the "fades from you" chat handler + OnUpdate expiry.
-- Recovery path: resync ammo state after /reload.
if rt.state == IDLE then if rt.state == IDLE then
local before = rt.state local stateKey = MTH_EA_FindAmmoStateByTexture()
MTH_EA_RecoverStateFromBuffs() if stateKey then
if MTH_EA_DebugMode and rt.state ~= before then rt.state = stateKey
rt.expiresAt = now + CYCLE_DURATION
rt.consumed = false
end end
MTH_EA_UpdateUI() MTH_EA_UpdateUI()
end end
+24 -24
View File
@@ -926,7 +926,7 @@ function FOM_OnEvent(event, arg1)
end end
if (foodID) then if (foodID) then
FOM_LastFood = GFWUtils.ItemLink(foodID); FOM_LastFood = GFWUtils.ItemLink(foodID);
GFWUtils.DebugLog("Manually fed "..FOM_LastFood); FOM_DebugLog("Manually fed "..FOM_LastFood);
end end
end end
return; return;
@@ -1245,31 +1245,31 @@ end
function FOM_CanFeed() function FOM_CanFeed()
local petInfo = MTH_FOM_GetCorePetInfo(); local petInfo = MTH_FOM_GetCorePetInfo();
if ( not (petInfo and petInfo.liveExists) ) then if ( not (petInfo and petInfo.liveExists) ) then
GFWUtils.DebugLog("Can't feed; pet doesn't exist."); FOM_DebugLog("Can't feed; pet doesn't exist.");
return false; return false;
end end
if ( tonumber(petInfo.health) and tonumber(petInfo.health) <= 0 ) then if ( tonumber(petInfo.health) and tonumber(petInfo.health) <= 0 ) then
GFWUtils.DebugLog("Can't feed; pet is dead."); FOM_DebugLog("Can't feed; pet is dead.");
return false; return false;
end end
if ( UnitHealth("player") <= 0 ) then if ( UnitHealth("player") <= 0 ) then
GFWUtils.DebugLog("Can't feed; I'm dead."); FOM_DebugLog("Can't feed; I'm dead.");
return false; return false;
end end
if ( CastingBarFrameStatusBar:IsVisible() ) then if ( CastingBarFrameStatusBar:IsVisible() ) then
GFWUtils.DebugLog("Can't feed; casting a spell / tradeksill."); FOM_DebugLog("Can't feed; casting a spell / tradeksill.");
return false; return false;
end end
if ( UnitOnTaxi("player") ) then if ( UnitOnTaxi("player") ) then
GFWUtils.DebugLog("Can't feed; flying."); FOM_DebugLog("Can't feed; flying.");
return false; return false;
end end
if ( FOM_State.InCombat ) or ( PlayerFrame.inCombat ) then if ( FOM_State.InCombat ) or ( PlayerFrame.inCombat ) then
GFWUtils.DebugLog("Can't feed; in combat."); FOM_DebugLog("Can't feed; in combat.");
return false; return false;
end end
if ( LootFrame:IsVisible() ) then if ( LootFrame:IsVisible() ) then
GFWUtils.DebugLog("Shouldn't feed; loot window is open."); FOM_DebugLog("Shouldn't feed; loot window is open.");
return false; return false;
end end
@@ -1290,7 +1290,7 @@ function FOM_CanFeed()
if ( buff ~= nil) then if ( buff ~= nil) then
for _, buffTexture in dontFeedBuffTextures do for _, buffTexture in dontFeedBuffTextures do
if ( buff == buffTexture ) then if ( buff == buffTexture ) then
GFWUtils.DebugLog("Can't feed; currently, eating, drinking, or feigning death."); FOM_DebugLog("Can't feed; currently, eating, drinking, or feigning death.");
return false; return false;
end end
end end
@@ -1303,7 +1303,7 @@ function FOM_CanFeed()
msg = string.lower(msg); msg = string.lower(msg);
for _, mountName in FOM_MOUNT_NAME_SUBSTRINGS do for _, mountName in FOM_MOUNT_NAME_SUBSTRINGS do
if (string.find(msg, mountName)) then if (string.find(msg, mountName)) then
GFWUtils.DebugLog("Can't feed; mounted."); FOM_DebugLog("Can't feed; mounted.");
return false; return false;
end end
end end
@@ -1856,13 +1856,13 @@ end
function FOM_AddFood(diet, food) function FOM_AddFood(diet, food)
if (FOM_Foods[diet] == nil) then if (FOM_Foods[diet] == nil) then
GFWUtils.DebugLog("FOM_Foods[diet] == nil"); FOM_DebugLog("FOM_Foods[diet] == nil");
end end
if (FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil) then if (FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil) then
GFWUtils.DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil"); FOM_DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil");
end end
if (FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil) then if (FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil) then
GFWUtils.DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil"); FOM_DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil");
end end
if ( GFWTable.IndexOf(FOM_Foods[diet], food) == 0 ) then if ( GFWTable.IndexOf(FOM_Foods[diet], food) == 0 ) then
if (FOM_AddedFoods == nil) then if (FOM_AddedFoods == nil) then
@@ -1898,13 +1898,13 @@ end
function FOM_RemoveFood(diet, food) function FOM_RemoveFood(diet, food)
if (FOM_Foods[diet] == nil) then if (FOM_Foods[diet] == nil) then
GFWUtils.DebugLog("FOM_Foods[diet] == nil"); FOM_DebugLog("FOM_Foods[diet] == nil");
end end
if (FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil) then if (FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil) then
GFWUtils.DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil"); FOM_DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil");
end end
if (FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil) then if (FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil) then
GFWUtils.DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil"); FOM_DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil");
end end
if ( GFWTable.IndexOf(FOM_Foods[diet], food) ~= 0 ) then if ( GFWTable.IndexOf(FOM_Foods[diet], food) ~= 0 ) then
if (FOM_RemovedFoods == nil) then if (FOM_RemovedFoods == nil) then
@@ -2341,7 +2341,7 @@ function FOM_Feed(aFood, options)
foodLevel = selectedFoodLevel, foodLevel = selectedFoodLevel,
}) })
GFWUtils.DebugLog("Picked "..FOM_LastFood.." (bag "..foodBag..", slot "..foodItem..") for feeding."); FOM_DebugLog("Picked "..FOM_LastFood.." (bag "..foodBag..", slot "..foodItem..") for feeding.");
if (FOM_Config.Debug) then if (FOM_Config.Debug) then
-- don't actually feed anything, just show what we would choose -- don't actually feed anything, just show what we would choose
return false; return false;
@@ -2708,12 +2708,12 @@ end
function FOM_IsUsefulFood(itemID, quantity) function FOM_IsUsefulFood(itemID, quantity)
local foodName = GetItemInfo(itemID); local foodName = GetItemInfo(itemID);
if (foodName == nil) then if (foodName == nil) then
GFWUtils.DebugLog("Can't get info for item ID "..itemID..", assuming it's OK to eat."); FOM_DebugLog("Can't get info for item ID "..itemID..", assuming it's OK to eat.");
return false; return false;
end end
if (FOM_Cooking and FOM_Cooking[FOM_RealmPlayer] and FOM_Cooking[FOM_RealmPlayer][itemID]) then if (FOM_Cooking and FOM_Cooking[FOM_RealmPlayer] and FOM_Cooking[FOM_RealmPlayer][itemID]) then
if (FOM_Cooking[FOM_RealmPlayer][itemID] >= FOM_Config.SaveForCookingLevel) then if (FOM_Cooking[FOM_RealmPlayer][itemID] >= FOM_Config.SaveForCookingLevel) then
GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; is good for cooking."); FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; is good for cooking.");
return true; return true;
end end
end end
@@ -2725,19 +2725,19 @@ function FOM_IsUsefulFood(itemID, quantity)
FOM_Quantity[foodName] = FOM_Quantity[foodName] + quantity; FOM_Quantity[foodName] = FOM_Quantity[foodName] + quantity;
end end
if (FOM_Quantity[foodName] > FOM_QuestFood[FOM_RealmPlayer][foodName]) then if (FOM_Quantity[foodName] > FOM_QuestFood[FOM_RealmPlayer][foodName]) then
GFWUtils.DebugLog("Not skipping "..quantity.."x "..foodName.."; is needed for quest, but we have more than enough."); FOM_DebugLog("Not skipping "..quantity.."x "..foodName.."; is needed for quest, but we have more than enough.");
return false; return false;
else else
GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; is needed for quest."); FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; is needed for quest.");
return true; return true;
end end
end end
end end
if (FOM_Config.AvoidBonusFood and FOM_IsInDiet(itemID, FOM_DIET_BONUS)) then if (FOM_Config.AvoidBonusFood and FOM_IsInDiet(itemID, FOM_DIET_BONUS)) then
GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; has bonus effect when eaten by player."); FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; has bonus effect when eaten by player.");
return true; return true;
end end
--GFWUtils.DebugLog("Not skipping "..quantity.."x "..foodName.."; doesn't have other uses."); --FOM_DebugLog("Not skipping "..quantity.."x "..foodName.."; doesn't have other uses.");
return false; return false;
end end
@@ -2775,7 +2775,7 @@ function FOM_IsInDiet(food, dietList)
diet = ""; diet = "";
end end
if (FOM_Foods[diet] == nil) then if (FOM_Foods[diet] == nil) then
GFWUtils.DebugLog("FOM_Foods[diet] == nil"); FOM_DebugLog("FOM_Foods[diet] == nil");
end end
if (FOM_RemovedFoods ~= nil and FOM_RemovedFoods[diet] ~= nil and GFWTable.IndexOf(FOM_RemovedFoods[diet], food) ~= 0) then if (FOM_RemovedFoods ~= nil and FOM_RemovedFoods[diet] ~= nil and GFWTable.IndexOf(FOM_RemovedFoods[diet], food) ~= 0) then
return false; return false;
+1 -1
View File
@@ -6,7 +6,7 @@
local MTH_FeedOMatic = { local MTH_FeedOMatic = {
name = "feedomatic", name = "feedomatic",
enabled = false, enabled = false,
version = "1.4.0", version = "1.4.1",
events = { events = {
"VARIABLES_LOADED", "VARIABLES_LOADED",
"MERCHANT_SHOW", "MERCHANT_SHOW",
+1 -1
View File
@@ -6,7 +6,7 @@
local MTH_ICU = { local MTH_ICU = {
name = "icu", name = "icu",
enabled = false, enabled = false,
version = "1.4.0", version = "1.4.1",
events = { events = {
"VARIABLES_LOADED", "VARIABLES_LOADED",
}, },
+21
View File
@@ -48,10 +48,25 @@ end
local MTHSmartAmmo_InitializeHooks local MTHSmartAmmo_InitializeHooks
MTHSmartAmmo_EnsureHooks = nil MTHSmartAmmo_EnsureHooks = nil
local MTH_SA_SPELL_EVENTS = {
"START_AUTOREPEAT_SPELL",
"STOP_AUTOREPEAT_SPELL",
"SPELLCAST_INTERRUPTED",
"SPELLCAST_FAILED",
"SPELLCAST_STOP",
"SPELLCAST_DELAYED",
}
function MTHSmartAmmo_SetSmartEnabled(enabled, silent) function MTHSmartAmmo_SetSmartEnabled(enabled, silent)
local saved = MTHSmartAmmo_GetSaved() local saved = MTHSmartAmmo_GetSaved()
if enabled then if enabled then
saved["enabled"] = 1 saved["enabled"] = 1
local evFrame = getglobal("MTH_SA_EventFrame")
if evFrame then
for _, ev in ipairs(MTH_SA_SPELL_EVENTS) do
evFrame:RegisterEvent(ev)
end
end
if MTHSmartAmmo_InitializeHooks then if MTHSmartAmmo_InitializeHooks then
MTHSmartAmmo_InitializeHooks() MTHSmartAmmo_InitializeHooks()
end end
@@ -63,6 +78,12 @@ function MTHSmartAmmo_SetSmartEnabled(enabled, silent)
end end
else else
saved["enabled"] = false saved["enabled"] = false
local evFrame = getglobal("MTH_SA_EventFrame")
if evFrame then
for _, ev in ipairs(MTH_SA_SPELL_EVENTS) do
evFrame:UnregisterEvent(ev)
end
end
if not silent and DEFAULT_CHAT_FRAME then if not silent and DEFAULT_CHAT_FRAME then
MTH_SA_Print("Smart Ammo Disabled.") MTH_SA_Print("Smart Ammo Disabled.")
end end
+1 -1
View File
@@ -7,7 +7,7 @@ MTH_SA_MANAGED_HOOKS = true
local MTH_SmartAmmo = { local MTH_SmartAmmo = {
name = "smartammo", name = "smartammo",
enabled = true, enabled = true,
version = "1.4.0", version = "1.4.1",
events = { events = {
"VARIABLES_LOADED", "VARIABLES_LOADED",
-- PLAYER_ENTERING_WORLD handled by engine's own frame -- PLAYER_ENTERING_WORLD handled by engine's own frame
+1 -1
View File
@@ -6,7 +6,7 @@
local MTH_Tooltips = { local MTH_Tooltips = {
name = "tooltips", name = "tooltips",
enabled = true, enabled = true,
version = "1.4.0", version = "1.4.1",
events = { events = {
"UPDATE_MOUSEOVER_UNIT", "UPDATE_MOUSEOVER_UNIT",
"UNIT_NAME_UPDATE", "UNIT_NAME_UPDATE",
+1
View File
@@ -86,6 +86,7 @@ ZHUNTER_TRACK_GIANTS = "Track Giants"
ZHUNTER_TRACK_MINERALS = "Find Minerals" ZHUNTER_TRACK_MINERALS = "Find Minerals"
ZHUNTER_TRACK_HERBS = "Find Herbs" ZHUNTER_TRACK_HERBS = "Find Herbs"
ZHUNTER_TRACK_TREASURE = "Find Treasure" ZHUNTER_TRACK_TREASURE = "Find Treasure"
ZHUNTER_TRACK_TREES = "Find Trees"
ZHUNTER_TRAP_FREEZING = "Freezing Trap" ZHUNTER_TRAP_FREEZING = "Freezing Trap"
ZHUNTER_TRAP_FROST = "Frost Trap" ZHUNTER_TRAP_FROST = "Frost Trap"
+1 -1
View File
@@ -8,7 +8,7 @@ MTH_ZH_MANAGED_HOOKS = true
local MTH_ZHunter = { local MTH_ZHunter = {
name = "zhunter", name = "zhunter",
enabled = true, enabled = true,
version = "1.4.0", version = "1.4.1",
events = { events = {
"VARIABLES_LOADED", "VARIABLES_LOADED",
-- PLAYER_ENTERING_WORLD handled by bootstrap frame + adjustment frames -- PLAYER_ENTERING_WORLD handled by bootstrap frame + adjustment frames
+5 -2
View File
@@ -249,7 +249,8 @@ end
function zButtonMounts_SetupSizeAndPosition() function zButtonMounts_SetupSizeAndPosition()
local saved = zButtonMounts_GetSaved() local saved = zButtonMounts_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then if saved["enabled"] == false or saved["enabled"] == 0 then
if MTH_ZH_MountsAdjust and MTH_ZH_MountsAdjust.SetScript then if MTH_ZH_MountsAdjust then
MTH_ZH_MountsAdjust:UnregisterAllEvents()
MTH_ZH_MountsAdjust:SetScript("OnEvent", nil) MTH_ZH_MountsAdjust:SetScript("OnEvent", nil)
end end
if zButtonMounts and zButtonMounts.Hide then if zButtonMounts and zButtonMounts.Hide then
@@ -257,7 +258,9 @@ function zButtonMounts_SetupSizeAndPosition()
end end
return return
end end
if MTH_ZH_MountsAdjust and MTH_ZH_MountsAdjust.SetScript then if MTH_ZH_MountsAdjust then
MTH_ZH_MountsAdjust:RegisterEvent("SPELLS_CHANGED")
MTH_ZH_MountsAdjust:RegisterEvent("PLAYER_ENTERING_WORLD")
MTH_ZH_MountsAdjust:SetScript("OnEvent", MTH_ZH_MountsAdjust_OnEvent) MTH_ZH_MountsAdjust:SetScript("OnEvent", MTH_ZH_MountsAdjust_OnEvent)
end end
local displayCount = zButtonMounts.found or 0 local displayCount = zButtonMounts.found or 0
+10 -2
View File
@@ -235,7 +235,8 @@ end
function zButtonPet_SetupSizeAndPosition() function zButtonPet_SetupSizeAndPosition()
local saved = zButtonPet_GetSaved() local saved = zButtonPet_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then if saved["enabled"] == false or saved["enabled"] == 0 then
if MTH_ZH_PetAdjust and MTH_ZH_PetAdjust.SetScript then if MTH_ZH_PetAdjust then
MTH_ZH_PetAdjust:UnregisterAllEvents()
MTH_ZH_PetAdjust:SetScript("OnEvent", nil) MTH_ZH_PetAdjust:SetScript("OnEvent", nil)
end end
if zButtonPet and zButtonPet.Hide then if zButtonPet and zButtonPet.Hide then
@@ -243,7 +244,14 @@ function zButtonPet_SetupSizeAndPosition()
end end
return return
end end
if MTH_ZH_PetAdjust and MTH_ZH_PetAdjust.SetScript then if MTH_ZH_PetAdjust then
MTH_ZH_PetAdjust:RegisterEvent("UNIT_HEALTH")
MTH_ZH_PetAdjust:RegisterEvent("UNIT_HAPPINESS")
MTH_ZH_PetAdjust:RegisterEvent("UNIT_PET")
MTH_ZH_PetAdjust:RegisterEvent("PET_BAR_UPDATE")
MTH_ZH_PetAdjust:RegisterEvent("PLAYER_ENTERING_WORLD")
MTH_ZH_PetAdjust:RegisterEvent("SPELLS_CHANGED")
MTH_ZH_PetAdjust:RegisterEvent("LEARNED_SPELL_IN_TAB")
MTH_ZH_PetAdjust:SetScript("OnEvent", MTH_ZH_PetAdjust_OnEvent) MTH_ZH_PetAdjust:SetScript("OnEvent", MTH_ZH_PetAdjust_OnEvent)
end end
local displayCount = zButtonPet.found or ZHUNTER_PET_MAX local displayCount = zButtonPet.found or ZHUNTER_PET_MAX
+5 -2
View File
@@ -249,7 +249,8 @@ end
function zButtonToys_SetupSizeAndPosition() function zButtonToys_SetupSizeAndPosition()
local saved = zButtonToys_GetSaved() local saved = zButtonToys_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then if saved["enabled"] == false or saved["enabled"] == 0 then
if MTH_ZH_ToysAdjust and MTH_ZH_ToysAdjust.SetScript then if MTH_ZH_ToysAdjust then
MTH_ZH_ToysAdjust:UnregisterAllEvents()
MTH_ZH_ToysAdjust:SetScript("OnEvent", nil) MTH_ZH_ToysAdjust:SetScript("OnEvent", nil)
end end
if zButtonToys and zButtonToys.Hide then if zButtonToys and zButtonToys.Hide then
@@ -257,7 +258,9 @@ function zButtonToys_SetupSizeAndPosition()
end end
return return
end end
if MTH_ZH_ToysAdjust and MTH_ZH_ToysAdjust.SetScript then if MTH_ZH_ToysAdjust then
MTH_ZH_ToysAdjust:RegisterEvent("SPELLS_CHANGED")
MTH_ZH_ToysAdjust:RegisterEvent("PLAYER_ENTERING_WORLD")
MTH_ZH_ToysAdjust:SetScript("OnEvent", MTH_ZH_ToysAdjust_OnEvent) MTH_ZH_ToysAdjust:SetScript("OnEvent", MTH_ZH_ToysAdjust_OnEvent)
end end
local displayCount = zButtonToys.found or 0 local displayCount = zButtonToys.found or 0
+11 -4
View File
@@ -5,7 +5,7 @@ end
local root = zButtonTrack_GetRoot() local root = zButtonTrack_GetRoot()
if not root["zButtonTrack"] then if not root["zButtonTrack"] then
root["zButtonTrack"] = {} root["zButtonTrack"] = {}
root["zButtonTrack"]["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} root["zButtonTrack"]["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
root["zButtonTrack"]["rows"] = 1 root["zButtonTrack"]["rows"] = 1
root["zButtonTrack"]["horizontal"] = nil root["zButtonTrack"]["horizontal"] = nil
root["zButtonTrack"]["vertical"] = nil root["zButtonTrack"]["vertical"] = nil
@@ -32,7 +32,8 @@ ZHunterMod_Track_Spells = {
ZHUNTER_TRACK_GIANTS, ZHUNTER_TRACK_GIANTS,
ZHUNTER_TRACK_MINERALS, ZHUNTER_TRACK_MINERALS,
ZHUNTER_TRACK_HERBS, ZHUNTER_TRACK_HERBS,
ZHUNTER_TRACK_TREASURE ZHUNTER_TRACK_TREASURE,
ZHUNTER_TRACK_TREES
} }
local ZHUNTER_TRACK_MAX = table.getn(ZHunterMod_Track_Spells) local ZHUNTER_TRACK_MAX = table.getn(ZHunterMod_Track_Spells)
@@ -311,7 +312,8 @@ function zButtonTrack_SetupSizeAndPosition()
zButtonTrack_EnsureConfig() zButtonTrack_EnsureConfig()
local saved = zButtonTrack_GetSaved() local saved = zButtonTrack_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then if saved["enabled"] == false or saved["enabled"] == 0 then
if MTH_ZH_TrackAdjust and MTH_ZH_TrackAdjust.SetScript then if MTH_ZH_TrackAdjust then
MTH_ZH_TrackAdjust:UnregisterAllEvents()
MTH_ZH_TrackAdjust:SetScript("OnEvent", nil) MTH_ZH_TrackAdjust:SetScript("OnEvent", nil)
end end
if zButtonTrack and zButtonTrack.Hide then if zButtonTrack and zButtonTrack.Hide then
@@ -319,7 +321,12 @@ function zButtonTrack_SetupSizeAndPosition()
end end
return return
end end
if MTH_ZH_TrackAdjust and MTH_ZH_TrackAdjust.SetScript then if MTH_ZH_TrackAdjust then
MTH_ZH_TrackAdjust:RegisterEvent("MINIMAP_UPDATE_TRACKING")
MTH_ZH_TrackAdjust:RegisterEvent("PLAYER_ENTERING_WORLD")
MTH_ZH_TrackAdjust:RegisterEvent("SPELLS_CHANGED")
MTH_ZH_TrackAdjust:RegisterEvent("CHARACTER_POINTS_CHANGED")
MTH_ZH_TrackAdjust:RegisterEvent("LEARNED_SPELL_IN_TAB")
MTH_ZH_TrackAdjust:SetScript("OnEvent", MTH_ZH_TrackAdjust_OnEvent) MTH_ZH_TrackAdjust:SetScript("OnEvent", MTH_ZH_TrackAdjust_OnEvent)
end end
local displayCount = zButtonTrack.found or ZHUNTER_TRACK_MAX local displayCount = zButtonTrack.found or ZHUNTER_TRACK_MAX
+8 -2
View File
@@ -154,7 +154,8 @@ function zButtonTrap_SetupSizeAndPosition()
zButtonTrap_EnsureConfig() zButtonTrap_EnsureConfig()
local saved = zButtonTrap_GetSaved() local saved = zButtonTrap_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then if saved["enabled"] == false or saved["enabled"] == 0 then
if MTH_ZH_TrapAdjust and MTH_ZH_TrapAdjust.SetScript then if MTH_ZH_TrapAdjust then
MTH_ZH_TrapAdjust:UnregisterAllEvents()
MTH_ZH_TrapAdjust:SetScript("OnEvent", nil) MTH_ZH_TrapAdjust:SetScript("OnEvent", nil)
end end
if zButtonTrap and zButtonTrap.Hide then if zButtonTrap and zButtonTrap.Hide then
@@ -162,7 +163,12 @@ function zButtonTrap_SetupSizeAndPosition()
end end
return return
end end
if MTH_ZH_TrapAdjust and MTH_ZH_TrapAdjust.SetScript then if MTH_ZH_TrapAdjust then
MTH_ZH_TrapAdjust:RegisterEvent("PLAYER_REGEN_ENABLED")
MTH_ZH_TrapAdjust:RegisterEvent("PLAYER_REGEN_DISABLED")
MTH_ZH_TrapAdjust:RegisterEvent("PLAYER_ENTERING_WORLD")
MTH_ZH_TrapAdjust:RegisterEvent("SPELLS_CHANGED")
MTH_ZH_TrapAdjust:RegisterEvent("CHARACTER_POINTS_CHANGED")
MTH_ZH_TrapAdjust:SetScript("OnEvent", MTH_ZH_TrapAdjust_OnEvent) MTH_ZH_TrapAdjust:SetScript("OnEvent", MTH_ZH_TrapAdjust_OnEvent)
end end
local displayCount = zButtonTrap.found or ZHUNTER_TRAP_MAX local displayCount = zButtonTrap.found or ZHUNTER_TRAP_MAX