6 Commits

Author SHA1 Message Date
Duvel c81ce85950 Merge pull request #13 from DuvelCorp/V1.4.1
v1.4.1 event leak fixes, chronometer trap fix, profile memory, autost…
2026-03-24 14:24:08 +01:00
DuvelCorp 680ddcba8a v1.4.1 event leak fixes, chronometer trap fix, profile memory, autostrip alloc fix 2026-03-24 14:21:58 +01:00
Duvel 5c08656532 Merge pull request #12 from DuvelCorp/V1.4.1
V1.4.1 performance fixes
2026-03-24 14:15:25 +01:00
DuvelCorp 8d80d0663c V1.4.1 performance fixes 2026-03-24 14:14:33 +01:00
Duvel 43e23e7616 Merge pull request #10 from DuvelCorp/v1.4.0
v1.4.0 Twow 1.18.1
2026-03-23 22:28:09 +01:00
Duvel f7b0318179 Add model viewer feature to README
Added model viewer feature for all beasts in the game.
2026-03-19 16:36:01 +01:00
27 changed files with 302 additions and 120 deletions
+25 -3
View File
@@ -2,17 +2,39 @@
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.
- Added **MM widget** module: tracks the new 3-state of Experimental ammo cycle (Fire → Nature → Arcane), the Lock and Load procs, and has adynamic cell that shows either Aimed Shot availability or the right shot to use following the current Experimental ammo proc if any. Lets Make MM great again. - Added **MM widget** module: tracks the new 3-state of Experimental ammo cycle (Fire → Nature → Arcane), the Lock and Load procs, and has a dynamic cell that shows either Aimed Shot availability or the right shot to use following the current Experimental ammo proc if any. Lets Make MM great again.
- Added new **Moth** pet family. - Added new **Moth** pet family.
@@ -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.
+8 -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,12 +63,16 @@ 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
The Book is the main GUI of MetaHunt, it allows to display the data constantly collected about you and your pet, and browse the addon's data to find anything a Hunter needs. The Book is the main GUI of MetaHunt, it allows to display the data constantly collected about you and your pet, and browse the addon's data to find anything a Hunter needs.
- Browse the MetaHunt datastores of NPCs (Beast, vendors, masters) and open the map to locate them like in pfQuest - Browse the MetaHunt datastores of NPCs (Beast, vendors, masters) and open the map to locate them like in pfQuest
- Model viewer of all beasts in the game.
- Track all info about the pet abilities that you know and don't know yet - Track all info about the pet abilities that you know and don't know yet
- Track all info about your stabled pets - Track all info about your stabled pets
- Keep an history of all your pets after you abandon them or if they run away. - Keep an history of all your pets after you abandon them or if they run away.
+18 -6
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()
AutoStrip_Trace("OnEvent evt=" .. tostring(event or "") if AutoStrip_TraceEnabled then
.. " runtime=" .. tostring(AutoStrip_On and 1 or 0) AutoStrip_Trace("OnEvent evt=" .. tostring(event or "")
.. " wasInCombat=" .. tostring(AutoStrip_WasInCombat and 1 or 0) .. " runtime=" .. tostring(AutoStrip_On and 1 or 0)
.. " playerInCombat=" .. tostring((type(UnitAffectingCombat) == "function" and UnitAffectingCombat("player")) and 1 or 0)) .. " wasInCombat=" .. tostring(AutoStrip_WasInCombat 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