7 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
DuvelCorp 8479607a13 v1.4.0 Twow 1.18.1 2026-03-23 22:25:10 +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
88 changed files with 66973 additions and 68726 deletions
+4
View File
@@ -9,3 +9,7 @@
tools/
LOC*.md
LOCALIZATION*.md
# Dev tooling — Python generators, data processing scripts, scratch files
# Not part of the addon, never ship this
.tools/
+5
View File
@@ -118,4 +118,9 @@
<Binding name="ZPet 6" header="ZPetHeader">
zButtonPet_KeyBinding(6)
</Binding>
<!-- ExpAmmo Action Button -->
<Binding name="ExpAmmo Action" header="ExpAmmoHeader">
MTH_EA_CastActionSpell();
</Binding>
</Ui>
+68
View File
@@ -2,6 +2,74 @@
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 1050+ 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
### 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.
- 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.
- 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 **Pollen Burst** pet ability.
- Added new **Aspect of the Viper** in zAspect.
- Added new **Chronometer** timer entries for 1.18.1 spells:
- Aimed Shot cooldown tracker
- Kill Command cooldown tracker
- Lock and Load proc timer
- Scent of Blood proc timer
- Added new **Chronometer** target debuff entries for the Experimental Ammo states:
- Poisonous Ammunition: 15s armor-reduction debuff (triggered when Serpent Sting consumes the Poisonous state)
- Enchanted Ammunition: 6s magic-resist debuff (triggered when Arcane Shot consumes the Enchanted state)
- Added the **5 new craftable ammo** to the Projectiles book's page, SmartAmmo and zAmmo button:
- **Bright Wood Arrows** (Survival: Journeyman, req. 30) — 10.5 DPS
- **Shade Wood Arrows** (Survival: Expert, req. 40) — 14.5 DPS
- **Smooth Ironfeather Arrows** (Survival: Artisan, req. 50) — 17.5 DPS
- **Starfeather Arrows** (Survival: Artisan, req. 55) — 19 DPS
- **Enchanted Thorium Shells** (Engineering: Artisan, req. 55) — 19 DPS
- Added new hunter-friends NPC of **Moonwhisper Coast** to the NPC Finder Book's page:
- **Hula Swiftmane** — Horde Stable Master (66.1, 39.1)
- **Ornala** — Horde Ammo Vendor (67.3, 37.1) — sells Arrows and Slugs
- **Badel Wildlance** — Alliance Stable Master (59.0, 24.9)
- **Elendon Truebough** — Alliance Ammo Vendor (58.8, 24.5) — sells Arrows
### Fixed
- 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 wasn't tall enough to display all families (wolves were hidden).
## [1.3.0] - 2026-03-19
+9
View File
@@ -2,6 +2,15 @@
-- MetaHunt: Hunter's Toolkit Addon
-- A unified addon merging FeedOMatic, Tooltips, and zhunter
-- Modern modular architecture with legacy addon support
--
-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-- TARGET RUNTIME: LUA 5.0 (WoW 1.12 / Turtle-WoW)
-- - Max 32 upvalues per function
-- - No # operator (use table.getn)
-- - No string.gmatch (use string.gfind)
-- - NEVER validate with Lua 5.1+ tools (false passes)
-- - Errors: check Logs/FrameXML.log first
-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
------------------------------------------------------
-- Initialize beast database after all files loaded
+4 -3
View File
@@ -1,5 +1,5 @@
## Interface: 11200
## Version: 1.3.0
## Version: 1.4.1
## Title: MetaHunt - |cff00ff00Hunter
## 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.
@@ -20,8 +20,6 @@ init\skins.xml
## Load database files (DB files must come before data\init.lua)
data\ds-beasts.lua
data\ds-beasts-extra.lua
data\ds-beasts-html-enrichment.lua
data\ds-vendors.lua
data\ds-vendors-extra.lua
data\ds-items.lua
@@ -31,6 +29,7 @@ data\ds-bags.lua
data\ds-items-atlas-sources.lua
data\ds-zones.lua
data\ds-zones-fallback.lua
data\ds-zones-wma.lua
data\ds-minimap-sizes.lua
data\ds-unit-coords.lua
data\ds-creature-coords.lua
@@ -39,6 +38,8 @@ data\ds-beasts-families-dbc.lua
data\ds-beasts-skins.lua
data\ds-pet-spells.lua
data\ds-pet-spells-trainer.lua
data\ds-hunter-spells.lua
data\ds-hunter-spells-dbc.lua
data\ds-racial.lua
data\init.lua
+11 -9
View File
@@ -1,14 +1,14 @@
# MetaHunt
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 provides a bunch useful tools for all huntards, wheter they are still levelling, lone-wolf, or HL raider.
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 of useful tools for all huntards, wheter they are still levelling, lone-wolf, or HL raider.
## 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 :
- All beasts, their location, 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 abilities ranks
- All Ammo (Arrows and Bullets)
@@ -21,6 +21,8 @@ MetaHunt ships with large up-to-date datastores for all Turtle WOW data a hunter
- Auto equip another ammo instantly during combat whenever you get out of your current ammo.
- Auto equip the right ammo when you swap from a box/xbow to a gun and the other way around.
## MM Widget
Lets Make MM great again. Tracks the new 3-state of Experimental ammo cycle (Fire → Nature → Arcane), the Lock&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.
## Tooltips
@@ -29,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.
- 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
@@ -61,18 +63,18 @@ 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.
## 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 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
- 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 your stabled pets
- Keep an history of all your pets after you abandon them or if they run away.
## What it will never do.
The goal of MetaHunt is to offer hunter's features that are not covered by existing Twow addons, and in others https://github.com/SabineWren/Quiver .
There's no point to reinvent the wheel, except is the wheel is broken. Nothing will work better than Quiver for auto-shot, castbar and tranqshot mgt. MetaHunt is build to work alongside of Quiver and is complementary to it, and it will remain like this unless Quiver turns to be not upgraded anymore.
+18 -6
View File
@@ -150,6 +150,10 @@ function AutoStrip_SetAutoStripToggle(enabled, silent)
if enabled then
saved["autostrip"] = 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
AutoStripDisplayAutoCast:Show()
end
@@ -159,6 +163,10 @@ function AutoStrip_SetAutoStripToggle(enabled, silent)
else
saved["autostrip"] = nil
AutoStrip_On = nil
if AutoStrip_Frame then
AutoStrip_Frame:UnregisterEvent("PLAYER_REGEN_DISABLED")
AutoStrip_Frame:UnregisterEvent("PLAYER_REGEN_ENABLED")
end
if AutoStripDisplayAutoCast then
AutoStripDisplayAutoCast:Hide()
end
@@ -252,10 +260,12 @@ function AutoStrip_UnequipAll(weaponsOnly)
end
local function AutoStrip_OnEvent()
AutoStrip_Trace("OnEvent evt=" .. tostring(event or "")
.. " runtime=" .. tostring(AutoStrip_On and 1 or 0)
.. " wasInCombat=" .. tostring(AutoStrip_WasInCombat and 1 or 0)
.. " playerInCombat=" .. tostring((type(UnitAffectingCombat) == "function" and UnitAffectingCombat("player")) and 1 or 0))
if AutoStrip_TraceEnabled then
AutoStrip_Trace("OnEvent evt=" .. tostring(event or "")
.. " runtime=" .. tostring(AutoStrip_On 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
local saved = AutoStrip_GetSaved()
AutoStrip_Trace("VARIABLES_LOADED saved.autostrip=" .. tostring(saved["autostrip"] and 1 or 0)
@@ -318,9 +328,11 @@ end
AutoStrip_Frame = CreateFrame("Frame", "MTH_AutoStripEvent")
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("PLAYER_REGEN_DISABLED")
AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_ENABLED")
AutoStrip_Frame:RegisterEvent("PLAYER_ENTERING_WORLD")
AutoStrip_Frame:RegisterEvent("PLAYER_LOGOUT")
AutoStrip_Frame:SetScript("OnEvent", AutoStrip_OnEvent)
+543
View File
@@ -0,0 +1,543 @@
------------------------------------------------------
-- MetaHunt: Beast Lore Scanner
-- TWoW 1.18.1 — "Nightmares of Ursol"
------------------------------------------------------
-- Fires when the player channels Beast Lore on a target.
-- Captures all available data and stores it in
-- MTH_SavedVariables.beastLoreScan.entries (account-wide).
--
-- Dedup rule: skips recording if the same creature name
-- already exists in this zone within 30 yards of current
-- player position (uses ds-minimap-sizes for yard scale).
-- A chat message is always printed either way.
------------------------------------------------------
local SPELL_BEAST_LORE = "Beast Lore"
local DEDUP_YARDS = 30
local FALLBACK_DEDUP_PCT = 0.015 -- ~1.5% of map width if zone size unknown
-- ── Tooltip probe ────────────────────────────────────────────
local MTH_BLS_Probe = nil
local function MTH_BLS_EnsureProbe()
if not MTH_BLS_Probe then
MTH_BLS_Probe = CreateFrame("GameTooltip", "MTH_BLSProbe", UIParent, "GameTooltipTemplate")
MTH_BLS_Probe:SetOwner(UIParent, "ANCHOR_NONE")
end
return MTH_BLS_Probe
end
-- Read left/right text lines from the probe (Lua 5.0 compatible: getglobal)
local function MTH_BLS_GetProbeLines()
local lines = {}
for i = 1, 24 do
local L = getglobal("MTH_BLSProbeTextLeft" .. i)
local R = getglobal("MTH_BLSProbeTextRight" .. i)
local lText = L and L:GetText() or nil
local rText = R and R:GetText() or nil
if (not lText or lText == "") and (not rText or rText == "") then
break
end
table.insert(lines, { left = lText or "", right = rText or "" })
end
return lines
end
-- Parse Beast Lore tooltip lines into structured fields.
-- Uses string.find with captures (Lua 5.0, no string.match).
local function MTH_BLS_ParseTooltip(lines)
local data = {
tameable = nil, -- true / false / nil (unknown)
diet = nil,
abilities = nil,
armor = nil,
health = nil,
minDmg = nil,
maxDmg = nil,
}
for _, line in ipairs(lines) do
local L = line.left or ""
local R = line.right or ""
-- Tameability ──────────────────────────────────────────
if string.find(L, "Cannot Be Tamed", 1, true) or string.find(R, "Cannot Be Tamed", 1, true) then
data.tameable = false
elseif string.find(L, "Can Be Tamed", 1, true) or string.find(R, "Can Be Tamed", 1, true)
or string.find(L, "Tameable", 1, true) or string.find(R, "Tameable", 1, true) then
data.tameable = true
end
-- Diet ─────────────────────────────────────────────────
if not data.diet then
local _, _, v = string.find(L, "^Diet:%s*(.*)")
if not v then _, _, v = string.find(R, "^Diet:%s*(.*)") end
if v and v ~= "" then data.diet = v end
end
-- Tamed Abilities ──────────────────────────────────────
if not data.abilities then
local _, _, v = string.find(L, "^Tamed Abilities:%s+(.*)")
if not v then _, _, v = string.find(R, "^Tamed Abilities:%s+(.*)") end
if v and v ~= "" then data.abilities = v end
end
-- Damage range ("107 - 133 Damage") ────────────────────
if not data.minDmg then
local _, _, lo, hi = string.find(L, "(%d+) %- (%d+) Damage")
if not lo then _, _, lo, hi = string.find(R, "(%d+) %- (%d+) Damage") end
if lo and hi then
data.minDmg = tonumber(lo)
data.maxDmg = tonumber(hi)
end
end
-- Armor ────────────────────────────────────────────────
if not data.armor then
local _, _, v = string.find(L, "Armor:%s*(%d+)")
if not v then _, _, v = string.find(R, "Armor:%s*(%d+)") end
if v then data.armor = tonumber(v) end
end
-- Health ───────────────────────────────────────────────
if not data.health then
local _, _, v = string.find(L, "Health:%s*(%d+)")
if not v then _, _, v = string.find(R, "Health:%s*(%d+)") end
if v then data.health = tonumber(v) end
end
end
return data
end
-- ── Location helpers ─────────────────────────────────────────
-- pfQuest AreaTable ID → WMA ID bridge (GetCurrentMapAreaID returns pfQ IDs)
local MTH_PFQ_TO_WMA = {
[1]=27,[3]=17,[4]=19,[8]=38,[10]=34,[11]=40,[12]=30,[14]=4,[15]=141,[16]=181,
[17]=11,[25]=519,[28]=22,[33]=37,[36]=15,[38]=35,[40]=39,[41]=32,[44]=36,
[45]=16,[46]=29,[47]=26,[51]=28,[85]=20,[130]=21,[139]=23,[141]=41,[148]=42,
[209]=650,[215]=9,[267]=24,[331]=43,[357]=121,[361]=182,[400]=61,[405]=101,
[406]=81,[408]=505,[409]=504,[440]=161,[490]=201,[491]=641,[493]=241,
[616]=501,[618]=281,[717]=611,[718]=516,[719]=609,[721]=518,[722]=639,
[796]=520,[876]=500,[1176]=605,[1337]=521,[1377]=261,[1477]=607,[1497]=382,
[1519]=301,[1537]=341,[1581]=514,[1583]=629,[1584]=623,[1637]=321,[1638]=362,
[1657]=381,[1769]=700,[1941]=523,[1977]=619,[2017]=652,[2040]=509,[2057]=648,
[2100]=517,[2159]=627,[2257]=659,[2366]=663,[2437]=603,[2557]=689,[2597]=401,
[2677]=635,[2717]=617,[3277]=443,[3358]=461,[3428]=654,[3429]=625,[3456]=667,
[3457]=682,[3478]=522,[4012]=502,[5023]=503,[5024]=511,[5053]=680,[5077]=670,
[5086]=674,[5087]=676,[5097]=678,[5103]=672,[5121]=507,[5130]=601,[5135]=644,
[5136]=643,[5138]=637,[5147]=655,[5148]=668,[5153]=645,[5163]=646,[5179]=510,
[5204]=662,[5208]=665,[5225]=513,[5536]=512,[5557]=683,[5561]=685,[5581]=686,
[5601]=691,[5602]=684,[5628]=693,[5640]=701,[5641]=698,[5642]=699,[5722]=702,
[5723]=657,[5731]=705,[5734]=704,
}
local function MTH_BLS_GetZoneId()
if type(SetMapToCurrentZone) == "function" then
pcall(SetMapToCurrentZone)
end
if type(GetCurrentMapAreaID) == "function" then
local ok, id = pcall(GetCurrentMapAreaID)
if ok and tonumber(id) and tonumber(id) > 0 then
local pfq = tonumber(id)
return MTH_PFQ_TO_WMA[pfq] or pfq
end
end
return 0
end
local function MTH_BLS_GetPlayerCoords()
if type(SetMapToCurrentZone) == "function" then
pcall(SetMapToCurrentZone)
end
if type(GetPlayerMapPosition) ~= "function" then return nil, nil end
local ok, x, y = pcall(GetPlayerMapPosition, "player")
if ok and x and y and (x ~= 0 or y ~= 0) then return x, y end
return nil, nil
end
-- Returns true if a beast with this name is already in the static MTH_DS_Beasts database.
-- We skip SavedVariables recording for beasts already catalogued in the DB.
local function MTH_BLS_IsInStaticDB(name)
if type(MTH_DS_Beasts) ~= "table" or not name or name == "" then return false end
for _, row in pairs(MTH_DS_Beasts) do
if type(row) == "table" and row.name == name then
return true
end
end
return false
end
-- ── Storage ──────────────────────────────────────────────────
local function MTH_BLS_EnsureStore()
if type(MTH_SavedVariables) ~= "table" then
MTH_SavedVariables = {}
end
if type(MTH_SavedVariables.beastLoreScan) ~= "table" then
MTH_SavedVariables.beastLoreScan = {}
end
if type(MTH_SavedVariables.beastLoreScan.entries) ~= "table" then
MTH_SavedVariables.beastLoreScan.entries = {}
end
return MTH_SavedVariables.beastLoreScan
end
-- ── Dedup ────────────────────────────────────────────────────
-- Returns the existing entry for a same-named beast in the same zone,
-- plus whether any of its recorded coords is within DEDUP_YARDS of (x, y).
local function MTH_BLS_FindEntry(name, zoneId, x, y)
local store = MTH_BLS_EnsureStore()
-- Normalize: treat 0 as unknown (entries are stored with nil for unknown zones)
if not zoneId or zoneId == 0 then zoneId = nil end
local mapW, mapH = nil, nil
if type(MTH_DS_MinimapSizes) == "table" and zoneId then
local sz = MTH_DS_MinimapSizes[zoneId]
if type(sz) == "table" then
mapW = tonumber(sz[1])
mapH = tonumber(sz[2])
end
end
local function IsNearby(ex, ey)
if not ex or not ey or not x or not y then return false end
local dx = ex - x
local dy = ey - y
if mapW and mapH then
return math.sqrt((dx * mapW)^2 + (dy * mapH)^2) < DEDUP_YARDS
else
-- No map size data: use a generous fallback (~5% of map width)
return math.sqrt(dx * dx + dy * dy) < 0.05
end
end
local entries = store.entries
for i = 1, table.getn(entries) do
local e = entries[i]
-- Match by name and zone. When either side has no zone, match on name alone
-- (coords will still be checked below; cross-zone false positives are
-- unlikely given players don't share coordinate spaces across zones).
local zoneMatch = (e.zoneId == zoneId) or (not e.zoneId) or (not zoneId)
if type(e) == "table"
and e.name == name
and zoneMatch
then
-- Check all recorded coords for this beast.
if type(e.coords) == "table" then
for j = 1, table.getn(e.coords) do
local c = e.coords[j]
if type(c) == "table" and IsNearby(c.x, c.y) then
return e, true -- entry found, nearby coord found
end
end
elseif IsNearby(e.x, e.y) then
-- Legacy single-coord entry
return e, true
end
return e, false -- entry found, but no coord nearby
end
end
return nil, false -- no entry for this beast in this zone
end
-- ── Main scan ────────────────────────────────────────────────
-- Per-session cooldown: prevents re-recording the same beast in the
-- same zone within SCAN_COOLDOWN seconds, as a safety net on top of
-- the coordinate-based dedup.
local MTH_BLS_ScanCooldowns = {}
local SCAN_COOLDOWN = 120 -- 2 minutes
local function MTH_BLS_Scan()
-- Basic target guards
if type(UnitExists) == "function" and not UnitExists("target") then return end
if type(UnitIsPlayer) == "function" and UnitIsPlayer("target") then return end
local name = (type(UnitName) == "function") and UnitName("target") or nil
if not name or name == "" then return end
-- ── Unit data ───────────────────────────────────────────
local level = (type(UnitLevel) == "function") and UnitLevel("target") or nil
local family = (type(UnitCreatureFamily) == "function") and UnitCreatureFamily("target") or nil
local healthMax = (type(UnitHealthMax) == "function") and UnitHealthMax("target") or nil
local minDmg, maxDmg, mainSpeed = nil, nil, nil
if type(UnitDamage) == "function" then
local ok, a, b, _, _, spd = pcall(UnitDamage, "target")
if ok then minDmg, maxDmg, mainSpeed = a, b, spd end
end
if not mainSpeed and type(UnitAttackSpeed) == "function" then
local ok, spd = pcall(UnitAttackSpeed, "target")
if ok then mainSpeed = spd end
end
local guid = nil
if type(UnitGUID) == "function" then
local ok, g = pcall(UnitGUID, "target")
if ok and g then guid = g end
end
-- ── Location ────────────────────────────────────────────
local zoneId = MTH_BLS_GetZoneId()
local x, y = MTH_BLS_GetPlayerCoords()
local zone = (type(GetZoneText) == "function") and GetZoneText() or ""
local subzone = (type(GetSubZoneText) == "function") and GetSubZoneText() or ""
-- Session cooldown: hard block on re-scanning the same beast in same zone
local cooldownKey = tostring(name) .. "|" .. tostring(zone)
local lastScan = MTH_BLS_ScanCooldowns[cooldownKey]
if lastScan and (GetTime() - lastScan) < SCAN_COOLDOWN then
MTH:Log("|cff888888Beast Lore: " .. tostring(name) .. " scanned recently — skipped|r")
return
end
-- ── Tooltip probe ───────────────────────────────────────
local probe = MTH_BLS_EnsureProbe()
probe:ClearLines()
local probeOk = pcall(function() probe:SetUnit("target") end)
local parsed = { tameable = nil, diet = nil, abilities = nil, armor = nil, health = nil }
if probeOk then
local lines = MTH_BLS_GetProbeLines()
parsed = MTH_BLS_ParseTooltip(lines)
end
-- Tooltip values override unit API (Beast Lore reveals more accurate data)
if parsed.minDmg then minDmg = parsed.minDmg end
if parsed.maxDmg then maxDmg = parsed.maxDmg end
if parsed.health then healthMax = parsed.health end
-- Fallback tameability: family present = tameable
if parsed.tameable == nil then
parsed.tameable = (family and family ~= "") and true or false
end
-- ── Dedup / upsert ──────────────────────────────────────
local function R3(v)
if type(v) ~= "number" then return nil end
return math.floor(v * 1000 + 0.5) / 1000
end
local function R2(v)
if type(v) ~= "number" then return nil end
return math.floor(v * 100 + 0.5) / 100
end
local rx, ry = R3(x), R3(y)
-- Mark scanned now (before storing) so any rapid re-trigger is blocked
MTH_BLS_ScanCooldowns[cooldownKey] = GetTime()
local existing, nearbyFound = MTH_BLS_FindEntry(name, zoneId, x, y)
if nearbyFound then
-- Already recorded at this location — do nothing.
MTH:Log("|cff888888Beast Lore: " .. tostring(name)
.. " already recorded nearby — skipped|r")
return
end
local store = MTH_BLS_EnsureStore()
if existing then
-- Known beast, new location — add coord to its list.
if type(existing.coords) ~= "table" then
-- Migrate legacy single coord into coords list.
existing.coords = {}
if existing.x or existing.y then
table.insert(existing.coords, { x = existing.x, y = existing.y, timestamp = existing.timestamp })
end
existing.x = nil
existing.y = nil
end
table.insert(existing.coords, { x = rx, y = ry, timestamp = (type(time) == "function") and time() or nil })
existing.lastUpdated = (type(time) == "function") and time() or nil
-- Update abilities/data if newly revealed by this cast.
if parsed.abilities and parsed.abilities ~= "" then existing.abilities = parsed.abilities end
local coordStr = (rx and ry)
and string.format(" (%.1f, %.1f)", rx * 100, ry * 100)
or ""
local abilitiesStr = (existing.abilities and existing.abilities ~= "")
and (" |cff88ddff[" .. existing.abilities .. "]|r")
or ""
MTH:Log("Beast Lore: |cffffaa00" .. tostring(name) .. "|r lv" .. (existing.level and tostring(existing.level) or "?")
.. " — new coord added" .. coordStr
.. abilitiesStr
.. " |cff888888[#" .. tostring(table.getn(store.entries)) .. " +" .. tostring(table.getn(existing.coords)) .. " loc]|r")
return
end
-- Skip recording if this beast is already in the static database.
if MTH_BLS_IsInStaticDB(name) then
MTH:Log("|cff888888Beast Lore: " .. tostring(name) .. " is already in the MetaHunt database — skipped|r")
return
end
-- New beast entirely.
local entry = {
name = name,
guid = guid,
level = level,
family = family,
tameable = parsed.tameable,
minDmg = minDmg and math.floor(minDmg + 0.5) or nil,
maxDmg = maxDmg and math.floor(maxDmg + 0.5) or nil,
attackSpeed = mainSpeed and R2(mainSpeed) or nil,
armor = parsed.armor or nil,
health = healthMax or nil,
diet = parsed.diet or nil,
abilities = parsed.abilities or nil,
coords = { { x = rx, y = ry, timestamp = (type(time) == "function") and time() or nil } },
zoneId = (zoneId and zoneId > 0) and zoneId or nil,
zone = (zone and zone ~= "") and zone or nil,
subzone = (subzone and subzone ~= "") and subzone or nil,
timestamp = (type(time) == "function") and time() or nil,
}
table.insert(store.entries, entry)
-- ── Chat confirmation ────────────────────────────────────
local tameStr = parsed.tameable
and "|cff33ff55Tameable|r"
or "|cffff4444Cannot be Tamed|r"
local famStr = (family and family ~= "")
and ("|cffffcc00" .. family .. "|r")
or "|cff888888unknown family|r"
local lvlStr = level and tostring(level) or "?"
local coordStr = (x and y)
and string.format(" (%.1f, %.1f)", x * 100, y * 100)
or ""
local zoneStr = (zone and zone ~= "") and (", " .. zone .. coordStr) or coordStr
local idx = table.getn(store.entries)
local abilitiesStr = ""
if parsed.abilities and parsed.abilities ~= "" then
abilitiesStr = " |cff88ddff[" .. parsed.abilities .. "]|r"
end
MTH:Log("|cff00ff88YOU FOUND AND RECORDED A NEW BEAST!|r |cffffaa00" .. tostring(name) .. "|r lv" .. lvlStr
.. "" .. tameStr .. "" .. famStr
.. zoneStr
.. abilitiesStr
.. " |cff888888[#" .. tostring(idx) .. "]|r")
end
-- ── Detection: event-gated tooltip poll ─────────────────────
-- SPELLCAST_CHANNEL_* events do not reliably fire in TurtleWoW 1.18.1.
-- Strategy: spellcast events open a short window (MTH_BLS_WindowEnd).
-- OnUpdate only runs during that window, checking the target tooltip
-- for Beast Lore-specific lines ("Diet:", "Tamed Abilities:").
-- If no event fires at all, the window stays closed and nothing runs.
local MTH_BLS_Frame = CreateFrame("Frame", "MTH_BeastLoreScanFrame")
local MTH_BLS_PollAccum = 0
local MTH_BLS_WindowEnd = 0 -- GetTime() deadline; 0 = window closed
local MTH_BLS_PollLast = nil -- target name already scanned this window
local WINDOW_DURATION = 6 -- seconds to probe after Beast Lore cast
local function MTH_BLS_OpenWindow()
MTH_BLS_WindowEnd = GetTime() + WINDOW_DURATION
MTH_BLS_PollLast = nil
end
-- [DISABLED] Beast Lore scan activation — not needed while full beast DB is shipped.
-- Re-enable by removing the `if false then` / `end` wrapper below.
if false then
-- Register all known spellcast event variants.
MTH_BLS_Frame:RegisterEvent("SPELLCAST_CHANNEL_START")
MTH_BLS_Frame:RegisterEvent("SPELLCAST_CHANNEL_STOP")
MTH_BLS_Frame:RegisterEvent("SPELLCAST_START")
MTH_BLS_Frame:RegisterEvent("SPELLCAST_STOP")
MTH_BLS_Frame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
MTH_BLS_Frame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
MTH_BLS_Frame:RegisterEvent("UNIT_SPELLCAST_START")
MTH_BLS_Frame:RegisterEvent("UNIT_SPELLCAST_STOP")
MTH_BLS_Frame:RegisterEvent("PLAYER_TARGET_CHANGED")
MTH_BLS_Frame:SetScript("OnEvent", function()
local evt = event or ""
if evt == "PLAYER_TARGET_CHANGED" then
-- New target: reset so re-targeting after a cast works.
MTH_BLS_PollLast = nil
return
end
-- Determine spell name from event args.
local isUnitEvt = string.sub(evt, 1, 15) == "UNIT_SPELLCAST_"
local spellName
if isUnitEvt then
if (arg1 or "") ~= "player" then return end
spellName = arg2 or ""
else
spellName = arg1 or ""
end
if string.find(spellName, SPELL_BEAST_LORE, 1, true) then
MTH_BLS_OpenWindow()
end
end)
MTH_BLS_Frame:SetScript("OnUpdate", function()
MTH_BLS_PollAccum = MTH_BLS_PollAccum + (arg1 or 0)
if MTH_BLS_PollAccum < 2.0 then return end
MTH_BLS_PollAccum = 0
if not (type(UnitExists) == "function" and UnitExists("target")) then return end
if type(UnitIsPlayer) == "function" and UnitIsPlayer("target") then return end
local name = (type(UnitName) == "function") and UnitName("target") or nil
if not name or name == "" then return end
if name == MTH_BLS_PollLast then return end
-- Probe the target tooltip for Beast Lore-specific lines.
local probe = MTH_BLS_EnsureProbe()
probe:ClearLines()
local probeOk = pcall(function() probe:SetUnit("target") end)
if not probeOk then return end
local hasData = false
for i = 1, 20 do
local L = getglobal("MTH_BLSProbeTextLeft" .. i)
if not L then break end
local txt = (L.GetText and L:GetText()) or ""
if string.find(txt, "Diet:", 1, true)
or string.find(txt, "Tamed Abilities:", 1, true)
or string.find(txt, "Cannot Be Tamed", 1, true)
then
hasData = true
break
end
end
if not hasData then return end
-- Beast Lore data confirmed — record and close window.
MTH_BLS_PollLast = name
MTH_BLS_WindowEnd = 0
local ok, err = pcall(MTH_BLS_Scan)
if not ok and MTH and MTH.Print then
MTH:Print("[BeastLore Scan] error: " .. tostring(err), "error")
end
end)
end -- [DISABLED] if false
-- ── Public accessors ─────────────────────────────────────────
-- Returns the first saved entry whose name matches (case-insensitive),
-- or nil if none found.
function MTH_BLS_FindSavedBeastByName(name)
local store = MTH_BLS_EnsureStore()
if not store or type(store.entries) ~= "table" then return nil end
local wantLower = string.lower(name or "")
if wantLower == "" then return nil end
for i = 1, table.getn(store.entries) do
local e = store.entries[i]
if type(e) == "table" and string.lower(e.name or "") == wantLower then
return e
end
end
return nil
end
+16 -4
View File
@@ -1,5 +1,5 @@
MTH_CONST = MTH_CONST or {}
MTH_CONST.version = MTH_CONST.version or "1.3.0"
MTH_CONST.version = MTH_CONST.version or "1.4.1"
MTH_CONST.WEAPON_TYPES = {
BOWS = "Bows",
@@ -24,6 +24,7 @@ MTH_CONST.AMMO = {
ICETHREADED = "Ice Threaded Bullet",
THORIUM = "Thorium Shells",
ROCKSHARD = "Rockshard Pellets",
CRAFTEDTHORIUM = "Enchanted Thorium Shells",
CANNONBALL = "Miniature Cannon Balls",
},
ARROWS = {
@@ -32,16 +33,19 @@ MTH_CONST.AMMO = {
RAZOR = "Razor Arrow",
FEATHER = "Feathered Arrow",
PRECISION = "Precision Arrow",
BRIGHT = "Bright Wood Arrows",
JAGGED = "Jagged Arrow",
SHADE = "Shade Wood Arrows",
ICETHREADED = "Ice Threaded Arrow",
SMOOTH = "Smooth Ironfeather Arrows",
THORIUM = "Thorium Headed Arrow",
STAR = "Starfeather Arrows",
DOOMSHOT = "Doomshot",
},
JUNKSHOTS = {
SERPENT = "Serpent Sting",
SCORPID = "Scorpid Sting",
VIPER = "Viper Sting",
ARCANE = "Arcane Shot",
CONCUSSIVE = "Concussive Shot",
DISTRACTING = "Distracting Shot",
BAITED = "Baited Shot",
@@ -69,6 +73,7 @@ BULLETS_ICETHREADED = MTH_CONST.AMMO.BULLETS.ICETHREADED
BULLETS_THORIUM = MTH_CONST.AMMO.BULLETS.THORIUM
BULLETS_ROCKSHARD = MTH_CONST.AMMO.BULLETS.ROCKSHARD
BULLETS_CANNONBALL = MTH_CONST.AMMO.BULLETS.CANNONBALL
BULLETS_CRAFTEDTHORIUM = MTH_CONST.AMMO.BULLETS.CRAFTEDTHORIUM
ARROWS_ROUGH = MTH_CONST.AMMO.ARROWS.ROUGH
ARROWS_SHARP = MTH_CONST.AMMO.ARROWS.SHARP
@@ -77,13 +82,16 @@ ARROWS_FEATHER = MTH_CONST.AMMO.ARROWS.FEATHER
ARROWS_PRECISION = MTH_CONST.AMMO.ARROWS.PRECISION
ARROWS_JAGGED = MTH_CONST.AMMO.ARROWS.JAGGED
ARROWS_ICETHREADED = MTH_CONST.AMMO.ARROWS.ICETHREADED
ARROWS_BRIGHT = MTH_CONST.AMMO.ARROWS.BRIGHT
ARROWS_SHADE = MTH_CONST.AMMO.ARROWS.SHADE
ARROWS_SMOOTH = MTH_CONST.AMMO.ARROWS.SMOOTH
ARROWS_THORIUM = MTH_CONST.AMMO.ARROWS.THORIUM
ARROWS_STAR = MTH_CONST.AMMO.ARROWS.STAR
ARROWS_DOOMSHOT = MTH_CONST.AMMO.ARROWS.DOOMSHOT
JUNKSHOT_SERPENT = MTH_CONST.AMMO.JUNKSHOTS.SERPENT
JUNKSHOT_SCORPID = MTH_CONST.AMMO.JUNKSHOTS.SCORPID
JUNKSHOT_VIPER = MTH_CONST.AMMO.JUNKSHOTS.VIPER
JUNKSHOT_ARCANE = MTH_CONST.AMMO.JUNKSHOTS.ARCANE
JUNKSHOT_CONCUSSIVE = MTH_CONST.AMMO.JUNKSHOTS.CONCUSSIVE
JUNKSHOT_DISTRACTING = MTH_CONST.AMMO.JUNKSHOTS.DISTRACTING
JUNKSHOT_BAITED = MTH_CONST.AMMO.JUNKSHOTS.BAITED
@@ -105,6 +113,7 @@ MTH_AMMO_BULLETS = {
BULLETS_ICETHREADED,
BULLETS_THORIUM,
BULLETS_ROCKSHARD,
BULLETS_CRAFTEDTHORIUM,
BULLETS_CANNONBALL,
}
@@ -114,9 +123,13 @@ MTH_AMMO_ARROWS = {
ARROWS_RAZOR,
ARROWS_FEATHER,
ARROWS_PRECISION,
ARROWS_BRIGHT,
ARROWS_JAGGED,
ARROWS_SHADE,
ARROWS_ICETHREADED,
ARROWS_SMOOTH,
ARROWS_THORIUM,
ARROWS_STAR,
ARROWS_DOOMSHOT,
}
@@ -124,7 +137,6 @@ MTH_AMMO_JUNKSHOTS = {
JUNKSHOT_SERPENT,
JUNKSHOT_SCORPID,
JUNKSHOT_VIPER,
JUNKSHOT_ARCANE,
JUNKSHOT_CONCUSSIVE,
JUNKSHOT_DISTRACTING,
JUNKSHOT_BAITED,
+7 -32
View File
@@ -1,5 +1,5 @@
MTH = MTH or {
version = "1.3.0",
version = "1.4.1",
name = "MetaHunt",
modules = {},
config = {},
@@ -266,15 +266,6 @@ if type(MTH_CharSavedVariables.modules) ~= "table" then
MTH_CharSavedVariables.modules = {}
end
local function MTH_ModuleStateDebug(message)
local text = "[MODULE STATE] " .. tostring(message or "")
if MTH and MTH.debug and MTH.Log then
MTH:Log(text, "debug")
elseif MTH and MTH.debug and MTH.Print then
MTH:Print(text, "debug")
end
end
local function MTH_IsPetUiFrameName(frameName)
local name = tostring(frameName or "")
if name == "" then
@@ -423,7 +414,6 @@ end
local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
if type(name) ~= "string" or name == "" then
MTH_ModuleStateDebug("read <invalid-name> fallback-default=" .. tostring(defaultEnabled and true or false))
return defaultEnabled and true or false
end
@@ -461,7 +451,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
local resolved = hardDefault and true or false
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
MTH_CharSavedVariables.modules[resolvedName].enabled = resolved
MTH_ModuleStateDebug("read " .. tostring(name) .. " seeded char default=" .. tostring(resolved))
return resolved
end
end
@@ -472,7 +461,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
local key = candidates[i]
if MTH_CharSavedVariables.moduleStates[key] ~= nil then
local resolved = MTH_CharSavedVariables.moduleStates[key] and true or false
MTH_ModuleStateDebug("read " .. tostring(name) .. " from char.moduleStates." .. tostring(key) .. "=" .. tostring(resolved))
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
return resolved
end
@@ -484,7 +472,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
local key = candidates[i]
if MTH_SavedVariables.moduleStates[key] ~= nil then
local resolved = MTH_SavedVariables.moduleStates[key] and true or false
MTH_ModuleStateDebug("read " .. tostring(name) .. " from moduleStates." .. tostring(key) .. "=" .. tostring(resolved))
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then
MTH_CharSavedVariables.modules[resolvedName] = {}
@@ -500,7 +487,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
local key = candidates[i]
if type(MTH_SavedVariables.modules[key]) == "table" and MTH_SavedVariables.modules[key].enabled ~= nil then
local resolved = MTH_SavedVariables.modules[key].enabled and true or false
MTH_ModuleStateDebug("read " .. tostring(name) .. " from modules." .. tostring(key) .. ".enabled=" .. tostring(resolved))
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then
MTH_CharSavedVariables.modules[resolvedName] = {}
@@ -515,7 +501,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
local key = candidates[i]
if type(MTH_SavedVariables[key]) == "table" and MTH_SavedVariables[key].enabled ~= nil then
local resolved = MTH_SavedVariables[key].enabled and true or false
MTH_ModuleStateDebug("read " .. tostring(name) .. " from legacy-top-level." .. tostring(key) .. ".enabled=" .. tostring(resolved))
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then
MTH_CharSavedVariables.modules[resolvedName] = {}
@@ -525,7 +510,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
end
end
MTH_ModuleStateDebug("read " .. tostring(name) .. " no-persisted-value fallback-default=" .. tostring(defaultEnabled and true or false))
return defaultEnabled and true or false
end
@@ -555,7 +539,6 @@ local function MTH_SetPersistedModuleEnabled(name, enabled)
enabled = enabled and true or false
MTH_CharSavedVariables.moduleStates[name] = enabled
MTH_CharSavedVariables.modules[name].enabled = enabled
MTH_ModuleStateDebug("write " .. tostring(name) .. " enabled=" .. tostring(enabled))
end
function MTH:InitEventRouter()
@@ -669,7 +652,6 @@ function MTH:RegisterModule(name, module)
end
if self.modules[name] then
if self.debug then print("|cFFFFAA00MetaHunt|r: Module '" .. name .. "' already registered") end
return false
end
@@ -684,8 +666,6 @@ function MTH:RegisterModule(name, module)
local initialEnabled = MTH_GetPersistedModuleEnabled(name, defaultEnabled)
module.enabled = initialEnabled and true or false
MTH_ModuleStateDebug("register " .. tostring(name) .. " default=" .. tostring(defaultEnabled) .. " initial=" .. tostring(module.enabled))
self.modules[name] = module
self:RegisterModuleEvents(name, module.events)
@@ -709,7 +689,6 @@ function MTH:RegisterModule(name, module)
self:_SetModuleEventSubscriptions(name, true)
end
if self.debug then print("|cFF00AA00MetaHunt|r: Module '" .. name .. "' registered") end
return true
end
@@ -774,7 +753,6 @@ function MTH:SetModuleEnabled(name, enabled)
if self.SetConfig then
self:SetConfig(name, "enabled", enabled)
end
MTH_ModuleStateDebug("request " .. tostring(name) .. " no-op runtime=" .. tostring(module.enabled) .. " persisted-synced")
return true
end
@@ -796,7 +774,6 @@ function MTH:SetModuleEnabled(name, enabled)
if self.SetConfig then
self:SetConfig(name, "enabled", enabled)
end
MTH_ModuleStateDebug("request " .. tostring(name) .. " applied runtime=" .. tostring(module.enabled))
return true
end
@@ -1035,6 +1012,12 @@ function MTH:Log(msg, severity)
return chatText
end
function MTH:DebugPrint(msg)
if self.debug then
self:Print("[DEBUG] " .. tostring(msg), "debug")
end
end
function MTH:Print(msg, severity)
return self:Log(msg, severity)
end
@@ -1083,12 +1066,6 @@ function MTH:SetMessageEnabled(key, enabled)
return true
end
function MTH:DebugPrint(msg)
if self.debug then
self:Print("[DEBUG] " .. tostring(msg), "debug")
end
end
function MTH_Log(message, severity)
if MTH and MTH.Log then
return MTH:Log(message, severity)
@@ -1270,12 +1247,10 @@ function MTH:ApplyPersistedModuleStates(source)
end
local persistedEnabled = MTH_GetPersistedModuleEnabled(name, defaultEnabled)
MTH_ModuleStateDebug("bootstrap " .. tostring(source or "") .. " " .. tostring(name) .. " persisted=" .. tostring(persistedEnabled) .. " runtime=" .. tostring(module.enabled and true or false))
if module.enabled ~= persistedEnabled then
local ok, err = self:SetModuleEnabled(name, persistedEnabled)
if not ok then
MTH_ModuleStateDebug("bootstrap apply failed " .. tostring(name) .. ": " .. tostring(err))
end
else
MTH_SetPersistedModuleEnabled(name, persistedEnabled)
-2
View File
@@ -623,13 +623,11 @@ function MTH_PT_ApplyScan(triggerReason)
local msg = "New pet data recorded (" .. tostring(added) .. " new rank(s)): " .. detailsText .. ". Known totals for this character: " .. tostring(totalBaselines) .. " ability type(s), " .. tostring(totalRanks) .. " rank(s)."
if MTH_PT_IsScanMessageEnabled() then
MTH:Print(msg)
MTH:Print("INFO: " .. msg, "debug")
end
else
local msg = "New pet data recorded (" .. tostring(added) .. " new rank(s)). Known totals for this character: " .. tostring(totalBaselines) .. " ability type(s), " .. tostring(totalRanks) .. " rank(s)."
if MTH_PT_IsScanMessageEnabled() then
MTH:Print(msg)
MTH:Print("INFO: " .. msg, "debug")
end
end
end
+172
View File
@@ -0,0 +1,172 @@
------------------------------------------------------
-- MetaHunt: Hunter Talent & Spellbook Scanner
-- Runs once on login and re-runs when spells/talents change.
--
-- Exposes:
-- MTH_HT_GetTalentRank(talentName) → currentRank (0 if unlearned)
-- MTH_HT_HasTalent(talentName) → true if rank >= 1
-- MTH_HT_GetSpellInfo(spellName) → { slot, rank, rankNum } or nil
-- MTH_HT_RescanTalents() → force re-scan of all talent tabs
-- MTH_HT_RescanSpellbook() → force re-scan of spellbook
--
-- Results cached in:
-- MTH_HT_Talents["TalentName"] = { tab, idx, rank, maxRank }
-- MTH_HT_Spells["SpellName"] = { slot, rank, rankNum }
-- (spell entry is the *highest rank* known for that name)
------------------------------------------------------
MTH_HT_Talents = {}
MTH_HT_Spells = {}
-- ---------------------------------------------------------------------------
-- Talent scanner
-- Uses GetNumTalentTabs / GetNumTalents / GetTalentInfo (all vanilla 1.12)
-- ---------------------------------------------------------------------------
function MTH_HT_RescanTalents()
MTH_HT_Talents = {}
local numTabs = GetNumTalentTabs and GetNumTalentTabs() or 0
for tabIdx = 1, numTabs do
local numTalents = GetNumTalents and GetNumTalents(tabIdx) or 0
for talIdx = 1, numTalents do
local name, _, _, _, currentRank, maxRank = GetTalentInfo(tabIdx, talIdx)
if name and name ~= "" then
local existing = MTH_HT_Talents[name]
-- If the same name appears in multiple tabs (unlikely), keep highest rank.
if not existing or (tonumber(currentRank) or 0) > (existing.rank or 0) then
MTH_HT_Talents[name] = {
tab = tabIdx,
idx = talIdx,
rank = tonumber(currentRank) or 0,
maxRank = tonumber(maxRank) or 0,
}
end
end
end
end
end
-- ---------------------------------------------------------------------------
-- Spellbook scanner
-- Iterates all player spell tabs and caches every known spell by name.
-- Stores the highest rank found (so MTH_HT_Spells["Aimed Shot"].slot is
-- always the actionable rank the player actually has).
-- ---------------------------------------------------------------------------
local function MTH_HT_ParseRankNum(rankStr)
if not rankStr or rankStr == "" then return 0 end
local _, _, n = string.find(tostring(rankStr), "(%d+)")
return tonumber(n) or 0
end
function MTH_HT_RescanSpellbook()
MTH_HT_Spells = {}
local numTabs = GetNumSpellTabs and GetNumSpellTabs() or 0
for tabIdx = 1, numTabs do
local _, _, offset, numSpells = GetSpellTabInfo(tabIdx)
for i = 1, numSpells do
local slot = offset + i
local name, rank = GetSpellName(slot, BOOKTYPE_SPELL)
if name and name ~= "" then
local rankNum = MTH_HT_ParseRankNum(rank)
local existing = MTH_HT_Spells[name]
if not existing or rankNum > (existing.rankNum or 0) then
MTH_HT_Spells[name] = {
slot = slot,
rank = rank or "",
rankNum = rankNum,
}
end
end
end
end
end
-- ---------------------------------------------------------------------------
-- Public accessors
-- ---------------------------------------------------------------------------
function MTH_HT_GetTalentRank(talentName)
local entry = MTH_HT_Talents[tostring(talentName or "")]
return entry and (entry.rank or 0) or 0
end
function MTH_HT_HasTalent(talentName)
return MTH_HT_GetTalentRank(talentName) >= 1
end
function MTH_HT_GetSpellInfo(spellName)
return MTH_HT_Spells[tostring(spellName or "")]
end
-- ---------------------------------------------------------------------------
-- Event-driven scanning
-- ---------------------------------------------------------------------------
local MTH_HT_Frame = CreateFrame("Frame", "MTH_HunterTalentScanFrame")
local MTH_HT_NeedTalentRescan = false
local MTH_HT_NeedSpellRescan = false
local MTH_HT_RescanDelay = 0.6 -- seconds after event before scanning
local MTH_HT_RescanElapsed = 0
MTH_HT_Frame:RegisterEvent("PLAYER_ENTERING_WORLD")
MTH_HT_Frame:RegisterEvent("LEARNED_SPELL_IN_TAB")
MTH_HT_Frame:RegisterEvent("SPELLS_CHANGED")
MTH_HT_Frame:RegisterEvent("CHARACTER_POINTS_CHANGED")
MTH_HT_Frame:SetScript("OnEvent", function()
if event == "PLAYER_ENTERING_WORLD" then
-- Immediate scan on login
MTH_HT_RescanTalents()
MTH_HT_RescanSpellbook()
if type(MTH_HT_OnScanComplete) == "function" then
MTH_HT_OnScanComplete()
end
-- Also schedule a deferred re-scan: GetTalentInfo can return stale
-- data for a brief window after PLAYER_ENTERING_WORLD on login.
MTH_HT_NeedTalentRescan = true
MTH_HT_NeedSpellRescan = true
MTH_HT_RescanElapsed = 0
this:Show() -- enable OnUpdate for the deferred pass
return
end
-- For other events, schedule a deferred rescan so we don't fire
-- multiple times if several events arrive in the same frame.
if event == "CHARACTER_POINTS_CHANGED" then
MTH_HT_NeedTalentRescan = true
end
if event == "LEARNED_SPELL_IN_TAB" or event == "SPELLS_CHANGED" then
MTH_HT_NeedSpellRescan = true
end
MTH_HT_RescanElapsed = 0
this:Show()
end)
MTH_HT_Frame:SetScript("OnUpdate", function()
MTH_HT_RescanElapsed = (MTH_HT_RescanElapsed or 0) + (arg1 or 0)
if MTH_HT_RescanElapsed < MTH_HT_RescanDelay then return end
-- Batch-flush pending scans
if MTH_HT_NeedTalentRescan then
MTH_HT_RescanTalents()
MTH_HT_NeedTalentRescan = false
end
if MTH_HT_NeedSpellRescan then
MTH_HT_RescanSpellbook()
MTH_HT_NeedSpellRescan = false
end
-- Notify dependents
if type(MTH_HT_OnScanComplete) == "function" then
MTH_HT_OnScanComplete()
end
this:Hide()
MTH_HT_RescanElapsed = 0
end)
MTH_HT_Frame:Hide()
+19 -11
View File
@@ -429,9 +429,7 @@ local function MTH_PETS_LogConsistency(line)
return
end
local function MTH_PETS_LogTame(line)
return
end
local function MTH_PETS_LogTame(_) end
local function MTH_PETS_FormatRowConsistency(row)
if type(row) ~= "table" then
@@ -856,11 +854,21 @@ local function MTH_PETS_ParseCreatureIdFromGuid(guid)
return nil
end
-- TBC-style string GUID: "Creature-realm-map-inst-?-ENTRY-spawn"
local _, _, creatureIdText = string.find(guidText, "^Creature%-%d+%-%d+%-%d+%-%d+%-(%d+)%-%d+$")
if creatureIdText then
return tonumber(creatureIdText)
end
-- Vanilla/TurtleWoW hex GUID: "0xF130EEEEEECCCCCC" — entry is bits 24-47 (hex chars 7-12)
if string.sub(guidText, 1, 2) == "0x" and string.len(guidText) >= 14 then
local entryHex = string.sub(guidText, 7, 12)
local parsed = tonumber(entryHex, 16)
if parsed and parsed > 0 then
return parsed
end
end
return nil
end
@@ -2553,7 +2561,6 @@ function MTH_PETS_RunSavedVarCleanup(pets)
pets._betaFreshStoreApplied = nil
if purged > 0 and MTH and MTH.Print then
MTH:Print("Cleaned up " .. tostring(purged) .. " stale pet-update records from SavedVariables.", "debug")
end
end
@@ -3400,7 +3407,6 @@ end
local function MTH_ST_DebugDumpLine(line)
if MTH and MTH.Print then
MTH:Print(tostring(line or ""), "debug")
end
end
@@ -3543,7 +3549,6 @@ function MTH_CommandPetsState()
.. " petTrainingLastScan=" .. tostring(petTraining and petTraining.lastScan or 0)
.. " hasCompletedPetScan=" .. tostring(petTraining and petTraining.hasCompletedPetScan or nil)
MTH:Print(summary)
MTH:Print("[PETSSTATE] " .. summary, "debug")
end
function MTH_CommandPetsReset()
@@ -3628,7 +3633,6 @@ function MTH_CommandPetsReset()
.. " preservedHistory=" .. tostring(historyCount)
.. " nextId=" .. tostring(store.nextId)
MTH:Print(line)
MTH:Print("[PETSRESET] " .. line, "debug")
return true
end
@@ -3784,9 +3788,8 @@ function MTH_ST_HandleSpellcastEvent(evt, eventArg1, eventArg2)
if evt == "SPELLCAST_START" or evt == "SPELLCAST_CHANNEL_START"
or evt == "UNIT_SPELLCAST_START" or evt == "UNIT_SPELLCAST_CHANNEL_START" then
if not MTH_PETS_IsTameBeastSpellName(castSpellName) then
return true
end
-- For vanilla SPELLCAST_* events arg1 is a duration (ms), not spell name.
-- Always forward to RecordTameAttempt — it has all the fallback/heuristic logic.
MTH_PETS_RecordTameAttempt(evt, castSpellName)
return true
end
@@ -4156,6 +4159,12 @@ function MTH_ST_InitService()
MTH_PetLifecycleEventFrame:RegisterEvent("UNIT_PET")
MTH_PetLifecycleEventFrame:RegisterEvent("PET_BAR_UPDATE")
MTH_PetLifecycleEventFrame:RegisterEvent("UNIT_HAPPINESS")
MTH_PetLifecycleEventFrame:RegisterEvent("SPELLCAST_CHANNEL_START")
MTH_PetLifecycleEventFrame:RegisterEvent("SPELLCAST_CHANNEL_STOP")
MTH_PetLifecycleEventFrame:RegisterEvent("SPELLCAST_START")
MTH_PetLifecycleEventFrame:RegisterEvent("SPELLCAST_STOP")
MTH_PetLifecycleEventFrame:RegisterEvent("SPELLCAST_FAILED")
MTH_PetLifecycleEventFrame:RegisterEvent("SPELLCAST_INTERRUPTED")
MTH_PetLifecycleEventFrame:RegisterEvent("CHAT_MSG_COMBAT_XP_GAIN")
MTH_PetLifecycleEventFrame:RegisterEvent("PLAYER_XP_UPDATE")
MTH_PetLifecycleEventFrame:RegisterEvent("CHAT_MSG_SYSTEM")
@@ -4172,7 +4181,6 @@ function MTH_ST_InitService()
MTH_PETS_InstallCoreRenameHook()
MTH_PETS_EmitLiveState("service:init", true)
if MTH_PETS_TRACE_CONSISTENCY and MTH and MTH.Print then
MTH:Print("[PETCONSIST] trace enabled", "debug")
end
end
+114 -50
View File
@@ -301,46 +301,6 @@ if type(MTH_CommandPetSpellScan) ~= "function" then
end
end
------------------------------------------------------
-- /mth diag — Runtime Diagnostics
------------------------------------------------------
function MTH_CommandDiag()
MTH:Print("======= MetaHunt Diagnostics =======", "debug")
-- 1. Lua version
local luaVer = _VERSION or "unknown"
MTH:Print("[DIAG] _VERSION = " .. tostring(luaVer), "debug")
MTH:Print("[DIAG] string.match = " .. tostring(type(string.match) == "function"), "debug")
MTH:Print("[DIAG] string.gfind = " .. tostring(type(string.gfind) == "function"), "debug")
-- 2. Active modules
local moduleCount = 0
local enabledModules = {}
if MTH.modules then
for name, mod in pairs(MTH.modules) do
moduleCount = moduleCount + 1
if mod.enabled then
table.insert(enabledModules, name)
end
end
end
MTH:Print("[DIAG] Registered modules: " .. tostring(moduleCount), "debug")
MTH:Print("[DIAG] Enabled: " .. table.concat(enabledModules, ", "), "debug")
-- 3. Event router state
local routerFrame = (MTH._eventRouter and MTH._eventRouter.frame) or nil
local routerEvents = (MTH._eventRouter and MTH._eventRouter.eventRefs) or {}
local eventCount = 0
for _ in pairs(routerEvents) do eventCount = eventCount + 1 end
MTH:Print("[DIAG] EventRouter frame: " .. tostring(routerFrame ~= nil) .. ", events: " .. tostring(eventCount), "debug")
-- 4. Debug frame initialized?
local dfInit = (MTH_DebugFrame and MTH_DebugFrame.initialized) and true or false
MTH:Print("[DIAG] DebugFrame initialized: " .. tostring(dfInit), "debug")
MTH:Print("======= End Diagnostics =======", "debug")
end
function SlashCmdList.MTH(msg, editbox)
if MTH and MTH.ApplyClassGate and MTH:ApplyClassGate("slash") then
return
@@ -352,24 +312,128 @@ function SlashCmdList.MTH(msg, editbox)
local lowerMsg = string.lower(msg)
local _, _, lowerCmd, lowerArg = string.find(lowerMsg, "^(%S+)%s*(.-)%s*$")
if msg == "" then
MTH:Print("Available: /mth options, /mth book, /mth diag, /mth err")
elseif lowerMsg == "options" then
MTH_CommandOptions()
elseif lowerMsg == "book" or lowerMsg == "hunterbook" then
MTH_CommandBook()
elseif lowerMsg == "peers" or lowerMsg == "who" then
MTH_CommandPeers()
elseif lowerMsg == "diag" then
MTH_CommandDiag()
MTH:Print("Available: /mth options, /mth book")
elseif lowerMsg == "err" or lowerMsg == "errors" or lowerMsg == "debug" then
if MTH_DebugFrame and MTH_DebugFrame.Toggle then
MTH_DebugFrame:Toggle()
else
MTH:Print("Debug frame is not available.")
end
elseif lowerMsg == "options" then
MTH_CommandOptions()
elseif lowerMsg == "book" or lowerMsg == "hunterbook" then
MTH_CommandBook()
elseif lowerMsg == "peers" or lowerMsg == "who" then
MTH_CommandPeers()
elseif lowerMsg == "zoneinfo" then
-- Dumps all available zone data for the current zone, for adding to ds-zones / ds-minimap-sizes
pcall(SetMapToCurrentZone)
local zoneName = (type(GetRealZoneText) == "function" and GetRealZoneText()) or ""
local subZone = (type(GetSubZoneText) == "function" and GetSubZoneText()) or ""
local zoneText = (type(GetZoneText) == "function" and GetZoneText()) or ""
local areaId = nil
if type(GetCurrentMapAreaID) == "function" then
local ok, v = pcall(GetCurrentMapAreaID)
if ok then areaId = v end
end
local cx, cy = nil, nil
if type(GetPlayerMapPosition) == "function" then
local ok, x, y = pcall(GetPlayerMapPosition, "player")
if ok then cx, cy = x, y end
end
local contId = nil
if type(GetCurrentMapContinent) == "function" then
local ok, v = pcall(GetCurrentMapContinent)
if ok then contId = v end
end
MTH:Print("|cffffff00=== Zone Info ===|r")
MTH:Print("GetRealZoneText: |cffffaa00" .. tostring(zoneName) .. "|r")
MTH:Print("GetZoneText: |cffffaa00" .. tostring(zoneText) .. "|r")
MTH:Print("GetSubZoneText: |cffffaa00" .. tostring(subZone) .. "|r")
MTH:Print("AreaID (GetCurrentMapAreaID): |cff88ffff" .. tostring(areaId) .. "|r")
MTH:Print("ContinentID: |cff88ffff" .. tostring(contId) .. "|r")
if cx and cy then
MTH:Print(string.format("Player map pos: |cff88ffff%.4f, %.4f|r (display: %.1f, %.1f)", cx, cy, cx*100, cy*100))
end
-- Also check if zone is in our tables
local inZones = MTH_DS_Zones and MTH_DS_Zones[tonumber(areaId)] and "YES" or "not in MTH_DS_Zones"
local inSizes = MTH_DS_MinimapSizes and MTH_DS_MinimapSizes[tonumber(areaId)] and "YES" or "not in ds-minimap-sizes"
MTH:Print("MTH_DS_Zones entry: " .. inZones)
MTH:Print("MTH_DS_MinimapSizes entry: " .. inSizes)
elseif lowerMsg == "npcid" then
-- Print the creature entry ID of the current target, or arm a listener for next NPC interaction
local function MTH_ParseCreatureEntryFromAnyGuid(guid)
if type(guid) ~= "string" or guid == "" then return nil end
-- Format 1: TBC-style "Creature-realm-map-inst-?-ENTRY-spawn"
local _, _, id1 = string.find(guid, "^Creature%-%d+%-%d+%-%d+%-%d+%-(%d+)%-%d+$")
if id1 then return tonumber(id1) end
-- Format 2: vanilla hex "0xF130EEEEEECCCCCC" — entry is bits 24-47 = hex chars 7-12
if string.sub(guid, 1, 2) == "0x" and string.len(guid) >= 14 then
local entryHex = string.sub(guid, 7, 12) -- 24 bits = up to 16M
local parsed = tonumber(entryHex, 16)
if parsed and parsed > 0 then return parsed end
end
return nil
end
local function MTH_PrintNpcId(unitToken)
unitToken = unitToken or "target"
local name = (type(UnitName) == "function") and UnitName(unitToken) or "?"
local level = (type(UnitLevel) == "function") and UnitLevel(unitToken) or "?"
-- Try UnitGUID first, then GetUnitGUID (TurtleWoW nameplate API)
local guid = nil
if type(UnitGUID) == "function" then
local ok, g = pcall(UnitGUID, unitToken)
if ok and g and g ~= "" then guid = g end
end
if (not guid or guid == "") and type(GetUnitGUID) == "function" then
local ok, g = pcall(GetUnitGUID, unitToken)
if ok and g and g ~= "" then guid = g end
end
local creatureId = MTH_ParseCreatureEntryFromAnyGuid(guid)
if creatureId then
MTH:Print(string.format("|cffffff00NPC:|r %s |cffffff00ID:|r |cff88ffff%s|r lvl: %s", tostring(name), tostring(creatureId), tostring(level)))
else
MTH:Print(string.format("|cffffff00NPC:|r %s lvl: %s |cffff8800GUID: %s|r", tostring(name), tostring(level), tostring(guid or "nil")))
MTH:Print("|cffaaaaaa(Could not parse creature ID from GUID)|r")
end
end
-- Try current target first
local hasTarget = (type(UnitExists) == "function") and UnitExists("target")
if hasTarget then
MTH_PrintNpcId("target")
end
-- Arm a one-shot frame for MERCHANT_SHOW / TRAINER_LIST_UPDATE / GOSSIP_SHOW
if not _G["MTH_NpcIdListenerFrame"] then
local f = CreateFrame("Frame", "MTH_NpcIdListenerFrame")
f:RegisterEvent("MERCHANT_SHOW")
f:RegisterEvent("TRAINER_LIST_UPDATE")
f:RegisterEvent("GOSSIP_SHOW")
f:SetScript("OnEvent", function()
MTH_PrintNpcId("target")
this:UnregisterEvent("MERCHANT_SHOW")
this:UnregisterEvent("TRAINER_LIST_UPDATE")
this:UnregisterEvent("GOSSIP_SHOW")
_G["MTH_NpcIdListenerFrame"] = nil
end)
if not hasTarget then
MTH:Print("|cffaaffaaArmed.|r Open any vendor, trainer, or stable master to capture their ID.")
end
end
elseif lowerCmd == "bls" then
if lowerArg == "reset" then
if type(MTH_SavedVariables) == "table" then
MTH_SavedVariables.beastLoreScan = { entries = {} }
end
MTH:Print("|cffff4444Beast Lore scan data wiped.|r All recorded beasts cleared.")
else
MTH:Print("Beast Lore Scan: |cffffff00/mth bls reset|r — wipe all recorded beast data")
end
else
MTH:Print("Unknown command: " .. tostring(msg))
MTH:Print("Available: /mth options, /mth book, /mth diag, /mth err")
MTH:Print("Available: /mth options, /mth book, /mth npcid, /mth bls reset")
end
end
+4 -30
View File
@@ -6,18 +6,6 @@
-- Uses MTH_DS_BeastSkins[familyName] generated by .tools/generators/gen_beast_skins.py
-- Skin rendering: PlayerModel:SetUnit(CreatureDisplayInfo.ID)
local function mv_log(msg)
if MTH_DebugFrame and type(MTH_DebugFrame.AddInfo) == "function" then
MTH_DebugFrame:AddInfo("[MV] " .. tostring(msg))
end
end
local function mv_err(msg)
if MTH_DebugFrame and type(MTH_DebugFrame.AddError) == "function" then
MTH_DebugFrame:AddError("[MV] " .. tostring(msg))
end
end
local MTH_MV = {
inited = false,
family = nil,
@@ -45,10 +33,8 @@ local MTH_MV = {
local function MTH_MV_ApplyModel(model, skinId)
if not model or not skinId then
mv_err("ApplyModel: nil model or skinId model="..tostring(model).." id="..tostring(skinId))
return
end
mv_log("ApplyModel id="..tostring(skinId))
model:SetUnit(skinId)
model:SetPosition(0, 0, 0)
model:SetModelScale(1)
@@ -106,14 +92,11 @@ MTH_MV_BuildSkinBeastList = function(skinId)
end
local function MTH_MV_Init()
if MTH_MV.inited then mv_log("Init: already done") return end
mv_log("Init: starting")
if MTH_MV.inited then return end
local backdrop = getglobal("MTH_BOOK_DetailBackdrop")
if not backdrop then
mv_err("Init: MTH_BOOK_DetailBackdrop not found")
return
end
mv_log("Init: backdrop found, creating previewFrame")
MTH_MV.inited = true
-- ----------------------------------------------------------------
@@ -136,7 +119,6 @@ local function MTH_MV_Init()
MTH_MV.previewFrame:SetBackdropBorderColor(0.35, 0.35, 0.35, 0.8)
MTH_MV.previewFrame:Hide()
mv_log("Init: previewFrame created, creating PlayerModel")
-- PlayerModel fills the inner area
MTH_MV.previewModel = CreateFrame("PlayerModel", nil, MTH_MV.previewFrame)
MTH_MV.previewModel:SetPoint("TOPLEFT", MTH_MV.previewFrame, "TOPLEFT", 3, -3)
@@ -158,7 +140,6 @@ local function MTH_MV_Init()
GameTooltip:Hide()
end)
mv_log("Init: previewModel created, creating popup")
-- ----------------------------------------------------------------
-- Popup frame (wider: left side = model viewer, right = beast list)
-- ----------------------------------------------------------------
@@ -343,7 +324,6 @@ local function MTH_MV_Init()
end
MTH_MV.popup = popup
mv_log("Init: complete")
end
-- ---------------------------------------------------------------------------
@@ -351,12 +331,10 @@ end
-- ---------------------------------------------------------------------------
function MTH_BOOK_ModelViewer_SetFamily(family, skinId)
mv_log("SetFamily: "..tostring(family).." skinId="..tostring(skinId))
MTH_MV_Init()
if not MTH_MV.inited then mv_err("SetFamily: init failed") return end
if not MTH_MV.inited then return end
local skins = MTH_DS_BeastSkins and type(MTH_DS_BeastSkins) == "table" and MTH_DS_BeastSkins[family]
if not skins or table.getn(skins) == 0 then
mv_log("SetFamily: no skins for "..tostring(family).." DS type="..type(MTH_DS_BeastSkins or false))
MTH_BOOK_ModelViewer_Clear()
return
end
@@ -380,7 +358,6 @@ function MTH_BOOK_ModelViewer_SetFamily(family, skinId)
MTH_BOOK_ModelViewer_Clear()
return
end
mv_log("SetFamily: "..table.getn(filteredSkins).." tameable skins (filtered from "..table.getn(skins)..")")
MTH_MV.family = family
MTH_MV.skins = filteredSkins
@@ -392,7 +369,6 @@ function MTH_BOOK_ModelViewer_SetFamily(family, skinId)
for i = 1, table.getn(filteredSkins) do
if filteredSkins[i].id == skinId then
MTH_MV.index = i
mv_log("SetFamily: skinId "..skinId.." matched skin index "..i)
break
end
end
@@ -409,7 +385,6 @@ function MTH_BOOK_ModelViewer_SetFamily(family, skinId)
end
function MTH_BOOK_ModelViewer_Clear()
mv_log("Clear")
if MTH_MV.previewFrame then MTH_MV.previewFrame:Hide() end
if not MTH_MV.keepPopup then
if MTH_MV.popup and MTH_MV.popup:IsShown() then MTH_MV.popup:Hide() end
@@ -420,10 +395,9 @@ function MTH_BOOK_ModelViewer_Clear()
end
function MTH_BOOK_ModelViewer_OpenPopup()
mv_log("OpenPopup skins="..table.getn(MTH_MV.skins))
MTH_MV_Init()
if not MTH_MV.popup then mv_err("OpenPopup: no popup frame") return end
if table.getn(MTH_MV.skins) == 0 then mv_log("OpenPopup: no skins") return end
if not MTH_MV.popup then return end
if table.getn(MTH_MV.skins) == 0 then return end
MTH_MV.popup:Show()
MTH_MV.popup:Raise()
MTH_MV_DisplayCurrent()
+98 -8
View File
@@ -29,13 +29,31 @@ function MTH_BOOK_GetBeastZoneSummary(beast)
return "-"
end
local seen = {}
local zoneNames = {}
-- Count coords per WMA zone ID to find the dominant zone.
local coordCount = {}
for i = 1, table.getn(beast.coords) do
local c = beast.coords[i]
if c and c[3] and not seen[c[3]] then
seen[c[3]] = true
table.insert(zoneNames, MTH_BOOK_GetZoneName(c[3]))
if c and c[3] then
local zid = c[3]
coordCount[zid] = (coordCount[zid] or 0) + 1
end
end
local zids = {}
for zid, _ in pairs(coordCount) do
table.insert(zids, zid)
end
-- Sort by frequency descending so the zone with most spawns is listed first.
table.sort(zids, function(a, b)
return (coordCount[a] or 0) > (coordCount[b] or 0)
end)
-- Resolve to zone names, deduplicating by name (multiple WMA IDs can resolve to the same zone).
local seenNames = {}
local zoneNames = {}
for i = 1, table.getn(zids) do
local name = MTH_BOOK_GetZoneName(zids[i])
if name and not seenNames[name] then
seenNames[name] = true
table.insert(zoneNames, name)
end
end
@@ -68,6 +86,69 @@ function MTH_BOOK_SplitAbilities(text)
return out
end
local _subzoneChildCache = nil
local function MTH_BOOK_EnsureSubzoneCache()
if _subzoneChildCache then return end
_subzoneChildCache = {}
if not MTH_DS_Zones then return end
for zid, row in pairs(MTH_DS_Zones) do
local parent = row.parent
local x1 = row.x1
local y1 = row.y1
local w = row.width
local h = row.height
if parent and x1 and y1 and w and h then
local names = row.names
local name = names and (names.enUS or names[GetLocale and GetLocale() or "enUS"] or names.deDE)
if name then
if not _subzoneChildCache[parent] then
_subzoneChildCache[parent] = {}
end
table.insert(_subzoneChildCache[parent], { x1, y1, x1 + w, y1 + h, name })
end
end
end
end
function MTH_BOOK_GetBeastSubZoneSummary(beast)
if not beast or not beast.coords or table.getn(beast.coords) == 0 then return nil end
MTH_BOOK_EnsureSubzoneCache()
if not _subzoneChildCache then return nil end
local counts = {}
for i = 1, table.getn(beast.coords) do
local c = beast.coords[i]
if c then
local cx, cy, wmaId = c[1], c[2], c[3]
if cx and cy and wmaId then
local pfqId = wmaId
if type(MTH_MAP_WMA_TO_PFQ) == "table" then
pfqId = MTH_MAP_WMA_TO_PFQ[wmaId] or wmaId
end
local children = _subzoneChildCache[pfqId]
if children then
for _, sub in ipairs(children) do
if cx >= sub[1] and cx <= sub[3] and cy >= sub[2] and cy <= sub[4] then
counts[sub[5]] = (counts[sub[5]] or 0) + 1
break
end
end
end
end
end
end
local bestName, bestCount = nil, 0
for name, count in pairs(counts) do
if count > bestCount then
bestName = name
bestCount = count
end
end
return bestName
end
function MTH_BOOK_HasUsableAbilities(beast)
if not beast then return false end
local abilities = MTH_BOOK_SplitAbilities(beast.abilities)
@@ -232,8 +313,11 @@ function MTH_BOOK_BeastMatches(beastId, beast)
end
if MTH_BOOK_STATE.petInZoneOnly then
local currentZoneId = MTH_BOOK_GetCurrentZoneId()
if currentZoneId and not MTH_BOOK_BeastHasZoneId(beast, currentZoneId) then
-- Use the zone ID cached once per BuildResults call (avoids N calls to
-- GetCurrentZoneId which is expensive). If zone ID is nil (new/unknown
-- zone like Moonwhisper Coast), no DB entry can match — exclude all.
local currentZoneId = MTH_BOOK_STATE._cachedZoneId
if not currentZoneId or not MTH_BOOK_BeastHasZoneId(beast, currentZoneId) then
return false
end
end
@@ -251,6 +335,12 @@ function MTH_BOOK_BeastMatches(beastId, beast)
end
end
if MTH_BOOK_STATE.petZoneFilter and MTH_BOOK_STATE.petZoneFilter ~= "all" then
if not MTH_BOOK_BeastHasZoneId(beast, MTH_BOOK_STATE.petZoneFilter) then
return false
end
end
return true
end
@@ -258,7 +348,7 @@ function MTH_BOOK_BeastSort(a, b)
local beasts = MTH_DS_Beasts
local ba = beasts and beasts[a]
local bb = beasts and beasts[b]
if not ba or not bb then return a < b end
if not ba or not bb then return tostring(a) < tostring(b) end
local la = MTH_BOOK_ParseLevel(ba.lvl) or 0
local lb = MTH_BOOK_ParseLevel(bb.lvl) or 0
if la ~= lb then return la < lb end
+346 -51
View File
@@ -69,6 +69,8 @@ local MTH_BOOK_STATE = {
petOnlyMyLevel = true,
itemOnlyMyLevel = false,
petInZoneOnly = false,
petContinent = "all",
petZoneFilter = "all",
itemSubtype = "all",
npcFunction = "all",
npcZone = "all",
@@ -274,7 +276,7 @@ local MTH_BOOK_CONTENT_LAYOUT_FAMILIES = {
listX = 16,
listY = -74,
listW = 728,
listH = 376,
listH = 456,
detailX = 748,
detailY = -74,
detailW = 1,
@@ -364,7 +366,7 @@ local function MTH_BOOK_UpdateCheckboxLayoutByMode()
getglobal("MTH_BOOK_HideNoAbilities"),
getglobal("MTH_BOOK_HideUnknown"),
}
local xOffsets = { 18, 86, 154, 232, 372 }
local xOffsets = { 18, 86, 154, 232, 345 }
local yOffset = -140
if MTH_BOOK_STATE.mode == "npcs" then
yOffset = -116
@@ -754,12 +756,15 @@ local function MTH_BOOK_ShowAllFilteredBeastsOnMap()
end
local nodes = {}
local firstZoneId = nil
for i = 1, table.getn(MTH_BOOK_STATE.results or {}) do
local beastId = tonumber(MTH_BOOK_STATE.results[i])
local beast = beastId and MTH_DS_Beasts and MTH_DS_Beasts[beastId]
if beast and beast.coords then
local beastDisplayName = (MTH and MTH.GetLocalizedBeastName and MTH:GetLocalizedBeastName(beastId, beast.name)) or beast.name or "Unknown"
local cr, cg, cb = 0.95, 0.82, 0.10
if MTH_Map and MTH_Map.GetFamilyColor then
cr, cg, cb = MTH_Map:GetFamilyColor(beast.family)
end
for j = 1, table.getn(beast.coords) do
local c = beast.coords[j]
if c and c[1] and c[2] and c[3] then
@@ -767,9 +772,6 @@ local function MTH_BOOK_ShowAllFilteredBeastsOnMap()
local y = tonumber(c[2])
local zoneId = tonumber(c[3])
if x and y and zoneId then
if not firstZoneId then
firstZoneId = zoneId
end
local details = string.format("Family: %s\nLevel: %s\nAbilities: %s", beast.family or "?", beast.lvl or "?", beast.abilities or "None")
table.insert(nodes, {
zoneId = zoneId,
@@ -778,7 +780,7 @@ local function MTH_BOOK_ShowAllFilteredBeastsOnMap()
title = string.format("%s (%d)", beastDisplayName, beastId),
detail = details,
beastId = beastId,
color = { 0.95, 0.82, 0.10 },
color = { cr, cg, cb },
})
end
end
@@ -794,8 +796,11 @@ local function MTH_BOOK_ShowAllFilteredBeastsOnMap()
if not MTH_Map:SetSource("focus") then
return
end
if firstZoneId and MTH_Map.OpenWorldMapForZone then
MTH_Map:OpenWorldMapForZone(firstZoneId)
-- Navigate to the player's current (filter) zone, not the first coord's zone ID
-- which may point to a different zone due to multi-zone beast spawn data.
local navZoneId = MTH_BOOK_STATE._cachedZoneId
if navZoneId and MTH_Map.OpenWorldMapForZone then
MTH_Map:OpenWorldMapForZone(navZoneId)
end
MTH_Map:UpdateWorldMap()
MTH_Map:UpdateMinimap()
@@ -1076,11 +1081,17 @@ end
MTH_BOOK_GetZoneName = function(zoneId)
local normalizedId = tonumber(zoneId) or zoneId
if not normalizedId then return "Zone " .. tostring(zoneId or "?") end
if MTH_DS_ZoneNamesFallback and MTH_DS_ZoneNamesFallback[normalizedId] then
return MTH_DS_ZoneNamesFallback[normalizedId]
-- Beast coords use WMA IDs. Always translate WMA→pfQ first so that e.g.
-- WMA 4 → pfQ 14 (Durotar) instead of hitting pfQ 4 (Blasted Lands) by accident.
local pfqId = normalizedId
if type(MTH_MAP_WMA_TO_PFQ) == "table" then
pfqId = MTH_MAP_WMA_TO_PFQ[normalizedId] or normalizedId
end
if not MTH_DS_Zones then return "Zone " .. tostring(zoneId or "?") end
local row = MTH_DS_Zones[normalizedId] or MTH_DS_Zones[tostring(normalizedId)]
if MTH_DS_ZoneNamesFallback and MTH_DS_ZoneNamesFallback[pfqId] then
return MTH_DS_ZoneNamesFallback[pfqId]
end
if not MTH_DS_Zones then return "Zone " .. tostring(normalizedId) end
local row = MTH_DS_Zones[pfqId] or MTH_DS_Zones[tostring(pfqId)]
if not row then return "Zone " .. tostring(normalizedId) end
local names = row.names
if not names then return "Zone " .. tostring(normalizedId) end
@@ -1109,7 +1120,12 @@ function MTH_BOOK_GetCurrentZoneId()
if MTH_Map and type(MTH_Map.GetMapIDByName) == "function" then
local mapId = MTH_Map:GetMapIDByName(zoneName)
if mapId then
return tonumber(mapId) or mapId
-- Translate pfQ → WMA so zone IDs match coord tuples in MTH_DS_Beasts.
local pfqId = tonumber(mapId)
if pfqId and type(MTH_MAP_PFQ_TO_WMA) == "table" then
return MTH_MAP_PFQ_TO_WMA[pfqId] or pfqId
end
return pfqId or mapId
end
end
@@ -1123,7 +1139,11 @@ function MTH_BOOK_GetCurrentZoneId()
if row and row.names then
for _, value in pairs(row.names) do
if MTH_BOOK_NormalizeZoneLookupName(value) == normalized then
return tonumber(zoneId) or zoneId
local pfqId = tonumber(zoneId) or zoneId
if type(pfqId) == "number" and type(MTH_MAP_PFQ_TO_WMA) == "table" then
return MTH_MAP_PFQ_TO_WMA[pfqId] or pfqId
end
return pfqId
end
end
end
@@ -1432,12 +1452,25 @@ local function MTH_BOOK_BuildResults()
local results = {}
if MTH_BOOK_STATE.mode == "pets" then
if not MTH_DS_Beasts then return results end
for beastId, beast in pairs(MTH_DS_Beasts) do
if MTH_BOOK_BeastMatches(beastId, beast) then
table.insert(results, beastId)
-- Cache zone info once for this build pass (avoids calling GetCurrentZoneId
-- once per beast, which is expensive and causes freezes on large datasets).
if MTH_BOOK_STATE.petInZoneOnly then
MTH_BOOK_STATE._cachedZoneId = MTH_BOOK_GetCurrentZoneId()
MTH_BOOK_STATE._cachedZoneName = (type(GetRealZoneText) == "function" and GetRealZoneText())
or (type(GetZoneText) == "function" and GetZoneText()) or nil
else
MTH_BOOK_STATE._cachedZoneId = nil
MTH_BOOK_STATE._cachedZoneName = nil
end
if MTH_DS_Beasts then
for beastId, beast in pairs(MTH_DS_Beasts) do
if MTH_BOOK_BeastMatches(beastId, beast) then
table.insert(results, beastId)
end
end
end
table.sort(results, MTH_BOOK_BeastSort)
MTH_BOOK_ApplyActiveSort(results)
return results
@@ -2054,6 +2087,77 @@ local function MTH_BOOK_UpdatePetLearnSourceDropdownText()
MTH_BOOK_DropdownSetText(sourceDropdown, MTH_BOOK_GetPetLearnSourceLabel(MTH_BOOK_STATE.petLearnSource))
end
local MTH_BOOK_BeastContinentOptions = {
{ value = "all", label = "" },
{ value = 1, label = "Kalimdor" },
{ value = 0, label = "E. Kingdoms" },
}
local MTH_BOOK_BeastZoneOptions = {
{ value = "all", label = "All Zones" },
}
local function MTH_BOOK_BuildBeastZoneOptions(continentMapId)
local seen = {}
local rows = {}
if MTH_DS_Beasts and MTH_DS_WMAZones then
for _, beast in pairs(MTH_DS_Beasts) do
if beast and beast.coords then
for i = 1, table.getn(beast.coords) do
local c = beast.coords[i]
if c and c[3] and not seen[c[3]] then
local wmaEntry = MTH_DS_WMAZones[c[3]]
if wmaEntry and wmaEntry.mapId == continentMapId then
seen[c[3]] = true
local zoneName = MTH_BOOK_GetZoneName and MTH_BOOK_GetZoneName(c[3])
if zoneName and string.sub(zoneName, 1, 5) ~= "Zone " then
table.insert(rows, { value = c[3], label = zoneName })
end
end
end
end
end
end
end
table.sort(rows, function(a, b)
return MTH_BOOK_SafeLower(a.label) < MTH_BOOK_SafeLower(b.label)
end)
MTH_BOOK_BeastZoneOptions = { { value = "all", label = "All Zones" } }
for i = 1, table.getn(rows) do
table.insert(MTH_BOOK_BeastZoneOptions, rows[i])
end
end
local function MTH_BOOK_GetBeastContinentLabel(value)
for i = 1, table.getn(MTH_BOOK_BeastContinentOptions) do
if MTH_BOOK_BeastContinentOptions[i].value == value then
return MTH_BOOK_BeastContinentOptions[i].label
end
end
return ""
end
local function MTH_BOOK_GetBeastZoneLabel(value)
for i = 1, table.getn(MTH_BOOK_BeastZoneOptions) do
if MTH_BOOK_BeastZoneOptions[i].value == value then
return MTH_BOOK_BeastZoneOptions[i].label
end
end
return "All Zones"
end
local function MTH_BOOK_UpdateBeastContinentDropdownText()
local dd = getglobal("MTH_BOOK_BeastContinentDropdown")
if not dd then return end
MTH_BOOK_DropdownSetText(dd, MTH_BOOK_GetBeastContinentLabel(MTH_BOOK_STATE.petContinent))
end
local function MTH_BOOK_UpdateBeastZoneDropdownText()
local dd = getglobal("MTH_BOOK_BeastZoneDropdown")
if not dd then return end
MTH_BOOK_DropdownSetText(dd, MTH_BOOK_GetBeastZoneLabel(MTH_BOOK_STATE.petZoneFilter))
end
local function MTH_BOOK_GetItemSubtypeLabelByValue(value)
local options = MTH_BOOK_GetItemSubtypeOptions()
for i = 1, table.getn(options) do
@@ -2089,7 +2193,7 @@ local function MTH_BOOK_UpdateQuickFilterControls()
if MTH_BOOK_IsItemMode() then
MTH_BOOK_STATE.pageSize = 18
elseif MTH_BOOK_STATE.mode == "families" then
MTH_BOOK_STATE.pageSize = 16
MTH_BOOK_STATE.pageSize = MTH_BOOK_MAX_ROWS
elseif MTH_BOOK_STATE.mode == "stable" then
MTH_BOOK_STATE.pageSize = 5
elseif MTH_BOOK_STATE.mode == "pethistory" then
@@ -2102,6 +2206,9 @@ local function MTH_BOOK_UpdateQuickFilterControls()
local abilityDropdown = getglobal("MTH_BOOK_AbilityDropdown")
local rankDropdown = getglobal("MTH_BOOK_RankDropdown")
local petLearnSourceDropdown = getglobal("MTH_BOOK_PetLearnSourceDropdown")
local beastContinentDropdown = getglobal("MTH_BOOK_BeastContinentDropdown")
local beastZoneDropdown = getglobal("MTH_BOOK_BeastZoneDropdown")
local beastZoneLabel = getglobal("MTH_BOOK_BeastZoneLabel")
local itemSubtypeDropdown = getglobal("MTH_BOOK_ItemSubtypeDropdown")
local npcFunctionDropdown = getglobal("MTH_BOOK_NPCFunctionDropdown")
local npcZoneDropdown = getglobal("MTH_BOOK_NPCZoneDropdown")
@@ -2222,6 +2329,19 @@ local function MTH_BOOK_UpdateQuickFilterControls()
end
end
if petLearnSourceDropdown then petLearnSourceDropdown:Hide() end
if beastZoneLabel then beastZoneLabel:Show() end
if beastContinentDropdown then
beastContinentDropdown:Show()
MTH_BOOK_UpdateBeastContinentDropdownText()
end
if beastZoneDropdown then
if MTH_BOOK_STATE.petContinent ~= "all" then
beastZoneDropdown:Show()
MTH_BOOK_UpdateBeastZoneDropdownText()
else
beastZoneDropdown:Hide()
end
end
if itemSubtypeDropdown then itemSubtypeDropdown:Hide() end
if npcFunctionDropdown then npcFunctionDropdown:Hide() end
if npcZoneDropdown then npcZoneDropdown:Hide() end
@@ -2257,6 +2377,9 @@ local function MTH_BOOK_UpdateQuickFilterControls()
petLearnSourceDropdown:Show()
MTH_BOOK_UpdatePetLearnSourceDropdownText()
end
if beastZoneLabel then beastZoneLabel:Hide() end
if beastContinentDropdown then beastContinentDropdown:Hide() end
if beastZoneDropdown then beastZoneDropdown:Hide() end
if itemSubtypeDropdown then itemSubtypeDropdown:Hide() end
if petOnlyMyLevel then
petOnlyMyLevel:ClearAllPoints()
@@ -2313,6 +2436,9 @@ local function MTH_BOOK_UpdateQuickFilterControls()
if abilityDropdown then abilityDropdown:Hide() end
if rankDropdown then rankDropdown:Hide() end
if petLearnSourceDropdown then petLearnSourceDropdown:Hide() end
if beastZoneLabel then beastZoneLabel:Hide() end
if beastContinentDropdown then beastContinentDropdown:Hide() end
if beastZoneDropdown then beastZoneDropdown:Hide() end
if itemSubtypeDropdown then itemSubtypeDropdown:Hide() end
if npcFunctionDropdown then npcFunctionDropdown:Show() end
if npcZoneDropdown then npcZoneDropdown:Hide() end
@@ -2367,6 +2493,9 @@ local function MTH_BOOK_UpdateQuickFilterControls()
if abilityDropdown then abilityDropdown:Hide() end
if rankDropdown then rankDropdown:Hide() end
if petLearnSourceDropdown then petLearnSourceDropdown:Hide() end
if beastZoneLabel then beastZoneLabel:Hide() end
if beastContinentDropdown then beastContinentDropdown:Hide() end
if beastZoneDropdown then beastZoneDropdown:Hide() end
if itemSubtypeDropdown then
itemSubtypeDropdown:ClearAllPoints()
itemSubtypeDropdown:SetPoint("TOPLEFT", itemSubtypeDropdown:GetParent(), "TOPLEFT", 238, -80)
@@ -2504,6 +2633,15 @@ local function MTH_BOOK_UpdateQuickFilterControls()
if MTH_BOOK_STATE.mode ~= "pets" and petInZoneOnly then
petInZoneOnly:Hide()
end
if MTH_BOOK_STATE.mode ~= "pets" and beastContinentDropdown then
beastContinentDropdown:Hide()
end
if MTH_BOOK_STATE.mode ~= "pets" and beastZoneDropdown then
beastZoneDropdown:Hide()
end
if MTH_BOOK_STATE.mode ~= "pets" and beastZoneLabel then
beastZoneLabel:Hide()
end
if MTH_BOOK_STATE.mode ~= "npcs" and npcInZoneOnly then
npcInZoneOnly:Hide()
end
@@ -2609,6 +2747,7 @@ local function MTH_BOOK_InitRankDropdown()
MTH_BOOK_UpdateRankDropdownText()
end
local function MTH_BOOK_InitPetLearnSourceDropdown()
local sourceDropdown = getglobal("MTH_BOOK_PetLearnSourceDropdown")
if not sourceDropdown then return end
@@ -2703,6 +2842,56 @@ local function MTH_BOOK_AddStableStyleKV(lines, label, value)
table.insert(lines, "|cff9a9a9a" .. tostring(label or "") .. ":|r |cffffffff" .. tostring(value or "-") .. "|r")
end
local function MTH_BOOK_GetOrCreateDetailTitleLabel()
local lbl = getglobal("MTH_BOOK_DetailTitleLabel")
if lbl then return lbl end
local parent = getglobal("MTH_BOOK_DetailBackdrop")
if not parent then return nil end
lbl = parent:CreateFontString("MTH_BOOK_DetailTitleLabel", "OVERLAY")
lbl:SetFontObject(GameFontNormal)
lbl:SetJustifyH("LEFT")
lbl:SetJustifyV("TOP")
lbl:SetPoint("TOPLEFT", parent, "TOPLEFT", 8, -8)
lbl:SetWidth(120)
lbl:Hide()
return lbl
end
local function MTH_BOOK_ShowDetailTitle(text)
local lbl = MTH_BOOK_GetOrCreateDetailTitleLabel()
if lbl then
lbl:SetText(tostring(text or ""))
lbl:Show()
end
local editBox = getglobal("MTH_BOOK_DetailBackdropDetailText")
local parent = getglobal("MTH_BOOK_DetailBackdrop")
if editBox and parent then
editBox:ClearAllPoints()
editBox:SetPoint("TOPLEFT", parent, "TOPLEFT", 6, -28)
end
end
local function MTH_BOOK_HideDetailTitle()
local lbl = getglobal("MTH_BOOK_DetailTitleLabel")
if lbl then lbl:Hide() end
local editBox = getglobal("MTH_BOOK_DetailBackdropDetailText")
local parent = getglobal("MTH_BOOK_DetailBackdrop")
if editBox and parent then
editBox:ClearAllPoints()
editBox:SetPoint("TOPLEFT", parent, "TOPLEFT", 6, -6)
end
end
local function MTH_BOOK_FormatBeastReact(reactA, reactH)
local function reactColor(r)
local rl = r and string.lower(r) or ""
if rl == "friendly" then return "|cFF44DD44" end
if rl == "neutral" then return "|cFFFFCC00" end
return "|cFFDD4444"
end
return reactColor(reactA) .. "A|r " .. reactColor(reactH) .. "H|r"
end
local function MTH_BOOK_FormatDateTimeValue(value)
local ts = tonumber(value)
if not ts or ts <= 0 then
@@ -2943,7 +3132,7 @@ end
function MTH_BOOK_SetDetailText(detail, text)
if not detail then return end
local wrapped = tostring(text or "")
if MTH_BOOK_STATE.mode ~= "pethistory" then
if MTH_BOOK_STATE.mode ~= "pethistory" and MTH_BOOK_STATE.mode ~= "pets" and MTH_BOOK_STATE.mode ~= "abilities" then
wrapped = MTH_BOOK_WrapDetailText(wrapped)
end
detail._mthLocking = true
@@ -2996,6 +3185,7 @@ end
function MTH_BOOK_UpdateDetail()
local detail = getglobal("MTH_BOOK_DetailBackdropDetailText")
if not detail then return end
MTH_BOOK_HideDetailTitle()
-- Hide model skin preview when not in a beast-list mode
if MTH_BOOK_STATE.mode ~= "pets" and MTH_BOOK_STATE.mode ~= "abilities" then
if MTH_BOOK_ModelViewer_Clear then MTH_BOOK_ModelViewer_Clear() end
@@ -3074,28 +3264,50 @@ function MTH_BOOK_UpdateDetail()
return
end
local beastId = selected.beastId
local beast = MTH_DS_Beasts and MTH_DS_Beasts[beastId]
if not beast then
MTH_BOOK_SetDetailText(detail, "|cFFFFD100Inspector|r\n\nSelect an entry from the list to view identity, stats, sources and locations.")
MTH_BOOK_UpdateOpenMapButton()
return
end
local lines = {}
local beastDisplayName = (MTH and MTH.GetLocalizedBeastName and MTH:GetLocalizedBeastName(beastId, beast.name)) or beast.name
table.insert(lines, "|cFFFFFF00" .. (beastDisplayName or "Unknown") .. "|r")
MTH_BOOK_AddDetailSection(lines, "Identity")
MTH_BOOK_AddDetailKV(lines, "ID", beastId)
MTH_BOOK_AddDetailKV(lines, "Family", beast.family or "?")
MTH_BOOK_ShowDetailTitle("|cFFFFFF00" .. (beastDisplayName or "Unknown") .. "|r")
MTH_BOOK_AddDetailSection(lines, "Stats")
MTH_BOOK_AddDetailKV(lines, "Level", beast.lvl or "?")
MTH_BOOK_AddDetailKV(lines, "Attack Speed", beast.attackSpeed or "?")
local respawnWindow = MTH_BOOK_FormatRespawnWindow(beast)
if respawnWindow then
MTH_BOOK_AddDetailKV(lines, "Respawn", respawnWindow)
local lines = {}
-- Identity block
MTH_BOOK_AddStableStyleKV(lines, "ID", beastId)
MTH_BOOK_AddStableStyleKV(lines, "Family", beast.family or "?")
local rankLabel = beast.rank
if rankLabel == "normal" or rankLabel == nil or rankLabel == "" then rankLabel = nil end
if rankLabel then MTH_BOOK_AddStableStyleKV(lines, "Rank", rankLabel) end
local spawnCount = (beast.coords and table.getn(beast.coords)) or 0
MTH_BOOK_AddStableStyleKV(lines, "Spawns", spawnCount > 0 and tostring(spawnCount) or "?")
if beast.reactA or beast.reactH then
table.insert(lines, "|cff9a9a9aReaction:|r " .. MTH_BOOK_FormatBeastReact(beast.reactA, beast.reactH))
end
-- Stats block
MTH_BOOK_AddStableStyleKV(lines, "Level", beast.lvl or "?")
MTH_BOOK_AddStableStyleKV(lines, "Atk Speed", beast.attackSpeed or "?")
local respawnWindow = MTH_BOOK_FormatRespawnWindow(beast)
if respawnWindow then MTH_BOOK_AddStableStyleKV(lines, "Respawn", respawnWindow) end
if beast.health then MTH_BOOK_AddStableStyleKV(lines, "Health", beast.health) end
if beast.armor then MTH_BOOK_AddStableStyleKV(lines, "Armor", beast.armor) end
if beast.dmgMin and beast.dmgMax then
MTH_BOOK_AddStableStyleKV(lines, "Damage", string.format("%.1f - %.1f", tonumber(beast.dmgMin) or 0, tonumber(beast.dmgMax) or 0))
end
if beast.abilities and beast.abilities ~= "" and beast.abilities ~= "None" then
MTH_BOOK_AddStableStyleKV(lines, "Abilities", beast.abilities)
end
local beastZone = MTH_BOOK_GetBeastZoneSummary and MTH_BOOK_GetBeastZoneSummary(beast)
if beastZone and beastZone ~= "-" then
MTH_BOOK_AddStableStyleKV(lines, "Zone", beastZone)
end
local subzone = MTH_BOOK_GetBeastSubZoneSummary and MTH_BOOK_GetBeastSubZoneSummary(beast)
if subzone then
MTH_BOOK_AddStableStyleKV(lines, "Subzone", subzone)
end
MTH_BOOK_AddDetailKV(lines, "Rare", beast.rare and "Yes" or "No")
MTH_BOOK_AddDetailKV(lines, "Abilities", beast.abilities or "None")
if MTH_BOOK_ModelViewer_SetFamily then MTH_BOOK_ModelViewer_SetFamily(beast.family, beast.skinId) end
MTH_BOOK_SetDetailText(detail, table.concat(lines, "\n"))
@@ -3116,22 +3328,36 @@ function MTH_BOOK_UpdateDetail()
MTH_BOOK_UpdateOpenMapButton()
return
end
MTH_BOOK_ShowDetailTitle("|cFFFFFF00" .. tostring(entry.abilityToken) .. "|r")
local lines = {}
table.insert(lines, "|cFFFFFF00" .. tostring(entry.abilityToken) .. "|r")
local beastDisplayName = (MTH and MTH.GetLocalizedBeastName and MTH:GetLocalizedBeastName(entry.beastId, beast.name)) or beast.name
MTH_BOOK_AddStableStyleKV(lines, "Beast", tostring(beastDisplayName or "Unknown") .. " (#" .. tostring(entry.beastId) .. ")")
MTH_BOOK_AddStableStyleKV(lines, "Family", beast.family or "?")
local rankLabel = beast.rank
if rankLabel == "normal" or rankLabel == nil or rankLabel == "" then rankLabel = nil end
if rankLabel then MTH_BOOK_AddStableStyleKV(lines, "Rank", rankLabel) end
MTH_BOOK_AddDetailSection(lines, "Identity")
MTH_BOOK_AddDetailKV(lines, "Beast", tostring(beastDisplayName or "Unknown") .. " (ID " .. tostring(entry.beastId) .. ")")
MTH_BOOK_AddDetailKV(lines, "Family", beast.family or "?")
MTH_BOOK_AddDetailSection(lines, "Stats")
MTH_BOOK_AddDetailKV(lines, "Level", beast.lvl or "?")
MTH_BOOK_AddDetailKV(lines, "Attack Speed", beast.attackSpeed or "?")
MTH_BOOK_AddStableStyleKV(lines, "Level", beast.lvl or "?")
MTH_BOOK_AddStableStyleKV(lines, "Atk Speed", beast.attackSpeed or "?")
local respawnWindow = MTH_BOOK_FormatRespawnWindow(beast)
if respawnWindow then
MTH_BOOK_AddDetailKV(lines, "Respawn", respawnWindow)
if respawnWindow then MTH_BOOK_AddStableStyleKV(lines, "Respawn", respawnWindow) end
if beast.health then MTH_BOOK_AddStableStyleKV(lines, "Health", beast.health) end
if beast.armor then MTH_BOOK_AddStableStyleKV(lines, "Armor", beast.armor) end
if beast.dmgMin and beast.dmgMax then
MTH_BOOK_AddStableStyleKV(lines, "Damage", string.format("%.1f - %.1f", tonumber(beast.dmgMin) or 0, tonumber(beast.dmgMax) or 0))
end
if beast.reactA or beast.reactH then
table.insert(lines, "|cff9a9a9aReaction:|r " .. MTH_BOOK_FormatBeastReact(beast.reactA, beast.reactH))
end
local beastZone = MTH_BOOK_GetBeastZoneSummary and MTH_BOOK_GetBeastZoneSummary(beast)
if beastZone and beastZone ~= "-" then
MTH_BOOK_AddStableStyleKV(lines, "Zone", beastZone)
end
local subzone = MTH_BOOK_GetBeastSubZoneSummary and MTH_BOOK_GetBeastSubZoneSummary(beast)
if subzone then
MTH_BOOK_AddStableStyleKV(lines, "Subzone", subzone)
end
MTH_BOOK_AddDetailKV(lines, "Rare", beast.rare and "Yes" or "No")
if MTH_BOOK_ModelViewer_SetFamily then MTH_BOOK_ModelViewer_SetFamily(beast.family, beast.skinId) end
MTH_BOOK_SetDetailText(detail, table.concat(lines, "\n"))
@@ -3659,6 +3885,7 @@ end
local function MTH_BOOK_GetRowValues(entry)
if MTH_BOOK_STATE.mode == "pets" then
-- MetaHunt DB entry
local beast = MTH_DS_Beasts and MTH_DS_Beasts[entry]
if not beast then return { "", "", "", "", "", "", "", "", "", "" } end
local beastDisplayName = (MTH and MTH.GetLocalizedBeastName and MTH:GetLocalizedBeastName(entry, beast.name)) or beast.name
@@ -4507,6 +4734,8 @@ local function MTH_BOOK_GetFilterWidgets()
npcFunctionDropdown = getglobal("MTH_BOOK_NPCFunctionDropdown"),
npcZoneDropdown = getglobal("MTH_BOOK_NPCZoneDropdown"),
petLearnSourceDropdown = getglobal("MTH_BOOK_PetLearnSourceDropdown"),
beastContinentDropdown = getglobal("MTH_BOOK_BeastContinentDropdown"),
beastZoneDropdown = getglobal("MTH_BOOK_BeastZoneDropdown"),
itemSubtypeDropdown = getglobal("MTH_BOOK_ItemSubtypeDropdown"),
petOnlyMyLevel = getglobal("MTH_BOOK_PetOnlyMyLevel"),
petInZoneOnly = getglobal("MTH_BOOK_PetInZoneOnly"),
@@ -4528,6 +4757,8 @@ local function MTH_BOOK_ResetStateForMode(mode)
MTH_BOOK_STATE.petOnlyMyLevel = false
MTH_BOOK_STATE.itemOnlyMyLevel = false
MTH_BOOK_STATE.petInZoneOnly = false
MTH_BOOK_STATE.petContinent = "all"
MTH_BOOK_STATE.petZoneFilter = "all"
MTH_BOOK_STATE.itemSubtype = "all"
MTH_BOOK_STATE.npcFunction = "all"
MTH_BOOK_STATE.npcZone = "all"
@@ -4591,6 +4822,8 @@ local function MTH_BOOK_ApplyStateToWidgets(widgets)
if widgets.petInZoneOnly then
widgets.petInZoneOnly:SetChecked(MTH_BOOK_STATE.mode == "pets" and MTH_BOOK_STATE.petInZoneOnly and 1 or nil)
end
if widgets.beastContinentDropdown then MTH_BOOK_UpdateBeastContinentDropdownText() end
if widgets.beastZoneDropdown then MTH_BOOK_UpdateBeastZoneDropdownText() end
if widgets.npcInZoneOnly then
widgets.npcInZoneOnly:SetChecked(MTH_BOOK_STATE.mode == "npcs" and MTH_BOOK_STATE.npcInZoneOnly and 1 or nil)
end
@@ -4840,6 +5073,8 @@ local function MTH_BOOK_ResetAllFiltersAndRefresh()
if widgets.abilityDropdown then MTH_BOOK_UpdateAbilityDropdownText() end
if widgets.rankDropdown then MTH_BOOK_UpdateRankDropdownText() end
if widgets.petLearnSourceDropdown then MTH_BOOK_UpdatePetLearnSourceDropdownText() end
if widgets.beastContinentDropdown then MTH_BOOK_UpdateBeastContinentDropdownText() end
if widgets.beastZoneDropdown then MTH_BOOK_UpdateBeastZoneDropdownText() end
if widgets.itemSubtypeDropdown then MTH_BOOK_UpdateItemSubtypeDropdownText() end
if widgets.npcFunctionDropdown or widgets.npcZoneDropdown then MTH_BOOK_UpdateNPCDropdownTexts() end
@@ -4847,6 +5082,71 @@ local function MTH_BOOK_ResetAllFiltersAndRefresh()
MTH_BOOK_RefreshFilter()
end
local function MTH_BOOK_WireBeastDropdowns()
local continentDD = getglobal("MTH_BOOK_BeastContinentDropdown")
if continentDD then
UIDropDownMenu_Initialize(continentDD, function()
for i = 1, table.getn(MTH_BOOK_BeastContinentOptions) do
local option = MTH_BOOK_BeastContinentOptions[i]
local info = MTH_BOOK_DropdownCreateInfo()
info.text = (option.label ~= "") and option.label or "(any)"
info.func = function()
MTH_BOOK_STATE.petContinent = option.value
MTH_BOOK_STATE.petZoneFilter = "all"
MTH_BOOK_STATE.page = 1
MTH_BOOK_STATE.selectedEntry = nil
MTH_BOOK_DropdownSetText(continentDD, info.text)
if option.value ~= "all" then
MTH_BOOK_BuildBeastZoneOptions(option.value)
local zoneDD = getglobal("MTH_BOOK_BeastZoneDropdown")
if zoneDD then
UIDropDownMenu_Initialize(zoneDD, MTH_BOOK_STATE._beastZoneInitFunc)
zoneDD:Show()
MTH_BOOK_UpdateBeastZoneDropdownText()
end
else
local zoneDD = getglobal("MTH_BOOK_BeastZoneDropdown")
if zoneDD then zoneDD:Hide() end
end
MTH_BOOK_RefreshFilter()
end
info.checked = (MTH_BOOK_STATE.petContinent == option.value)
UIDropDownMenu_AddButton(info)
end
end)
UIDropDownMenu_SetWidth(80, continentDD)
UIDropDownMenu_JustifyText("LEFT", continentDD)
MTH_BOOK_UpdateBeastContinentDropdownText()
end
local zoneInitFunc = function()
local zoneDD = getglobal("MTH_BOOK_BeastZoneDropdown")
for i = 1, table.getn(MTH_BOOK_BeastZoneOptions) do
local option = MTH_BOOK_BeastZoneOptions[i]
local info = MTH_BOOK_DropdownCreateInfo()
info.text = option.label
info.func = function()
MTH_BOOK_STATE.petZoneFilter = option.value
MTH_BOOK_STATE.page = 1
MTH_BOOK_STATE.selectedEntry = nil
if zoneDD then MTH_BOOK_DropdownSetText(zoneDD, option.label) end
MTH_BOOK_RefreshFilter()
end
info.checked = (MTH_BOOK_STATE.petZoneFilter == option.value)
UIDropDownMenu_AddButton(info)
end
end
MTH_BOOK_STATE._beastZoneInitFunc = zoneInitFunc
local zoneDD = getglobal("MTH_BOOK_BeastZoneDropdown")
if zoneDD then
UIDropDownMenu_Initialize(zoneDD, zoneInitFunc)
UIDropDownMenu_SetWidth(120, zoneDD)
UIDropDownMenu_JustifyText("LEFT", zoneDD)
MTH_BOOK_UpdateBeastZoneDropdownText()
end
end
local function MTH_BOOK_WireUI(frame)
if frame and frame.SetBackdropColor then
frame:SetBackdropColor(0.05, 0.05, 0.05, 1.00)
@@ -4868,12 +5168,6 @@ local function MTH_BOOK_WireUI(frame)
local requireVendor = getglobal("MTH_BOOK_RequireVendor")
local requireDrop = getglobal("MTH_BOOK_RequireDrop")
local requireObject = getglobal("MTH_BOOK_RequireObject")
local abilityDropdown = getglobal("MTH_BOOK_AbilityDropdown")
local rankDropdown = getglobal("MTH_BOOK_RankDropdown")
local petLearnSourceDropdown = getglobal("MTH_BOOK_PetLearnSourceDropdown")
local itemSubtypeDropdown = getglobal("MTH_BOOK_ItemSubtypeDropdown")
local npcFunctionDropdown = getglobal("MTH_BOOK_NPCFunctionDropdown")
local npcZoneDropdown = getglobal("MTH_BOOK_NPCZoneDropdown")
local petBookScanButton = getglobal("MTH_BOOK_PetBookScanButton")
local hideNoAbilities = getglobal("MTH_BOOK_HideNoAbilities")
local hideUnknown = getglobal("MTH_BOOK_HideUnknown")
@@ -4934,6 +5228,7 @@ local function MTH_BOOK_WireUI(frame)
MTH_BOOK_InitFamilyDropdown()
MTH_BOOK_InitAbilityDropdown()
MTH_BOOK_InitRankDropdown()
MTH_BOOK_WireBeastDropdowns()
MTH_BOOK_InitPetLearnSourceDropdown()
MTH_BOOK_InitItemSubtypeDropdown()
MTH_BOOK_InitNPCFunctionDropdown()
+21 -2
View File
@@ -57,6 +57,14 @@
</Anchors>
</FontString>
<FontString name="$parentBeastZoneLabel" inherits="GameFontNormalSmall" text="Zone:" hidden="true">
<Anchors>
<Anchor point="TOPLEFT">
<Offset><AbsDimension x="464" y="-142"/></Offset>
</Anchor>
</Anchors>
</FontString>
</Layer>
</Layers>
@@ -265,7 +273,7 @@
</Frame>
<CheckButton name="$parentPetInZoneOnly" inherits="UICheckButtonTemplate" hidden="true">
<Anchors>
<Anchor point="TOPLEFT"><Offset><AbsDimension x="488" y="-112"/></Offset></Anchor>
<Anchor point="TOPLEFT"><Offset><AbsDimension x="526" y="-106"/></Offset></Anchor>
</Anchors>
</CheckButton>
<Button name="$parentShowAllOnMapButton" inherits="UIPanelButtonTemplate" text="Show all on map" hidden="true">
@@ -298,8 +306,19 @@
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="232" y="-140"/></Offset></Anchor></Anchors>
</CheckButton>
<CheckButton name="$parentHideUnknown" inherits="UICheckButtonTemplate">
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="372" y="-140"/></Offset></Anchor></Anchors>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="290" y="-140"/></Offset></Anchor></Anchors>
</CheckButton>
<Frame name="$parentBeastContinentDropdown" inherits="UIDropDownMenuTemplate" hidden="true">
<Anchors>
<Anchor point="TOPLEFT"><Offset><AbsDimension x="482" y="-136"/></Offset></Anchor>
</Anchors>
</Frame>
<Frame name="$parentBeastZoneDropdown" inherits="UIDropDownMenuTemplate" hidden="true">
<Anchors>
<Anchor point="TOPLEFT"><Offset><AbsDimension x="592" y="-136"/></Offset></Anchor>
</Anchors>
</Frame>
<Frame name="$parentListSliderBackdrop">
<Size><AbsDimension x="22" y="322"/></Size>
+46 -22
View File
@@ -12,6 +12,7 @@ MTH_Map = {
mapZoneCache = {},
focusNodes = {},
pendingZoneOpenId = nil,
pendingZoneOpenPfqId = nil,
pendingZoneOpenSourceId = nil,
pendingZoneOpenAttempts = 0,
pendingZoneOpenNextAttemptAt = 0,
@@ -60,11 +61,6 @@ local function MTH_Map_Mod(a, b)
return 0
end
local function MTH_Map_Log(msg)
if MTH and MTH.debug and MTH.Print then
MTH:Print("[MAP] " .. tostring(msg), "debug")
end
end
local function MTH_Map_NormalizeName(name)
if not name then return "" end
@@ -130,12 +126,18 @@ local function MTH_Map_GetZoneNameById(zoneId)
local normalizedId = tonumber(zoneId) or zoneId
if not normalizedId then return nil end
if MTH_DS_ZoneNamesFallback and MTH_DS_ZoneNamesFallback[normalizedId] then
return MTH_DS_ZoneNamesFallback[normalizedId]
-- Translate WMA→pfQ first so WMA IDs don't accidentally hit wrong pfQ entries.
local pfqId = normalizedId
if type(MTH_MAP_WMA_TO_PFQ) == "table" then
pfqId = MTH_MAP_WMA_TO_PFQ[normalizedId] or normalizedId
end
if MTH_DS_ZoneNamesFallback and MTH_DS_ZoneNamesFallback[pfqId] then
return MTH_DS_ZoneNamesFallback[pfqId]
end
if not MTH_DS_Zones then return nil end
local row = MTH_DS_Zones[normalizedId] or MTH_DS_Zones[tostring(normalizedId)]
local row = MTH_DS_Zones[pfqId] or MTH_DS_Zones[tostring(pfqId)]
if not row or not row.names then return nil end
return row.names.enUS or row.names[GetLocale()] or row.names.deDE or row.names.frFR
end
@@ -327,7 +329,6 @@ function MTH_Map:BuildZoneLookup()
for _ in pairs(self.zoneNameNormToId) do
count = count + 1
end
MTH_Map_Log("Zone lookup rebuilt: " .. tostring(count) .. " entries")
end
function MTH_Map:GetMapIDByName(name)
@@ -418,6 +419,15 @@ function MTH_Map:ResolveZoneHierarchy(zoneId)
return resolved
end
-- Translate a pfQ AreaTable ID to a WMA ID (for zone matching against coord tuples).
-- Falls back to the pfQ ID itself if no mapping exists (sub-zones, custom zones).
local function MTH_Map_PfqToWma(pfqId)
if type(MTH_MAP_PFQ_TO_WMA) == "table" then
return MTH_MAP_PFQ_TO_WMA[pfqId] or pfqId
end
return pfqId
end
function MTH_Map:GetCurrentMapID()
local continent = GetCurrentMapContinent and GetCurrentMapContinent() or nil
local zone = GetCurrentMapZone and GetCurrentMapZone() or nil
@@ -434,6 +444,7 @@ function MTH_Map:GetCurrentMapID()
if mapId then
local resolved = self:ResolveZoneHierarchy(mapId)
local normalized = resolved.zoneId or mapId
normalized = MTH_Map_PfqToWma(normalized)
self.lastMapContext = string.format("continent=%s zone=%s mapZone='%s' real=nil mapId=%s normalized=%s", tostring(continent), tostring(zone), tostring(zoneName), tostring(mapId), tostring(normalized))
return normalized
end
@@ -449,6 +460,7 @@ function MTH_Map:GetCurrentMapID()
mapId = self:GetMapIDByName(real)
local resolved = self:ResolveZoneHierarchy(mapId)
local normalized = resolved.zoneId or mapId
normalized = MTH_Map_PfqToWma(normalized)
self.lastMapContext = string.format("continent=%s zone=%s mapZone='%s' real='%s' mapId=%s normalized=%s", tostring(continent), tostring(zone), tostring(zoneName), tostring(real), tostring(mapId), tostring(normalized))
return normalized
end
@@ -467,6 +479,7 @@ end
local function MTH_Map_ClearPendingZoneOpen()
MTH_Map.pendingZoneOpenId = nil
MTH_Map.pendingZoneOpenPfqId = nil
MTH_Map.pendingZoneOpenSourceId = nil
MTH_Map.pendingZoneOpenAttempts = 0
MTH_Map.pendingZoneOpenNextAttemptAt = 0
@@ -532,8 +545,12 @@ end
function MTH_Map:OpenWorldMapForZone(zoneId)
local zid = tonumber(zoneId)
if not zid then return false end
local resolved = self:ResolveZoneHierarchy(zid)
local targetZoneId = tonumber(resolved.zoneId or zid) or zid
-- Translate WMA ID → pfQ so game map APIs (pfMap, SetMapZoom) work correctly.
local pfqZid = (type(MTH_MAP_WMA_TO_PFQ) == "table" and MTH_MAP_WMA_TO_PFQ[zid]) or zid
local resolved = self:ResolveZoneHierarchy(pfqZid)
local targetZoneId = tonumber(resolved.zoneId or pfqZid) or pfqZid
-- WMA ID of this zone, for comparing against GetCurrentMapID() which returns WMA IDs.
local targetWmaId = (type(MTH_MAP_PFQ_TO_WMA) == "table" and MTH_MAP_PFQ_TO_WMA[targetZoneId]) or zid
if ToggleWorldMap then
if not WorldMapFrame or not WorldMapFrame:IsShown() then
@@ -546,34 +563,39 @@ function MTH_Map:OpenWorldMapForZone(zoneId)
if pfMap and pfMap.SetMapByID then
pfMap:SetMapByID(targetZoneId)
local currentAfterPF = self:GetCurrentMapID()
if tonumber(currentAfterPF) == tonumber(targetZoneId) then
if tonumber(currentAfterPF) == tonumber(targetWmaId) then
MTH_Map_ClearPendingZoneOpen()
return true
end
end
local zoomApplied = MTH_Map_ApplyWorldMapZone(targetZoneId, zid)
local zoomApplied = MTH_Map_ApplyWorldMapZone(zid, zid)
if zoomApplied then
local currentAfterZoom = self:GetCurrentMapID()
if tonumber(currentAfterZoom) == tonumber(targetZoneId) then
if tonumber(currentAfterZoom) == tonumber(targetWmaId) then
MTH_Map_ClearPendingZoneOpen()
return true
end
end
local nowMapId = self:GetCurrentMapID()
if tonumber(nowMapId) == tonumber(targetZoneId) then
if tonumber(nowMapId) == tonumber(targetWmaId) then
MTH_Map_ClearPendingZoneOpen()
return true
end
self.pendingZoneOpenId = targetZoneId
self.pendingZoneOpenSourceId = zid
self.pendingZoneOpenId = targetWmaId
self.pendingZoneOpenPfqId = targetZoneId
self.pendingZoneOpenSourceId = pfqZid
self.pendingZoneOpenAttempts = 8
self.pendingZoneOpenNextAttemptAt = (GetTime and GetTime() or 0) + 0.25
return true
end
function MTH_Map:GetFamilyColor(family)
return MTH_Map_GetFamilyColor(family)
end
function MTH_Map:FocusBeast(beastId, beast)
local id = tonumber(beastId)
if not id then return false end
@@ -890,7 +912,6 @@ function MTH_Map:RebuildNodes()
end
end
MTH_Map_Log("Rebuilt nodes for source '" .. tostring(self.activeSource) .. "'")
end
function MTH_Map:UpdateWorldMap()
@@ -1019,6 +1040,11 @@ function MTH_Map:UpdateMinimap()
local minimapSizes = MTH_DS_MinimapSizes or (pfDB and pfDB["minimap"])
local mapSize = minimapSizes and minimapSizes[mapId]
if not mapSize and type(MTH_MAP_WMA_TO_PFQ) == "table" then
-- Fallback: try the pfQ key (for sub-zones not yet mapped to WMA)
local pfqId = MTH_MAP_WMA_TO_PFQ[mapId]
mapSize = pfqId and minimapSizes and minimapSizes[pfqId]
end
if not mapSize then
self.lastMiniReason = self.verboseMiniReasons and "missing-minimap-size" or "missing-size"
self._lastMiniState = nil
@@ -1227,7 +1253,6 @@ function MTH_Map:RegisterDefaultProviders()
end
if unresolvedCount > 0 then
MTH_Map_Log("drops source: " .. tostring(unresolvedCount) .. " drop-creature links have no loaded coordinates (sample IDs: " .. table.concat(unresolvedSamples, ", ") .. ")")
end
return nodes
@@ -1274,9 +1299,9 @@ function MTH_Map:Init()
if WorldMapFrame and WorldMapFrame:IsShown() then
if pfMap and pfMap.SetMapByID then
pfMap:SetMapByID(MTH_Map.pendingZoneOpenId)
pfMap:SetMapByID(MTH_Map.pendingZoneOpenPfqId or MTH_Map.pendingZoneOpenId)
end
MTH_Map_ApplyWorldMapZone(MTH_Map.pendingZoneOpenId, MTH_Map.pendingZoneOpenSourceId)
MTH_Map_ApplyWorldMapZone(MTH_Map.pendingZoneOpenId or MTH_Map.pendingZoneOpenPfqId, MTH_Map.pendingZoneOpenId or MTH_Map.pendingZoneOpenPfqId)
local nowMapId = MTH_Map:GetCurrentMapID()
if tonumber(nowMapId) == tonumber(MTH_Map.pendingZoneOpenId) then
MTH_Map_ClearPendingZoneOpen()
@@ -1318,5 +1343,4 @@ function MTH_Map:Init()
end)
end
MTH_Map_Log("Map system initialized")
end
+133
View File
@@ -0,0 +1,133 @@
------------------------------------------------------
-- MetaHunt: Experimental Ammunition Options Panel
-- TWoW 1.18.1 — "Nightmares of Ursol"
------------------------------------------------------
local function MTH_EA_OPT_Ready()
return type(MTH_GetFrame) == "function"
and type(MTH_CreateCheckbox) == "function"
and type(MTH_CreateSlider) == "function"
end
local function MTH_EA_OPT_GetCfg()
if type(MTH_SavedVariables) ~= "table" then return {} end
if type(MTH_SavedVariables.modules) ~= "table" then return {} end
return MTH_SavedVariables.modules["expammo"] or {}
end
local MTH_EA_OPT_built = false
-- Helper: create a pre-wired checkbox
local function MTH_EA_OPT_CB(container, name, label, yOff, isChecked, onClick)
local cb = MTH_CreateCheckbox(container, name, label, yOff, 20)
if cb then
cb:SetChecked(isChecked and 1 or 0)
cb:SetScript("OnClick", function()
local v = this:GetChecked()
onClick(v == 1 or v == true)
end)
end
return cb
end
-- Helper: section header label
local function MTH_EA_OPT_Header(container, text, yOff)
local fs = container:CreateFontString(nil, "ARTWORK", "GameFontNormal")
fs:SetPoint("TOPLEFT", container, "TOPLEFT", 20, yOff)
fs:SetText("|cffff9900" .. text .. "|r")
end
local function MTH_EA_OPT_BuildUI(container)
if MTH_EA_OPT_built then return end
MTH_EA_OPT_built = true
local cfg = MTH_EA_OPT_GetCfg()
-- Title
local title = container:CreateFontString(nil, "ARTWORK", "GameFontHighlightLarge")
title:SetPoint("TOPLEFT", container, "TOPLEFT", 20, -16)
title:SetText("MM Widget — Experimental Ammunition Tracker")
-- Short description
local desc = container:CreateFontString(nil, "ARTWORK", "GameFontNormal")
desc:SetPoint("TOPLEFT", container, "TOPLEFT", 20, -46)
desc:SetWidth(540)
desc:SetJustifyH("LEFT")
desc:SetJustifyV("TOP")
desc:SetText(
"Tracks the 1.18.1 ammo cycling mechanic.\n"
.. "Aimed Shot starts a 60s cycle: "
.. "|cffff8833Explosive|r \226\134\146 |cff33ff55Poisonous|r \226\134\146 |cff6633ffEnchanted|r\n"
.. "Each state is consumed by its matching shot (Multi-Shot / Serpent Sting / Arcane Shot)."
)
-- ── Section: Module ──────────────────────────────────────
MTH_EA_OPT_Header(container, "Module", -112)
local moduleEnabled = true
if MTH and MTH.IsModuleEnabled then
moduleEnabled = MTH:IsModuleEnabled("expammo", true) and true or false
end
MTH_EA_OPT_CB(container, "MTH_ExpAmmoModuleCB",
"Enable MM Widget module",
-132, moduleEnabled,
function(v)
if MTH and MTH.SetModuleEnabled then
MTH:SetModuleEnabled("expammo", v)
end
if MTH_ExpAmmo then MTH_ExpAmmo.SetEnabled(v) end
end)
-- ── Section: Tracker Visibility ─────────────────────────
MTH_EA_OPT_Header(container, "Tracker Visibility", -166)
MTH_EA_OPT_CB(container, "MTH_ExpAmmoShowLnLCB",
"Show Lock and Load cell (top)",
-186, cfg.showLnL ~= false,
function(v) if MTH_ExpAmmo then MTH_ExpAmmo.SetShowLnL(v) end end)
MTH_EA_OPT_CB(container, "MTH_ExpAmmoShowHintCB",
"Show action hint cell (bottom)",
-210, cfg.showHint ~= false,
function(v) if MTH_ExpAmmo then MTH_ExpAmmo.SetShowHint(v) end end)
MTH_EA_OPT_CB(container, "MTH_ExpAmmoHideOOCCB",
"Hide widget when out of combat",
-234, cfg.hideOOC == true,
function(v) if MTH_ExpAmmo then MTH_ExpAmmo.SetHideOOC(v) end end)
-- ── Section: Appearance ──────────────────────────────────
MTH_EA_OPT_Header(container, "Appearance", -268)
local sizeSlider = MTH_CreateSlider(container, "MTH_ExpAmmoCellSizeSlider",
"Cell Size (px)", 20, 80, 4, -288)
if sizeSlider then
sizeSlider:SetValue(math.max(20, math.min(80, cfg.cellSize or 40)))
sizeSlider.onChange = function(val)
if MTH_ExpAmmo then MTH_ExpAmmo.SetCellSize(val) end
end
end
MTH_EA_OPT_CB(container, "MTH_ExpAmmoBigCDCB",
"Large cooldown numbers (centered in cell)",
-352, cfg.bigCD == true,
function(v) if MTH_ExpAmmo then MTH_ExpAmmo.SetBigCD(v) end end)
-- ── Notes ───────────────────────────────────────────────
local tip = container:CreateFontString(nil, "ARTWORK", "GameFontNormal")
tip:SetPoint("TOPLEFT", container, "TOPLEFT", 20, -388)
tip:SetWidth(540)
tip:SetJustifyH("LEFT")
tip:SetTextColor(0.3, 0.7, 1.0)
tip:SetText("Tip: hold ALT and drag the tracker widget to reposition it.")
end
function MTH_SetupExpAmmoOptions()
if not MTH_EA_OPT_Ready() then return end
local container = MTH_GetFrame("MetaHuntOptionsExpAmmo")
if not container then return end
local ok, err = pcall(MTH_EA_OPT_BuildUI, container)
if not ok and MTH and MTH.Print then
MTH:Print("[MTH ExpAmmo OPTIONS] " .. tostring(err), "error")
end
end
+9 -2
View File
@@ -3,8 +3,8 @@ local MTH_OPTIONS_SETUP = {} -- Track which frames have been set up
MTH_OPTIONS_CONST = MTH_OPTIONS_CONST or {}
MTH_OPTIONS_CONST.NAV_DEFAULT_WIDTH = MTH_OPTIONS_CONST.NAV_DEFAULT_WIDTH or 120
MTH_OPTIONS_CONST.WINDOW_PADDING = MTH_OPTIONS_CONST.WINDOW_PADDING or 12
MTH_OPTIONS_CONST.CONTENT_TOP_OFFSET = MTH_OPTIONS_CONST.CONTENT_TOP_OFFSET or -72
MTH_OPTIONS_CONST.CONTENT_HEIGHT = MTH_OPTIONS_CONST.CONTENT_HEIGHT or 540
MTH_OPTIONS_CONST.CONTENT_TOP_OFFSET = MTH_OPTIONS_CONST.CONTENT_TOP_OFFSET or -58
MTH_OPTIONS_CONST.CONTENT_HEIGHT = MTH_OPTIONS_CONST.CONTENT_HEIGHT or 566
MTH_OPTIONS_CONST.CLOSE_BTN_SIZE = MTH_OPTIONS_CONST.CLOSE_BTN_SIZE or 22
MTH_OPTIONS_CONST.CLOSE_BTN_OFFSET_X = MTH_OPTIONS_CONST.CLOSE_BTN_OFFSET_X or -8
MTH_OPTIONS_CONST.CLOSE_BTN_OFFSET_Y = MTH_OPTIONS_CONST.CLOSE_BTN_OFFSET_Y or -8
@@ -205,6 +205,13 @@ function MTH_SelectOptionsTab(tabKey)
MTH_SetupAutoQuestOptions()
MTH_OPTIONS_SETUP["AutoQuest"] = true
end
elseif tabKey == "ExpAmmo" then
if not MTH_OPTIONS_SETUP["ExpAmmo"] then
if type(MTH_SetupExpAmmoOptions) == "function" then
MTH_SetupExpAmmoOptions()
MTH_OPTIONS_SETUP["ExpAmmo"] = true
end
end
elseif tabKey == "ICU" then
if type(MTH_SetupICUOptions) == "function" then
MTH_SetupICUOptions()
+2
View File
@@ -44,6 +44,7 @@ MTH_OPTIONS_TABS = MTH_OPTIONS_TABS or {
{ key = "AutoBuy", label = "Auto Buy", frame = "MetaHuntOptionsAutoBuy" },
{ key = "AutoQuest", label = "Auto Quest", frame = "MetaHuntOptionsAutoQuest" },
{ key = "ICU", label = "ICU", frame = "MetaHuntOptionsICU" },
{ key = "ExpAmmo", label = "MM Widget", frame = "MetaHuntOptionsExpAmmo" },
{ key = "ChronometerGeneral", label = "General", frame = "MetaHuntOptionsChronometer" },
{ key = "ChronometerBar", label = "Bar", frame = "MetaHuntOptionsChronometer" },
{ key = "ChronometerClassSpells", label = "Hunter Spells", frame = "MetaHuntOptionsChronometer" },
@@ -60,6 +61,7 @@ MTH_OPTIONS_TREE = MTH_OPTIONS_TREE or {
{ label = "Auto Quest", key = "AutoQuest" },
{ label = "Feed-O-Matic", key = "FeedOMatic" },
{ label = "ICU", key = "ICU" },
{ label = "MM Widget", key = "ExpAmmo" },
{
label = "zButtons",
node = "zButtons",
+3 -2
View File
@@ -46,12 +46,12 @@
<Frames>
<Frame name="$parentNav" enableMouse="true">
<Size>
<AbsDimension x="120" y="540"/>
<AbsDimension x="120" y="566"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="12" y="-72"/>
<AbsDimension x="12" y="-58"/>
</Offset>
</Anchor>
</Anchors>
@@ -82,6 +82,7 @@
<Frame name="$parentAutoBuy" hidden="true" enableMouse="true"/>
<Frame name="$parentAutoQuest" hidden="true" enableMouse="true"/>
<Frame name="$parentICU" hidden="true" enableMouse="true"/>
<Frame name="$parentExpAmmo" hidden="true" enableMouse="true"/>
<Frame name="$parentChronometer" hidden="true" enableMouse="true"/>
<Frame name="$parentCredits" hidden="true" enableMouse="true"/>
+3
View File
@@ -6,6 +6,9 @@ function MTH_ST_LifecycleService:HandleEvent(evt, eventArg1, eventArg2)
if type(MTH_ST_HandlePlayerEnteringWorld) == "function" and MTH_ST_HandlePlayerEnteringWorld(evt) then
return true, "lifecycle-enter-world"
end
if type(MTH_ST_HandleSpellcastEvent) == "function" and MTH_ST_HandleSpellcastEvent(evt, eventArg1, eventArg2) then
return true, "lifecycle-spellcast"
end
if type(MTH_ST_HandleUnitPetEvent) == "function" and MTH_ST_HandleUnitPetEvent(evt, eventArg1) then
if evt == "UNIT_PET" then
if eventArg1 == "player" then
+26 -2
View File
@@ -19,6 +19,30 @@ local function MTH_Profile_DeepCopy(orig)
return copy
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()
if type(MTH_SavedVariables) ~= "table" then
MTH_SavedVariables = {}
@@ -47,13 +71,13 @@ local function MTH_Profile_BuildSnapshot()
-- Account-wide module option values (e.g. feedomatic)
snap.config = (type(MTH_SavedVariables) == "table"
and type(MTH_SavedVariables.modules) == "table")
and MTH_Profile_DeepCopy(MTH_SavedVariables.modules)
and MTH_Profile_CopyModules(MTH_SavedVariables.modules)
or {}
-- Per-character module option values (ICU, Chronometer, AutoBuy, SmartAmmo, etc.)
snap.charConfig = (type(MTH_CharSavedVariables) == "table"
and type(MTH_CharSavedVariables.modules) == "table")
and MTH_Profile_DeepCopy(MTH_CharSavedVariables.modules)
and MTH_Profile_CopyModules(MTH_CharSavedVariables.modules)
or {}
-- Per-character module enabled/disabled states
+2 -2
View File
@@ -221,8 +221,8 @@ end
function VC:ResetPublishDelay()
local now = VC_GetTimeNow()
if self.lastPublishedAt and (now - self.lastPublishedAt) < 600 then
return -- 10-minute cooldown between publishes
if self.lastPublishedAt and (now - self.lastPublishedAt) < 3600 then
return -- 1-hour cooldown between publishes
end
self.nextPublishAt = now + math.random(10, 20)
end
File diff suppressed because it is too large Load Diff
+9 -9
View File
@@ -1,7 +1,7 @@
-- MetaHunt: Beast family DBC enrichment (scales, food validation)
-- AUTO-GENERATED by .tools — do not edit by hand.
-- Source DBC(s): CreatureFamily.dbc, ItemPetFood.dbc
-- Generated: 2026-03-17 08:39 UTC
-- Generated: 2026-03-20 13:57 UTC
if not MTH_DS_Families then return end
@@ -295,14 +295,14 @@ if MTH_DS_Families["Wind Serpents"] then
end
-- DBC ID=35 PetFoodMask=1009 scale=[0.60-0.80]
if MTH_DS_Families["Serpents (Cobra)"] then
MTH_DS_Families["Serpents (Cobra)"]["dbcId"] = 35
MTH_DS_Families["Serpents (Cobra)"]["minScale"] = 0.6
MTH_DS_Families["Serpents (Cobra)"]["maxScale"] = 0.8
MTH_DS_Families["Serpents (Cobra)"]["minScaleLevel"] = 1
MTH_DS_Families["Serpents (Cobra)"]["maxScaleLevel"] = 60
MTH_DS_Families["Serpents (Cobra)"]["foodMask"] = 1009
MTH_DS_Families["Serpents (Cobra)"]["foodDbc"] = {
if MTH_DS_Families["Serpents"] then
MTH_DS_Families["Serpents"]["dbcId"] = 35
MTH_DS_Families["Serpents"]["minScale"] = 0.6
MTH_DS_Families["Serpents"]["maxScale"] = 0.8
MTH_DS_Families["Serpents"]["minScaleLevel"] = 1
MTH_DS_Families["Serpents"]["maxScaleLevel"] = 60
MTH_DS_Families["Serpents"]["foodMask"] = 1009
MTH_DS_Families["Serpents"]["foodDbc"] = {
"meat",
"fungus",
"fruit",
+18 -1
View File
@@ -233,7 +233,7 @@ MTH_DS_Families = {
"Scorpid Poison",
},
},
["Serpents (Cobra)"] = {
["Serpents"] = {
["icon"] = "Ability_Hunter_Pet_Serpent1",
["named"] = 10,
["coords"] = 13,
@@ -333,4 +333,21 @@ MTH_DS_Families = {
"Growl",
},
},
-- ── Added TWoW 1.18.1 "Nightmares of Ursol" ──────────────────
["Moths"] = {
["icon"] = "Ability_Hunter_Pet_Moth", -- TODO: confirm MPQ icon name
["named"] = 0,
["coords"] = 0,
["food"] = {
"fruit",
"fungus",
},
["abilities"] = {
"Bite",
"Cower",
"Growl",
"Pollen Burst", -- family unique: 40 Focus, Instant, 30s CD
-- Heals party 308-338 (30yd), -20% atk speed targets (10yd, 8s)
},
},
}
File diff suppressed because it is too large Load Diff
+19 -3
View File
@@ -1,8 +1,8 @@
-- MetaHunt: Beast appearance skin variants per family
-- AUTO-GENERATED by .tools — do not edit by hand.
-- Source DBC(s): CreatureDisplayInfo.dbc, CreatureModelData.dbc
-- Generated: 2026-03-17 14:49 UTC
-- Total skins: 244 across 19 families
-- Generated: 2026-03-23 15:09 UTC
-- Total skins: 258 across 20 families
if not MTH_DS then MTH_DS = {} end
@@ -28,6 +28,8 @@ MTH_DS_BeastSkins = {
{id=20635, tex="BearSkinBrownDiseased", unique=true, modelPath="Creature\\bear\\Bear.mdx"},
{id=20636, tex="BearSkinBlueDiseased", unique=true, modelPath="Creature\\bear\\Bear.mdx"},
{id=20637, tex="BearSkinWhiteDiseased", unique=true, modelPath="Creature\\bear\\Bear.mdx"},
{id=21549, tex="bearskinblue2", unique=true, modelPath="Creature\\bear\\Bear.mdx"},
{id=21550, tex="bearskinblue3", unique=true, modelPath="Creature\\bear\\Bear.mdx"},
},
["Boars"] = {
{id=193, tex="BoarSkinIvory", unique=false, modelPath="Creature\\Boar\\Boar.mdx"},
@@ -151,6 +153,18 @@ MTH_DS_BeastSkins = {
{id=2714, tex="HyenaSkinWhite", unique=false, modelPath="Creature\\Hyena\\Hyena.mdx"},
{id=2726, tex="HyenaSkinBlack", unique=false, modelPath="Creature\\Hyena\\Hyena.mdx"},
},
["Moths"] = {
{id=21298, tex="mothardenwealdmount_blue", unique=true, modelPath="Creature\\mothardenwealdmount\\mothardenwealdmount.mdx"},
{id=21299, tex="mothardenwealdmount_dark", unique=true, modelPath="Creature\\mothardenwealdmount\\mothardenwealdmount.mdx"},
{id=21300, tex="mothardenwealdmount_mint", unique=true, modelPath="Creature\\mothardenwealdmount\\mothardenwealdmount.mdx"},
{id=21301, tex="mothardenwealdmount_red", unique=true, modelPath="Creature\\mothardenwealdmount\\mothardenwealdmount.mdx"},
{id=21431, tex="MothSkinBeige", unique=true, modelPath="Creature\\Moth\\Moth.mdx"},
{id=21432, tex="MothSkinBlue", unique=true, modelPath="Creature\\Moth\\Moth.mdx"},
{id=21433, tex="mothskingrey", unique=true, modelPath="Creature\\Moth\\Moth.mdx"},
{id=21434, tex="MothSkinRed", unique=true, modelPath="Creature\\Moth\\Moth.mdx"},
{id=21435, tex="MothSkinWhite", unique=true, modelPath="Creature\\Moth\\Moth.mdx"},
{id=21436, tex="mothskinyellow", unique=true, modelPath="Creature\\Moth\\Moth.mdx"},
},
["Owls"] = {
{id=4566, tex="OwlBrown", unique=false, modelPath="Creature\\Owl\\Owl.mdx"},
{id=4877, tex="OwlGrey", unique=false, modelPath="Creature\\Owl\\Owl.mdx"},
@@ -194,7 +208,7 @@ MTH_DS_BeastSkins = {
{id=18373, tex="SilithidScarabSkinGreen", unique=true, modelPath="Creature\\SILITHIDSCARAB\\SilithidScarab.mdx"},
{id=21268, tex="ScorpionskinDarkIron", unique=true, modelPath="Creature\\Scorpion\\Scorpion.mdx"},
},
["Serpents (Cobra)"] = {
["Serpents"] = {
{id=1206, tex="SnakeSkinBlack", unique=false, modelPath="Creature\\snake\\snake.mdx"},
{id=1986, tex="SnakeSkinDarkGreenYellow", unique=false, modelPath="Creature\\snake\\snake.mdx"},
{id=1987, tex="SnakeSkinYellowBlack", unique=false, modelPath="Creature\\snake\\snake.mdx"},
@@ -242,6 +256,8 @@ MTH_DS_BeastSkins = {
{id=20511, tex="HawkstriderGreen", unique=true, modelPath="Creature\\Hawkstrider\\Hawkstrider.mdx"},
{id=20512, tex="HawkstriderRed", unique=true, modelPath="Creature\\Hawkstrider\\Hawkstrider.mdx"},
{id=20513, tex="HawkstriderWhite", unique=true, modelPath="Creature\\Hawkstrider\\Hawkstrider.mdx"},
{id=21554, tex="TallStriderSkinBlue", unique=true, modelPath="Creature\\Tallstrider\\TallStrider.mdx"},
{id=21555, tex="TallStriderSkinViolet", unique=true, modelPath="Creature\\Tallstrider\\TallStrider.mdx"},
},
["Turtles"] = {
{id=1244, tex="SeaTurtleSkin", unique=false, modelPath="Creature\\SeaTurtle\\SeaTurtle.mdx"},
File diff suppressed because it is too large Load Diff
+26481 -1541
View File
File diff suppressed because it is too large Load Diff
+11602 -11602
View File
File diff suppressed because it is too large Load Diff
+844
View File
@@ -0,0 +1,844 @@
-- MetaHunt: Hunter spell data extracted from Spell.dbc (SpellFamilyName=9). Field layout: 173 fields. Indexed by spell ID: MTH_DS_HunterSpellsDBC[spellId]. Named lookup (rank 1): MTH_DS_HunterSpellsByName['SpellName'].
-- AUTO-GENERATED by .tools — do not edit by hand.
-- Source DBC(s): Spell.dbc, SpellCastTimes.dbc, SpellDuration.dbc, SpellIcon.dbc
-- Generated: 2026-03-20 14:10 UTC
if not MTH_DS then MTH_DS = {} end
MTH_DS_HunterSpellsDBC = {}
do
local t = MTH_DS_HunterSpellsDBC
t[19596] = {name="[Deprecated] Bestial Swiftness",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19574] = {name="[Deprecated] Bestial Wrath",cast=0,cd=120000,categoryCD=120000,recoveryCD=0,duration=1200000,manaCost=0,icon="",familyFlags=0}
t[19500] = {name="[Deprecated] Hawk Eye",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19457] = {name="[Deprecated] Improved Arcane Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19458] = {name="[Deprecated] Improved Arcane Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24386] = {name="[Deprecated] Improved Aspect of the Monkey",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24387] = {name="[Deprecated] Improved Aspect of the Monkey",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19424] = {name="[Deprecated] Improved Hunter's Mark",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19425] = {name="[Deprecated] Improved Hunter's Mark",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19494] = {name="[Deprecated] Improved Scorpid Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19234] = {name="[Deprecated] Improved Wing Clip",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19235] = {name="[Deprecated] Improved Wing Clip",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19374] = {name="[Deprecated] Killer Instinct",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19375] = {name="[Deprecated] Killer Instinct",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19562] = {name="[Deprecated] Pathfinding",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19563] = {name="[Deprecated] Pathfinding",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[14275] = {name="[Deprecated] Scorpid Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=6000,manaCost=90,icon="",familyFlags=32768}
t[14276] = {name="[Deprecated] Scorpid Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=3600000,manaCost=125,icon="",familyFlags=32768}
t[14277] = {name="[Deprecated] Scorpid Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=165,icon="",familyFlags=32768}
t[19611] = {name="[Deprecated] Thick Hide",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19613] = {name="[Deprecated] Thick Hide",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51520] = {name="[Deprecated] Trueshot Aura Percent Bonus",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=0,icon="",familyFlags=0}
t[51521] = {name="[Deprecated] Trueshot Aura Percent Bonus",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=0,icon="",familyFlags=0}
t[51522] = {name="[Deprecated] Trueshot Aura Percent Bonus",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=0,icon="",familyFlags=0}
t[28752] = {name="Adrenaline Rush",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19434] = {name="Aimed Shot",cast=3000,cd=6000,categoryCD=0,recoveryCD=6000,duration=60000,manaCost=75,icon="",familyFlags=131072}
t[20900] = {name="Aimed Shot",cast=3000,cd=6000,categoryCD=0,recoveryCD=6000,duration=5000,manaCost=115,icon="",familyFlags=131072}
t[20901] = {name="Aimed Shot",cast=3000,cd=6000,categoryCD=0,recoveryCD=6000,duration=1000,manaCost=160,icon="",familyFlags=131072}
t[20902] = {name="Aimed Shot",cast=3000,cd=6000,categoryCD=0,recoveryCD=6000,duration=0,manaCost=210,icon="",familyFlags=131072}
t[20903] = {name="Aimed Shot",cast=3000,cd=6000,categoryCD=0,recoveryCD=6000,duration=0,manaCost=260,icon="",familyFlags=131072}
t[20904] = {name="Aimed Shot",cast=3000,cd=6000,categoryCD=0,recoveryCD=6000,duration=0,manaCost=310,icon="",familyFlags=131072}
t[27632] = {name="Aimed Shot",cast=3000,cd=6000,categoryCD=0,recoveryCD=6000,duration=0,manaCost=310,icon="",familyFlags=131072}
t[23721] = {name="Arcane Infused",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[3044] = {name="Arcane Shot",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=600000,manaCost=25,icon="",familyFlags=2048}
t[14281] = {name="Arcane Shot",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=30000,manaCost=35,icon="",familyFlags=2048}
t[14282] = {name="Arcane Shot",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=60000,manaCost=50,icon="",familyFlags=2048}
t[14283] = {name="Arcane Shot",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=5000,manaCost=80,icon="",familyFlags=2048}
t[14284] = {name="Arcane Shot",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=1000,manaCost=105,icon="",familyFlags=2048}
t[14285] = {name="Arcane Shot",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=0,manaCost=135,icon="",familyFlags=2048}
t[14286] = {name="Arcane Shot",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=0,manaCost=160,icon="",familyFlags=2048}
t[14287] = {name="Arcane Shot",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=0,manaCost=190,icon="",familyFlags=2048}
t[23157] = {name="Arcane Shot Mana Reduction",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[13161] = {name="Aspect of the Beast",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1800000,manaCost=50,icon="",familyFlags=0}
t[5118] = {name="Aspect of the Cheetah",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=40,icon="",familyFlags=2097152}
t[45651] = {name="Aspect of the Fox",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=120000,manaCost=140,icon="",familyFlags=0}
t[13165] = {name="Aspect of the Hawk",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=20,icon="",familyFlags=1048576}
t[14318] = {name="Aspect of the Hawk",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=20000,manaCost=35,icon="",familyFlags=1048576}
t[14319] = {name="Aspect of the Hawk",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=5000,manaCost=50,icon="",familyFlags=1048576}
t[14320] = {name="Aspect of the Hawk",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=11000,manaCost=70,icon="",familyFlags=1048576}
t[14321] = {name="Aspect of the Hawk",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=90,icon="",familyFlags=1048576}
t[14322] = {name="Aspect of the Hawk",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=110,icon="",familyFlags=1048576}
t[25296] = {name="Aspect of the Hawk",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=120,icon="",familyFlags=1048576}
t[13163] = {name="Aspect of the Monkey",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=120000,manaCost=20,icon="",familyFlags=524288}
t[13159] = {name="Aspect of the Pack",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=100,icon="",familyFlags=2097152}
t[45652] = {name="Aspect of the Snake",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=120000,manaCost=20,icon="",familyFlags=0}
t[45664] = {name="Aspect of the Snake",cast=0,cd=1500,categoryCD=1500,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[45649] = {name="Aspect of the Turtle",cast=0,cd=180000,categoryCD=180000,recoveryCD=0,duration=60000,manaCost=10,icon="",familyFlags=0}
t[20043] = {name="Aspect of the Wild",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=90,icon="",familyFlags=0}
t[20190] = {name="Aspect of the Wild",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=115,icon="",familyFlags=0}
t[45650] = {name="Aspect of the Wolf",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=20,icon="",familyFlags=1048576}
t[51496] = {name="Aspect of the Wolf",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=20000,manaCost=35,icon="",familyFlags=1048576}
t[51497] = {name="Aspect of the Wolf",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=5000,manaCost=50,icon="",familyFlags=1048576}
t[51498] = {name="Aspect of the Wolf",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=11000,manaCost=70,icon="",familyFlags=1048576}
t[51499] = {name="Aspect of the Wolf",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=90,icon="",familyFlags=1048576}
t[51500] = {name="Aspect of the Wolf",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=110,icon="",familyFlags=1048576}
t[51501] = {name="Aspect of the Wolf",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=120,icon="",familyFlags=1048576}
t[75] = {name="Auto Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=0,icon="",familyFlags=1}
t[46023] = {name="Avoidance",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19767] = {name="Aynasha's Bow",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[46321] = {name="Baited Shot",cast=0,cd=8000,categoryCD=8000,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19461] = {name="Barrage",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19462] = {name="Barrage",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24691] = {name="Barrage",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[22996] = {name="Battle Standard",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[23005] = {name="Battle Standard",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[23034] = {name="Battle Standard",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[23035] = {name="Battle Standard",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[23538] = {name="Battle Standard",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[23539] = {name="Battle Standard",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[47355] = {name="Beast Mastery",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[29233] = {name="Beast of the Unseen Path",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19590] = {name="Bestial Discipline",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19592] = {name="Bestial Discipline",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19603] = {name="Bestial Fury",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19605] = {name="Bestial Fury",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19606] = {name="Bestial Fury",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19607] = {name="Bestial Fury",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19608] = {name="Bestial Fury",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51554] = {name="Bestial Precision",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51555] = {name="Bestial Precision",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24395] = {name="Bestial Wrath",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=0,icon="",familyFlags=0}
t[24396] = {name="Bestial Wrath",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=0,icon="",familyFlags=0}
t[24397] = {name="Bestial Wrath",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=0,icon="",familyFlags=0}
t[26592] = {name="Bestial Wrath",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=0,icon="",familyFlags=0}
t[17253] = {name="Bite",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=10000,manaCost=35,icon="",familyFlags=0}
t[17255] = {name="Bite",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=15000,manaCost=35,icon="",familyFlags=0}
t[17256] = {name="Bite",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=230000,manaCost=35,icon="",familyFlags=0}
t[17257] = {name="Bite",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=160000,manaCost=35,icon="",familyFlags=0}
t[17258] = {name="Bite",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=6000,manaCost=35,icon="",familyFlags=0}
t[17259] = {name="Bite",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=1200000,manaCost=35,icon="",familyFlags=0}
t[17260] = {name="Bite",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=0,manaCost=35,icon="",familyFlags=0}
t[17261] = {name="Bite",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=0,manaCost=35,icon="",familyFlags=0}
t[36523] = {name="Bubble Barrier",cast=0,cd=30000,categoryCD=0,recoveryCD=30000,duration=60000,manaCost=20,icon="",familyFlags=0}
t[36524] = {name="Bubble Barrier",cast=0,cd=30000,categoryCD=0,recoveryCD=30000,duration=160000,manaCost=20,icon="",familyFlags=0}
t[36525] = {name="Bubble Barrier",cast=0,cd=30000,categoryCD=0,recoveryCD=30000,duration=1200000,manaCost=20,icon="",familyFlags=0}
t[36526] = {name="Bubble Barrier",cast=0,cd=30000,categoryCD=0,recoveryCD=30000,duration=0,manaCost=20,icon="",familyFlags=0}
t[51575] = {name="Carve",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=60000,manaCost=0,icon="",familyFlags=0}
t[52415] = {name="Carve",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=11000,manaCost=0,icon="",familyFlags=0}
t[52416] = {name="Carve",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=0,manaCost=0,icon="",familyFlags=0}
t[24348] = {name="Cheetah Sprint",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[3009] = {name="Claw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=25,icon="",familyFlags=0}
t[3010] = {name="Claw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=25,icon="",familyFlags=0}
t[16827] = {name="Claw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=25,icon="",familyFlags=0}
t[16828] = {name="Claw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=15000,manaCost=25,icon="",familyFlags=0}
t[16829] = {name="Claw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=230000,manaCost=25,icon="",familyFlags=0}
t[16830] = {name="Claw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=160000,manaCost=25,icon="",familyFlags=0}
t[16831] = {name="Claw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=6000,manaCost=25,icon="",familyFlags=0}
t[16832] = {name="Claw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=25,icon="",familyFlags=0}
t[19239] = {name="Clever Traps",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19245] = {name="Clever Traps",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[20576] = {name="Command",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[21563] = {name="Command",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[5116] = {name="Concussive Shot",cast=0,cd=12000,categoryCD=12000,recoveryCD=0,duration=15000,manaCost=0,icon="",familyFlags=512}
t[23158] = {name="Concussive Shot Cooldown Reduction",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[49559] = {name="Coordinated Assault",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[28317] = {name="Copy of Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[19306] = {name="Counterattack",cast=0,cd=5000,categoryCD=0,recoveryCD=5000,duration=1800000,manaCost=45,icon="",familyFlags=0}
t[20909] = {name="Counterattack",cast=0,cd=5000,categoryCD=0,recoveryCD=5000,duration=3600000,manaCost=65,icon="",familyFlags=0}
t[20910] = {name="Counterattack",cast=0,cd=5000,categoryCD=0,recoveryCD=5000,duration=0,manaCost=85,icon="",familyFlags=0}
t[36548] = {name="Death Roll",cast=0,cd=30000,categoryCD=30000,recoveryCD=0,duration=60000,manaCost=50,icon="",familyFlags=0}
t[36549] = {name="Death Roll",cast=0,cd=30000,categoryCD=30000,recoveryCD=0,duration=60000,manaCost=50,icon="",familyFlags=0}
t[36550] = {name="Death Roll",cast=0,cd=30000,categoryCD=30000,recoveryCD=0,duration=1800000,manaCost=50,icon="",familyFlags=0}
t[36551] = {name="Death Roll",cast=0,cd=30000,categoryCD=30000,recoveryCD=0,duration=1200000,manaCost=50,icon="",familyFlags=0}
t[36552] = {name="Death Roll",cast=0,cd=30000,categoryCD=30000,recoveryCD=0,duration=0,manaCost=50,icon="",familyFlags=0}
t[36553] = {name="Death Roll",cast=0,cd=30000,categoryCD=30000,recoveryCD=0,duration=0,manaCost=50,icon="",familyFlags=0}
t[24992] = {name="Demonic Transformation",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=0,icon="",familyFlags=0}
t[23578] = {name="Detect Weakness",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19263] = {name="Deterrence",cast=0,cd=300000,categoryCD=300000,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=0}
t[781] = {name="Disengage",cast=0,cd=5000,categoryCD=0,recoveryCD=5000,duration=60000,manaCost=50,icon="",familyFlags=0}
t[14272] = {name="Disengage",cast=0,cd=5000,categoryCD=0,recoveryCD=5000,duration=0,manaCost=100,icon="",familyFlags=0}
t[14273] = {name="Disengage",cast=0,cd=5000,categoryCD=0,recoveryCD=5000,duration=0,manaCost=150,icon="",familyFlags=0}
t[14274] = {name="Distracting Shot",cast=0,cd=8000,categoryCD=0,recoveryCD=8000,duration=60000,manaCost=30,icon="",familyFlags=65536}
t[15629] = {name="Distracting Shot",cast=0,cd=8000,categoryCD=0,recoveryCD=8000,duration=1800000,manaCost=50,icon="",familyFlags=65536}
t[15630] = {name="Distracting Shot",cast=0,cd=8000,categoryCD=0,recoveryCD=8000,duration=1200000,manaCost=70,icon="",familyFlags=65536}
t[15631] = {name="Distracting Shot",cast=0,cd=8000,categoryCD=0,recoveryCD=8000,duration=0,manaCost=90,icon="",familyFlags=65536}
t[15632] = {name="Distracting Shot",cast=0,cd=8000,categoryCD=0,recoveryCD=8000,duration=0,manaCost=110,icon="",familyFlags=65536}
t[20736] = {name="Distracting Shot",cast=0,cd=8000,categoryCD=0,recoveryCD=8000,duration=30000,manaCost=20,icon="",familyFlags=65536}
t[19416] = {name="Efficiency",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19417] = {name="Efficiency",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19418] = {name="Efficiency",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19419] = {name="Efficiency",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19420] = {name="Efficiency",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51552] = {name="Elusiveness",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51553] = {name="Elusiveness",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51517] = {name="Endless Quiver",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51518] = {name="Endless Quiver",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19583] = {name="Endurance Training",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19584] = {name="Endurance Training",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19585] = {name="Endurance Training",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19586] = {name="Endurance Training",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19587] = {name="Endurance Training",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19184] = {name="Entrapment",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19387] = {name="Entrapment",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19388] = {name="Entrapment",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19389] = {name="Entrapment",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19390] = {name="Entrapment",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[13813] = {name="Explosive Trap",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=0,manaCost=275,icon="",familyFlags=128}
t[14316] = {name="Explosive Trap",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=0,manaCost=395,icon="",familyFlags=128}
t[14317] = {name="Explosive Trap",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=0,manaCost=520,icon="",familyFlags=128}
t[13812] = {name="Explosive Trap Effect",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=4}
t[14314] = {name="Explosive Trap Effect",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=4}
t[14315] = {name="Explosive Trap Effect",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=4}
t[51519] = {name="Extra Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=0,icon="",familyFlags=1}
t[1002] = {name="Eyes of the Beast",cast=2000,cd=0,categoryCD=0,recoveryCD=0,duration=120000,manaCost=20,icon="",familyFlags=4194304}
t[17331] = {name="Fang of the Crystal Spider",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[52402] = {name="Faster Bleeds 5 (Hunter)",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[5384] = {name="Feign Death",cast=0,cd=30000,categoryCD=30000,recoveryCD=0,duration=1800000,manaCost=80,icon="Spell_Nature_Regenerate",familyFlags=256}
t[19598] = {name="Ferocity",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19599] = {name="Ferocity",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19600] = {name="Ferocity",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19601] = {name="Ferocity",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19602] = {name="Ferocity",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[46269] = {name="Fire Breath",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=10000,manaCost=50,icon="",familyFlags=0}
t[46270] = {name="Fire Breath",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=0,manaCost=50,icon="",familyFlags=0}
t[19781] = {name="Flame Spear",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=75000,manaCost=0,icon="",familyFlags=0}
t[1543] = {name="Flare",cast=0,cd=15000,categoryCD=15000,recoveryCD=0,duration=6000,manaCost=50,icon="Spell_Magic_PolymorphChicken",familyFlags=0}
t[1499] = {name="Freezing Trap",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=60000,manaCost=50,icon="",familyFlags=128}
t[14310] = {name="Freezing Trap",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=1200000,manaCost=75,icon="",familyFlags=128}
t[14311] = {name="Freezing Trap",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=0,manaCost=100,icon="",familyFlags=128}
t[27753] = {name="Freezing Trap",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=0,manaCost=100,icon="Spell_Nature_Regenerate",familyFlags=128}
t[21750] = {name="Freezing Trap (TEST)",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=60000,manaCost=50,icon="",familyFlags=0}
t[3355] = {name="Freezing Trap Effect",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=8}
t[14308] = {name="Freezing Trap Effect",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=0,icon="",familyFlags=8}
t[14309] = {name="Freezing Trap Effect",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=8}
t[19621] = {name="Frenzy",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19622] = {name="Frenzy",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19623] = {name="Frenzy",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19624] = {name="Frenzy",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19625] = {name="Frenzy",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[13809] = {name="Frost Trap",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=5000,manaCost=60,icon="",familyFlags=128}
t[13810] = {name="Frost Trap Aura",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=5000,manaCost=0,icon="",familyFlags=16}
t[14207] = {name="Frost Trap Effect",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=5000,manaCost=0,icon="",familyFlags=16}
t[24597] = {name="Furious Howl",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=0,manaCost=50,icon="",familyFlags=0}
t[24603] = {name="Furious Howl",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=1200000,manaCost=50,icon="",familyFlags=0}
t[24604] = {name="Furious Howl",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=60000,manaCost=50,icon="",familyFlags=0}
t[24605] = {name="Furious Howl",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=160000,manaCost=50,icon="",familyFlags=0}
t[46296] = {name="Grace",cast=0,cd=60000,categoryCD=60000,recoveryCD=0,duration=60000,manaCost=10,icon="Spell_Nature_GuardianWard",familyFlags=0}
t[14824] = {name="Haste",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[14825] = {name="Haste",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[14826] = {name="Haste",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[14827] = {name="Haste",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[14828] = {name="Haste",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[14829] = {name="Haste",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[29413] = {name="Haste",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[29414] = {name="Haste",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[29415] = {name="Haste",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[29416] = {name="Haste",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[29417] = {name="Haste",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[29418] = {name="Haste",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19498] = {name="Hawk Eye",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19499] = {name="Hawk Eye",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[21942] = {name="Hunter Giant Stalker",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[1130] = {name="Hunter's Mark",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=600000,manaCost=15,icon="",familyFlags=1024}
t[14323] = {name="Hunter's Mark",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=45000,manaCost=30,icon="",familyFlags=1024}
t[14324] = {name="Hunter's Mark",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=45,icon="",familyFlags=1024}
t[14325] = {name="Hunter's Mark",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=60,icon="",familyFlags=1024}
t[13795] = {name="Immolation Trap",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=230000,manaCost=50,icon="",familyFlags=128}
t[14302] = {name="Immolation Trap",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=240000,manaCost=90,icon="",familyFlags=128}
t[14303] = {name="Immolation Trap",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=1000,manaCost=135,icon="",familyFlags=128}
t[14304] = {name="Immolation Trap",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=0,manaCost=190,icon="",familyFlags=128}
t[14305] = {name="Immolation Trap",cast=0,cd=15000,categoryCD=0,recoveryCD=15000,duration=0,manaCost=245,icon="",familyFlags=128}
t[13797] = {name="Immolation Trap Effect",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=230000,manaCost=0,icon="",familyFlags=4}
t[14298] = {name="Immolation Trap Effect",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=240000,manaCost=0,icon="Spell_Nature_MoonGlow",familyFlags=4}
t[14299] = {name="Immolation Trap Effect",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1000,manaCost=0,icon="Spell_Nature_MoonGlow",familyFlags=4}
t[14300] = {name="Immolation Trap Effect",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="Spell_Nature_MoonGlow",familyFlags=4}
t[14301] = {name="Immolation Trap Effect",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="Spell_Nature_MoonGlow",familyFlags=4}
t[15860] = {name="Impale",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="Spell_Holy_Resurrection",familyFlags=1}
t[16001] = {name="Impale",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="Spell_Holy_Resurrection",familyFlags=1}
t[24049] = {name="Impale",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=0,icon="Spell_Holy_Resurrection",familyFlags=1}
t[26548] = {name="Impale",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=0,icon="Spell_Holy_Resurrection",familyFlags=1}
t[23559] = {name="Improved Aspect of the Hawk",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19407] = {name="Improved Concussive Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19412] = {name="Improved Concussive Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19413] = {name="Improved Concussive Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19414] = {name="Improved Concussive Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19415] = {name="Improved Concussive Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24465] = {name="Improved Concussive Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19378] = {name="Improved Explosive Trap",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19379] = {name="Improved Explosive Trap",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19557] = {name="Improved Eyes of the Beast",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19558] = {name="Improved Eyes of the Beast",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[45662] = {name="Improved Eyes of the Beast",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[45663] = {name="Improved Eyes of the Beast",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19286] = {name="Improved Feign Death",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19287] = {name="Improved Feign Death",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24432] = {name="Improved Feign Death",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19288] = {name="Improved Freezing Trap",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24298] = {name="Improved Freezing Trap",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24299] = {name="Improved Freezing Trap",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19421] = {name="Improved Hunter's Mark",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19422] = {name="Improved Hunter's Mark",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19423] = {name="Improved Hunter's Mark",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19246] = {name="Improved Immolation Trap",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19247] = {name="Improved Immolation Trap",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19248] = {name="Improved Immolation Trap",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19572] = {name="Improved Mend Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19573] = {name="Improved Mend Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[23560] = {name="Improved Mend Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24406] = {name="Improved Mend Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19549] = {name="Improved Primal Aspects",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19550] = {name="Improved Primal Aspects",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19551] = {name="Improved Primal Aspects",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19575] = {name="Improved Revive Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24443] = {name="Improved Revive Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19491] = {name="Improved Scorpid Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19493] = {name="Improved Scorpid Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24467] = {name="Improved Serpent Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51515] = {name="Improved Steady Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51516] = {name="Improved Steady Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19464] = {name="Improved Stings",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19465] = {name="Improved Stings",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19466] = {name="Improved Stings",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19467] = {name="Improved Stings",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19468] = {name="Improved Stings",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[52603] = {name="Improved Swift Aspects",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[23566] = {name="Improved Volley and Multishot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19228] = {name="Improved Wing Clip",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19232] = {name="Improved Wing Clip",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19233] = {name="Improved Wing Clip",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[22854] = {name="Increased Hunter Pet Damage",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[27205] = {name="Increased Pet Damage +3%",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[52413] = {name="Increased Pet Damage +4%",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[41827] = {name="Kill Command",cast=0,cd=12000,categoryCD=12000,recoveryCD=0,duration=0,manaCost=0,icon="Spell_Holy_PrayerOfHealing",familyFlags=0}
t[41828] = {name="Kill Command",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19162] = {name="Killer Instinct",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19163] = {name="Killer Instinct",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19165] = {name="Killer Instinct",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19370] = {name="Killer Instinct",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19371] = {name="Killer Instinct",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19373] = {name="Killer Instinct",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[20907] = {name="Lacerate",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=80,icon="INV_Gauntlets_06",familyFlags=0}
t[20908] = {name="Lacerate",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=95,icon="INV_Gauntlets_06",familyFlags=0}
t[24118] = {name="Lacerate",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=65,icon="INV_Gauntlets_06",familyFlags=0}
t[24119] = {name="Lacerate",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=80,icon="INV_Gauntlets_06",familyFlags=0}
t[24120] = {name="Lacerate",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=95,icon="INV_Gauntlets_06",familyFlags=0}
t[45653] = {name="Lacerate",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=65,icon="INV_Gauntlets_06",familyFlags=0}
t[45654] = {name="Lacerate",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=80,icon="INV_Gauntlets_06",familyFlags=0}
t[45655] = {name="Lacerate",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=95,icon="INV_Gauntlets_06",familyFlags=0}
t[45656] = {name="Lacerate",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=0,icon="",familyFlags=0}
t[45657] = {name="Lacerate",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=80,icon="INV_Gauntlets_06",familyFlags=0}
t[45658] = {name="Lacerate",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=95,icon="INV_Gauntlets_06",familyFlags=0}
t[48049] = {name="Lacerate",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[48050] = {name="Lacerate",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="INV_Gauntlets_06",familyFlags=0}
t[24844] = {name="Lightning Breath",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=50,icon="Spell_Shadow_GatherShadows",familyFlags=0}
t[25008] = {name="Lightning Breath",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=30000,manaCost=50,icon="Spell_Shadow_GatherShadows",familyFlags=0}
t[25009] = {name="Lightning Breath",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=160000,manaCost=50,icon="Spell_Shadow_GatherShadows",familyFlags=0}
t[25010] = {name="Lightning Breath",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1000,manaCost=50,icon="Spell_Shadow_GatherShadows",familyFlags=0}
t[25011] = {name="Lightning Breath",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=50,icon="Spell_Shadow_GatherShadows",familyFlags=0}
t[25012] = {name="Lightning Breath",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=50,icon="Spell_Shadow_GatherShadows",familyFlags=0}
t[19168] = {name="Lightning Reflexes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19180] = {name="Lightning Reflexes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19181] = {name="Lightning Reflexes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24296] = {name="Lightning Reflexes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24297] = {name="Lightning Reflexes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[46297] = {name="Lizard Bolt",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=30000,manaCost=35,icon="Ability_Gouge",familyFlags=0}
t[46298] = {name="Lizard Bolt",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=160000,manaCost=35,icon="Ability_Gouge",familyFlags=0}
t[46299] = {name="Lizard Bolt",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1000,manaCost=35,icon="Ability_Gouge",familyFlags=0}
t[46300] = {name="Lizard Bolt",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=35,icon="Ability_Gouge",familyFlags=0}
t[46301] = {name="Lizard Bolt",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=35,icon="Ability_Gouge",familyFlags=0}
t[136] = {name="Mend Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=30000,manaCost=50,icon="",familyFlags=8388608}
t[3111] = {name="Mend Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=90,icon="",familyFlags=8388608}
t[3661] = {name="Mend Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=5000,manaCost=155,icon="",familyFlags=8388608}
t[3662] = {name="Mend Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1000,manaCost=225,icon="",familyFlags=8388608}
t[13542] = {name="Mend Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=300,icon="",familyFlags=8388608}
t[13543] = {name="Mend Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=385,icon="",familyFlags=8388608}
t[13544] = {name="Mend Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=480,icon="",familyFlags=8388608}
t[1495] = {name="Mongoose Bite",cast=0,cd=5000,categoryCD=0,recoveryCD=5000,duration=230000,manaCost=30,icon="Trade_BrewPoison",familyFlags=2}
t[14269] = {name="Mongoose Bite",cast=0,cd=5000,categoryCD=0,recoveryCD=5000,duration=1800000,manaCost=40,icon="Trade_BrewPoison",familyFlags=2}
t[14270] = {name="Mongoose Bite",cast=0,cd=5000,categoryCD=0,recoveryCD=5000,duration=0,manaCost=50,icon="Trade_BrewPoison",familyFlags=2}
t[14271] = {name="Mongoose Bite",cast=0,cd=5000,categoryCD=0,recoveryCD=5000,duration=0,manaCost=65,icon="Trade_BrewPoison",familyFlags=2}
t[19485] = {name="Mortal Shots",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19487] = {name="Mortal Shots",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19488] = {name="Mortal Shots",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19489] = {name="Mortal Shots",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19490] = {name="Mortal Shots",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[2643] = {name="Multi-Shot",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=20000,manaCost=100,icon="",familyFlags=4096}
t[14288] = {name="Multi-Shot",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=1800000,manaCost=140,icon="",familyFlags=4096}
t[14289] = {name="Multi-Shot",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=3600000,manaCost=175,icon="",familyFlags=4096}
t[14290] = {name="Multi-Shot",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=0,manaCost=210,icon="",familyFlags=4096}
t[25294] = {name="Multi-Shot",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=0,manaCost=230,icon="",familyFlags=4096}
t[28751] = {name="Multi-Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[28539] = {name="Multi-Shot Damage Increase",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[52602] = {name="Multishot and Carve Cooldown",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[28761] = {name="Not There",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[36532] = {name="Packleader",cast=0,cd=90000,categoryCD=90000,recoveryCD=0,duration=60000,manaCost=50,icon="INV_Potion_40",familyFlags=0}
t[36562] = {name="Packleader",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="INV_Potion_40",familyFlags=0}
t[19559] = {name="Pathfinding",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19560] = {name="Pathfinding",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[52685] = {name="Pet Focus Regen Bonus",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51512] = {name="Piercing Shots",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51513] = {name="Piercing Shots",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51514] = {name="Piercing Shots",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=120000,manaCost=0,icon="",familyFlags=0}
t[46292] = {name="Pin",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=230000,manaCost=10,icon="",familyFlags=0}
t[46293] = {name="Pin",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=6000,manaCost=10,icon="",familyFlags=0}
t[46294] = {name="Pin",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=10,icon="",familyFlags=0}
t[46295] = {name="Pin",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=10,icon="",familyFlags=0}
t[51576] = {name="Planning Ahead",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51577] = {name="Planning Ahead",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51578] = {name="Planning Ahead Dummy",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[46271] = {name="Poison Spit",cast=0,cd=8000,categoryCD=8000,recoveryCD=8000,duration=300000,manaCost=35,icon="Spell_Nature_LightningShield",familyFlags=0}
t[46272] = {name="Poison Spit",cast=0,cd=8000,categoryCD=8000,recoveryCD=8000,duration=0,manaCost=35,icon="Spell_Nature_LightningShield",familyFlags=0}
t[46273] = {name="Poison Spit",cast=0,cd=8000,categoryCD=8000,recoveryCD=8000,duration=0,manaCost=35,icon="Spell_Nature_LightningShield",familyFlags=0}
t[24450] = {name="Prowl",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=1800000,manaCost=40,icon="Spell_Fire_Fireball02",familyFlags=0}
t[24452] = {name="Prowl",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=1200000,manaCost=40,icon="Spell_Fire_Fireball02",familyFlags=0}
t[24453] = {name="Prowl",cast=0,cd=10000,categoryCD=0,recoveryCD=10000,duration=0,manaCost=40,icon="Spell_Fire_Fireball02",familyFlags=0}
t[51547] = {name="Quick Shots",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51548] = {name="Quick Shots",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51549] = {name="Quick Shots",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51550] = {name="Quick Shots",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51551] = {name="Quick Shots",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51542] = {name="Quick Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="Spell_Shadow_ImpPhaseShift",familyFlags=0}
t[51543] = {name="Quick Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="Spell_Shadow_ImpPhaseShift",familyFlags=0}
t[51544] = {name="Quick Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="Spell_Shadow_ImpPhaseShift",familyFlags=0}
t[51545] = {name="Quick Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="Spell_Shadow_ImpPhaseShift",familyFlags=0}
t[51546] = {name="Quick Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="Spell_Shadow_ImpPhaseShift",familyFlags=0}
t[19511] = {name="Ranged Weapon Specialization",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[3045] = {name="Rapid Fire",cast=0,cd=300000,categoryCD=0,recoveryCD=300000,duration=240000,manaCost=100,icon="",familyFlags=32}
t[28755] = {name="Rapid Fire",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[2973] = {name="Raptor Strike",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=10000,manaCost=15,icon="Spell_Nature_NatureTouchGrow",familyFlags=2}
t[14260] = {name="Raptor Strike",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=15000,manaCost=25,icon="Spell_Nature_NatureTouchGrow",familyFlags=2}
t[14261] = {name="Raptor Strike",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=230000,manaCost=35,icon="Spell_Nature_NatureTouchGrow",familyFlags=2}
t[14262] = {name="Raptor Strike",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=160000,manaCost=45,icon="Spell_Nature_NatureTouchGrow",familyFlags=2}
t[14263] = {name="Raptor Strike",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=6000,manaCost=55,icon="Spell_Nature_NatureTouchGrow",familyFlags=2}
t[14264] = {name="Raptor Strike",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=1200000,manaCost=70,icon="Spell_Nature_NatureTouchGrow",familyFlags=2}
t[14265] = {name="Raptor Strike",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=0,manaCost=85,icon="Spell_Nature_NatureTouchGrow",familyFlags=2}
t[14266] = {name="Raptor Strike",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=0,manaCost=100,icon="Spell_Nature_NatureTouchGrow",familyFlags=2}
t[23989] = {name="Readiness",cast=0,cd=300000,categoryCD=300000,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51570] = {name="Resourcefulness",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51571] = {name="Resourcefulness",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51572] = {name="Resourcefulness",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51573] = {name="Resourcefulness",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51574] = {name="Resourcefulness",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[982] = {name="Revive Pet",cast=10000,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=16777216}
t[23499] = {name="Revive Pet",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=16777216}
t[36535] = {name="Roar of Fortitude",cast=0,cd=120000,categoryCD=120000,recoveryCD=0,duration=1800000,manaCost=50,icon="",familyFlags=0}
t[36536] = {name="Savage Rend",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=10000,manaCost=35,icon="INV_Gauntlets_06",familyFlags=0}
t[36537] = {name="Savage Rend",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=30000,manaCost=35,icon="INV_Gauntlets_06",familyFlags=0}
t[36538] = {name="Savage Rend",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=160000,manaCost=35,icon="INV_Gauntlets_06",familyFlags=0}
t[36539] = {name="Savage Rend",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=1000,manaCost=35,icon="INV_Gauntlets_06",familyFlags=0}
t[36540] = {name="Savage Rend",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=0,manaCost=35,icon="INV_Gauntlets_06",familyFlags=0}
t[36541] = {name="Savage Rend",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=0,manaCost=35,icon="INV_Gauntlets_06",familyFlags=0}
t[46282] = {name="Savage Rend",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=25,icon="",familyFlags=0}
t[46283] = {name="Savage Rend",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=25,icon="",familyFlags=0}
t[46284] = {name="Savage Rend",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=25,icon="",familyFlags=0}
t[46285] = {name="Savage Rend",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=25,icon="",familyFlags=0}
t[46286] = {name="Savage Rend",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=25,icon="",familyFlags=0}
t[19159] = {name="Savage Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19160] = {name="Savage Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19503] = {name="Scatter Shot",cast=0,cd=30000,categoryCD=30000,recoveryCD=0,duration=1800000,manaCost=0,icon="INV_Flask_05",familyFlags=262144}
t[23601] = {name="Scatter Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1800000,manaCost=0,icon="INV_Flask_05",familyFlags=262144}
t[24583] = {name="Scorpid Poison",cast=0,cd=3000,categoryCD=0,recoveryCD=3000,duration=160000,manaCost=25,icon="Spell_Nature_LightningShield",familyFlags=0}
t[24586] = {name="Scorpid Poison",cast=0,cd=3000,categoryCD=0,recoveryCD=3000,duration=1200000,manaCost=25,icon="Spell_Nature_LightningShield",familyFlags=0}
t[24587] = {name="Scorpid Poison",cast=0,cd=3000,categoryCD=0,recoveryCD=3000,duration=0,manaCost=25,icon="Spell_Nature_LightningShield",familyFlags=0}
t[24640] = {name="Scorpid Poison",cast=0,cd=3000,categoryCD=0,recoveryCD=3000,duration=15000,manaCost=25,icon="Spell_Nature_LightningShield",familyFlags=0}
t[45659] = {name="Scorpid Stike",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=165,icon="",familyFlags=32768}
t[3043] = {name="Scorpid Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=45000,manaCost=70,icon="",familyFlags=32768}
t[51509] = {name="Scorpid Sting Damage Reduction",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=45000,manaCost=0,icon="",familyFlags=0}
t[24423] = {name="Screech",cast=0,cd=5000,categoryCD=5000,recoveryCD=0,duration=15000,manaCost=20,icon="",familyFlags=0}
t[24577] = {name="Screech",cast=0,cd=5000,categoryCD=5000,recoveryCD=0,duration=160000,manaCost=20,icon="",familyFlags=0}
t[24578] = {name="Screech",cast=0,cd=5000,categoryCD=5000,recoveryCD=0,duration=0,manaCost=20,icon="",familyFlags=0}
t[24579] = {name="Screech",cast=0,cd=5000,categoryCD=5000,recoveryCD=0,duration=0,manaCost=20,icon="",familyFlags=0}
t[1978] = {name="Serpent Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=120000,manaCost=15,icon="",familyFlags=16384}
t[13549] = {name="Serpent Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=30,icon="",familyFlags=16384}
t[13550] = {name="Serpent Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=20000,manaCost=50,icon="",familyFlags=16384}
t[13551] = {name="Serpent Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=240000,manaCost=80,icon="",familyFlags=16384}
t[13552] = {name="Serpent Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=115,icon="",familyFlags=16384}
t[13553] = {name="Serpent Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=3600000,manaCost=150,icon="",familyFlags=16384}
t[13554] = {name="Serpent Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=190,icon="",familyFlags=16384}
t[13555] = {name="Serpent Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=230,icon="",familyFlags=16384}
t[25295] = {name="Serpent Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=250,icon="",familyFlags=16384}
t[45661] = {name="Serpent Strike",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=250,icon="",familyFlags=16384}
t[29218] = {name="Server Spell",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[26064] = {name="Shell Shield",cast=0,cd=60000,categoryCD=60000,recoveryCD=0,duration=60000,manaCost=10,icon="",familyFlags=0}
t[6660] = {name="Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[15547] = {name="Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[15620] = {name="Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[16100] = {name="Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[16496] = {name="Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[17353] = {name="Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[18561] = {name="Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[20463] = {name="Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[22121] = {name="Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[22411] = {name="Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[22907] = {name="Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[23073] = {name="Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[23337] = {name="Shoot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[2480] = {name="Shoot Bow",cast=1000,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=0,icon="",familyFlags=1}
t[7919] = {name="Shoot Crossbow",cast=1000,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=0,icon="",familyFlags=1}
t[7918] = {name="Shoot Gun",cast=1000,cd=0,categoryCD=0,recoveryCD=0,duration=10000,manaCost=0,icon="",familyFlags=1}
t[25200] = {name="Shoot Silithus Rifleman Long Range",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[26282] = {name="Shoot Tauren Rifleman",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[28318] = {name="Slime Shot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[19501] = {name="Spell - Reuse 19501",cast=0,cd=30000,categoryCD=30000,recoveryCD=0,duration=1800000,manaCost=0,icon="",familyFlags=262144}
t[27919] = {name="Spit",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=1}
t[28758] = {name="Stalker's Ally",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[3035] = {name="Steady Shot",cast=1000,cd=0,categoryCD=0,recoveryCD=0,duration=120000,manaCost=0,icon="",familyFlags=0}
t[3036] = {name="Steady Shot",cast=1000,cd=0,categoryCD=0,recoveryCD=0,duration=120000,manaCost=0,icon="",familyFlags=0}
t[3037] = {name="Steady Shot",cast=1000,cd=0,categoryCD=0,recoveryCD=0,duration=45000,manaCost=0,icon="",familyFlags=0}
t[3038] = {name="Steady Shot",cast=1000,cd=0,categoryCD=0,recoveryCD=0,duration=1800000,manaCost=0,icon="",familyFlags=0}
t[3668] = {name="Steady Shot",cast=1000,cd=0,categoryCD=0,recoveryCD=0,duration=11000,manaCost=0,icon="",familyFlags=0}
t[45970] = {name="Steady Shot",cast=1000,cd=0,categoryCD=0,recoveryCD=0,duration=11000,manaCost=0,icon="",familyFlags=0}
t[45972] = {name="Steady Shot",cast=1000,cd=0,categoryCD=0,recoveryCD=0,duration=11000,manaCost=0,icon="",familyFlags=0}
t[45974] = {name="Steady Shot",cast=1000,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[52684] = {name="Steady Shot and Raptor Strike Crit Bonus",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51579] = {name="Stinging Nettle",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51580] = {name="Stinging Nettle",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[36531] = {name="Strider Presence",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=50,icon="",familyFlags=0}
t[49557] = {name="Strike Together",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[49558] = {name="Strike Together",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[26173] = {name="Striker's Arcane Shot Bonus",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[26174] = {name="Striker's Rapid Fire Bonus",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24416] = {name="Superior Aspects",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24269] = {name="Superior Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24270] = {name="Superior Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24271] = {name="Superior Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24272] = {name="Superior Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24273] = {name="Superior Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19290] = {name="Surefooted",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19294] = {name="Surefooted",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24283] = {name="Surefooted",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24286] = {name="Surefooted",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[24287] = {name="Surefooted",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19255] = {name="Survivalist",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19256] = {name="Survivalist",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19257] = {name="Survivalist",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19258] = {name="Survivalist",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19259] = {name="Survivalist",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19552] = {name="Swift Aspects",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19553] = {name="Swift Aspects",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19554] = {name="Swift Aspects",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19555] = {name="Swift Aspects",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19556] = {name="Swift Aspects",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19454] = {name="Swiftshot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19455] = {name="Swiftshot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19456] = {name="Swiftshot",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[46287] = {name="Swipe",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=10000,manaCost=20,icon="Spell_Frost_ChillingBolt",familyFlags=0}
t[46288] = {name="Swipe",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=10000,manaCost=20,icon="Spell_Frost_ChillingBolt",familyFlags=0}
t[46289] = {name="Swipe",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=10000,manaCost=20,icon="Spell_Frost_ChillingBolt",familyFlags=0}
t[46290] = {name="Swipe",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=10000,manaCost=20,icon="Spell_Frost_ChillingBolt",familyFlags=0}
t[46291] = {name="Swipe",cast=0,cd=10000,categoryCD=10000,recoveryCD=0,duration=10000,manaCost=20,icon="Spell_Frost_ChillingBolt",familyFlags=0}
t[19678] = {name="Tame Adult Plainstrider",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[19683] = {name="Tame Armored Scorpid",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[44017] = {name="Tame Armored Scorpid",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[46705] = {name="Tame Ashfeather Swooper",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[46701] = {name="Tame Blackvenom Scorpid",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[50904] = {name="Tame Decrepit Darkhound",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[44007] = {name="Tame Decrepit Darkhound.",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[19681] = {name="Tame Dire Mottled Boar",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[44013] = {name="Tame Dire Mottled Boar.",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[46091] = {name="Tame Elder Crimson Lynx",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[50905] = {name="Tame Greater Dusk Bat",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[44009] = {name="Tame Greater Duskbat",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[19597] = {name="Tame Ice Claw Bear",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[44023] = {name="Tame Ice Claw Bear",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[46093] = {name="Tame Ivory Hawkstrider",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[19677] = {name="Tame Large Crag Boar",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[44019] = {name="Tame Large Crag Boar.",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[46095] = {name="Tame Lavender Mana Wyrm",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[46703] = {name="Tame Muckreef Crawler",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[19685] = {name="Tame Nightsaber Stalker",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[19679] = {name="Tame Prairie Stalker",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[44003] = {name="Tame Prowler",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[19676] = {name="Tame Snow Leopard",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[44021] = {name="Tame Snow Leopard",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[44001] = {name="Tame Stonetusk Boar",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[19686] = {name="Tame Strigid Screecher",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[19682] = {name="Tame Surf Crawler",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[44015] = {name="Tame Surf Crawler",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[19680] = {name="Tame Swoop",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[44011] = {name="Tame Tirisfal Plagued Bear",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[50906] = {name="Tame Tirisfal Plagued Bear",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[19684] = {name="Tame Webwood Lurker",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[44005] = {name="Tame Young Forest Bear",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2048}
t[8875] = {name="Tamed Pet Passive (DND)",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=33554432}
t[19580] = {name="Tamed Pet Passive (DND)",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=67108864}
t[19581] = {name="Tamed Pet Passive (DND)",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=134217728}
t[19582] = {name="Tamed Pet Passive (DND)",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=268435456}
t[19589] = {name="Tamed Pet Passive (DND)",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=536870912}
t[19591] = {name="Tamed Pet Passive (DND)",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=1073741824}
t[20782] = {name="Tamed Pet Passive (DND)",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[20784] = {name="Tamed Pet Passive (DND)",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=2147483648}
t[19609] = {name="Thick Hide",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19610] = {name="Thick Hide",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19612] = {name="Thick Hide",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[10277] = {name="Throw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=0}
t[15607] = {name="Throw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=0}
t[15795] = {name="Throw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=0}
t[16000] = {name="Throw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=0}
t[19785] = {name="Throw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=75000,manaCost=0,icon="",familyFlags=0}
t[22887] = {name="Throw",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=60000,manaCost=0,icon="",familyFlags=0}
t[26090] = {name="Thunderstomp",cast=0,cd=40000,categoryCD=40000,recoveryCD=0,duration=1800000,manaCost=60,icon="",familyFlags=0}
t[26187] = {name="Thunderstomp",cast=0,cd=40000,categoryCD=40000,recoveryCD=0,duration=1200000,manaCost=60,icon="",familyFlags=0}
t[26188] = {name="Thunderstomp",cast=0,cd=40000,categoryCD=40000,recoveryCD=0,duration=0,manaCost=60,icon="",familyFlags=0}
t[51156] = {name="Thunderstomp",cast=0,cd=40000,categoryCD=40000,recoveryCD=0,duration=0,manaCost=60,icon="",familyFlags=0}
t[19801] = {name="Tranquilizing Shot",cast=0,cd=20000,categoryCD=20000,recoveryCD=0,duration=0,manaCost=270,icon="Ability_Warrior_Disarm",familyFlags=65536}
t[19376] = {name="Trap Mastery",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19377] = {name="Trap Mastery",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51581] = {name="Trap Mastery",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19506] = {name="Trueshot Aura",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=0,icon="",familyFlags=0}
t[20905] = {name="Trueshot Aura",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[20906] = {name="Trueshot Aura",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19616] = {name="Unleashed Fury",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19617] = {name="Unleashed Fury",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19618] = {name="Unleashed Fury",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19619] = {name="Unleashed Fury",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[19620] = {name="Unleashed Fury",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[26176] = {name="Unseen Path Pet Bonus",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51586] = {name="Untamed Trapper",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51584] = {name="Vicious Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[51585] = {name="Vicious Strikes",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[3034] = {name="Viper Sting",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=1000,manaCost=135,icon="",familyFlags=65536}
t[14279] = {name="Viper Sting",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=0,manaCost=175,icon="",familyFlags=65536}
t[14280] = {name="Viper Sting",cast=0,cd=6000,categoryCD=0,recoveryCD=6000,duration=0,manaCost=215,icon="",familyFlags=65536}
t[45660] = {name="Viper Strike",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=215,icon="",familyFlags=65536}
t[1510] = {name="Volley",cast=0,cd=60000,categoryCD=0,recoveryCD=60000,duration=1200000,manaCost=350,icon="",familyFlags=8192}
t[14294] = {name="Volley",cast=0,cd=60000,categoryCD=0,recoveryCD=60000,duration=0,manaCost=420,icon="",familyFlags=8192}
t[14295] = {name="Volley",cast=0,cd=60000,categoryCD=0,recoveryCD=60000,duration=0,manaCost=490,icon="",familyFlags=8192}
t[22908] = {name="Volley",cast=0,cd=60000,categoryCD=0,recoveryCD=60000,duration=0,manaCost=0,icon="",familyFlags=8192}
t[36533] = {name="Web",cast=0,cd=60000,categoryCD=0,recoveryCD=60000,duration=0,manaCost=50,icon="Spell_Holy_Heal02",familyFlags=0}
t[26226] = {name="Widow Bite",cast=0,cd=4000,categoryCD=0,recoveryCD=4000,duration=60000,manaCost=40,icon="Ability_Hunter_AimedShot",familyFlags=0}
t[2974] = {name="Wing Clip",cast=0,cd=3000,categoryCD=0,recoveryCD=3000,duration=30000,manaCost=40,icon="INV_Food_Egg_02",familyFlags=64}
t[14267] = {name="Wing Clip",cast=0,cd=3000,categoryCD=0,recoveryCD=3000,duration=11000,manaCost=60,icon="INV_Food_Egg_02",familyFlags=64}
t[14268] = {name="Wing Clip",cast=0,cd=3000,categoryCD=0,recoveryCD=3000,duration=0,manaCost=80,icon="INV_Food_Egg_02",familyFlags=64}
t[27633] = {name="Wing Clip",cast=0,cd=3000,categoryCD=0,recoveryCD=3000,duration=0,manaCost=80,icon="INV_Food_Egg_02",familyFlags=64}
t[19386] = {name="Wyvern Sting",cast=0,cd=120000,categoryCD=0,recoveryCD=120000,duration=1200000,manaCost=115,icon="",familyFlags=65536}
t[24131] = {name="Wyvern Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=1200000,manaCost=0,icon="",familyFlags=65536}
t[24132] = {name="Wyvern Sting",cast=0,cd=120000,categoryCD=0,recoveryCD=120000,duration=0,manaCost=155,icon="",familyFlags=65536}
t[24133] = {name="Wyvern Sting",cast=0,cd=120000,categoryCD=0,recoveryCD=120000,duration=0,manaCost=205,icon="",familyFlags=65536}
t[24134] = {name="Wyvern Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=65536}
t[24135] = {name="Wyvern Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=65536}
t[24335] = {name="Wyvern Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=205,icon="",familyFlags=0}
t[24336] = {name="Wyvern Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=65536}
t[26180] = {name="Wyvern Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=0}
t[26233] = {name="Wyvern Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=65536}
t[26748] = {name="Wyvern Sting",cast=0,cd=0,categoryCD=0,recoveryCD=0,duration=0,manaCost=0,icon="",familyFlags=65536}
end
MTH_DS_HunterSpellsByName = {}
do
local t = MTH_DS_HunterSpellsByName
t["[Deprecated] Bestial Swiftness"] = MTH_DS_HunterSpellsDBC[19596]
t["[Deprecated] Bestial Wrath"] = MTH_DS_HunterSpellsDBC[19574]
t["[Deprecated] Hawk Eye"] = MTH_DS_HunterSpellsDBC[19500]
t["[Deprecated] Improved Arcane Shot"] = MTH_DS_HunterSpellsDBC[19457]
t["[Deprecated] Improved Aspect of the Monkey"] = MTH_DS_HunterSpellsDBC[24386]
t["[Deprecated] Improved Hunter's Mark"] = MTH_DS_HunterSpellsDBC[19424]
t["[Deprecated] Improved Scorpid Sting"] = MTH_DS_HunterSpellsDBC[19494]
t["[Deprecated] Improved Wing Clip"] = MTH_DS_HunterSpellsDBC[19234]
t["[Deprecated] Killer Instinct"] = MTH_DS_HunterSpellsDBC[19374]
t["[Deprecated] Pathfinding"] = MTH_DS_HunterSpellsDBC[19562]
t["[Deprecated] Scorpid Sting"] = MTH_DS_HunterSpellsDBC[14275]
t["[Deprecated] Thick Hide"] = MTH_DS_HunterSpellsDBC[19611]
t["[Deprecated] Trueshot Aura Percent Bonus"] = MTH_DS_HunterSpellsDBC[51520]
t["Adrenaline Rush"] = MTH_DS_HunterSpellsDBC[28752]
t["Aimed Shot"] = MTH_DS_HunterSpellsDBC[19434]
t["Arcane Infused"] = MTH_DS_HunterSpellsDBC[23721]
t["Arcane Shot"] = MTH_DS_HunterSpellsDBC[3044]
t["Arcane Shot Mana Reduction"] = MTH_DS_HunterSpellsDBC[23157]
t["Aspect of the Beast"] = MTH_DS_HunterSpellsDBC[13161]
t["Aspect of the Cheetah"] = MTH_DS_HunterSpellsDBC[5118]
t["Aspect of the Fox"] = MTH_DS_HunterSpellsDBC[45651]
t["Aspect of the Hawk"] = MTH_DS_HunterSpellsDBC[13165]
t["Aspect of the Monkey"] = MTH_DS_HunterSpellsDBC[13163]
t["Aspect of the Pack"] = MTH_DS_HunterSpellsDBC[13159]
t["Aspect of the Snake"] = MTH_DS_HunterSpellsDBC[45652]
t["Aspect of the Turtle"] = MTH_DS_HunterSpellsDBC[45649]
t["Aspect of the Wild"] = MTH_DS_HunterSpellsDBC[20043]
t["Aspect of the Wolf"] = MTH_DS_HunterSpellsDBC[45650]
t["Auto Shot"] = MTH_DS_HunterSpellsDBC[75]
t["Avoidance"] = MTH_DS_HunterSpellsDBC[46023]
t["Aynasha's Bow"] = MTH_DS_HunterSpellsDBC[19767]
t["Baited Shot"] = MTH_DS_HunterSpellsDBC[46321]
t["Barrage"] = MTH_DS_HunterSpellsDBC[19461]
t["Battle Standard"] = MTH_DS_HunterSpellsDBC[22996]
t["Beast Mastery"] = MTH_DS_HunterSpellsDBC[47355]
t["Beast of the Unseen Path"] = MTH_DS_HunterSpellsDBC[29233]
t["Bestial Discipline"] = MTH_DS_HunterSpellsDBC[19590]
t["Bestial Fury"] = MTH_DS_HunterSpellsDBC[19603]
t["Bestial Precision"] = MTH_DS_HunterSpellsDBC[51554]
t["Bestial Wrath"] = MTH_DS_HunterSpellsDBC[24395]
t["Bite"] = MTH_DS_HunterSpellsDBC[17253]
t["Bubble Barrier"] = MTH_DS_HunterSpellsDBC[36523]
t["Carve"] = MTH_DS_HunterSpellsDBC[51575]
t["Cheetah Sprint"] = MTH_DS_HunterSpellsDBC[24348]
t["Claw"] = MTH_DS_HunterSpellsDBC[3009]
t["Clever Traps"] = MTH_DS_HunterSpellsDBC[19239]
t["Command"] = MTH_DS_HunterSpellsDBC[20576]
t["Concussive Shot"] = MTH_DS_HunterSpellsDBC[5116]
t["Concussive Shot Cooldown Reduction"] = MTH_DS_HunterSpellsDBC[23158]
t["Coordinated Assault"] = MTH_DS_HunterSpellsDBC[49559]
t["Copy of Shoot"] = MTH_DS_HunterSpellsDBC[28317]
t["Counterattack"] = MTH_DS_HunterSpellsDBC[19306]
t["Death Roll"] = MTH_DS_HunterSpellsDBC[36548]
t["Demonic Transformation"] = MTH_DS_HunterSpellsDBC[24992]
t["Detect Weakness"] = MTH_DS_HunterSpellsDBC[23578]
t["Deterrence"] = MTH_DS_HunterSpellsDBC[19263]
t["Disengage"] = MTH_DS_HunterSpellsDBC[781]
t["Distracting Shot"] = MTH_DS_HunterSpellsDBC[14274]
t["Efficiency"] = MTH_DS_HunterSpellsDBC[19416]
t["Elusiveness"] = MTH_DS_HunterSpellsDBC[51552]
t["Endless Quiver"] = MTH_DS_HunterSpellsDBC[51517]
t["Endurance Training"] = MTH_DS_HunterSpellsDBC[19583]
t["Entrapment"] = MTH_DS_HunterSpellsDBC[19184]
t["Explosive Trap"] = MTH_DS_HunterSpellsDBC[13813]
t["Explosive Trap Effect"] = MTH_DS_HunterSpellsDBC[13812]
t["Extra Shot"] = MTH_DS_HunterSpellsDBC[51519]
t["Eyes of the Beast"] = MTH_DS_HunterSpellsDBC[1002]
t["Fang of the Crystal Spider"] = MTH_DS_HunterSpellsDBC[17331]
t["Faster Bleeds 5 (Hunter)"] = MTH_DS_HunterSpellsDBC[52402]
t["Feign Death"] = MTH_DS_HunterSpellsDBC[5384]
t["Ferocity"] = MTH_DS_HunterSpellsDBC[19598]
t["Fire Breath"] = MTH_DS_HunterSpellsDBC[46269]
t["Flame Spear"] = MTH_DS_HunterSpellsDBC[19781]
t["Flare"] = MTH_DS_HunterSpellsDBC[1543]
t["Freezing Trap"] = MTH_DS_HunterSpellsDBC[1499]
t["Freezing Trap (TEST)"] = MTH_DS_HunterSpellsDBC[21750]
t["Freezing Trap Effect"] = MTH_DS_HunterSpellsDBC[3355]
t["Frenzy"] = MTH_DS_HunterSpellsDBC[19621]
t["Frost Trap"] = MTH_DS_HunterSpellsDBC[13809]
t["Frost Trap Aura"] = MTH_DS_HunterSpellsDBC[13810]
t["Frost Trap Effect"] = MTH_DS_HunterSpellsDBC[14207]
t["Furious Howl"] = MTH_DS_HunterSpellsDBC[24597]
t["Grace"] = MTH_DS_HunterSpellsDBC[46296]
t["Haste"] = MTH_DS_HunterSpellsDBC[14824]
t["Hawk Eye"] = MTH_DS_HunterSpellsDBC[19498]
t["Hunter Giant Stalker"] = MTH_DS_HunterSpellsDBC[21942]
t["Hunter's Mark"] = MTH_DS_HunterSpellsDBC[1130]
t["Immolation Trap"] = MTH_DS_HunterSpellsDBC[13795]
t["Immolation Trap Effect"] = MTH_DS_HunterSpellsDBC[13797]
t["Impale"] = MTH_DS_HunterSpellsDBC[15860]
t["Improved Aspect of the Hawk"] = MTH_DS_HunterSpellsDBC[23559]
t["Improved Concussive Shot"] = MTH_DS_HunterSpellsDBC[19407]
t["Improved Explosive Trap"] = MTH_DS_HunterSpellsDBC[19378]
t["Improved Eyes of the Beast"] = MTH_DS_HunterSpellsDBC[19557]
t["Improved Feign Death"] = MTH_DS_HunterSpellsDBC[19286]
t["Improved Freezing Trap"] = MTH_DS_HunterSpellsDBC[19288]
t["Improved Hunter's Mark"] = MTH_DS_HunterSpellsDBC[19421]
t["Improved Immolation Trap"] = MTH_DS_HunterSpellsDBC[19246]
t["Improved Mend Pet"] = MTH_DS_HunterSpellsDBC[19572]
t["Improved Primal Aspects"] = MTH_DS_HunterSpellsDBC[19549]
t["Improved Revive Pet"] = MTH_DS_HunterSpellsDBC[19575]
t["Improved Scorpid Sting"] = MTH_DS_HunterSpellsDBC[19491]
t["Improved Serpent Sting"] = MTH_DS_HunterSpellsDBC[24467]
t["Improved Steady Shot"] = MTH_DS_HunterSpellsDBC[51515]
t["Improved Stings"] = MTH_DS_HunterSpellsDBC[19464]
t["Improved Swift Aspects"] = MTH_DS_HunterSpellsDBC[52603]
t["Improved Volley and Multishot"] = MTH_DS_HunterSpellsDBC[23566]
t["Improved Wing Clip"] = MTH_DS_HunterSpellsDBC[19228]
t["Increased Hunter Pet Damage"] = MTH_DS_HunterSpellsDBC[22854]
t["Increased Pet Damage +3%"] = MTH_DS_HunterSpellsDBC[27205]
t["Increased Pet Damage +4%"] = MTH_DS_HunterSpellsDBC[52413]
t["Kill Command"] = MTH_DS_HunterSpellsDBC[41827]
t["Killer Instinct"] = MTH_DS_HunterSpellsDBC[19162]
t["Lacerate"] = MTH_DS_HunterSpellsDBC[20907]
t["Lightning Breath"] = MTH_DS_HunterSpellsDBC[24844]
t["Lightning Reflexes"] = MTH_DS_HunterSpellsDBC[19168]
t["Lizard Bolt"] = MTH_DS_HunterSpellsDBC[46297]
t["Mend Pet"] = MTH_DS_HunterSpellsDBC[136]
t["Mongoose Bite"] = MTH_DS_HunterSpellsDBC[1495]
t["Mortal Shots"] = MTH_DS_HunterSpellsDBC[19485]
t["Multi-Shot"] = MTH_DS_HunterSpellsDBC[2643]
t["Multi-Shot Damage Increase"] = MTH_DS_HunterSpellsDBC[28539]
t["Multishot and Carve Cooldown"] = MTH_DS_HunterSpellsDBC[52602]
t["Not There"] = MTH_DS_HunterSpellsDBC[28761]
t["Packleader"] = MTH_DS_HunterSpellsDBC[36532]
t["Pathfinding"] = MTH_DS_HunterSpellsDBC[19559]
t["Pet Focus Regen Bonus"] = MTH_DS_HunterSpellsDBC[52685]
t["Piercing Shots"] = MTH_DS_HunterSpellsDBC[51512]
t["Pin"] = MTH_DS_HunterSpellsDBC[46292]
t["Planning Ahead"] = MTH_DS_HunterSpellsDBC[51576]
t["Planning Ahead Dummy"] = MTH_DS_HunterSpellsDBC[51578]
t["Poison Spit"] = MTH_DS_HunterSpellsDBC[46271]
t["Prowl"] = MTH_DS_HunterSpellsDBC[24450]
t["Quick Shots"] = MTH_DS_HunterSpellsDBC[51547]
t["Quick Strikes"] = MTH_DS_HunterSpellsDBC[51542]
t["Ranged Weapon Specialization"] = MTH_DS_HunterSpellsDBC[19511]
t["Rapid Fire"] = MTH_DS_HunterSpellsDBC[3045]
t["Raptor Strike"] = MTH_DS_HunterSpellsDBC[2973]
t["Readiness"] = MTH_DS_HunterSpellsDBC[23989]
t["Resourcefulness"] = MTH_DS_HunterSpellsDBC[51570]
t["Revive Pet"] = MTH_DS_HunterSpellsDBC[982]
t["Roar of Fortitude"] = MTH_DS_HunterSpellsDBC[36535]
t["Savage Rend"] = MTH_DS_HunterSpellsDBC[36536]
t["Savage Strikes"] = MTH_DS_HunterSpellsDBC[19159]
t["Scatter Shot"] = MTH_DS_HunterSpellsDBC[19503]
t["Scorpid Poison"] = MTH_DS_HunterSpellsDBC[24583]
t["Scorpid Stike"] = MTH_DS_HunterSpellsDBC[45659]
t["Scorpid Sting"] = MTH_DS_HunterSpellsDBC[3043]
t["Scorpid Sting Damage Reduction"] = MTH_DS_HunterSpellsDBC[51509]
t["Screech"] = MTH_DS_HunterSpellsDBC[24423]
t["Serpent Sting"] = MTH_DS_HunterSpellsDBC[1978]
t["Serpent Strike"] = MTH_DS_HunterSpellsDBC[45661]
t["Server Spell"] = MTH_DS_HunterSpellsDBC[29218]
t["Shell Shield"] = MTH_DS_HunterSpellsDBC[26064]
t["Shoot"] = MTH_DS_HunterSpellsDBC[6660]
t["Shoot Bow"] = MTH_DS_HunterSpellsDBC[2480]
t["Shoot Crossbow"] = MTH_DS_HunterSpellsDBC[7919]
t["Shoot Gun"] = MTH_DS_HunterSpellsDBC[7918]
t["Shoot Silithus Rifleman Long Range"] = MTH_DS_HunterSpellsDBC[25200]
t["Shoot Tauren Rifleman"] = MTH_DS_HunterSpellsDBC[26282]
t["Slime Shot"] = MTH_DS_HunterSpellsDBC[28318]
t["Spell - Reuse 19501"] = MTH_DS_HunterSpellsDBC[19501]
t["Spit"] = MTH_DS_HunterSpellsDBC[27919]
t["Stalker's Ally"] = MTH_DS_HunterSpellsDBC[28758]
t["Steady Shot"] = MTH_DS_HunterSpellsDBC[3035]
t["Steady Shot and Raptor Strike Crit Bonus"] = MTH_DS_HunterSpellsDBC[52684]
t["Stinging Nettle"] = MTH_DS_HunterSpellsDBC[51579]
t["Strider Presence"] = MTH_DS_HunterSpellsDBC[36531]
t["Strike Together"] = MTH_DS_HunterSpellsDBC[49557]
t["Striker's Arcane Shot Bonus"] = MTH_DS_HunterSpellsDBC[26173]
t["Striker's Rapid Fire Bonus"] = MTH_DS_HunterSpellsDBC[26174]
t["Superior Aspects"] = MTH_DS_HunterSpellsDBC[24416]
t["Superior Strikes"] = MTH_DS_HunterSpellsDBC[24269]
t["Surefooted"] = MTH_DS_HunterSpellsDBC[19290]
t["Survivalist"] = MTH_DS_HunterSpellsDBC[19255]
t["Swift Aspects"] = MTH_DS_HunterSpellsDBC[19552]
t["Swiftshot"] = MTH_DS_HunterSpellsDBC[19454]
t["Swipe"] = MTH_DS_HunterSpellsDBC[46287]
t["Tame Adult Plainstrider"] = MTH_DS_HunterSpellsDBC[19678]
t["Tame Armored Scorpid"] = MTH_DS_HunterSpellsDBC[19683]
t["Tame Ashfeather Swooper"] = MTH_DS_HunterSpellsDBC[46705]
t["Tame Blackvenom Scorpid"] = MTH_DS_HunterSpellsDBC[46701]
t["Tame Decrepit Darkhound"] = MTH_DS_HunterSpellsDBC[50904]
t["Tame Decrepit Darkhound."] = MTH_DS_HunterSpellsDBC[44007]
t["Tame Dire Mottled Boar"] = MTH_DS_HunterSpellsDBC[19681]
t["Tame Dire Mottled Boar."] = MTH_DS_HunterSpellsDBC[44013]
t["Tame Elder Crimson Lynx"] = MTH_DS_HunterSpellsDBC[46091]
t["Tame Greater Dusk Bat"] = MTH_DS_HunterSpellsDBC[50905]
t["Tame Greater Duskbat"] = MTH_DS_HunterSpellsDBC[44009]
t["Tame Ice Claw Bear"] = MTH_DS_HunterSpellsDBC[19597]
t["Tame Ivory Hawkstrider"] = MTH_DS_HunterSpellsDBC[46093]
t["Tame Large Crag Boar"] = MTH_DS_HunterSpellsDBC[19677]
t["Tame Large Crag Boar."] = MTH_DS_HunterSpellsDBC[44019]
t["Tame Lavender Mana Wyrm"] = MTH_DS_HunterSpellsDBC[46095]
t["Tame Muckreef Crawler"] = MTH_DS_HunterSpellsDBC[46703]
t["Tame Nightsaber Stalker"] = MTH_DS_HunterSpellsDBC[19685]
t["Tame Prairie Stalker"] = MTH_DS_HunterSpellsDBC[19679]
t["Tame Prowler"] = MTH_DS_HunterSpellsDBC[44003]
t["Tame Snow Leopard"] = MTH_DS_HunterSpellsDBC[19676]
t["Tame Stonetusk Boar"] = MTH_DS_HunterSpellsDBC[44001]
t["Tame Strigid Screecher"] = MTH_DS_HunterSpellsDBC[19686]
t["Tame Surf Crawler"] = MTH_DS_HunterSpellsDBC[19682]
t["Tame Swoop"] = MTH_DS_HunterSpellsDBC[19680]
t["Tame Tirisfal Plagued Bear"] = MTH_DS_HunterSpellsDBC[44011]
t["Tame Webwood Lurker"] = MTH_DS_HunterSpellsDBC[19684]
t["Tame Young Forest Bear"] = MTH_DS_HunterSpellsDBC[44005]
t["Tamed Pet Passive (DND)"] = MTH_DS_HunterSpellsDBC[8875]
t["Thick Hide"] = MTH_DS_HunterSpellsDBC[19609]
t["Throw"] = MTH_DS_HunterSpellsDBC[10277]
t["Thunderstomp"] = MTH_DS_HunterSpellsDBC[26090]
t["Tranquilizing Shot"] = MTH_DS_HunterSpellsDBC[19801]
t["Trap Mastery"] = MTH_DS_HunterSpellsDBC[19376]
t["Trueshot Aura"] = MTH_DS_HunterSpellsDBC[19506]
t["Unleashed Fury"] = MTH_DS_HunterSpellsDBC[19616]
t["Unseen Path Pet Bonus"] = MTH_DS_HunterSpellsDBC[26176]
t["Untamed Trapper"] = MTH_DS_HunterSpellsDBC[51586]
t["Vicious Strikes"] = MTH_DS_HunterSpellsDBC[51584]
t["Viper Sting"] = MTH_DS_HunterSpellsDBC[3034]
t["Viper Strike"] = MTH_DS_HunterSpellsDBC[45660]
t["Volley"] = MTH_DS_HunterSpellsDBC[1510]
t["Web"] = MTH_DS_HunterSpellsDBC[36533]
t["Widow Bite"] = MTH_DS_HunterSpellsDBC[26226]
t["Wing Clip"] = MTH_DS_HunterSpellsDBC[2974]
t["Wyvern Sting"] = MTH_DS_HunterSpellsDBC[19386]
end
+224
View File
@@ -0,0 +1,224 @@
-- ds-hunter-spells.lua
-- Hunter spell data for TWoW 1.18.1 "Nightmares of Ursol"
-- Used by: ExpAmmo cycle tracker, HunterBook (future spell reference tab)
--
-- TODO markers:
-- SPELL_ID : exact spell ID not yet extracted from Spell.dbc (needs MPQ)
-- ICON : icon texture not yet confirmed from game files
-- VERIFY : value observed in patch notes but subject to change on PTR/live
-- PENDING : mechanic not yet verified against live server
if not MTH_DS then MTH_DS = {} end
-- ============================================================
-- BASELINE HUNTER SPELLS (available to all specs from 1.18.1)
-- ============================================================
MTH_DS_HunterSpells = {
["baseline"] = {
{
["name"] = "Steady Shot",
["addedIn"] = "1.18.1",
["note"] = "Moved from Marksmanship talent tree to baseline at level 20.",
["castTime"] = "1.5s", -- TODO VERIFY
["cooldown"] = "n/a",
["school"] = "Physical",
["icon"] = "Ability_Hunter_SteadyShot", -- TODO ICON confirm
},
{
["name"] = "Trueshot Aura",
["addedIn"] = "1.18.1",
["note"] = "Moved from Marksmanship capstone to baseline. All hunters now get this.",
["castTime"] = "Instant",
["cooldown"] = "n/a",
["school"] = "Physical",
["icon"] = "Ability_Trueshot", -- TODO ICON confirm
},
{
["name"] = "Aspect of the Viper",
["addedIn"] = "1.18.1",
["note"] = "New baseline aspect learned at level 56. Regenerates mana while dealing reduced damage.",
["castTime"] = "Instant",
["cooldown"] = "n/a",
["school"] = "Nature",
["icon"] = "Spell_Nature_Poison", -- TODO ICON confirm
},
{
["name"] = "Volley",
["addedIn"] = "1.18.1",
["note"] = "Changed from channelled to a 3-second cast AoE. Now a proper cast-bar spell.",
["castTime"] = "3s", -- TODO VERIFY
["cooldown"] = "n/a",
["school"] = "Physical",
["icon"] = "Ability_Whirlwind", -- TODO ICON confirm
},
},
-- ============================================================
-- MARKSMANSHIP TALENTS (1.18.1 changes)
-- ============================================================
["marksmanship"] = {
{
["name"] = "Aimed Shot",
["addedIn"] = "1.18.1",
["note"] = "Now has a visible 2s cast bar. Triggers ExpAmmo cycle start (resets to FIRE state).",
["castTime"] = "2s",
["cooldown"] = "26s", -- TODO VERIFY vs Spell.dbc
["school"] = "Physical",
["icon"] = "Inv_Spear_07", -- TODO ICON confirm
["expAmmoTrigger"] = true, -- resets ExpAmmo cycle to state 1 (FIRE)
},
{
["name"] = "Lock and Load",
["addedIn"] = "1.18.1",
["talentRow"] = 7, -- MM capstone row
["note"] = "10s proc buff. Triggered by Aimed Shot crit or trap activation (TODO VERIFY exact condition).",
["castTime"] = "Instant",
["cooldown"] = "n/a",
["duration"] = "10s", -- TODO VERIFY
["school"] = "Physical",
["type"] = "buff_proc",
["icon"] = "Ability_Hunter_LockAndLoad", -- TODO ICON confirm
},
{
["name"] = "Rapid Fire",
["note"] = "15% haste, 15s duration, 5min CD. Unchanged in 1.18.1 baseline values.",
["castTime"] = "Instant",
["cooldown"] = "5min",
["duration"] = "15s",
["school"] = "Physical",
["type"] = "buff",
["icon"] = "Ability_Hunter_RapidKilling",
},
},
-- ============================================================
-- BEAST MASTERY TALENTS (1.18.1 changes)
-- ============================================================
["beastmastery"] = {
{
["name"] = "Bestial Wrath",
["note"] = "Returned to BM tree. 18s buff, 90s CD (1.5min). Pet immune to fear/CC during.",
["castTime"] = "Instant",
["cooldown"] = "90s",
["duration"] = "18s", -- TODO VERIFY
["school"] = "Physical",
["type"] = "buff",
["icon"] = "Ability_Druid_Ferociousbite", -- TODO ICON confirm
},
{
["name"] = "Kill Command",
["addedIn"] = "1.18.1",
["talentRow"] = 7, -- BM capstone row
["note"] = "8s CD, triggered on crit. Commands pet to inflict bonus damage on next hit.",
["castTime"] = "Instant",
["cooldown"] = "8s",
["school"] = "Physical",
["icon"] = "Ability_Hunter_KillCommand", -- TODO ICON confirm
},
{
["name"] = "Scent of Blood",
["addedIn"] = "1.18.1",
["talentRow"] = 5,
["note"] = "8s pet rage proc buff. Triggers when Bestial Wrath is active (TODO VERIFY exact condition).",
["castTime"] = "Instant (proc)",
["cooldown"] = "n/a",
["duration"] = "8s", -- TODO VERIFY
["school"] = "Physical",
["type"] = "buff_proc",
["icon"] = "Ability_Warrior_BloodFrenzy", -- TODO ICON confirm
},
{
["name"] = "Baited Shot",
["removedIn"] = "1.18.1",
["note"] = "REMOVED. Replaced by Kill Command as the BM capstone. Any saved data for this spell can be cleared.",
["deprecated"] = true,
},
},
-- ============================================================
-- SURVIVAL TALENTS (1.18.1 changes)
-- ============================================================
["survival"] = {
{
["name"] = "Alone Against the World",
["addedIn"] = "1.18.1",
["talentRow"] = 2,
["note"] = "New 2-point talent. Bonus to pet/self when no group members nearby (TODO VERIFY exact bonus values).",
["type"] = "passive",
["icon"] = "Ability_Hunter_AloneAgainstTheWorld", -- TODO ICON confirm
},
{
["name"] = "Lacerate",
["addedIn"] = "1.18.1",
["note"] = "40% Attack Power bleed, +15% from all bleed sides. (TODO VERIFY: rank values from Spell.dbc).",
["castTime"] = "Instant",
["school"] = "Physical",
["type"] = "dot",
["icon"] = "Ability_Hunter_Lacerate", -- TODO ICON confirm
},
},
-- ============================================================
-- EXPERIMENTAL AMMUNITION (new 1.18.1 mechanic)
-- States cycle: FIRE -> ARCANE -> NATURE -> (loop)
-- Aimed Shot resets cycle to FIRE each time it is fired.
-- ============================================================
["expAmmoStates"] = {
{
["state"] = 1,
["label"] = "Fire Ammo",
["school"] = "Fire",
["duration"] = "60s", -- TODO VERIFY from server
["consumeSpell"] = "Multi-Shot", -- TODO VERIFY spell that consumes this state
["icon"] = "Spell_Fire_FlameBolt", -- TODO ICON confirm
["buffName"] = nil, -- TODO: exact buff name from Spell.dbc
},
{
["state"] = 2,
["label"] = "Arcane Ammo",
["school"] = "Arcane",
["duration"] = "60s", -- TODO VERIFY
["consumeSpell"] = "Arcane Shot", -- TODO VERIFY
["icon"] = "Spell_Arcane_ArcaneMissiles", -- TODO ICON confirm
["buffName"] = nil, -- TODO: exact buff name from Spell.dbc
},
{
["state"] = 3,
["label"] = "Nature Ammo",
["school"] = "Nature",
["duration"] = "60s", -- TODO VERIFY
["consumeSpell"] = "Serpent Sting", -- TODO VERIFY
["icon"] = "Spell_Nature_NatureBolt", -- TODO ICON confirm
["buffName"] = nil, -- TODO: exact buff name from Spell.dbc
},
},
}
+5
View File
@@ -137,6 +137,11 @@ local MTH_DS_AtlasSources = {
[9426] = {["boss"] = true, },
[9456] = {["boss"] = true, },
[9487] = {["boss"] = true, },
[42198] = {["crafted"] = true, },
[42199] = {["crafted"] = true, },
[42200] = {["crafted"] = true, },
[42201] = {["crafted"] = true, },
[42202] = {["crafted"] = true, },
}
for itemId, sourceMap in pairs(MTH_DS_AtlasSources) do
+26
View File
@@ -6308,6 +6308,13 @@ MTH_DS_ItemOrigins = {
["level"] = 25,
["classification"] = 0,
},
{
["id"] = 62906,
["name"] = "Elendon Truebough",
["tag"] = "Weapons",
["level"] = 44,
["classification"] = 0,
},
},
},
},
@@ -11066,6 +11073,12 @@ MTH_DS_ItemOrigins = {
["level"] = 40,
["classification"] = 0,
},
{
["id"] = 62843,
["name"] = "Ornala",
["level"] = 53,
["classification"] = 0,
},
},
},
},
@@ -11747,6 +11760,19 @@ MTH_DS_ItemOrigins = {
["level"] = 25,
["classification"] = 0,
},
{
["id"] = 62906,
["name"] = "Elendon Truebough",
["tag"] = "Weapons",
["level"] = 44,
["classification"] = 0,
},
{
["id"] = 62843,
["name"] = "Ornala",
["level"] = 53,
["classification"] = 0,
},
},
},
},
+45
View File
@@ -1121,6 +1121,51 @@ MTH_DS_AmmoItems = {
[13219] = 0,
},
},
[42198] = {
["name"] = "Bright Wood Arrows",
["level"] = 35,
["reqlevel"] = 30,
["icon"] = "INV_Ammo_Arrow_02",
["subtype"] = "arrow",
["dps"] = 10.5,
["crafted"] = true,
},
[42199] = {
["name"] = "Shade Wood Arrows",
["level"] = 45,
["reqlevel"] = 40,
["icon"] = "INV_Ammo_Arrow_02",
["subtype"] = "arrow",
["dps"] = 14.5,
["crafted"] = true,
},
[42200] = {
["name"] = "Smooth Ironfeather Arrows",
["level"] = 55,
["reqlevel"] = 50,
["icon"] = "INV_Ammo_Arrow_02",
["subtype"] = "arrow",
["dps"] = 17.5,
["crafted"] = true,
},
[42201] = {
["name"] = "Starfeather Arrows",
["level"] = 60,
["reqlevel"] = 55,
["icon"] = "INV_Ammo_Arrow_02",
["subtype"] = "arrow",
["dps"] = 19,
["crafted"] = true,
},
[42202] = {
["name"] = "Enchanted Thorium Shells",
["level"] = 60,
["reqlevel"] = 55,
["icon"] = "INV_Ammo_Bullet_03",
["subtype"] = "bullet",
["dps"] = 19,
["crafted"] = true,
},
}
MTH_DS_Items = MTH_DS_AmmoItems
+125 -117
View File
@@ -2,120 +2,128 @@ if not MTH_DS then MTH_DS = {} end
MTH_DS_MinimapSizes = {
[0] = { 0, 0 },
[1] = { 4925, 3283.34 },
[3] = { 2487.5, 1658.34 },
[4] = { 3350, 2233.3 },
[8] = { 2293.75, 1529.17 },
[10] = { 2700, 1800.03 },
[11] = { 4135.42, 2756.25 },
[12] = { 3470.84, 2314.62 },
[14] = { 5287.5, 3525 },
[15] = { 5250, 3500 },
[16] = { 5070.84, 3381.25 },
[17] = { 10133.34, 6756.25 },
[25] = { 711.56, 468.68 },
[28] = { 4300, 2866.67 },
[33] = { 6381.25, 4254.1 },
[36] = { 2800, 1866.67 },
[38] = { 2758.33, 1839.58 },
[40] = { 3500, 2333.3 },
[41] = { 2500, 1666.63 },
[44] = { 2170.84, 1447.9 },
[45] = { 3600, 2400 },
[46] = { 2929.16, 1952.08 },
[47] = { 3850, 2566.67 },
[51] = { 2231.25, 1487.5 },
[85] = { 4518.75, 3012.5 },
[130] = { 4200, 2800 },
[139] = { 3870.83, 2581.25 },
[141] = { 5091.66, 3393.7 },
[148] = { 6550, 4366.66 },
[209] = { 381, 254 },
[215] = { 5137.5, 3425 },
[267] = { 3200, 2133.33 },
[331] = { 5766.67, 3843.75 },
[357] = { 6950, 4633.33 },
[361] = { 5750, 3833.33 },
[400] = { 4400, 2933.33 },
[405] = { 4495.83, 2997.91 },
[406] = { 6018, 4010 },
[408] = { 3092.1, 2047 },
[409] = { 2901.45, 1915.9 },
[440] = { 6900, 4600 },
[490] = { 3700, 2466.66 },
[491] = { 736.45, 490.96 },
[493] = { 2308.33, 1539.59 },
[616] = { 3206, 2142 },
[618] = { 7100, 4733.33 },
[717] = { 378.15, 252.1 },
[718] = { 572.78, 381.85 },
[719] = { 1221.87, 806.42 },
[721] = { 769.67, 513.11 },
[722] = { 881, 589 },
[796] = { 203.66, 135.04 },
[876] = { 828, 541 },
[1176] = { 1383.33, 922.91 },
[1337] = { 893.67, 595.78 },
[1377] = { 3483.33, 2322.92 },
[1477] = { 695.03, 463.35 },
[1497] = { 959.37, 640.11 },
[1519] = { 1737.5, 1158.34 },
[1537] = { 790.63, 527.61 },
[1581] = { 449.89, 300 },
[1583] = { 886.84, 591.23 },
[1584] = { 1985, 1268 },
[1637] = { 1402.61, 935.42 },
[1638] = { 1043.75, 695.83 },
[1657] = { 1058.33, 705.71 },
[1941] = { 1348.24, 888.09 },
[1977] = { 2120.83, 1414.6 },
[2017] = { 1185.35, 789.86 },
[2040] = { 1468, 976 },
[2057] = { 320.05, 213.37 },
[2100] = { 2112.09, 1410.89 },
[2159] = { 483.11, 322.08 },
[2257] = { 312, 208 },
[2366] = { 1085.86, 726.61 },
[2437] = { 738.86, 492.57 },
[2557] = { 1324, 869 },
[2597] = { 4237.5, 2825 },
[2677] = { 499.43, 332.95 },
[2717] = { 1495, 983 },
[3277] = { 1145.84, 764.58 },
[3358] = { 1756.25, 1170.83 },
[3428] = { 977.56, 651.7 },
[3429] = { 2512.5, 1675 },
[3456] = { 1991.69, 1318.42 },
[3457] = { 823, 549 },
[3478] = { 4139.02, 2946 },
[4012] = { 3159, 2108 },
[5023] = { 988.63, 1393.17 },
[5024] = { 1608, 1075 },
[5053] = { 1007.7, 671.8 },
[5077] = { 2643.21, 1751.16 },
[5086] = { 546.75, 391.9 },
[5087] = { 354.5, 234.74 },
[5097] = { 1273.1, 853.72 },
[5103] = { 752.12, 510.33 },
[5121] = { 3227, 2187 },
[5130] = { 1432, 977 },
[5135] = { 320.19, 213.46 },
[5136] = { 619.98, 413.32 },
[5138] = { 656.59, 434.97 },
[5144] = { 309, 208 },
[5147] = { 2777.54, 1851.69 },
[5148] = { 652.1, 439.67 },
[5153] = { 612.69, 408.46 },
[5163] = { 703.3, 468.87 },
[5179] = { 3666, 2442 },
[5204] = { 1271.99, 845.48 },
[5208] = { 1250.18, 837.44 },
[5225] = { 3082, 2061 },
[5536] = { 2472, 1665 },
[5557] = { 2800, 1868 },
[5561] = { 3098, 2068 },
[5581] = { 3241, 2157 },
[5601] = { 1634, 1073 },
[5602] = { 5387, 3584 },
[5628] = { 1980, 1350 },
}
[9] = { 5137.50, 3425.00 }, -- Mulgore
[11] = { 2487.50, 1658.34 }, -- Barrens
[15] = { 2170.84, 1447.90 }, -- Alterac
[19] = { 5287.50, 3525.00 }, -- BlastedLands
[20] = { 4518.75, 3012.50 }, -- Tirisfal
[21] = { 4200.00, 2800.00 }, -- Silverpine
[22] = { 2231.25, 1487.50 }, -- WesternPlaguelands
[23] = { 3870.83, 2581.25 }, -- EasternPlaguelands
[24] = { 3200.00, 2133.33 }, -- Hilsbrad
[26] = { 3850.00, 2566.67 }, -- Hinterlands
[27] = { 4925.00, 3283.34 }, -- DunMorogh
[29] = { 2929.16, 1952.08 }, -- BurningSteppes
[30] = { 3470.84, 2314.62 }, -- Elwynn
[32] = { 5091.66, 3393.70 }, -- DeadwindPass
[34] = { 2700.00, 1800.03 }, -- Duskwood
[35] = { 2293.75, 1529.17 }, -- LochModan
[37] = { 6381.25, 4254.10 }, -- Stranglethorn
[39] = { 4135.42, 2756.25 }, -- Westfall
[40] = { 10133.34, 6756.25 }, -- Wetlands
[41] = { 5250.00, 3500.00 }, -- Teldrassil
[42] = { 6550.00, 4366.66 }, -- Darkshore
[43] = { 5766.67, 3843.75 }, -- Ashenvale
[61] = { 4400.00, 2933.33 }, -- ThousandNeedles
[81] = { 6018.00, 4010.00 }, -- StonetalonMountains
[101] = { 4495.83, 2997.91 }, -- Desolace
[121] = { 6950.00, 4633.33 }, -- Feralas
[141] = { 2800.00, 1866.67 }, -- Dustwallow
[161] = { 6900.00, 4600.00 }, -- Tanaris
[181] = { 3600.00, 2400.00 }, -- Azshara
[182] = { 5750.00, 3833.33 }, -- Felwood
[201] = { 3700.00, 2466.66 }, -- UngoroCrater
[241] = { 2308.33, 1539.59 }, -- Moonglade
[261] = { 3483.33, 2322.92 }, -- Silithus
[281] = { 7100.00, 4733.33 }, -- Winterspring
[301] = { 1737.50, 1158.34 }, -- Stormwind
[321] = { 1402.61, 935.42 }, -- Orgrimmar
[341] = { 790.63, 527.61 }, -- Ironforge
[362] = { 1043.75, 695.83 }, -- ThunderBluff
[381] = { 1058.33, 705.71 }, -- Darnassus
[382] = { 959.37, 640.11 }, -- Undercity
[401] = { 4237.50, 2825.00 }, -- AlteracValley
[443] = { 1145.84, 764.58 }, -- WarsongGulch
[461] = { 1756.25, 1170.83 }, -- ArathiBasin
[500] = { 828.00, 541.00 }, -- pfQ876
[501] = { 3206.00, 2142.00 }, -- pfQ616
[502] = { 3159.00, 2108.00 }, -- pfQ4012
[503] = { 988.63, 1393.17 }, -- pfQ5023
[504] = { 2901.45, 1915.90 }, -- pfQ409
[505] = { 3092.10, 2047.00 }, -- pfQ408
[507] = { 3227.00, 2187.00 }, -- pfQ5121
[509] = { 1468.00, 976.00 }, -- pfQ2040
[510] = { 3666.00, 2442.00 }, -- pfQ5179
[511] = { 1608.00, 1075.00 }, -- pfQ5024
[512] = { 2472.00, 1665.00 }, -- pfQ5536
[513] = { 3082.00, 2061.00 }, -- pfQ5225
[514] = { 449.89, 300.00 }, -- pfQ1581
[516] = { 572.78, 381.85 }, -- pfQ718
[517] = { 2112.09, 1410.89 }, -- pfQ2100
[518] = { 769.67, 513.11 }, -- pfQ721
[519] = { 711.56, 468.68 }, -- pfQ25
[520] = { 203.66, 135.04 }, -- pfQ796
[521] = { 893.67, 595.78 }, -- pfQ1337
[522] = { 4139.02, 2946.00 }, -- pfQ3478
[523] = { 1348.24, 888.09 }, -- pfQ1941
[601] = { 1432.00, 977.00 }, -- pfQ5130
[603] = { 738.86, 492.57 }, -- pfQ2437
[605] = { 1383.33, 922.91 }, -- pfQ1176
[607] = { 695.03, 463.35 }, -- pfQ1477
[609] = { 1221.87, 806.42 }, -- pfQ719
[611] = { 378.15, 252.10 }, -- pfQ717
[617] = { 1495.00, 983.00 }, -- pfQ2717
[619] = { 2120.83, 1414.60 }, -- pfQ1977
[623] = { 1985.00, 1268.00 }, -- pfQ1584
[625] = { 2512.50, 1675.00 }, -- pfQ3429
[627] = { 483.11, 322.08 }, -- pfQ2159
[629] = { 886.84, 591.23 }, -- pfQ1583
[635] = { 499.43, 332.95 }, -- pfQ2677
[637] = { 656.59, 434.97 }, -- pfQ5138
[639] = { 881.00, 589.00 }, -- pfQ722
[641] = { 736.45, 490.96 }, -- pfQ491
[643] = { 619.98, 413.32 }, -- pfQ5136
[644] = { 320.19, 213.46 }, -- pfQ5135
[645] = { 612.69, 408.46 }, -- pfQ5153
[646] = { 703.30, 468.87 }, -- pfQ5163
[648] = { 320.05, 213.37 }, -- pfQ2057
[650] = { 381.00, 254.00 }, -- pfQ209
[652] = { 1185.35, 789.86 }, -- pfQ2017
[654] = { 977.56, 651.70 }, -- pfQ3428
[655] = { 2777.54, 1851.69 }, -- pfQ5147
[657] = { 619.00, 410.00 }, -- pfQ5723
[659] = { 312.00, 208.00 }, -- pfQ2257
[662] = { 1271.99, 845.48 }, -- pfQ5204
[663] = { 1085.86, 726.61 }, -- pfQ2366
[665] = { 1250.18, 837.44 }, -- pfQ5208
[667] = { 1991.69, 1318.42 }, -- pfQ3456
[668] = { 652.10, 439.67 }, -- pfQ5148
[670] = { 2643.21, 1751.16 }, -- pfQ5077
[672] = { 752.12, 510.33 }, -- pfQ5103
[674] = { 546.75, 391.90 }, -- pfQ5086
[676] = { 354.50, 234.74 }, -- pfQ5087
[678] = { 1273.10, 853.72 }, -- pfQ5097
[680] = { 1007.70, 671.80 }, -- pfQ5053
[682] = { 823.00, 549.00 }, -- pfQ3457
[683] = { 2800.00, 1868.00 }, -- pfQ5557
[684] = { 5387.00, 3584.00 }, -- pfQ5602
[685] = { 3098.00, 2068.00 }, -- pfQ5561
[686] = { 3241.00, 2157.00 }, -- pfQ5581
[689] = { 1324.00, 869.00 }, -- pfQ2557
[691] = { 1634.00, 1073.00 }, -- pfQ5601
[693] = { 1980.00, 1350.00 }, -- pfQ5628
[698] = { 1234.00, 829.00 }, -- pfQ5641
[699] = { 7856.00, 5241.00 }, -- pfQ5642
[700] = { 861.00, 607.00 }, -- pfQ1769
[701] = { 1347.00, 971.00 }, -- pfQ5640
[702] = { 1047.00, 694.00 }, -- pfQ5722
[704] = { 1011.00, 653.00 }, -- pfQ5734
[705] = { 440.00, 279.00 }, -- pfQ5731
[613] = { 1125.00, 740.00 },
[615] = { 893.67, 595.78 },
[621] = { 1919.00, 1250.00 },
[631] = { 1170.00, 785.00 },
[633] = { 2112.09, 1410.89 },
[696] = { 1425.00, 962.00 },
[5144] = { 309.00, 208.00 },
}
+1 -24
View File
@@ -1,7 +1,7 @@
-- MetaHunt: Pet spell DBC acquire-method overlay (learnMethod, minRank, nextSpellId)
-- AUTO-GENERATED by .tools — do not edit by hand.
-- Source DBC(s): SkillLineAbility.dbc, SkillLine.dbc
-- Generated: 2026-03-17 07:31 UTC
-- Generated: 2026-03-20 13:57 UTC
-- This file patches MTH_DS_PetSpells.allSpells entries with DBC-authoritative
-- learnMethod, minRank, and nextSpellId values.
@@ -121,32 +121,9 @@ local _acquire = {
[26190] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[26202] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[28343] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36554] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36555] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36556] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36557] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36558] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36559] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36560] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36561] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36563] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36564] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36565] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36566] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36567] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36568] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36569] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36570] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36571] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36572] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36573] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[36574] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[46023] = { learnMethod="trainer", minRank=0, nextSpellId=0, skillLineId=261 },
[46276] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[46303] = { learnMethod="trainer", minRank=0, nextSpellId=0, skillLineId=261 },
[46304] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[46307] = { learnMethod="trainer", minRank=0, nextSpellId=0, skillLineId=261 },
[46310] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[51154] = { learnMethod="trainer", minRank=0, nextSpellId=0, skillLineId=261 },
[51155] = { learnMethod="trainer", minRank=0, nextSpellId=0, skillLineId=261 },
[51157] = { learnMethod="trainer", minRank=0, nextSpellId=0, skillLineId=261 },
+45 -7
View File
@@ -25,6 +25,7 @@ MTH_DS_PetSpells = {
"Strider Presence",
"Thunderstomp",
"Web",
"Pollen Burst",
},
["allSpells"] = {
{
@@ -1804,15 +1805,30 @@ MTH_DS_PetSpells = {
"(6) Apply Aura #26: Root",
},
["icon"] = "Ability_Ensnare",
["id"] = 4167,
["id"] = 36533,
["name"] = "Web",
["range"] = "20 yards (Short Range)",
["rank"] = "",
["rankNumber"] = 0,
["school"] = "Physical",
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=4167",
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=36533",
["trainLevel"] = 22,
},
{
["ability"] = "Pollen Burst",
["castTime"] = "Instant",
["cooldown"] = "30 seconds",
["cost"] = "40 Focus",
["description"] = "Heal party members within 30 yards for 308 to 338 and reduce the attack speed of targets within 10 yards by 20% for 8 sec.",
["icon"] = "pollen_burst_2",
["id"] = 42051,
["name"] = "Pollen Burst",
["rank"] = "",
["rankNumber"] = 0,
["school"] = "Nature",
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=42051",
["trainLevel"] = 1,
},
},
["byAbility"] = {
["Bite"] = {
@@ -3744,17 +3760,39 @@ MTH_DS_PetSpells = {
"(6) Apply Aura #26: Root",
},
["icon"] = "Ability_Ensnare",
["id"] = 4167,
["id"] = 36533,
["name"] = "Web",
["range"] = "20 yards (Short Range)",
["rank"] = "",
["rankNumber"] = 0,
["school"] = "Physical",
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=4167",
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=36533",
["trainLevel"] = 22,
},
},
},
["Pollen Burst"] = {
["ability"] = "Pollen Burst",
["searchUrl"] = "https://database.turtlecraft.gg/?search=Pollen+Burst",
["spellCount"] = 1,
["spells"] = {
{
["ability"] = "Pollen Burst",
["castTime"] = "Instant",
["cooldown"] = "30 seconds",
["cost"] = "40 Focus",
["description"] = "Heal party members within 30 yards for 308 to 338 and reduce the attack speed of targets within 10 yards by 20% for 8 sec.",
["icon"] = "pollen_burst_2",
["id"] = 42051,
["name"] = "Pollen Burst",
["rank"] = "",
["rankNumber"] = 0,
["school"] = "Nature",
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=42051",
["trainLevel"] = 1,
},
},
},
},
["cleanedBy"] = "post-process quality rules v2 hard-gate",
["droppedDuplicates"] = {
@@ -4293,14 +4331,14 @@ MTH_DS_PetSpells = {
{
["ability"] = "Web",
["droppedId"] = 12023,
["keptId"] = 4167,
["keptId"] = 36533,
["mode"] = "lower-score",
["rankNumber"] = 0,
},
{
["ability"] = "Web",
["droppedId"] = 36533,
["keptId"] = 4167,
["droppedId"] = 4167,
["keptId"] = 36533,
["mode"] = "lower-score",
["rankNumber"] = 0,
},
+8 -4
View File
@@ -1,7 +1,7 @@
-- MetaHunt: Stable slot prices
-- AUTO-GENERATED by .tools — do not edit by hand.
-- Source DBC(s): StableSlotPrices.dbc
-- Generated: 2026-03-17 07:31 UTC
-- Generated: 2026-03-20 13:57 UTC
if not MTH_DS then MTH_DS = {} end
@@ -12,6 +12,7 @@ MTH_DS_StableSlotPrices = {
["cost_silver"] = 5,
["cost_copper_remainder"] = 0,
["display"] = "0g 5s 0c",
["acquireMethod"] = "gold",
},
[2] = {
["cost_copper"] = 50000,
@@ -19,6 +20,7 @@ MTH_DS_StableSlotPrices = {
["cost_silver"] = 0,
["cost_copper_remainder"] = 0,
["display"] = "5g 0s 0c",
["acquireMethod"] = "gold",
},
[3] = {
["cost_copper"] = 2500000,
@@ -26,12 +28,14 @@ MTH_DS_StableSlotPrices = {
["cost_silver"] = 0,
["cost_copper_remainder"] = 0,
["display"] = "250g 0s 0c",
["acquireMethod"] = "gold",
},
[4] = {
["cost_copper"] = 1,
["cost_copper"] = 0,
["cost_gold"] = 0,
["cost_silver"] = 0,
["cost_copper_remainder"] = 1,
["display"] = "0g 0s 1c",
["cost_copper_remainder"] = 0,
["display"] = "Shop",
["acquireMethod"] = "shop",
},
}
+23493 -23493
View File
File diff suppressed because it is too large Load Diff
+223 -167
View File
File diff suppressed because it is too large Load Diff
+219 -219
View File
File diff suppressed because it is too large Load Diff
+14 -1
View File
@@ -1,7 +1,7 @@
-- MetaHunt: Zone DBC enrichment (worldBounds, dbcAreaId, dbcMapId, dbcName)
-- AUTO-GENERATED by .tools — do not edit by hand.
-- Source DBC(s): WorldMapArea.dbc, AreaTable.dbc
-- Generated: 2026-03-17 07:31 UTC
-- Generated: 2026-03-20 13:57 UTC
if not MTH_DS_Zones then return end
@@ -70,6 +70,19 @@ if MTH_DS_Zones[1497] then
}
end
-- WMA ID=508 map=1 'AmaniAlor'
if MTH_DS_Zones[2041] then
MTH_DS_Zones[2041]["dbcAreaId"] = 2041
MTH_DS_Zones[2041]["dbcMapId"] = 1
MTH_DS_Zones[2041]["dbcName"] = "AmaniAlor"
MTH_DS_Zones[2041]["worldBounds"] = {
["left"] = 3112.0,
["right"] = 1599.0,
["top"] = 3437.0,
["bottom"] = 2434.0,
}
end
-- WMA ID=509 map=0 'AlahThalas'
if MTH_DS_Zones[2040] then
MTH_DS_Zones[2040]["dbcAreaId"] = 2040
+2
View File
@@ -72,4 +72,6 @@ MTH_DS_ZoneNamesFallback = {
[5581] = "Northwind",
[5601] = "Dragonmaw Retreat",
[5602] = "Grim Reaches",
[5641] = "Windhorn Canyon",
[5642] = "Moonwhisper Coast",
}
+128 -193
View File
@@ -1,7 +1,7 @@
-- MetaHunt: Zones present in DBC but not in MTH_DS_Zones (TWoW custom zones)
-- AUTO-GENERATED by .tools — do not edit by hand.
-- Source DBC(s): WorldMapArea.dbc, AreaTable.dbc
-- Generated: 2026-03-17 07:31 UTC
-- Generated: 2026-03-20 13:57 UTC
if not MTH_DS_Zones then MTH_DS_Zones = {} end
@@ -14,7 +14,7 @@ if not MTH_DS_Zones[14] then
["dbcMapId"] = 1,
["dbcName"] = "Durotar",
["worldBounds"] = { left=-1962.50, right=-7250.00, top=1808.33, bottom=-1716.67 },
["names"] = { ["deDE"] = "Durotar", ["enUS"] = "Durotar", ["esES"] = "Durotar", ["ptBR"] = "Durotar", ["ruRU"] = "Дуротар", ["zhCN"] = "杜隆塔尔" },
["names"] = { ["enUS"] = "Durotar", ["esES"] = "Durotar", ["ptBR"] = "Durotar", ["zhCN"] = "杜隆塔尔" },
}
end
@@ -27,7 +27,7 @@ if not MTH_DS_Zones[215] then
["dbcMapId"] = 1,
["dbcName"] = "Mulgore",
["worldBounds"] = { left=2047.92, right=-3089.58, top=-272.92, bottom=-3697.92 },
["names"] = { ["deDE"] = "Mulgore", ["enUS"] = "Mulgore", ["esES"] = "Mulgore", ["ptBR"] = "Mulgore", ["ruRU"] = "Мулгор", ["zhCN"] = "莫高雷" },
["names"] = { ["enUS"] = "Mulgore", ["esES"] = "Mulgore", ["ptBR"] = "Mulgore", ["zhCN"] = "莫高雷" },
}
end
@@ -40,7 +40,7 @@ if not MTH_DS_Zones[17] then
["dbcMapId"] = 1,
["dbcName"] = "Barrens",
["worldBounds"] = { left=2622.92, right=-7510.42, top=1612.50, bottom=-5143.75 },
["names"] = { ["deDE"] = "Brachland", ["enUS"] = "The Barrens", ["esES"] = "Los Baldíos", ["ptBR"] = "Sertões", ["ruRU"] = "Степи", ["zhCN"] = "贫瘠之地" },
["names"] = { ["enUS"] = "The Barrens", ["esES"] = "Los Baldíos", ["ptBR"] = "Os Barrens", ["zhCN"] = "贫瘠之地" },
}
end
@@ -79,7 +79,7 @@ if not MTH_DS_Zones[36] then
["dbcMapId"] = 0,
["dbcName"] = "Alterac",
["worldBounds"] = { left=783.33, right=-2016.67, top=1500.00, bottom=-366.67 },
["names"] = { ["deDE"] = "Alteracgebirge", ["enUS"] = "Alterac Mountains", ["esES"] = "Montañas de Alterac", ["ptBR"] = "Montanhas de Alterac", ["ruRU"] = "Альтеракские Горы", ["zhCN"] = "奥特兰克山脉" },
["names"] = { ["enUS"] = "Alterac Mountains", ["esES"] = "Montañas de Alterac", ["ptBR"] = "Montanhas de Alterac", ["zhCN"] = "奥特兰克山脉" },
}
end
@@ -92,7 +92,7 @@ if not MTH_DS_Zones[45] then
["dbcMapId"] = 0,
["dbcName"] = "Arathi",
["worldBounds"] = { left=-866.67, right=-4466.67, top=-133.33, bottom=-2533.33 },
["names"] = { ["deDE"] = "Arathihochland", ["enUS"] = "Arathi Highlands", ["esES"] = "Tierras Altas de Arathi", ["ptBR"] = "Planalto Arathi", ["ruRU"] = "Нагорье Арати", ["zhCN"] = "阿拉希高地" },
["names"] = { ["enUS"] = "Arathi Highlands", ["esES"] = "Tierras Altas de Arathi", ["ptBR"] = "Planalto Arathi", ["zhCN"] = "阿拉希高地" },
}
end
@@ -105,7 +105,7 @@ if not MTH_DS_Zones[3] then
["dbcMapId"] = 0,
["dbcName"] = "Badlands",
["worldBounds"] = { left=-2079.17, right=-4566.67, top=-5889.58, bottom=-7547.92 },
["names"] = { ["deDE"] = "Ödland", ["enUS"] = "Badlands", ["esES"] = "Tierras Inhóspitas", ["ptBR"] = "Ermos", ["ruRU"] = "Бесплодные Земли", ["zhCN"] = "荒芜之地" },
["names"] = { ["enUS"] = "Badlands", ["esES"] = "Tierras Inhóspitas", ["ptBR"] = "Ermos", ["zhCN"] = "荒芜之地" },
}
end
@@ -118,7 +118,7 @@ if not MTH_DS_Zones[4] then
["dbcMapId"] = 0,
["dbcName"] = "BlastedLands",
["worldBounds"] = { left=-1241.67, right=-4591.67, top=-10566.67, bottom=-12800.00 },
["names"] = { ["deDE"] = "Verwüstete Lande", ["enUS"] = "Blasted Lands", ["esES"] = "Las Tierras Devastadas", ["ptBR"] = "Barreira do Inferno", ["ruRU"] = "Выжженные Земли", ["zhCN"] = "诅咒之地" },
["names"] = { ["enUS"] = "Blasted Lands", ["esES"] = "Tierras Devastadas", ["ptBR"] = "Terras Devastadas", ["zhCN"] = "诅咒之地" },
}
end
@@ -131,7 +131,7 @@ if not MTH_DS_Zones[85] then
["dbcMapId"] = 0,
["dbcName"] = "Tirisfal",
["worldBounds"] = { left=3033.33, right=-1485.42, top=3837.50, bottom=825.00 },
["names"] = { ["deDE"] = "Tirisfal", ["enUS"] = "Tirisfal Glades", ["esES"] = "Claros de Tirisfal", ["ptBR"] = "Clareiras de Tirisfal", ["ruRU"] = "Тирисфальские Леса", ["zhCN"] = "提瑞斯法林地" },
["names"] = { ["enUS"] = "Tirisfal Glades", ["esES"] = "Claros de Tirisfal", ["ptBR"] = "Os Bosques de Tirisfal", ["zhCN"] = "提瑞斯法林地" },
}
end
@@ -144,7 +144,7 @@ if not MTH_DS_Zones[130] then
["dbcMapId"] = 0,
["dbcName"] = "Silverpine",
["worldBounds"] = { left=3450.00, right=-750.00, top=1666.67, bottom=-1133.33 },
["names"] = { ["deDE"] = "Silberwald", ["enUS"] = "Silverpine Forest", ["esES"] = "Bosque de Argénteos", ["ptBR"] = "Floresta de Pinhaprata", ["ruRU"] = "Серебряный Бор", ["zhCN"] = "银松森林" },
["names"] = { ["enUS"] = "Silverpine Forest", ["esES"] = "Bosque de Argénteos", ["ptBR"] = "Floresta Silverpine", ["zhCN"] = "银松森林" },
}
end
@@ -157,7 +157,7 @@ if not MTH_DS_Zones[28] then
["dbcMapId"] = 0,
["dbcName"] = "WesternPlaguelands",
["worldBounds"] = { left=416.67, right=-3883.33, top=3366.67, bottom=500.00 },
["names"] = { ["deDE"] = "Westliche Pestländer", ["enUS"] = "Western Plaguelands", ["esES"] = "Tierras de la Peste del Oeste", ["ptBR"] = "Terras Pestilentas Ocidentais", ["ruRU"] = "Западные Чумные Земли", ["zhCN"] = "西瘟疫之地" },
["names"] = { ["enUS"] = "Western Plaguelands", ["esES"] = "Tierras de la Peste del Oeste", ["ptBR"] = "Plaguelands Ocidentais", ["zhCN"] = "西瘟疫之地" },
}
end
@@ -170,7 +170,7 @@ if not MTH_DS_Zones[139] then
["dbcMapId"] = 0,
["dbcName"] = "EasternPlaguelands",
["worldBounds"] = { left=-2185.42, right=-6056.25, top=3800.00, bottom=1218.75 },
["names"] = { ["deDE"] = "Östliche Pestländer", ["enUS"] = "Eastern Plaguelands", ["esES"] = "Tierras de la Peste del Este", ["ptBR"] = "Terras Pestilentas Orientais", ["ruRU"] = "Восточные Чумные Земли", ["zhCN"] = "东瘟疫之地" },
["names"] = { ["enUS"] = "Eastern Plaguelands", ["esES"] = "Tierras de la Peste del Este", ["ptBR"] = "Terras Pestilentas Orientais", ["zhCN"] = "东瘟疫之地" },
}
end
@@ -183,7 +183,7 @@ if not MTH_DS_Zones[267] then
["dbcMapId"] = 0,
["dbcName"] = "Hilsbrad",
["worldBounds"] = { left=1066.67, right=-2133.33, top=400.00, bottom=-1733.33 },
["names"] = { ["deDE"] = "Vorgebirge des Hügellandes", ["enUS"] = "Hillsbrad Foothills", ["esES"] = "Laderas de Trabalomas", ["ptBR"] = "Contraforte de Eira dos Montes", ["ruRU"] = "Предгорья Хилсбрада", ["zhCN"] = "希尔斯布莱德丘陵" },
["names"] = { ["enUS"] = "Hillsbrad Foothills", ["esES"] = "Laderas de Trabalomas", ["ptBR"] = "Contrafortes de Eira dos Montes", ["zhCN"] = "希尔斯布莱德丘陵" },
}
end
@@ -196,7 +196,7 @@ if not MTH_DS_Zones[47] then
["dbcMapId"] = 0,
["dbcName"] = "Hinterlands",
["worldBounds"] = { left=-1575.00, right=-5425.00, top=1466.67, bottom=-1100.00 },
["names"] = { ["deDE"] = "Hinterland", ["enUS"] = "The Hinterlands", ["esES"] = "Tierras del Interior", ["ptBR"] = "Terras Agrestes", ["ruRU"] = "Внутренние Земли", ["zhCN"] = "辛特兰" },
["names"] = { ["enUS"] = "The Hinterlands", ["esES"] = "Tierras del Interior", ["ptBR"] = "As Terras Interiores", ["zhCN"] = "辛特兰" },
}
end
@@ -209,7 +209,7 @@ if not MTH_DS_Zones[1] then
["dbcMapId"] = 0,
["dbcName"] = "DunMorogh",
["worldBounds"] = { left=1802.08, right=-3122.92, top=-3877.08, bottom=-7160.42 },
["names"] = { ["deDE"] = "Dun Morogh", ["enUS"] = "Dun Morogh", ["esES"] = "Dun Morogh", ["ptBR"] = "Dun Morogh", ["ruRU"] = "Дун Морог", ["zhCN"] = "丹莫罗" },
["names"] = { ["enUS"] = "Dun Morogh", ["esES"] = "Dun Morogh", ["ptBR"] = "Dun Morogh", ["zhCN"] = "丹莫罗" },
}
end
@@ -222,7 +222,7 @@ if not MTH_DS_Zones[51] then
["dbcMapId"] = 0,
["dbcName"] = "SearingGorge",
["worldBounds"] = { left=-322.92, right=-2554.17, top=-6100.00, bottom=-7587.50 },
["names"] = { ["deDE"] = "Sengende Schlucht", ["enUS"] = "Searing Gorge", ["esES"] = "La Garganta de Fuego", ["ptBR"] = "Garganta Abrasadora", ["ruRU"] = "Тлеющее Ущелье", ["zhCN"] = "灼热峡谷" },
["names"] = { ["enUS"] = "Searing Gorge", ["esES"] = "La Garganta de Fuego", ["ptBR"] = "Desfiladeiro Searing", ["zhCN"] = "灼热峡谷" },
}
end
@@ -235,7 +235,7 @@ if not MTH_DS_Zones[46] then
["dbcMapId"] = 0,
["dbcName"] = "BurningSteppes",
["worldBounds"] = { left=-266.67, right=-3195.83, top=-7031.25, bottom=-8983.33 },
["names"] = { ["deDE"] = "Brennende Steppe", ["enUS"] = "Burning Steppes", ["esES"] = "Las Estepas Ardientes", ["ptBR"] = "Estepes Ardentes", ["ruRU"] = "Пылающие Степи", ["zhCN"] = "燃烧平原" },
["names"] = { ["enUS"] = "Burning Steppes", ["esES"] = "Las Estepas Ardientes", ["ptBR"] = "Estepes Ardentes", ["zhCN"] = "燃烧平原" },
}
end
@@ -248,7 +248,7 @@ if not MTH_DS_Zones[12] then
["dbcMapId"] = 0,
["dbcName"] = "Elwynn",
["worldBounds"] = { left=1535.42, right=-1935.42, top=-7939.58, bottom=-10254.17 },
["names"] = { ["deDE"] = "Wald von Elwynn", ["enUS"] = "Elwynn Forest", ["esES"] = "Bosque de Elwynn", ["ptBR"] = "Floresta de Elwynn", ["ruRU"] = "Элвиннский Лес", ["zhCN"] = "艾尔文森林" },
["names"] = { ["enUS"] = "Elwynn Forest", ["esES"] = "Bosque de Elwynn", ["ptBR"] = "Floresta de Elwynn", ["zhCN"] = "艾尔文森林" },
}
end
@@ -261,7 +261,7 @@ if not MTH_DS_Zones[41] then
["dbcMapId"] = 0,
["dbcName"] = "DeadwindPass",
["worldBounds"] = { left=-833.33, right=-3333.33, top=-9866.67, bottom=-11533.33 },
["names"] = { ["deDE"] = "Gebirgspass der Totenwinde", ["enUS"] = "Deadwind Pass", ["esES"] = "Paso de la Muerte", ["ptBR"] = "Trilha do Vento Morto", ["ruRU"] = "Перевал Мертвого Ветра", ["zhCN"] = "逆风小径" },
["names"] = { ["enUS"] = "Deadwind Pass", ["esES"] = "Paso de la Muerte", ["ptBR"] = "Desfiladeiro da Morte", ["zhCN"] = "逆风小径" },
}
end
@@ -274,7 +274,7 @@ if not MTH_DS_Zones[10] then
["dbcMapId"] = 0,
["dbcName"] = "Duskwood",
["worldBounds"] = { left=833.33, right=-1866.67, top=-9716.67, bottom=-11516.67 },
["names"] = { ["deDE"] = "Dämmerwald", ["enUS"] = "Duskwood", ["esES"] = "Bosque del Ocaso", ["ptBR"] = "Floresta do Crepúsculo", ["ruRU"] = "Сумеречный Лес", ["zhCN"] = "暮色森林" },
["names"] = { ["enUS"] = "Duskwood", ["esES"] = "Bosque del Ocaso", ["ptBR"] = "Floresta do Crepúsculo", ["zhCN"] = "暮色森林" },
}
end
@@ -287,7 +287,7 @@ if not MTH_DS_Zones[38] then
["dbcMapId"] = 0,
["dbcName"] = "LochModan",
["worldBounds"] = { left=-1993.75, right=-4752.08, top=-4487.50, bottom=-6327.08 },
["names"] = { ["deDE"] = "Loch Modan", ["enUS"] = "Loch Modan", ["esES"] = "Loch Modan", ["ptBR"] = "Loch Modan", ["ruRU"] = "Лок Модан", ["zhCN"] = "洛克莫丹" },
["names"] = { ["enUS"] = "Loch Modan", ["esES"] = "Loch Modan", ["ptBR"] = "Loch Modan", ["zhCN"] = "洛克莫丹" },
}
end
@@ -300,7 +300,7 @@ if not MTH_DS_Zones[44] then
["dbcMapId"] = 0,
["dbcName"] = "Redridge",
["worldBounds"] = { left=-1570.83, right=-3741.67, top=-8575.00, bottom=-10022.92 },
["names"] = { ["deDE"] = "Rotkammgebirge", ["enUS"] = "Redridge Mountains", ["esES"] = "Montañas Crestagrana", ["ptBR"] = "Montanhas Cristarrubra", ["ruRU"] = "Красногорье", ["zhCN"] = "赤脊山" },
["names"] = { ["enUS"] = "Redridge Mountains", ["esES"] = "Montañas Crestagrana", ["ptBR"] = "Montanhas Redridge", ["zhCN"] = "赤脊山" },
}
end
@@ -313,7 +313,7 @@ if not MTH_DS_Zones[33] then
["dbcMapId"] = 0,
["dbcName"] = "Stranglethorn",
["worldBounds"] = { left=2220.83, right=-4160.42, top=-11168.75, bottom=-15422.92 },
["names"] = { ["deDE"] = "Schlingendorntal", ["enUS"] = "Stranglethorn Vale", ["esES"] = "Vega de Tuercespina", ["ptBR"] = "Selva do Espinhaço", ["ruRU"] = "Тернистая Долина", ["zhCN"] = "荆棘谷" },
["names"] = { ["enUS"] = "Stranglethorn Vale", ["esES"] = "Vega de Tuercespina", ["ptBR"] = "Vale Stranglethorn", ["zhCN"] = "荆棘谷" },
}
end
@@ -326,7 +326,7 @@ if not MTH_DS_Zones[8] then
["dbcMapId"] = 0,
["dbcName"] = "SwampOfSorrows",
["worldBounds"] = { left=-2222.92, right=-4516.67, top=-9620.83, bottom=-11150.00 },
["names"] = { ["deDE"] = "Sümpfe des Elends", ["enUS"] = "Swamp of Sorrows", ["esES"] = "Pantano de las Penas", ["ptBR"] = "Pântano das Mágoas", ["ruRU"] = "Болото Печали", ["zhCN"] = "悲伤沼泽" },
["names"] = { ["enUS"] = "Swamp of Sorrows", ["esES"] = "Pantano de las Penas", ["ptBR"] = "Pantano das Tristezas", ["zhCN"] = "悲伤沼泽" },
}
end
@@ -339,7 +339,7 @@ if not MTH_DS_Zones[40] then
["dbcMapId"] = 0,
["dbcName"] = "Westfall",
["worldBounds"] = { left=3016.67, right=-483.33, top=-9400.00, bottom=-11733.33 },
["names"] = { ["deDE"] = "Westfall", ["enUS"] = "Westfall", ["esES"] = "Páramos de Poniente", ["ptBR"] = "Cerro Oeste", ["ruRU"] = "Западный Край", ["zhCN"] = "西部荒野" },
["names"] = { ["enUS"] = "Westfall", ["esES"] = "Páramos del Poniente", ["ptBR"] = "Westfall", ["zhCN"] = "西部荒野" },
}
end
@@ -352,7 +352,7 @@ if not MTH_DS_Zones[11] then
["dbcMapId"] = 0,
["dbcName"] = "Wetlands",
["worldBounds"] = { left=-389.58, right=-4525.00, top=-2147.92, bottom=-4904.17 },
["names"] = { ["deDE"] = "Sumpfland", ["enUS"] = "Wetlands", ["esES"] = "Los Humedales", ["ptBR"] = "Pantanal", ["ruRU"] = "Болотина", ["zhCN"] = "湿地" },
["names"] = { ["enUS"] = "Wetlands", ["esES"] = "Los Humedales", ["ptBR"] = "Pântanos", ["zhCN"] = "湿地" },
}
end
@@ -365,7 +365,7 @@ if not MTH_DS_Zones[141] then
["dbcMapId"] = 1,
["dbcName"] = "Teldrassil",
["worldBounds"] = { left=3814.58, right=-1277.08, top=11831.25, bottom=8437.50 },
["names"] = { ["deDE"] = "Teldrassil", ["enUS"] = "Teldrassil", ["esES"] = "Teldrassil", ["ptBR"] = "Teldrassil", ["ruRU"] = "Тельдрассил", ["zhCN"] = "泰达希尔" },
["names"] = { ["enUS"] = "Teldrassil", ["esES"] = "Teldrassil", ["ptBR"] = "Teldrassil", ["zhCN"] = "泰达希尔" },
}
end
@@ -378,7 +378,7 @@ if not MTH_DS_Zones[148] then
["dbcMapId"] = 1,
["dbcName"] = "Darkshore",
["worldBounds"] = { left=2941.67, right=-3608.33, top=8333.33, bottom=3966.67 },
["names"] = { ["deDE"] = "Dunkelküste", ["enUS"] = "Darkshore", ["esES"] = "Costa Oscura", ["ptBR"] = "Costa Negra", ["ruRU"] = "Темные Берега", ["zhCN"] = "黑海岸" },
["names"] = { ["enUS"] = "Darkshore", ["esES"] = "Costa Oscura", ["ptBR"] = "Costa Negra", ["zhCN"] = "黑海岸" },
}
end
@@ -391,7 +391,7 @@ if not MTH_DS_Zones[331] then
["dbcMapId"] = 1,
["dbcName"] = "Ashenvale",
["worldBounds"] = { left=1700.00, right=-4066.67, top=4672.92, bottom=829.17 },
["names"] = { ["deDE"] = "Eschental", ["enUS"] = "Ashenvale", ["esES"] = "Vallefresno", ["ptBR"] = "Vale Gris", ["ruRU"] = "Ясеневый Лес", ["zhCN"] = "灰谷" },
["names"] = { ["enUS"] = "Ashenvale", ["esES"] = "Vallefresno", ["ptBR"] = "Vale das Cinzas", ["zhCN"] = "灰谷" },
}
end
@@ -404,7 +404,7 @@ if not MTH_DS_Zones[400] then
["dbcMapId"] = 1,
["dbcName"] = "ThousandNeedles",
["worldBounds"] = { left=-433.33, right=-4833.33, top=-3966.67, bottom=-6900.00 },
["names"] = { ["deDE"] = "Tausend Nadeln", ["enUS"] = "Thousand Needles", ["esES"] = "Las Mil Agujas", ["ptBR"] = "Mil Agulhas", ["ruRU"] = "Тысяча Игл", ["zhCN"] = "千针石林" },
["names"] = { ["enUS"] = "Thousand Needles", ["esES"] = "Las Mil Agujas", ["ptBR"] = "As Mil Agulhas", ["zhCN"] = "千针石林" },
}
end
@@ -416,8 +416,8 @@ if not MTH_DS_Zones[406] then
["dbcAreaId"] = 406,
["dbcMapId"] = 1,
["dbcName"] = "StonetalonMountains",
["worldBounds"] = { left=3949.00, right=-2069.00, top=3441.00, bottom=-569.00 },
["names"] = { ["deDE"] = "Steinkrallengebirge", ["enUS"] = "Stonetalon Mountains", ["esES"] = "Sierra Espolón", ["ptBR"] = "Cordilheira das Torres de Pedra", ["ruRU"] = "Когтистые Горы", ["zhCN"] = "石爪山脉" },
["worldBounds"] = { left=3245.83, right=-1637.50, top=2916.67, bottom=-339.58 },
["names"] = { ["enUS"] = "Stonetalon Mountains", ["esES"] = "Montañas de Colina Roca", ["ptBR"] = "Montanhas Stonetalon", ["zhCN"] = "石爪山脉" },
}
end
@@ -430,7 +430,7 @@ if not MTH_DS_Zones[405] then
["dbcMapId"] = 1,
["dbcName"] = "Desolace",
["worldBounds"] = { left=4233.33, right=-262.50, top=452.08, bottom=-2545.83 },
["names"] = { ["deDE"] = "Desolace", ["enUS"] = "Desolace", ["esES"] = "Desolace", ["ptBR"] = "Desolação", ["ruRU"] = "Пустоши", ["zhCN"] = "凄凉之地" },
["names"] = { ["enUS"] = "Desolace", ["esES"] = "Desolace", ["ptBR"] = "Desolação", ["zhCN"] = "凄凉之地" },
}
end
@@ -443,7 +443,7 @@ if not MTH_DS_Zones[357] then
["dbcMapId"] = 1,
["dbcName"] = "Feralas",
["worldBounds"] = { left=5441.67, right=-1508.33, top=-2366.67, bottom=-7000.00 },
["names"] = { ["deDE"] = "Feralas", ["enUS"] = "Feralas", ["esES"] = "Feralas", ["ptBR"] = "Feralas", ["ruRU"] = "Фералас", ["zhCN"] = "菲拉斯" },
["names"] = { ["enUS"] = "Feralas", ["esES"] = "Feralas", ["ptBR"] = "Feralas", ["zhCN"] = "菲拉斯" },
}
end
@@ -456,7 +456,7 @@ if not MTH_DS_Zones[15] then
["dbcMapId"] = 1,
["dbcName"] = "Dustwallow",
["worldBounds"] = { left=-975.00, right=-6225.00, top=-2033.33, bottom=-5533.33 },
["names"] = { ["deDE"] = "Düstermarschen", ["enUS"] = "Dustwallow Marsh", ["esES"] = "Marjal Revolcafango", ["ptBR"] = "Pântano Vadeoso", ["ruRU"] = "Пылевые Топи", ["zhCN"] = "尘泥沼泽" },
["names"] = { ["enUS"] = "Dustwallow Marsh", ["esES"] = "Marjal Revolcafango", ["ptBR"] = "Pântano Vadeante", ["zhCN"] = "尘泥沼泽" },
}
end
@@ -469,7 +469,7 @@ if not MTH_DS_Zones[440] then
["dbcMapId"] = 1,
["dbcName"] = "Tanaris",
["worldBounds"] = { left=-218.75, right=-7118.75, top=-5875.00, bottom=-10475.00 },
["names"] = { ["deDE"] = "Tanaris", ["enUS"] = "Tanaris", ["esES"] = "Tanaris", ["ptBR"] = "Tanaris", ["ruRU"] = "Танарис", ["zhCN"] = "塔纳利斯" },
["names"] = { ["enUS"] = "Tanaris", ["esES"] = "Tanaris", ["ptBR"] = "Tanaris", ["zhCN"] = "塔纳利斯" },
}
end
@@ -482,7 +482,7 @@ if not MTH_DS_Zones[16] then
["dbcMapId"] = 1,
["dbcName"] = "Aszhara",
["worldBounds"] = { left=-3277.08, right=-8347.92, top=5341.67, bottom=1960.42 },
["names"] = { ["deDE"] = "Azshara", ["enUS"] = "Azshara", ["esES"] = "Azshara", ["ptBR"] = "Azshara", ["ruRU"] = "Азшара", ["zhCN"] = "艾萨拉" },
["names"] = { ["enUS"] = "Azshara", ["esES"] = "Azshara", ["ptBR"] = "Azshara", ["zhCN"] = "艾萨拉" },
}
end
@@ -495,7 +495,7 @@ if not MTH_DS_Zones[361] then
["dbcMapId"] = 1,
["dbcName"] = "Felwood",
["worldBounds"] = { left=1641.67, right=-4108.33, top=7133.33, bottom=3300.00 },
["names"] = { ["deDE"] = "Teufelswald", ["enUS"] = "Felwood", ["esES"] = "Frondavil", ["ptBR"] = "Selva Maleva", ["ruRU"] = "Оскверненный Лес", ["zhCN"] = "费伍德森林" },
["names"] = { ["enUS"] = "Felwood", ["esES"] = "Frondavil", ["ptBR"] = "Selva Maleva", ["zhCN"] = "费伍德森林" },
}
end
@@ -508,7 +508,7 @@ if not MTH_DS_Zones[490] then
["dbcMapId"] = 1,
["dbcName"] = "UngoroCrater",
["worldBounds"] = { left=533.33, right=-3166.67, top=-5966.67, bottom=-8433.33 },
["names"] = { ["deDE"] = "Krater von Un'Goro", ["enUS"] = "Un'Goro Crater", ["esES"] = "Cráter de Un'goro", ["ptBR"] = "Cratera Un'goro", ["ruRU"] = "Кратер Ун'Горо", ["zhCN"] = "安戈洛环形山" },
["names"] = { ["enUS"] = "Un'Goro Crater", ["esES"] = "Crater Un'Goro", ["ptBR"] = "Cratera Un'Goro", ["zhCN"] = "安戈洛环形山" },
}
end
@@ -521,7 +521,7 @@ if not MTH_DS_Zones[493] then
["dbcMapId"] = 1,
["dbcName"] = "Moonglade",
["worldBounds"] = { left=-1381.25, right=-3689.58, top=8491.67, bottom=6952.08 },
["names"] = { ["deDE"] = "Mondlichtung", ["enUS"] = "Moonglade", ["esES"] = "Claro de la Luna", ["ptBR"] = "Clareira da Lua", ["ruRU"] = "Лунная Поляна", ["zhCN"] = "月光林地" },
["names"] = { ["enUS"] = "Moonglade", ["esES"] = "Claro de la Luna", ["ptBR"] = "Moonglade", ["zhCN"] = "月光林地" },
}
end
@@ -534,7 +534,7 @@ if not MTH_DS_Zones[1377] then
["dbcMapId"] = 1,
["dbcName"] = "Silithus",
["worldBounds"] = { left=2537.50, right=-945.83, top=-5958.33, bottom=-8281.25 },
["names"] = { ["deDE"] = "Silithus", ["enUS"] = "Silithus", ["esES"] = "Silithus", ["ptBR"] = "Silithus", ["ruRU"] = "Силитус", ["zhCN"] = "希利苏斯" },
["names"] = { ["enUS"] = "Silithus", ["esES"] = "Silithus", ["ptBR"] = "Silithus", ["zhCN"] = "希利苏斯" },
}
end
@@ -547,7 +547,7 @@ if not MTH_DS_Zones[618] then
["dbcMapId"] = 1,
["dbcName"] = "Winterspring",
["worldBounds"] = { left=-316.67, right=-7416.67, top=8533.33, bottom=3800.00 },
["names"] = { ["deDE"] = "Winterquell", ["enUS"] = "Winterspring", ["esES"] = "Cuna del Invierno", ["ptBR"] = "Hibérnia", ["ruRU"] = "Зимние Ключи", ["zhCN"] = "冬泉谷" },
["names"] = { ["enUS"] = "Winterspring", ["esES"] = "Winterspring", ["ptBR"] = "Inverno", ["zhCN"] = "冬泉谷" },
}
end
@@ -560,7 +560,7 @@ if not MTH_DS_Zones[1537] then
["dbcMapId"] = 0,
["dbcName"] = "Ironforge",
["worldBounds"] = { left=-713.59, right=-1504.22, top=-4569.24, bottom=-5096.85 },
["names"] = { ["deDE"] = "Eisenschmiede", ["enUS"] = "Ironforge", ["esES"] = "Forjaz", ["ptBR"] = "Altaforja", ["ruRU"] = "Стальгорн", ["zhCN"] = "铁炉堡" },
["names"] = { ["enUS"] = "Ironforge", ["esES"] = "Forjaz", ["ptBR"] = "Altaforja", ["zhCN"] = "铁炉堡" },
}
end
@@ -573,7 +573,7 @@ if not MTH_DS_Zones[2597] then
["dbcMapId"] = 30,
["dbcName"] = "AlteracValley",
["worldBounds"] = { left=1781.25, right=-2456.25, top=1085.42, bottom=-1739.58 },
["names"] = { ["deDE"] = "Alteractal", ["enUS"] = "Alterac Valley", ["esES"] = "Valle de Alterac", ["ptBR"] = "Vale Alterac", ["ruRU"] = "Альтеракская Долина", ["zhCN"] = "奥特兰克山谷" },
["names"] = { ["enUS"] = "Alterac Valley", ["esES"] = "Valle de Alterac", ["ptBR"] = "Vale Alterac", ["zhCN"] = "奥特兰克山谷" },
}
end
@@ -586,7 +586,7 @@ if not MTH_DS_Zones[3277] then
["dbcMapId"] = 489,
["dbcName"] = "WarsongGulch",
["worldBounds"] = { left=2041.67, right=895.83, top=1627.08, bottom=862.50 },
["names"] = { ["deDE"] = "Kriegshymnenschlucht", ["enUS"] = "Warsong Gulch", ["esES"] = "Garganta Grito de Guerra", ["ptBR"] = "Ravina Brado Guerreiro", ["ruRU"] = "Ущелье Песни Войны", ["zhCN"] = "战歌峡谷" },
["names"] = { ["enUS"] = "Warsong Gulch", ["esES"] = "Garganta de Warsong", ["ptBR"] = "Garganta Grito de Guerra", ["zhCN"] = "战歌峡谷" },
}
end
@@ -599,7 +599,7 @@ if not MTH_DS_Zones[3358] then
["dbcMapId"] = 529,
["dbcName"] = "ArathiBasin",
["worldBounds"] = { left=1858.33, right=102.08, top=1508.33, bottom=337.50 },
["names"] = { ["deDE"] = "Arathibecken", ["enUS"] = "Arathi Basin", ["esES"] = "Cuenca de Arathi", ["ptBR"] = "Bacia Arathi", ["ruRU"] = "Низина Арати", ["zhCN"] = "阿拉希盆地" },
["names"] = { ["enUS"] = "Arathi Basin", ["esES"] = "Cuenca de Arathi", ["ptBR"] = "Bacia Arathi", ["zhCN"] = "阿拉希盆地" },
}
end
@@ -612,7 +612,7 @@ if not MTH_DS_Zones[876] then
["dbcMapId"] = 1,
["dbcName"] = "GMIsland",
["worldBounds"] = { left=16748.00, right=15920.00, top=16525.00, bottom=15984.00 },
["names"] = { ["deDE"] = "GM-Insel", ["enUS"] = "GM Island", ["esES"] = "Isla GM", ["ptBR"] = "Ilha GM", ["ruRU"] = "Остров ГМ", ["zhCN"] = "GM岛" },
["names"] = { ["enUS"] = "GM Island", ["esES"] = "Isla GM", ["ptBR"] = "Ilha GM", ["zhCN"] = "GM岛" },
}
end
@@ -625,7 +625,7 @@ if not MTH_DS_Zones[616] then
["dbcMapId"] = 1,
["dbcName"] = "Hyjal",
["worldBounds"] = { left=-1080.00, right=-4286.00, top=6125.00, bottom=3983.00 },
["names"] = { ["deDE"] = "Hyjal", ["enUS"] = "Hyjal", ["esES"] = "Hyjal", ["ptBR"] = "Hyjal", ["ruRU"] = "Хиджал", ["zhCN"] = "海加尔山" },
["names"] = { ["enUS"] = "Hyjal", ["esES"] = "Hyjal", ["ptBR"] = "Hyjal", ["zhCN"] = "海加尔山" },
}
end
@@ -638,7 +638,7 @@ if not MTH_DS_Zones[4012] then
["dbcMapId"] = 0,
["dbcName"] = "ScarletEnclave",
["worldBounds"] = { left=-4050.00, right=-7209.00, top=3087.00, bottom=979.00 },
["names"] = { ["deDE"] = "Scharlachrote Enklave", ["enUS"] = "Scarlet Enclave", ["esES"] = "Enclave Escarlata", ["ptBR"] = "Enclave Scarlet", ["ruRU"] = "Анклав Алого Ордена", ["zhCN"] = "血色领地" },
["names"] = { ["enUS"] = "Scarlet Enclave", ["esES"] = "Enclave Escarlata", ["ptBR"] = "Enclave Scarlet", ["zhCN"] = "东瘟疫之地:血色领地" },
}
end
@@ -651,7 +651,7 @@ if not MTH_DS_Zones[5023] then
["dbcMapId"] = 27,
["dbcName"] = "Sunnyglade",
["worldBounds"] = { left=719.47, right=-269.16, top=2000.77, bottom=607.60 },
["names"] = { ["deDE"] = "Sonnenhain Tal", ["enUS"] = "Sunnyglade Valley", ["esES"] = "Valle Claro Sol", ["ptBR"] = "Vale Sunnyglade", ["ruRU"] = "Солнечная Долина", ["zhCN"] = "阳光林地山谷" },
["names"] = { ["enUS"] = "Sunnyglade Valley", ["esES"] = "Valle Claro Sol", ["ptBR"] = "Vale Sunnyglade", ["zhCN"] = "阳光林地山谷" },
}
end
@@ -664,7 +664,7 @@ if not MTH_DS_Zones[409] then
["dbcMapId"] = 0,
["dbcName"] = "Lapidis",
["worldBounds"] = { left=4933.33, right=2031.88, top=-11043.48, bottom=-12959.42 },
["names"] = { ["deDE"] = "Insel des Doktor Lapidis", ["enUS"] = "Lapidis Isle", ["esES"] = "Isla Lapidis", ["ptBR"] = "Isla Lapidis", ["ruRU"] = "Остров Доктора Лапидиса", ["zhCN"] = "拉匹迪斯之岛" },
["names"] = { ["enUS"] = "Lapidis Isle", ["esES"] = "Isla Lapidis", ["ptBR"] = "Isla Lapidis", ["zhCN"] = "拉匹迪斯之岛" },
}
end
@@ -677,7 +677,20 @@ if not MTH_DS_Zones[408] then
["dbcMapId"] = 0,
["dbcName"] = "Gillijim",
["worldBounds"] = { left=4436.22, right=1344.12, top=-12528.71, bottom=-14575.72 },
["names"] = { ["deDE"] = "Gillijims Insel", ["enUS"] = "Gillijim's Isle", ["esES"] = "Isla de Gillijim", ["ptBR"] = "Ilha de Gillijim", ["ruRU"] = "Остров Гиллиджима", ["zhCN"] = "吉利吉姆之岛" },
["names"] = { ["enUS"] = "Gillijim's Isle", ["esES"] = "Isla de Gillijim", ["ptBR"] = "Ilha de Gillijim", ["zhCN"] = "吉利吉姆之岛" },
}
end
-- DBC WMA ID=506 MapID=31 'AlteracValleyClassic'
if not MTH_DS_Zones[2597] then
MTH_DS_Zones[2597] = {
["continent"] = 31,
["parent"] = 31,
["dbcAreaId"] = 2597,
["dbcMapId"] = 31,
["dbcName"] = "AlteracValleyClassic",
["worldBounds"] = { left=1781.25, right=-2456.25, top=1085.42, bottom=-1739.58 },
["names"] = { ["enUS"] = "Alterac Valley", ["esES"] = "Valle de Alterac", ["ptBR"] = "Vale Alterac", ["zhCN"] = "奥特兰克山谷" },
}
end
@@ -690,7 +703,7 @@ if not MTH_DS_Zones[5121] then
["dbcMapId"] = 1,
["dbcName"] = "TelAbim",
["worldBounds"] = { left=-5179.00, right=-8406.00, top=-7184.00, bottom=-9371.00 },
["names"] = { ["deDE"] = "Tel'Abim", ["enUS"] = "Tel'Abim", ["esES"] = "Tel'Abim", ["ptBR"] = "Tel'Abim", ["ruRU"] = "Тель'Абим", ["zhCN"] = "泰拉比姆" },
["names"] = { ["enUS"] = "Tel'Abim", ["esES"] = "Tel'Abim", ["ptBR"] = "Tel'Abim", ["zhCN"] = "泰拉比姆" },
}
end
@@ -703,7 +716,7 @@ if not MTH_DS_Zones[5179] then
["dbcMapId"] = 0,
["dbcName"] = "Gilneas",
["worldBounds"] = { left=3253.00, right=-413.00, top=-359.00, bottom=-2801.00 },
["names"] = { ["deDE"] = "Gilneas", ["enUS"] = "Gilneas", ["esES"] = "Gilneas", ["ptBR"] = "Gilneas", ["ruRU"] = "Гилнеас", ["zhCN"] = "吉尔尼斯" },
["names"] = { ["enUS"] = "Gilneas", ["esES"] = "Gilneas", ["ptBR"] = "Gilneas", ["zhCN"] = "吉尔尼斯" },
}
end
@@ -716,7 +729,7 @@ if not MTH_DS_Zones[5024] then
["dbcMapId"] = 1,
["dbcName"] = "Icepoint",
["worldBounds"] = { left=-5595.00, right=-7203.00, top=14405.00, bottom=13330.00 },
["names"] = { ["deDE"] = "Eisfels", ["enUS"] = "Icepoint Rock", ["esES"] = "Roca Punto de Hielo", ["ptBR"] = "Roca Punto de Hielo", ["ruRU"] = "Ледяная Скала", ["zhCN"] = "冰点岩" },
["names"] = { ["enUS"] = "Icepoint Rock", ["esES"] = "Roca Punto de Hielo", ["ptBR"] = "Roca Punto de Hielo", ["zhCN"] = "冰点岩" },
}
end
@@ -729,7 +742,7 @@ if not MTH_DS_Zones[5536] then
["dbcMapId"] = 1,
["dbcName"] = "BlackstoneIsland",
["worldBounds"] = { left=-6274.00, right=-8746.00, top=799.00, bottom=-866.00 },
["names"] = { ["deDE"] = "Schwarzstein Insel", ["enUS"] = "Blackstone Island", ["esES"] = "Isla Piedra Negra", ["ptBR"] = "Ilha Negrito", ["ruRU"] = "Остров Черного Камня", ["zhCN"] = "黑石岛" },
["names"] = { ["enUS"] = "Blackstone Island", ["esES"] = "Isla Piedra Negra", ["ptBR"] = "Ilha Negrito", ["zhCN"] = "黑石岛" },
}
end
@@ -742,7 +755,7 @@ if not MTH_DS_Zones[5225] then
["dbcMapId"] = 0,
["dbcName"] = "ThalassianHighlands",
["worldBounds"] = { left=-1005.00, right=-4087.00, top=4952.00, bottom=2891.00 },
["names"] = { ["deDE"] = "Thalassisches Hochland", ["enUS"] = "Thalassian Highlands", ["esES"] = "Tierras Altas Thalassianas", ["ptBR"] = "Terras Altas Thalassianas", ["ruRU"] = "Талассийские Высоты", ["zhCN"] = "萨拉斯高地" },
["names"] = { ["enUS"] = "Thalassian Highlands", ["esES"] = "Tierras Altas Thalassianas", ["ptBR"] = "Terras Altas Thalassianas", ["zhCN"] = "萨拉斯高地" },
}
end
@@ -755,7 +768,7 @@ if not MTH_DS_Zones[1581] then
["dbcMapId"] = 0,
["dbcName"] = "DeadminesEntrance",
["worldBounds"] = { left=1793.18, right=1343.29, top=-11054.94, bottom=-11354.86 },
["names"] = { ["deDE"] = "Die Todesminen", ["enUS"] = "The Deadmines", ["esES"] = "Las Minas de la Muerte", ["ptBR"] = "Minas Mortas", ["ruRU"] = "Мертвые Копи", ["zhCN"] = "死亡矿井" },
["names"] = { ["enUS"] = "The Deadmines", ["esES"] = "Las Minas de la Muerte", ["ptBR"] = "As Minas Mortas", ["zhCN"] = "死亡矿井" },
}
end
@@ -768,7 +781,7 @@ if not MTH_DS_Zones[718] then
["dbcMapId"] = 1,
["dbcName"] = "WailingCavernsEntrance",
["worldBounds"] = { left=-1900.87, right=-2473.65, top=-488.64, bottom=-870.49 },
["names"] = { ["deDE"] = "Höhlen des Wehklagens", ["enUS"] = "Wailing Caverns", ["esES"] = "Cuevas de los Lamentos", ["ptBR"] = "Caverna Ululante", ["ruRU"] = "Пещеры Стенаний", ["zhCN"] = "哀嚎洞穴" },
["names"] = { ["enUS"] = "Wailing Caverns", ["esES"] = "Cuevas de los Lamentos", ["ptBR"] = "Cavernas Uivantes", ["zhCN"] = "哀嚎洞穴" },
}
end
@@ -781,7 +794,7 @@ if not MTH_DS_Zones[2100] then
["dbcMapId"] = 1,
["dbcName"] = "MaraudonEntrance",
["worldBounds"] = { left=3208.00, right=2384.00, top=-1096.00, bottom=-1646.00 },
["names"] = { ["deDE"] = "Maraudon", ["enUS"] = "Maraudon", ["esES"] = "Maraudon", ["ptBR"] = "Maraudon", ["ruRU"] = "Мародон", ["zhCN"] = "玛拉顿" },
["names"] = { ["enUS"] = "Maraudon", ["esES"] = "Maraudon", ["ptBR"] = "Maraudon", ["zhCN"] = "玛拉顿" },
}
end
@@ -794,7 +807,7 @@ if not MTH_DS_Zones[721] then
["dbcMapId"] = 0,
["dbcName"] = "GnomereganEntrance",
["worldBounds"] = { left=1027.64, right=456.45, top=-4806.32, bottom=-5185.46 },
["names"] = { ["deDE"] = "Gnomeregan", ["enUS"] = "Gnomeregan", ["esES"] = "Gnomeregan", ["ptBR"] = "Gnomeregan", ["ruRU"] = "Гномреган", ["zhCN"] = "诺莫瑞根" },
["names"] = { ["enUS"] = "Gnomeregan", ["esES"] = "Gnomeregan", ["ptBR"] = "Gnomeregan", ["zhCN"] = "诺莫瑞根" },
}
end
@@ -807,7 +820,7 @@ if not MTH_DS_Zones[25] then
["dbcMapId"] = 0,
["dbcName"] = "BlackrockMountain",
["worldBounds"] = { left=-760.94, right=-1472.50, top=-7327.82, bottom=-7796.50 },
["names"] = { ["deDE"] = "Der Schwarzfels", ["enUS"] = "Blackrock Mountain", ["esES"] = "Montaña Roca Negra", ["ptBR"] = "Montanha Rocha Negra", ["ruRU"] = "Черная Гора", ["zhCN"] = "黑石山" },
["names"] = { ["enUS"] = "Blackrock Mountain", ["esES"] = "Montaña Roca Negra", ["ptBR"] = "Montanha Rocha Negra", ["zhCN"] = "黑石山" },
}
end
@@ -820,7 +833,7 @@ if not MTH_DS_Zones[796] then
["dbcMapId"] = 0,
["dbcName"] = "ScarletMonasteryEntrance",
["worldBounds"] = { left=-659.96, right=-863.62, top=2947.37, bottom=2812.33 },
["names"] = { ["deDE"] = "Das Scharlachrote Kloster", ["enUS"] = "Scarlet Monastery", ["esES"] = "Monasterio Escarlata", ["ptBR"] = "Monastério Escarlate", ["ruRU"] = "Монастырь Алого Ордена", ["zhCN"] = "血色修道院" },
["names"] = { ["enUS"] = "Scarlet Monastery", ["esES"] = "Monasterio Escarlata", ["ptBR"] = "Monastério Scarlet", ["zhCN"] = "血色修道院" },
}
end
@@ -833,7 +846,7 @@ if not MTH_DS_Zones[1337] then
["dbcMapId"] = 0,
["dbcName"] = "UldamanEntrance",
["worldBounds"] = { left=-2747.15, right=-3310.46, top=-5953.41, bottom=-6329.51 },
["names"] = { ["deDE"] = "Uldaman", ["enUS"] = "Uldaman", ["esES"] = "Uldaman", ["ptBR"] = "Uldaman", ["ruRU"] = "Ульдаман", ["zhCN"] = "奥达曼" },
["names"] = { ["enUS"] = "Uldaman", ["esES"] = "Uldaman", ["ptBR"] = "Uldaman", ["zhCN"] = "奥达曼" },
}
end
@@ -846,7 +859,7 @@ if not MTH_DS_Zones[3478] then
["dbcMapId"] = 1,
["dbcName"] = "AhnQirajEntrance",
["worldBounds"] = { left=3932.67, right=-206.35, top=-8005.20, bottom=-10951.25 },
["names"] = { ["deDE"] = "Tore von Ahn'Qiraj", ["enUS"] = "Gates of Ahn'Qiraj", ["esES"] = "Puertas de Ahn'Qiraj", ["ptBR"] = "Portões de Ahn'Qiraj", ["ruRU"] = "Врата Ан'Киража", ["zhCN"] = "安其拉之门" },
["names"] = { ["enUS"] = "Gates of Ahn'Qiraj", ["esES"] = "Puertas de Ahn'Qiraj", ["ptBR"] = "Portões de Ahn'Qiraj", ["zhCN"] = "安其拉之门" },
}
end
@@ -859,7 +872,7 @@ if not MTH_DS_Zones[1941] then
["dbcMapId"] = 1,
["dbcName"] = "CavernsOfTime",
["worldBounds"] = { left=-3695.85, right=-5044.09, top=-8023.09, bottom=-8911.18 },
["names"] = { ["deDE"] = "Höhlen der Zeit", ["enUS"] = "Caverns of Time", ["esES"] = "Cavernas del Tiempo", ["ptBR"] = "Cavernas do Tempo", ["ruRU"] = "Пещеры Времени", ["zhCN"] = "时光之穴" },
["names"] = { ["enUS"] = "Caverns of Time", ["esES"] = "Cavernas del Tiempo", ["ptBR"] = "Cavernas do Tempo", ["zhCN"] = "时光之穴" },
}
end
@@ -872,7 +885,7 @@ if not MTH_DS_Zones[5130] then
["dbcMapId"] = 813,
["dbcName"] = "WinterVeilVale",
["worldBounds"] = { left=1916.00, right=484.00, top=-2332.00, bottom=-3309.00 },
["names"] = { ["deDE"] = "Winterhauchtal", ["enUS"] = "Winter Veil Vale", ["esES"] = "Valle del Velo Invernal", ["ptBR"] = "Vale do Véu de Inverno", ["ruRU"] = "Долина Зимнего Покрова", ["zhCN"] = "冬幕谷" },
["names"] = { ["enUS"] = "Winter Veil Vale", ["esES"] = "Valle del Velo Invernal", ["ptBR"] = "Vale do Véu de Inverno", ["zhCN"] = "冬幕谷" },
}
end
@@ -885,7 +898,7 @@ if not MTH_DS_Zones[2437] then
["dbcMapId"] = 389,
["dbcName"] = "Ragefire",
["worldBounds"] = { left=452.87, right=-285.99, top=39.62, bottom=-452.95 },
["names"] = { ["deDE"] = "Der Flammenschlund", ["enUS"] = "Ragefire Chasm", ["esES"] = "Sima Ígnea", ["ptBR"] = "Cavernas Ígneas", ["ruRU"] = "Огненная Пропасть", ["zhCN"] = "怒焰裂谷" },
["names"] = { ["enUS"] = "Ragefire Chasm", ["esES"] = "Sima Ígnea", ["ptBR"] = "Cavernas Ragefire", ["zhCN"] = "怒焰裂谷" },
}
end
@@ -898,7 +911,7 @@ if not MTH_DS_Zones[1176] then
["dbcMapId"] = 209,
["dbcName"] = "ZulFarrak",
["worldBounds"] = { left=1625.00, right=241.67, top=2052.08, bottom=1129.17 },
["names"] = { ["deDE"] = "Zul'Farrak", ["enUS"] = "Zul'Farrak", ["esES"] = "Zul'Farrak", ["ptBR"] = "Zul'farrak", ["ruRU"] = "Зул'Фаррак", ["zhCN"] = "祖尔法拉克" },
["names"] = { ["enUS"] = "Zul'Farrak", ["esES"] = "Zul'Farrak", ["ptBR"] = "Zul'Farrak", ["zhCN"] = "祖尔法拉克" },
}
end
@@ -911,7 +924,7 @@ if not MTH_DS_Zones[1477] then
["dbcMapId"] = 109,
["dbcName"] = "TheTempleOfAtalHakkar",
["worldBounds"] = { left=442.76, right=-252.27, top=-255.17, bottom=-718.52 },
["names"] = { ["deDE"] = "Der Tempel von Atal'Hakkar", ["enUS"] = "The Temple of Atal'Hakkar", ["esES"] = "El Templo de Atal'hakkar", ["ptBR"] = "Templo de Atal'hakkar", ["ruRU"] = "Храм Атал'Хаккара", ["zhCN"] = "阿塔哈卡神庙" },
["names"] = { ["enUS"] = "The Temple of Atal'Hakkar", ["esES"] = "Templo de Atal'Hakkar", ["ptBR"] = "O Templo de Atal'Hakkar", ["zhCN"] = "阿塔哈卡神庙" },
}
end
@@ -924,7 +937,7 @@ if not MTH_DS_Zones[719] then
["dbcMapId"] = 48,
["dbcName"] = "BlackFathomDeeps",
["worldBounds"] = { left=485.41, right=-736.46, top=-107.91, bottom=-914.33 },
["names"] = { ["deDE"] = "Tiefschwarze Grotte", ["enUS"] = "Blackfathom Deeps", ["esES"] = "Cavernas de Brazanegra", ["ptBR"] = "Profundezas Negras", ["ruRU"] = "Непроглядная Пучина", ["zhCN"] = "黑暗深渊" },
["names"] = { ["enUS"] = "Blackfathom Deeps", ["esES"] = "Cavernas de Brazanegra", ["ptBR"] = "Profundezas Negras", ["zhCN"] = "黑暗深渊" },
}
end
@@ -937,7 +950,7 @@ if not MTH_DS_Zones[717] then
["dbcMapId"] = 34,
["dbcName"] = "TheStockade",
["worldBounds"] = { left=189.82, right=-188.33, top=220.63, bottom=-31.47 },
["names"] = { ["deDE"] = "Das Verlies", ["enUS"] = "The Stockade", ["esES"] = "Las Mazmorras", ["ptBR"] = "O Cárcere", ["ruRU"] = "Тюрьма", ["zhCN"] = "监狱" },
["names"] = { ["enUS"] = "The Stockade", ["esES"] = "La Mazmorras", ["ptBR"] = "A Prisão", ["zhCN"] = "监狱" },
}
end
@@ -950,7 +963,7 @@ if not MTH_DS_Zones[721] then
["dbcMapId"] = 90,
["dbcName"] = "Gnomeregan",
["worldBounds"] = { left=491.90, right=-277.77, top=-180.89, bottom=-694.00 },
["names"] = { ["deDE"] = "Gnomeregan", ["enUS"] = "Gnomeregan", ["esES"] = "Gnomeregan", ["ptBR"] = "Gnomeregan", ["ruRU"] = "Гномреган", ["zhCN"] = "诺莫瑞根" },
["names"] = { ["enUS"] = "Gnomeregan", ["esES"] = "Gnomeregan", ["ptBR"] = "Gnomeregan", ["zhCN"] = "诺莫瑞根" },
}
end
@@ -963,7 +976,7 @@ if not MTH_DS_Zones[1337] then
["dbcMapId"] = 70,
["dbcName"] = "Uldaman",
["worldBounds"] = { left=645.12, right=-248.55, top=204.31, bottom=-391.47 },
["names"] = { ["deDE"] = "Uldaman", ["enUS"] = "Uldaman", ["esES"] = "Uldaman", ["ptBR"] = "Uldaman", ["ruRU"] = "Ульдаман", ["zhCN"] = "奥达曼" },
["names"] = { ["enUS"] = "Uldaman", ["esES"] = "Uldaman", ["ptBR"] = "Uldaman", ["zhCN"] = "奥达曼" },
}
end
@@ -975,8 +988,8 @@ if not MTH_DS_Zones[2717] then
["dbcAreaId"] = 2717,
["dbcMapId"] = 409,
["dbcName"] = "MoltenCore",
["worldBounds"] = { left=-11.00, right=-1506.00, top=1439.00, bottom=456.00 },
["names"] = { ["deDE"] = "Geschmolzener Kern", ["enUS"] = "Molten Core", ["esES"] = "Núcleo de Magma", ["ptBR"] = "Núcleo Derretido", ["ruRU"] = "Огненные Недра", ["zhCN"] = "熔火之心" },
["worldBounds"] = { left=-130.76, right=-1395.56, top=1303.06, bottom=459.86 },
["names"] = { ["enUS"] = "Molten Core", ["esES"] = "Núcleo de Magma", ["ptBR"] = "Núcleo Derretido", ["zhCN"] = "熔火之心" },
}
end
@@ -989,7 +1002,7 @@ if not MTH_DS_Zones[1977] then
["dbcMapId"] = 309,
["dbcName"] = "ZulGurub",
["worldBounds"] = { left=-612.50, right=-2733.33, top=-11225.00, bottom=-12639.58 },
["names"] = { ["deDE"] = "Zul'Gurub", ["enUS"] = "Zul'Gurub", ["esES"] = "Zul'Gurub", ["ptBR"] = "Zul'gurub", ["ruRU"] = "Зул'Гуруб", ["zhCN"] = "祖尔格拉布" },
["names"] = { ["enUS"] = "Zul'Gurub", ["esES"] = "Zul'Gurub", ["ptBR"] = "Zul'Gurub", ["zhCN"] = "祖尔格拉布" },
}
end
@@ -1002,7 +1015,7 @@ if not MTH_DS_Zones[2557] then
["dbcMapId"] = 429,
["dbcName"] = "DireMaul",
["worldBounds"] = { left=887.50, right=-387.50, top=1050.00, bottom=200.00 },
["names"] = { ["deDE"] = "Düsterbruch", ["enUS"] = "Dire Maul", ["esES"] = "La Masacre", ["ptBR"] = "Gládio Cruel", ["ruRU"] = "Забытый Город", ["zhCN"] = "厄运之槌" },
["names"] = { ["enUS"] = "Dire Maul", ["esES"] = "La Masacre", ["ptBR"] = "Gládio Cruel", ["zhCN"] = "厄运之槌" },
}
end
@@ -1014,8 +1027,8 @@ if not MTH_DS_Zones[1584] then
["dbcAreaId"] = 1584,
["dbcMapId"] = 230,
["dbcName"] = "BlackrockDepths",
["worldBounds"] = { left=875.00, right=-1110.00, top=1513.00, bottom=245.00 },
["names"] = { ["deDE"] = "Schwarzfelstiefen", ["enUS"] = "Blackrock Depths", ["esES"] = "Profundidades de Roca Negra", ["ptBR"] = "Abismo Rocha Negra", ["ruRU"] = "Глубины Черной Горы", ["zhCN"] = "黑石深渊" },
["worldBounds"] = { left=522.34, right=-884.72, top=1186.68, bottom=248.64 },
["names"] = { ["enUS"] = "Blackrock Depths", ["esES"] = "Profundidades de Roca Negra", ["ptBR"] = "Abismo Rocha Negra", ["zhCN"] = "黑石深渊" },
}
end
@@ -1028,7 +1041,7 @@ if not MTH_DS_Zones[3429] then
["dbcMapId"] = 509,
["dbcName"] = "RuinsofAhnQiraj",
["worldBounds"] = { left=3035.42, right=522.92, top=-8233.33, bottom=-9908.33 },
["names"] = { ["deDE"] = "Ruinen von Ahn'Qiraj", ["enUS"] = "Ruins of Ahn'Qiraj", ["esES"] = "Ruinas de Ahn'Qiraj", ["ptBR"] = "Ruínas de Ahn'qiraj", ["ruRU"] = "Руины Ан'Киража", ["zhCN"] = "安其拉废墟" },
["names"] = { ["enUS"] = "Ruins of Ahn'Qiraj", ["esES"] = "Ruinas de Ahn'Qiraj", ["ptBR"] = "Ruínas de Ahn'Qiraj", ["zhCN"] = "安其拉废墟" },
}
end
@@ -1041,7 +1054,7 @@ if not MTH_DS_Zones[2159] then
["dbcMapId"] = 249,
["dbcName"] = "OnyxiasLair",
["worldBounds"] = { left=111.38, right=-371.73, top=98.25, bottom=-223.83 },
["names"] = { ["deDE"] = "Onyxias Hort", ["enUS"] = "Onyxia's Lair", ["esES"] = "Guarida de Onyxia", ["ptBR"] = "Covil da Onyxia", ["ruRU"] = "Логово Ониксии", ["zhCN"] = "奥妮克希亚的巢穴" },
["names"] = { ["enUS"] = "Onyxia's Lair", ["esES"] = "Guarida de Onyxia", ["ptBR"] = "Caverna de Onyxia", ["zhCN"] = "奥妮克希亚的巢穴" },
}
end
@@ -1054,7 +1067,7 @@ if not MTH_DS_Zones[1583] then
["dbcMapId"] = 229,
["dbcName"] = "BlackrockSpire",
["worldBounds"] = { left=10.59, right=-876.25, top=304.40, bottom=-286.83 },
["names"] = { ["deDE"] = "Schwarzfelsspitze", ["enUS"] = "Blackrock Spire", ["esES"] = "Cumbre de Roca Negra", ["ptBR"] = "Pico da Rocha Negra", ["ruRU"] = "Пик Черной Горы", ["zhCN"] = "黑石塔" },
["names"] = { ["enUS"] = "Blackrock Spire", ["esES"] = "Cumbre de Roca Negra", ["ptBR"] = "Pico Rocha Negra", ["zhCN"] = "黑石塔" },
}
end
@@ -1067,7 +1080,7 @@ if not MTH_DS_Zones[718] then
["dbcMapId"] = 43,
["dbcName"] = "WailingCaverns",
["worldBounds"] = { left=790.00, right=-380.00, top=215.00, bottom=-570.00 },
["names"] = { ["deDE"] = "Höhlen des Wehklagens", ["enUS"] = "Wailing Caverns", ["esES"] = "Cuevas de los Lamentos", ["ptBR"] = "Caverna Ululante", ["ruRU"] = "Пещеры Стенаний", ["zhCN"] = "哀嚎洞穴" },
["names"] = { ["enUS"] = "Wailing Caverns", ["esES"] = "Cuevas de los Lamentos", ["ptBR"] = "Cavernas Uivantes", ["zhCN"] = "哀嚎洞穴" },
}
end
@@ -1080,7 +1093,7 @@ if not MTH_DS_Zones[2100] then
["dbcMapId"] = 349,
["dbcName"] = "Maraudon",
["worldBounds"] = { left=485.41, right=-1626.68, top=1199.76, bottom=-211.13 },
["names"] = { ["deDE"] = "Maraudon", ["enUS"] = "Maraudon", ["esES"] = "Maraudon", ["ptBR"] = "Maraudon", ["ruRU"] = "Мародон", ["zhCN"] = "玛拉顿" },
["names"] = { ["enUS"] = "Maraudon", ["esES"] = "Maraudon", ["ptBR"] = "Maraudon", ["zhCN"] = "玛拉顿" },
}
end
@@ -1093,7 +1106,7 @@ if not MTH_DS_Zones[2677] then
["dbcMapId"] = 469,
["dbcName"] = "BlackwingLair",
["worldBounds"] = { left=-844.62, right=-1344.05, top=-7394.12, bottom=-7727.07 },
["names"] = { ["deDE"] = "Pechschwingenhort", ["enUS"] = "Blackwing Lair", ["esES"] = "Guarida de Alanegra", ["ptBR"] = "Covil Asa Negra", ["ruRU"] = "Логово Крыла Тьмы", ["zhCN"] = "黑翼之巢" },
["names"] = { ["enUS"] = "Blackwing Lair", ["esES"] = "Guarida Alanegra", ["ptBR"] = "Covil Asa Negra", ["zhCN"] = "黑翼之巢" },
}
end
@@ -1106,7 +1119,7 @@ if not MTH_DS_Zones[5138] then
["dbcMapId"] = 36,
["dbcName"] = "TheDeadmines",
["worldBounds"] = { left=-322.94, right=-979.53, top=36.93, bottom=-398.04 },
["names"] = { ["deDE"] = "Die Todesminen", ["enUS"] = "The Deadmines", ["esES"] = "Las Minas de la Muerte", ["ptBR"] = "Minas Mortas", ["ruRU"] = "Мертвые Копи", ["zhCN"] = "死亡矿井" },
["names"] = { ["enUS"] = "The Deadmines", ["esES"] = "Las Minas de la Muerte", ["ptBR"] = "As Minas Mortas", ["zhCN"] = "死亡矿井" },
}
end
@@ -1118,8 +1131,8 @@ if not MTH_DS_Zones[722] then
["dbcAreaId"] = 722,
["dbcMapId"] = 129,
["dbcName"] = "RazorfenDowns",
["worldBounds"] = { left=1271.00, right=390.00, top=2683.00, bottom=2094.00 },
["names"] = { ["deDE"] = "Hügel der Klingenhauer", ["enUS"] = "Razorfen Downs", ["esES"] = "Zahúrda Rajacieno", ["ptBR"] = "Urzal dos Mortos", ["ruRU"] = "Курганы Иглошкурых", ["zhCN"] = "剃刀高地" },
["worldBounds"] = { left=1279.94, right=570.89, top=2682.55, bottom=2209.85 },
["names"] = { ["enUS"] = "Razorfen Downs", ["esES"] = "Tierras Bajas de Rajacieno", ["ptBR"] = "Razorfen Downs", ["zhCN"] = "剃刀高地" },
}
end
@@ -1132,7 +1145,7 @@ if not MTH_DS_Zones[491] then
["dbcMapId"] = 47,
["dbcName"] = "RazorfenKraul",
["worldBounds"] = { left=2058.92, right=1322.47, top=2349.64, bottom=1858.68 },
["names"] = { ["deDE"] = "Kral der Klingenhauer", ["enUS"] = "Razorfen Kraul", ["esES"] = "Horado Rajacieno", ["ptBR"] = "Urzal dos Tuscos", ["ruRU"] = "Лабиринты Иглошкурых", ["zhCN"] = "剃刀沼泽" },
["names"] = { ["enUS"] = "Razorfen Kraul", ["esES"] = "Madriguera de Rajacieno", ["ptBR"] = "Razorfen Kraul", ["zhCN"] = "剃刀沼泽" },
}
end
@@ -1145,7 +1158,7 @@ if not MTH_DS_Zones[5136] then
["dbcMapId"] = 189,
["dbcName"] = "ScarletMonastery",
["worldBounds"] = { left=1567.97, right=947.99, top=2030.18, bottom=1616.86 },
["names"] = { ["deDE"] = "Friedhof des Scharlachroten Klosters", ["enUS"] = "Scarlet Monastery Graveyard", ["esES"] = "Cementerio Monasterio Escarlata", ["ptBR"] = "Cemitério do Monastério Escarlate", ["ruRU"] = "Кладбище Монастыря Алого Ордена", ["zhCN"] = "血色修道院-墓地" },
["names"] = { ["enUS"] = "Scarlet Monastery Graveyard", ["esES"] = "Cementerio Monasterio Escarlata", ["ptBR"] = "Cemitério do Monastério Escarlate", ["zhCN"] = "血色修道院-墓地" },
}
end
@@ -1158,7 +1171,7 @@ if not MTH_DS_Zones[5135] then
["dbcMapId"] = 189,
["dbcName"] = "ScarletMonastery2f",
["worldBounds"] = { left=-162.27, right=-482.46, top=307.37, bottom=93.91 },
["names"] = { ["deDE"] = "Bibliothek des Scharlachroten Klosters", ["enUS"] = "Scarlet Monastery Library", ["esES"] = "Biblioteca Monasterio Escarlata", ["ptBR"] = "Biblioteca do Monastério Escarlate", ["ruRU"] = "Библиотека Монастыря Алого Ордена", ["zhCN"] = "血色修道院-图书馆" },
["names"] = { ["enUS"] = "Scarlet Monastery Library", ["esES"] = "Biblioteca Monasterio Escarlata", ["ptBR"] = "Biblioteca do Monastério Escarlate", ["zhCN"] = "血色修道院-图书馆" },
}
end
@@ -1171,7 +1184,7 @@ if not MTH_DS_Zones[5153] then
["dbcMapId"] = 189,
["dbcName"] = "ScarletMonastery3f",
["worldBounds"] = { left=50.27, right=-562.42, top=2009.10, bottom=1600.64 },
["names"] = { ["deDE"] = "Waffenkammer des Scharlachroten Klosters", ["enUS"] = "Scarlet Monastery Armory", ["esES"] = "Armería Monasterio Escarlata", ["ptBR"] = "Arsenal do Monastério Escarlate", ["ruRU"] = "Оружейная Монастыря Алого Ордена", ["zhCN"] = "血色修道院-军械库" },
["names"] = { ["enUS"] = "Scarlet Monastery Armory", ["esES"] = "Armería Monasterio Escarlata", ["ptBR"] = "Arsenal do Monastério Escarlate", ["zhCN"] = "血色修道院-军械库" },
}
end
@@ -1184,7 +1197,7 @@ if not MTH_DS_Zones[5163] then
["dbcMapId"] = 189,
["dbcName"] = "ScarletMonastery4f",
["worldBounds"] = { left=1743.99, right=1040.69, top=1281.29, bottom=812.42 },
["names"] = { ["deDE"] = "Kathedrale des Scharlachroten Klosters", ["enUS"] = "Scarlet Monastery Cathedral", ["esES"] = "Catedral Monasterio Escarlata", ["ptBR"] = "Catedral do Monastério Escarlate", ["ruRU"] = "Собор Монастыря Алого Ордена", ["zhCN"] = "血色修道院-大教堂" },
["names"] = { ["enUS"] = "Scarlet Monastery Cathedral", ["esES"] = "Catedral Monasterio Escarlata", ["ptBR"] = "Catedral do Monastério Escarlate", ["zhCN"] = "血色修道院-大教堂" },
}
end
@@ -1197,7 +1210,7 @@ if not MTH_DS_Zones[2057] then
["dbcMapId"] = 289,
["dbcName"] = "Scholomance",
["worldBounds"] = { left=251.41, right=-68.64, top=317.70, bottom=104.33 },
["names"] = { ["deDE"] = "Scholomance", ["enUS"] = "Scholomance", ["esES"] = "Scholomance", ["ptBR"] = "Scolomântia", ["ruRU"] = "Некроситет", ["zhCN"] = "通灵学院" },
["names"] = { ["enUS"] = "Scholomance", ["esES"] = "Scholomance", ["ptBR"] = "Scholomance", ["zhCN"] = "通灵学院" },
}
end
@@ -1210,7 +1223,7 @@ if not MTH_DS_Zones[209] then
["dbcMapId"] = 33,
["dbcName"] = "ShadowfangKeep",
["worldBounds"] = { left=2436.00, right=2055.00, top=-61.00, bottom=-315.00 },
["names"] = { ["deDE"] = "Burg Schattenfang", ["enUS"] = "Shadowfang Keep", ["esES"] = "Castillo de Colmillo Oscuro", ["ptBR"] = "Bastilha da Presa Negra", ["ruRU"] = "Крепость Темного Клыка", ["zhCN"] = "影牙城堡" },
["names"] = { ["enUS"] = "Shadowfang Keep", ["esES"] = "Fortaleza Colmillo Oscuro", ["ptBR"] = "Fortaleza Shadowfang", ["zhCN"] = "影牙城堡" },
}
end
@@ -1223,7 +1236,7 @@ if not MTH_DS_Zones[2017] then
["dbcMapId"] = 329,
["dbcName"] = "Stratholme",
["worldBounds"] = { left=-2639.83, right=-3825.18, top=4163.90, bottom=3374.04 },
["names"] = { ["deDE"] = "Stratholme", ["enUS"] = "Stratholme", ["esES"] = "Stratholme", ["ptBR"] = "Stratholme", ["ruRU"] = "Стратхольм", ["zhCN"] = "斯坦索姆" },
["names"] = { ["enUS"] = "Stratholme", ["esES"] = "Stratholme", ["ptBR"] = "Stratholme", ["zhCN"] = "斯坦索姆" },
}
end
@@ -1236,7 +1249,7 @@ if not MTH_DS_Zones[3428] then
["dbcMapId"] = 531,
["dbcName"] = "AhnQiraj",
["worldBounds"] = { left=2515.63, right=1538.07, top=-8051.80, bottom=-8703.50 },
["names"] = { ["deDE"] = "Ahn'Qiraj", ["enUS"] = "Ahn'Qiraj", ["esES"] = "Ahn'Qiraj", ["ptBR"] = "Ahn'qiraj", ["ruRU"] = "Ан'Кираж", ["zhCN"] = "安其拉" },
["names"] = { ["enUS"] = "Ahn'Qiraj", ["esES"] = "Ahn'Qiraj", ["ptBR"] = "Ahn'Qiraj", ["zhCN"] = "安其拉" },
}
end
@@ -1249,7 +1262,7 @@ if not MTH_DS_Zones[5147] then
["dbcMapId"] = 531,
["dbcName"] = "AhnQiraj2f",
["worldBounds"] = { left=2915.62, right=138.08, top=-7659.29, bottom=-9510.98 },
["names"] = { ["deDE"] = "Ahn'Qiraj", ["enUS"] = "Ahn'Qiraj", ["esES"] = "Ahn'Qiraj", ["ptBR"] = "Ahn'qiraj", ["ruRU"] = "Ан'Кираж", ["zhCN"] = "安其拉" },
["names"] = { ["enUS"] = "Ahn'Qiraj", ["esES"] = "Ahn'Qiraj", ["ptBR"] = "Ahn'Qiraj", ["zhCN"] = "安其拉" },
}
end
@@ -1262,7 +1275,7 @@ if not MTH_DS_Zones[3457] then
["dbcMapId"] = 532,
["dbcName"] = "Karazhan",
["worldBounds"] = { left=-1614.00, right=-2212.00, top=-10780.00, bottom=-11179.00 },
["names"] = { ["deDE"] = "Turm von Karazhan", ["enUS"] = "Tower of Karazhan", ["esES"] = "Torre de Karazhan", ["ptBR"] = "Torre de Karazhan", ["ruRU"] = "Каражан", ["zhCN"] = "卡拉赞之塔" },
["names"] = { ["enUS"] = "Tower of Karazhan", ["esES"] = "Torre de Karazhan", ["ptBR"] = "Karazhan", ["zhCN"] = "卡拉赞" },
}
end
@@ -1275,7 +1288,7 @@ if not MTH_DS_Zones[2257] then
["dbcMapId"] = 369,
["dbcName"] = "DeeprunTram",
["worldBounds"] = { left=2623.50, right=2311.50, top=95.50, bottom=-112.50 },
["names"] = { ["deDE"] = "Tiefenbahn", ["enUS"] = "Deeprun Tram", ["esES"] = "Tranvía Subterráneo", ["ptBR"] = "Metrô Correfundo", ["ruRU"] = "Подземный Поезд", ["zhCN"] = "矿道地铁" },
["names"] = { ["enUS"] = "Deeprun Tram", ["esES"] = "Tranvía Subterráneo", ["ptBR"] = "Metrô Correfundo", ["zhCN"] = "矿道地铁" },
}
end
@@ -1288,7 +1301,7 @@ if not MTH_DS_Zones[5144] then
["dbcMapId"] = 369,
["dbcName"] = "DeeprunTram2f",
["worldBounds"] = { left=187.50, right=-121.50, top=95.50, bottom=-112.50 },
["names"] = { ["deDE"] = "Tiefenbahn", ["enUS"] = "Deeprun Tram", ["esES"] = "Tranvía Subterráneo", ["ptBR"] = "Metrô Correfundo", ["ruRU"] = "Подземный Поезд", ["zhCN"] = "矿道地铁" },
["names"] = { ["enUS"] = "Deeprun Tram", ["esES"] = "Tranvía Profundocircuito", ["ptBR"] = "Metrô Correfundo", ["zhCN"] = "矿道地铁" },
}
end
@@ -1301,7 +1314,7 @@ if not MTH_DS_Zones[5204] then
["dbcMapId"] = 269,
["dbcName"] = "BlackMorass",
["worldBounds"] = { left=7338.47, right=6066.48, top=-1247.55, bottom=-2093.03 },
["names"] = { ["deDE"] = "Der Schwarze Morast", ["enUS"] = "The Black Morass", ["esES"] = "El Morass Negro", ["ptBR"] = "Lamaçal Negro", ["ruRU"] = "Черные Топи", ["zhCN"] = "黑色沼泽" },
["names"] = { ["enUS"] = "The Black Morass", ["esES"] = "El Morass Negro", ["ptBR"] = "Lamaçal Negro", ["zhCN"] = "黑色沼泽" },
}
end
@@ -1314,7 +1327,7 @@ if not MTH_DS_Zones[2366] then
["dbcMapId"] = 269,
["dbcName"] = "BlackMorass2f",
["worldBounds"] = { left=7651.85, right=6565.99, top=-1500.47, bottom=-2227.08 },
["names"] = { ["deDE"] = "Der Schwarze Morast", ["enUS"] = "The Black Morass", ["esES"] = "La Ciénaga Negra", ["ptBR"] = "O Morass Negro", ["ruRU"] = "Черные Топи", ["zhCN"] = "黑色沼泽" },
["names"] = { ["enUS"] = "The Black Morass", ["esES"] = "La Ciénaga Negra", ["ptBR"] = "O Morass Negro", ["zhCN"] = "黑色沼泽" },
}
end
@@ -1327,7 +1340,7 @@ if not MTH_DS_Zones[5208] then
["dbcMapId"] = 815,
["dbcName"] = "GilneasCity",
["worldBounds"] = { left=3290.32, right=2040.14, top=-760.72, bottom=-1598.16 },
["names"] = { ["deDE"] = "Gilneas", ["enUS"] = "Gilneas City", ["esES"] = "Ciudad Gilneas", ["ptBR"] = "Cidade de Gilneas", ["ruRU"] = "Гилнеас", ["zhCN"] = "吉尔尼斯城" },
["names"] = { ["enUS"] = "Gilneas City", ["esES"] = "Ciudad Gilneas", ["ptBR"] = "Cidade de Gilneas", ["zhCN"] = "吉尔尼斯城" },
}
end
@@ -1340,7 +1353,7 @@ if not MTH_DS_Zones[3456] then
["dbcMapId"] = 533,
["dbcName"] = "Naxxramas",
["worldBounds"] = { left=-2375.27, right=-4366.96, top=3656.70, bottom=2338.28 },
["names"] = { ["deDE"] = "Naxxramas", ["enUS"] = "Naxxramas", ["esES"] = "Naxxramas", ["ptBR"] = "Naxxramas", ["ruRU"] = "Наксрамас", ["zhCN"] = "纳克萨玛斯" },
["names"] = { ["enUS"] = "Naxxramas", ["esES"] = "Naxxramas", ["ptBR"] = "Naxxramas", ["zhCN"] = "纳克萨玛斯" },
}
end
@@ -1353,7 +1366,7 @@ if not MTH_DS_Zones[5148] then
["dbcMapId"] = 533,
["dbcName"] = "Naxxramas2f",
["worldBounds"] = { left=-4869.36, right=-5521.46, top=3816.56, bottom=3376.89 },
["names"] = { ["deDE"] = "Die Höhere Nekropole", ["enUS"] = "The Upper Necropolis", ["esES"] = "La Necropolis Superior", ["ptBR"] = "Necrópole Superior", ["ruRU"] = "Верхний Некрополь", ["zhCN"] = "上层大墓地" },
["names"] = { ["enUS"] = "The Upper Necropolis", ["esES"] = "La Necropolis Superior", ["ptBR"] = "Necrópole Superior", ["zhCN"] = "上层大墓地" },
}
end
@@ -1366,7 +1379,7 @@ if not MTH_DS_Zones[5077] then
["dbcMapId"] = 802,
["dbcName"] = "CrescentGrove",
["worldBounds"] = { left=1207.72, right=-1435.49, top=882.98, bottom=-868.18 },
["names"] = { ["deDE"] = "Mondsichelhain", ["enUS"] = "Crescent Grove", ["esES"] = "Claro de la Media Luna", ["ptBR"] = "Bosque Crescente", ["ruRU"] = "Роща Полумесяца", ["zhCN"] = "新月林地" },
["names"] = { ["enUS"] = "Crescent Grove", ["esES"] = "Claro de la Media Luna", ["ptBR"] = "Bosque Crescente", ["zhCN"] = "新月林地" },
}
end
@@ -1379,7 +1392,7 @@ if not MTH_DS_Zones[5103] then
["dbcMapId"] = 808,
["dbcName"] = "HateforgeQuarry",
["worldBounds"] = { left=-3024.33, right=-3776.45, top=-7888.28, bottom=-8398.61 },
["names"] = { ["deDE"] = "Steinbruch der Hassschmiede", ["enUS"] = "Hateforge Quarry", ["esES"] = "Cantera Hateforge", ["ptBR"] = "Pedreira Forja do Ódio", ["ruRU"] = "Карьер Кузни Ненависти", ["zhCN"] = "仇恨熔炉采石场" },
["names"] = { ["enUS"] = "Hateforge Quarry", ["esES"] = "Cantera Hateforge", ["ptBR"] = "Pedreira Forja do Ódio", ["zhCN"] = "仇恨熔炉采石场" },
}
end
@@ -1392,7 +1405,7 @@ if not MTH_DS_Zones[5086] then
["dbcMapId"] = 800,
["dbcName"] = "KarazhanCrypt",
["worldBounds"] = { left=-1302.51, right=-1849.26, top=-10916.17, bottom=-11308.14 },
["names"] = { ["deDE"] = "Karazhan Krypta", ["enUS"] = "Karazhan Crypt", ["esES"] = "Cripta de Karazhan", ["ptBR"] = "Cripta de Karazhan", ["ruRU"] = "Склеп Каражана", ["zhCN"] = "卡拉赞墓穴" },
["names"] = { ["enUS"] = "Karazhan Crypt", ["esES"] = "Cripta de Karazhan", ["ptBR"] = "Cripta Karazhan", ["zhCN"] = "卡拉赞墓穴" },
}
end
@@ -1405,7 +1418,7 @@ if not MTH_DS_Zones[5087] then
["dbcMapId"] = 35,
["dbcName"] = "StormwindVault",
["worldBounds"] = { left=314.34, right=-40.16, top=89.30, bottom=-145.44 },
["names"] = { ["deDE"] = "Gewölbe von Sturmwind", ["enUS"] = "Stormwind Vault", ["esES"] = "Cámara de Ventormenta", ["ptBR"] = "Cofre de Ventobravo", ["ruRU"] = "Тюрьма Штормграда", ["zhCN"] = "暴风城地牢" },
["names"] = { ["enUS"] = "Stormwind Vault", ["esES"] = "Bóveda de Ventormenta", ["ptBR"] = "Cofre Stormwind", ["zhCN"] = "暴风城地牢" },
}
end
@@ -1418,7 +1431,7 @@ if not MTH_DS_Zones[5097] then
["dbcMapId"] = 807,
["dbcName"] = "EmeraldSanctum",
["worldBounds"] = { left=3939.10, right=2666.00, top=3519.72, bottom=2666.00 },
["names"] = { ["deDE"] = "Smaragdsanktum", ["enUS"] = "Emerald Sanctum", ["esES"] = "Sanctum Esmeralda", ["ptBR"] = "Santuário Esmeralda", ["ruRU"] = "Изумрудное Святилище", ["zhCN"] = "翡翠圣殿" },
["names"] = { ["enUS"] = "Emerald Sanctum", ["esES"] = "Sanctum Esmeralda", ["ptBR"] = "Santuário Esmeralda", ["zhCN"] = "翡翠圣殿" },
}
end
@@ -1431,7 +1444,7 @@ if not MTH_DS_Zones[5053] then
["dbcMapId"] = 801,
["dbcName"] = "Moomoo",
["worldBounds"] = { left=17296.30, right=16288.62, top=17158.52, bottom=16486.73 },
["names"] = { ["deDE"] = "Moomoo Hain", ["enUS"] = "Moomoo Grove", ["esES"] = "Claro Moomoo", ["ptBR"] = "Bosque Moomoo", ["ruRU"] = "Роща Муумуу", ["zhCN"] = "奶牛树林" },
["names"] = { ["enUS"] = "Moomoo Grove", ["esES"] = "Claro Moomoo", ["ptBR"] = "Bosque Moomoo", ["zhCN"] = "奶牛树林" },
}
end
@@ -1444,7 +1457,7 @@ if not MTH_DS_Zones[3457] then
["dbcMapId"] = 814,
["dbcName"] = "UpperKarazhan",
["worldBounds"] = { left=-1378.00, right=-2201.00, top=-10887.00, bottom=-11436.00 },
["names"] = { ["deDE"] = "Turm von Karazhan", ["enUS"] = "Tower of Karazhan", ["esES"] = "Torre de Karazhan", ["ptBR"] = "Torre de Karazhan", ["ruRU"] = "Каражан", ["zhCN"] = "卡拉赞之塔" },
["names"] = { ["enUS"] = "Tower of Karazhan", ["esES"] = "Torre de Karazhan", ["ptBR"] = "Karazhan", ["zhCN"] = "卡拉赞" },
}
end
@@ -1457,84 +1470,6 @@ if not MTH_DS_Zones[5557] then
["dbcMapId"] = 814,
["dbcName"] = "UpperKarazhan2f",
["worldBounds"] = { left=-1483.00, right=-4283.00, top=-5800.00, bottom=-7668.00 },
["names"] = { ["deDE"] = "Der Fels der Verwüstung", ["enUS"] = "The Rock of Desolation", ["esES"] = "La Roca de la Desolación", ["ptBR"] = "A Pedra da Desolação", ["ruRU"] = "Скала Запустения", ["zhCN"] = "荒芜巨岩" },
}
end
-- DBC WMA ID=684 MapID=0 'GrimReaches'
if not MTH_DS_Zones[5602] then
MTH_DS_Zones[5602] = {
["continent"] = 0,
["parent"] = 0,
["dbcAreaId"] = 5602,
["dbcMapId"] = 0,
["dbcName"] = "GrimReaches",
["worldBounds"] = { left=-2072.00, right=-7459.00, top=-2904.00, bottom=-6488.00 },
["names"] = { ["deDE"] = "Düsterweiten", ["enUS"] = "Grim Reaches", ["esES"] = "Territorios Sombríos", ["ptBR"] = "Recônditos Sombrios", ["ruRU"] = "Пределы Мрака", ["zhCN"] = "冷酷海岸" },
}
end
-- DBC WMA ID=685 MapID=0 'Balor'
if not MTH_DS_Zones[5561] then
MTH_DS_Zones[5561] = {
["continent"] = 0,
["parent"] = 0,
["dbcAreaId"] = 5561,
["dbcMapId"] = 0,
["dbcName"] = "Balor",
["worldBounds"] = { left=4728.00, right=1630.00, top=-7577.00, bottom=-9645.00 },
["names"] = { ["deDE"] = "Balor", ["enUS"] = "Balor", ["esES"] = "Balor", ["ptBR"] = "Balor", ["ruRU"] = "Балор", ["zhCN"] = "巴洛" },
}
end
-- DBC WMA ID=686 MapID=0 'Northwind'
if not MTH_DS_Zones[5581] then
MTH_DS_Zones[5581] = {
["continent"] = 0,
["parent"] = 0,
["dbcAreaId"] = 5581,
["dbcMapId"] = 0,
["dbcName"] = "Northwind",
["worldBounds"] = { left=2258.00, right=-983.00, top=-6327.00, bottom=-8484.00 },
["names"] = { ["deDE"] = "Nordwind", ["enUS"] = "Northwind", ["esES"] = "Viento Norte", ["ptBR"] = "Vento Norte", ["ruRU"] = "Северный Ветер", ["zhCN"] = "北风领" },
}
end
-- DBC WMA ID=689 MapID=1 'DireMaulEntrance'
if not MTH_DS_Zones[2557] then
MTH_DS_Zones[2557] = {
["continent"] = 1,
["parent"] = 1,
["dbcAreaId"] = 2557,
["dbcMapId"] = 1,
["dbcName"] = "DireMaulEntrance",
["worldBounds"] = { left=2014.00, right=690.00, top=-3401.00, bottom=-4270.00 },
["names"] = { ["deDE"] = "Düsterbruch", ["enUS"] = "Dire Maul", ["esES"] = "La Masacre", ["ptBR"] = "Gládio Cruel", ["ruRU"] = "Забытый Город", ["zhCN"] = "厄运之槌" },
}
end
-- DBC WMA ID=691 MapID=816 'DragonmawRetreat'
if not MTH_DS_Zones[5601] then
MTH_DS_Zones[5601] = {
["continent"] = 816,
["parent"] = 816,
["dbcAreaId"] = 5601,
["dbcMapId"] = 816,
["dbcName"] = "DragonmawRetreat",
["worldBounds"] = { left=-3428.00, right=-5062.00, top=-5599.00, bottom=-6672.00 },
["names"] = { ["deDE"] = "Drachenmal Zuflucht", ["enUS"] = "Dragonmaw Retreat", ["esES"] = "Retiro Faucedraco", ["ptBR"] = "Retiro Presa do Dragão", ["ruRU"] = "Приют Драконьей Пасти", ["zhCN"] = "龙喉居所" },
}
end
-- DBC WMA ID=693 MapID=818 'StormwroughtRuins'
if not MTH_DS_Zones[5628] then
MTH_DS_Zones[5628] = {
["continent"] = 818,
["parent"] = 818,
["dbcAreaId"] = 5628,
["dbcMapId"] = 818,
["dbcName"] = "StormwroughtRuins",
["worldBounds"] = { left=-3365.00, right=-5345.00, top=-5424.00, bottom=-6774.00 },
["names"] = { ["deDE"] = "Ruine von Sturmschmied", ["enUS"] = "Stormwrought Ruins", ["esES"] = "Ruinas Forjatormenta", ["ptBR"] = "Ruínas Forjatormenta", ["ruRU"] = "Выкованные Бурей Руины", ["zhCN"] = "风暴废墟" },
["names"] = { ["enUS"] = "???", ["esES"] = "???", ["ptBR"] = "???", ["zhCN"] = "外域" },
}
end
+402
View File
@@ -0,0 +1,402 @@
-- MetaHunt: WMA (WorldMapArea.dbc) zone reference data
-- AUTO-GENERATED by .tools/migrate_wma.py — do not edit by hand.
-- Source: Haxxor WMA CSV (patch-9.mpq)
--
-- Provides MTH_MAP_PFQ_TO_WMA: pfQ AreaTable ID → WMA ID lookup
-- Used by map-markers.lua to translate GetCurrentMapAreaID() results
-- and by GetCurrentMapID() to return WMA zone IDs for coord matching.
--
-- Provides MTH_DS_WMAZones: WMA ID → worldBounds + pfqAreaId
-- Used for map overlay features without modifying the pfQ-keyed MTH_DS_Zones.
if not MTH_DS then MTH_DS = {} end
-- pfQ AreaTable ID → WMA ID runtime bridge
MTH_MAP_PFQ_TO_WMA = {
[1] = 27, -- DunMorogh
[3] = 17, -- Badlands
[4] = 19, -- BlastedLands
[8] = 38, -- SwampOfSorrows
[10] = 34, -- Duskwood
[11] = 40, -- Wetlands
[12] = 30, -- Elwynn
[14] = 4, -- Durotar
[15] = 141, -- Dustwallow
[16] = 181, -- Aszhara
[17] = 11, -- Barrens
[25] = 519, -- BlackrockMountain
[28] = 22, -- WesternPlaguelands
[33] = 37, -- Stranglethorn
[36] = 15, -- Alterac
[38] = 35, -- LochModan
[40] = 39, -- Westfall
[41] = 32, -- DeadwindPass
[44] = 36, -- Redridge
[45] = 16, -- Arathi
[46] = 29, -- BurningSteppes
[47] = 26, -- Hinterlands
[51] = 28, -- SearingGorge
[85] = 20, -- Tirisfal
[130] = 21, -- Silverpine
[139] = 23, -- EasternPlaguelands
[141] = 41, -- Teldrassil
[148] = 42, -- Darkshore
[209] = 650, -- ShadowfangKeep
[215] = 9, -- Mulgore
[267] = 24, -- Hilsbrad
[331] = 43, -- Ashenvale
[357] = 121, -- Feralas
[361] = 182, -- Felwood
[400] = 61, -- ThousandNeedles
[405] = 101, -- Desolace
[406] = 81, -- StonetalonMountains
[408] = 505, -- Gillijim
[409] = 504, -- Lapidis
[440] = 161, -- Tanaris
[490] = 201, -- UngoroCrater
[491] = 641, -- RazorfenKraul
[493] = 241, -- Moonglade
[616] = 501, -- Hyjal
[618] = 281, -- Winterspring
[717] = 611, -- TheStockade
[718] = 516, -- WailingCavernsEntrance
[719] = 609, -- BlackFathomDeeps
[721] = 518, -- GnomereganEntrance
[722] = 639, -- RazorfenDowns
[796] = 520, -- ScarletMonasteryEntrance
[876] = 500, -- GMIsland
[1176] = 605, -- ZulFarrak
[1337] = 521, -- UldamanEntrance
[1377] = 261, -- Silithus
[1477] = 607, -- TheTempleOfAtalHakkar
[1497] = 382, -- Undercity
[1519] = 301, -- Stormwind
[1537] = 341, -- Ironforge
[1581] = 514, -- DeadminesEntrance
[1583] = 629, -- BlackrockSpire
[1584] = 623, -- BlackrockDepths
[1637] = 321, -- Orgrimmar
[1638] = 362, -- ThunderBluff
[1657] = 381, -- Darnassus
[1769] = 700, -- TimbermawTunnels
[1941] = 523, -- CavernsOfTime
[1977] = 619, -- ZulGurub
[2017] = 652, -- Stratholme
[2040] = 509, -- AlahThalas
[2057] = 648, -- Scholomance
[2100] = 517, -- MaraudonEntrance
[2159] = 627, -- OnyxiasLair
[2257] = 659, -- DeeprunTram
[2366] = 663, -- BlackMorass2f
[2437] = 603, -- Ragefire
[2557] = 689, -- DireMaulEntrance
[2597] = 401, -- AlteracValley
[2677] = 635, -- BlackwingLair
[2717] = 617, -- MoltenCore
[3277] = 443, -- WarsongGulch
[3358] = 461, -- ArathiBasin
[3428] = 654, -- AhnQiraj
[3429] = 625, -- RuinsofAhnQiraj
[3456] = 667, -- Naxxramas
[3457] = 682, -- UpperKarazhan
[3478] = 522, -- AhnQirajEntrance
[4012] = 502, -- ScarletEnclave
[5023] = 503, -- Sunnyglade
[5024] = 511, -- Icepoint
[5053] = 680, -- Moomoo
[5077] = 670, -- CrescentGrove
[5086] = 674, -- KarazhanCrypt
[5087] = 676, -- StormwindVault
[5097] = 678, -- EmeraldSanctum
[5103] = 672, -- HateforgeQuarry
[5121] = 507, -- TelAbim
[5130] = 601, -- WinterVeilVale
[5135] = 644, -- ScarletMonastery2f
[5136] = 643, -- ScarletMonastery
[5138] = 637, -- TheDeadmines
[5147] = 655, -- AhnQiraj2f
[5148] = 668, -- Naxxramas2f
[5153] = 645, -- ScarletMonastery3f
[5163] = 646, -- ScarletMonastery4f
[5179] = 510, -- Gilneas
[5204] = 662, -- BlackMorass
[5208] = 665, -- GilneasCity
[5225] = 513, -- ThalassianHighlands
[5536] = 512, -- BlackstoneIsland
[5557] = 683, -- UpperKarazhan2f
[5561] = 685, -- Balor
[5581] = 686, -- Northwind
[5601] = 691, -- DragonmawRetreat
[5602] = 684, -- GrimReaches
[5628] = 693, -- StormwroughtRuins
[5640] = 701, -- TimbermawEntrance
[5641] = 698, -- WindhornCanyon
[5642] = 699, -- Moonwhisper
[5722] = 702, -- ThornGorge
[5723] = 657, -- Karazhan
[5731] = 705, -- WindhornCanyonEntrance
[5734] = 704, -- FrostmaneHollow
}
-- WMA ID → pfQ AreaTable ID (for fallback lookups)
MTH_MAP_WMA_TO_PFQ = {
[4] = 14, -- Durotar
[9] = 215, -- Mulgore
[11] = 17, -- Barrens
[15] = 36, -- Alterac
[16] = 45, -- Arathi
[17] = 3, -- Badlands
[19] = 4, -- BlastedLands
[20] = 85, -- Tirisfal
[21] = 130, -- Silverpine
[22] = 28, -- WesternPlaguelands
[23] = 139, -- EasternPlaguelands
[24] = 267, -- Hilsbrad
[26] = 47, -- Hinterlands
[27] = 1, -- DunMorogh
[28] = 51, -- SearingGorge
[29] = 46, -- BurningSteppes
[30] = 12, -- Elwynn
[32] = 41, -- DeadwindPass
[34] = 10, -- Duskwood
[35] = 38, -- LochModan
[36] = 44, -- Redridge
[37] = 33, -- Stranglethorn
[38] = 8, -- SwampOfSorrows
[39] = 40, -- Westfall
[40] = 11, -- Wetlands
[41] = 141, -- Teldrassil
[42] = 148, -- Darkshore
[43] = 331, -- Ashenvale
[61] = 400, -- ThousandNeedles
[81] = 406, -- StonetalonMountains
[101] = 405, -- Desolace
[121] = 357, -- Feralas
[141] = 15, -- Dustwallow
[161] = 440, -- Tanaris
[181] = 16, -- Aszhara
[182] = 361, -- Felwood
[201] = 490, -- UngoroCrater
[241] = 493, -- Moonglade
[261] = 1377, -- Silithus
[281] = 618, -- Winterspring
[301] = 1519, -- Stormwind
[321] = 1637, -- Orgrimmar
[341] = 1537, -- Ironforge
[362] = 1638, -- ThunderBluff
[381] = 1657, -- Darnassus
[382] = 1497, -- Undercity
[401] = 2597, -- AlteracValley
[443] = 3277, -- WarsongGulch
[461] = 3358, -- ArathiBasin
[500] = 876, -- GMIsland
[501] = 616, -- Hyjal
[502] = 4012, -- ScarletEnclave
[503] = 5023, -- Sunnyglade
[504] = 409, -- Lapidis
[505] = 408, -- Gillijim
[507] = 5121, -- TelAbim
[509] = 2040, -- AlahThalas
[510] = 5179, -- Gilneas
[511] = 5024, -- Icepoint
[512] = 5536, -- BlackstoneIsland
[513] = 5225, -- ThalassianHighlands
[514] = 1581, -- DeadminesEntrance
[516] = 718, -- WailingCavernsEntrance
[517] = 2100, -- MaraudonEntrance
[518] = 721, -- GnomereganEntrance
[519] = 25, -- BlackrockMountain
[520] = 796, -- ScarletMonasteryEntrance
[521] = 1337, -- UldamanEntrance
[522] = 3478, -- AhnQirajEntrance
[523] = 1941, -- CavernsOfTime
[601] = 5130, -- WinterVeilVale
[603] = 2437, -- Ragefire
[605] = 1176, -- ZulFarrak
[607] = 1477, -- TheTempleOfAtalHakkar
[609] = 719, -- BlackFathomDeeps
[611] = 717, -- TheStockade
[617] = 2717, -- MoltenCore
[619] = 1977, -- ZulGurub
[623] = 1584, -- BlackrockDepths
[625] = 3429, -- RuinsofAhnQiraj
[627] = 2159, -- OnyxiasLair
[629] = 1583, -- BlackrockSpire
[635] = 2677, -- BlackwingLair
[637] = 5138, -- TheDeadmines
[639] = 722, -- RazorfenDowns
[641] = 491, -- RazorfenKraul
[643] = 5136, -- ScarletMonastery
[644] = 5135, -- ScarletMonastery2f
[645] = 5153, -- ScarletMonastery3f
[646] = 5163, -- ScarletMonastery4f
[648] = 2057, -- Scholomance
[650] = 209, -- ShadowfangKeep
[652] = 2017, -- Stratholme
[654] = 3428, -- AhnQiraj
[655] = 5147, -- AhnQiraj2f
[657] = 5723, -- Karazhan
[659] = 2257, -- DeeprunTram
[662] = 5204, -- BlackMorass
[663] = 2366, -- BlackMorass2f
[665] = 5208, -- GilneasCity
[667] = 3456, -- Naxxramas
[668] = 5148, -- Naxxramas2f
[670] = 5077, -- CrescentGrove
[672] = 5103, -- HateforgeQuarry
[674] = 5086, -- KarazhanCrypt
[676] = 5087, -- StormwindVault
[678] = 5097, -- EmeraldSanctum
[680] = 5053, -- Moomoo
[682] = 3457, -- UpperKarazhan
[683] = 5557, -- UpperKarazhan2f
[684] = 5602, -- GrimReaches
[685] = 5561, -- Balor
[686] = 5581, -- Northwind
[689] = 2557, -- DireMaulEntrance
[691] = 5601, -- DragonmawRetreat
[693] = 5628, -- StormwroughtRuins
[698] = 5641, -- WindhornCanyon
[699] = 5642, -- Moonwhisper
[700] = 1769, -- TimbermawTunnels
[701] = 5640, -- TimbermawEntrance
[702] = 5722, -- ThornGorge
[704] = 5734, -- FrostmaneHollow
[705] = 5731, -- WindhornCanyonEntrance
}
-- WMA ID → worldBounds + pfqAreaId (for map overlay and minimap calibration)
MTH_DS_WMAZones = {
[4] = { pfqAreaId=14, mapId=1, left=-1962.50, right=-7250.00, top=1808.33, bottom=-1716.67, width=5287.50, height=3525.00 }, -- Durotar
[9] = { pfqAreaId=215, mapId=1, left=2047.92, right=-3089.58, top=-272.92, bottom=-3697.92, width=5137.50, height=3425.00 }, -- Mulgore
[11] = { pfqAreaId=17, mapId=1, left=2622.92, right=-7510.42, top=1612.50, bottom=-5143.75, width=10133.34, height=6756.25 }, -- Barrens
[13] = { pfqAreaId=0, mapId=1, left=17066.60, right=-19733.21, top=12799.90, bottom=-11733.30, width=36799.81, height=24533.20 }, -- Kalimdor
[14] = { pfqAreaId=0, mapId=0, left=16000.00, right=-19199.90, top=7466.60, bottom=-16000.00, width=35199.90, height=23466.60 }, -- Azeroth
[15] = { pfqAreaId=36, mapId=0, left=783.33, right=-2016.67, top=1500.00, bottom=-366.67, width=2800.00, height=1866.67 }, -- Alterac
[16] = { pfqAreaId=45, mapId=0, left=-866.67, right=-4466.67, top=-133.33, bottom=-2533.33, width=3600.00, height=2400.00 }, -- Arathi
[17] = { pfqAreaId=3, mapId=0, left=-2079.17, right=-4566.67, top=-5889.58, bottom=-7547.92, width=2487.50, height=1658.34 }, -- Badlands
[19] = { pfqAreaId=4, mapId=0, left=-1241.67, right=-4591.67, top=-10566.67, bottom=-12800.00, width=3350.00, height=2233.33 }, -- BlastedLands
[20] = { pfqAreaId=85, mapId=0, left=3033.33, right=-1485.42, top=3837.50, bottom=825.00, width=4518.75, height=3012.50 }, -- Tirisfal
[21] = { pfqAreaId=130, mapId=0, left=3450.00, right=-750.00, top=1666.67, bottom=-1133.33, width=4200.00, height=2800.00 }, -- Silverpine
[22] = { pfqAreaId=28, mapId=0, left=416.67, right=-3883.33, top=3366.67, bottom=500.00, width=4300.00, height=2866.67 }, -- WesternPlaguelands
[23] = { pfqAreaId=139, mapId=0, left=-2185.42, right=-6056.25, top=3800.00, bottom=1218.75, width=3870.83, height=2581.25 }, -- EasternPlaguelands
[24] = { pfqAreaId=267, mapId=0, left=1066.67, right=-2133.33, top=400.00, bottom=-1733.33, width=3200.00, height=2133.33 }, -- Hilsbrad
[26] = { pfqAreaId=47, mapId=0, left=-1575.00, right=-5425.00, top=1466.67, bottom=-1100.00, width=3850.00, height=2566.67 }, -- Hinterlands
[27] = { pfqAreaId=1, mapId=0, left=1802.08, right=-3122.92, top=-3877.08, bottom=-7160.42, width=4925.00, height=3283.34 }, -- DunMorogh
[28] = { pfqAreaId=51, mapId=0, left=-322.92, right=-2554.17, top=-6100.00, bottom=-7587.50, width=2231.25, height=1487.50 }, -- SearingGorge
[29] = { pfqAreaId=46, mapId=0, left=-266.67, right=-3195.83, top=-7031.25, bottom=-8983.33, width=2929.16, height=1952.08 }, -- BurningSteppes
[30] = { pfqAreaId=12, mapId=0, left=1535.42, right=-1935.42, top=-7939.58, bottom=-10254.17, width=3470.84, height=2314.59 }, -- Elwynn
[32] = { pfqAreaId=41, mapId=0, left=-833.33, right=-3333.33, top=-9866.67, bottom=-11533.33, width=2500.00, height=1666.66 }, -- DeadwindPass
[34] = { pfqAreaId=10, mapId=0, left=833.33, right=-1866.67, top=-9716.67, bottom=-11516.67, width=2700.00, height=1800.00 }, -- Duskwood
[35] = { pfqAreaId=38, mapId=0, left=-1993.75, right=-4752.08, top=-4487.50, bottom=-6327.08, width=2758.33, height=1839.58 }, -- LochModan
[36] = { pfqAreaId=44, mapId=0, left=-1570.83, right=-3741.67, top=-8575.00, bottom=-10022.92, width=2170.84, height=1447.92 }, -- Redridge
[37] = { pfqAreaId=33, mapId=0, left=2220.83, right=-4160.42, top=-11168.75, bottom=-15422.92, width=6381.25, height=4254.17 }, -- Stranglethorn
[38] = { pfqAreaId=8, mapId=0, left=-2222.92, right=-4516.67, top=-9620.83, bottom=-11150.00, width=2293.75, height=1529.17 }, -- SwampOfSorrows
[39] = { pfqAreaId=40, mapId=0, left=3016.67, right=-483.33, top=-9400.00, bottom=-11733.33, width=3500.00, height=2333.33 }, -- Westfall
[40] = { pfqAreaId=11, mapId=0, left=-389.58, right=-4525.00, top=-2147.92, bottom=-4904.17, width=4135.42, height=2756.25 }, -- Wetlands
[41] = { pfqAreaId=141, mapId=1, left=3814.58, right=-1277.08, top=11831.25, bottom=8437.50, width=5091.66, height=3393.75 }, -- Teldrassil
[42] = { pfqAreaId=148, mapId=1, left=2941.67, right=-3608.33, top=8333.33, bottom=3966.67, width=6550.00, height=4366.66 }, -- Darkshore
[43] = { pfqAreaId=331, mapId=1, left=1700.00, right=-4066.67, top=4672.92, bottom=829.17, width=5766.67, height=3843.75 }, -- Ashenvale
[61] = { pfqAreaId=400, mapId=1, left=-433.33, right=-4833.33, top=-3966.67, bottom=-6900.00, width=4400.00, height=2933.33 }, -- ThousandNeedles
[81] = { pfqAreaId=406, mapId=1, left=3949.00, right=-2069.00, top=3441.00, bottom=-569.00, width=6018.00, height=4010.00 }, -- StonetalonMountains
[101] = { pfqAreaId=405, mapId=1, left=4233.33, right=-262.50, top=452.08, bottom=-2545.83, width=4495.83, height=2997.91 }, -- Desolace
[121] = { pfqAreaId=357, mapId=1, left=5441.67, right=-1508.33, top=-2366.67, bottom=-7000.00, width=6950.00, height=4633.33 }, -- Feralas
[141] = { pfqAreaId=15, mapId=1, left=-975.00, right=-6225.00, top=-2033.33, bottom=-5533.33, width=5250.00, height=3500.00 }, -- Dustwallow
[161] = { pfqAreaId=440, mapId=1, left=-218.75, right=-7118.75, top=-5875.00, bottom=-10475.00, width=6900.00, height=4600.00 }, -- Tanaris
[181] = { pfqAreaId=16, mapId=1, left=-3277.08, right=-8347.92, top=5341.67, bottom=1960.42, width=5070.84, height=3381.25 }, -- Aszhara
[182] = { pfqAreaId=361, mapId=1, left=1641.67, right=-4108.33, top=7133.33, bottom=3300.00, width=5750.00, height=3833.33 }, -- Felwood
[201] = { pfqAreaId=490, mapId=1, left=533.33, right=-3166.67, top=-5966.67, bottom=-8433.33, width=3700.00, height=2466.66 }, -- UngoroCrater
[241] = { pfqAreaId=493, mapId=1, left=-1381.25, right=-3689.58, top=8491.67, bottom=6952.08, width=2308.33, height=1539.59 }, -- Moonglade
[261] = { pfqAreaId=1377, mapId=1, left=2537.50, right=-945.83, top=-5958.33, bottom=-8281.25, width=3483.33, height=2322.92 }, -- Silithus
[281] = { pfqAreaId=618, mapId=1, left=-316.67, right=-7416.67, top=8533.33, bottom=3800.00, width=7100.00, height=4733.33 }, -- Winterspring
[301] = { pfqAreaId=1519, mapId=0, left=1722.92, right=-14.58, top=-7995.83, bottom=-9154.17, width=1737.50, height=1158.34 }, -- Stormwind
[321] = { pfqAreaId=1637, mapId=1, left=-3680.60, right=-5083.21, top=2273.88, bottom=1338.46, width=1402.61, height=935.42 }, -- Orgrimmar
[341] = { pfqAreaId=1537, mapId=0, left=-713.59, right=-1504.22, top=-4569.24, bottom=-5096.85, width=790.63, height=527.61 }, -- Ironforge
[362] = { pfqAreaId=1638, mapId=1, left=516.67, right=-527.08, top=-850.00, bottom=-1545.83, width=1043.75, height=695.83 }, -- ThunderBluff
[381] = { pfqAreaId=1657, mapId=1, left=2938.36, right=1880.03, top=10238.32, bottom=9532.59, width=1058.33, height=705.73 }, -- Darnassus
[382] = { pfqAreaId=1497, mapId=0, left=873.19, right=-86.18, top=1877.95, bottom=1237.84, width=959.37, height=640.11 }, -- Undercity
[401] = { pfqAreaId=2597, mapId=30, left=1781.25, right=-2456.25, top=1085.42, bottom=-1739.58, width=4237.50, height=2825.00 }, -- AlteracValley
[443] = { pfqAreaId=3277, mapId=489, left=2041.67, right=895.83, top=1627.08, bottom=862.50, width=1145.84, height=764.58 }, -- WarsongGulch
[461] = { pfqAreaId=3358, mapId=529, left=1858.33, right=102.08, top=1508.33, bottom=337.50, width=1756.25, height=1170.83 }, -- ArathiBasin
[500] = { pfqAreaId=876, mapId=1, left=16748.00, right=15920.00, top=16525.00, bottom=15984.00, width=828.00, height=541.00 }, -- GMIsland
[501] = { pfqAreaId=616, mapId=1, left=-1080.00, right=-4286.00, top=6125.00, bottom=3983.00, width=3206.00, height=2142.00 }, -- Hyjal
[502] = { pfqAreaId=4012, mapId=0, left=-4050.00, right=-7209.00, top=3087.00, bottom=979.00, width=3159.00, height=2108.00 }, -- ScarletEnclave
[503] = { pfqAreaId=5023, mapId=27, left=1013.00, right=-435.00, top=1823.00, bottom=858.00, width=1448.00, height=965.00 }, -- Sunnyglade
[504] = { pfqAreaId=409, mapId=0, left=4933.33, right=2031.88, top=-11043.48, bottom=-12959.42, width=2901.45, height=1915.94 }, -- Lapidis
[505] = { pfqAreaId=408, mapId=0, left=4436.22, right=1344.12, top=-12528.71, bottom=-14575.72, width=3092.10, height=2047.01 }, -- Gillijim
[507] = { pfqAreaId=5121, mapId=1, left=-5179.00, right=-8406.00, top=-7184.00, bottom=-9371.00, width=3227.00, height=2187.00 }, -- TelAbim
[509] = { pfqAreaId=2040, mapId=0, left=-2169.00, right=-3637.00, top=4907.00, bottom=3931.00, width=1468.00, height=976.00 }, -- AlahThalas
[510] = { pfqAreaId=5179, mapId=0, left=3253.00, right=-413.00, top=-359.00, bottom=-2801.00, width=3666.00, height=2442.00 }, -- Gilneas
[511] = { pfqAreaId=5024, mapId=1, left=-5595.00, right=-7203.00, top=14405.00, bottom=13330.00, width=1608.00, height=1075.00 }, -- Icepoint
[512] = { pfqAreaId=5536, mapId=1, left=-6274.00, right=-8746.00, top=799.00, bottom=-866.00, width=2472.00, height=1665.00 }, -- BlackstoneIsland
[513] = { pfqAreaId=5225, mapId=0, left=-1005.00, right=-4087.00, top=4952.00, bottom=2891.00, width=3082.00, height=2061.00 }, -- ThalassianHighlands
[514] = { pfqAreaId=1581, mapId=0, left=1793.18, right=1343.29, top=-11054.94, bottom=-11354.86, width=449.89, height=299.92 }, -- DeadminesEntrance
[516] = { pfqAreaId=718, mapId=1, left=-1900.87, right=-2473.65, top=-488.64, bottom=-870.49, width=572.78, height=381.85 }, -- WailingCavernsEntrance
[517] = { pfqAreaId=2100, mapId=1, left=3208.00, right=2384.00, top=-1096.00, bottom=-1646.00, width=824.00, height=550.00 }, -- MaraudonEntrance
[518] = { pfqAreaId=721, mapId=0, left=1027.64, right=456.45, top=-4806.32, bottom=-5185.46, width=571.19, height=379.14 }, -- GnomereganEntrance
[519] = { pfqAreaId=25, mapId=0, left=-760.94, right=-1472.50, top=-7327.82, bottom=-7796.50, width=711.56, height=468.68 }, -- BlackrockMountain
[520] = { pfqAreaId=796, mapId=0, left=-659.96, right=-863.62, top=2947.37, bottom=2812.33, width=203.66, height=135.04 }, -- ScarletMonasteryEntrance
[521] = { pfqAreaId=1337, mapId=0, left=-2747.15, right=-3310.46, top=-5953.41, bottom=-6329.51, width=563.31, height=376.10 }, -- UldamanEntrance
[522] = { pfqAreaId=3478, mapId=1, left=3932.67, right=-206.35, top=-8005.20, bottom=-10951.25, width=4139.02, height=2946.05 }, -- AhnQirajEntrance
[523] = { pfqAreaId=1941, mapId=1, left=-3695.85, right=-5044.09, top=-8023.09, bottom=-8911.18, width=1348.24, height=888.09 }, -- CavernsOfTime
[601] = { pfqAreaId=5130, mapId=813, left=1916.00, right=484.00, top=-2332.00, bottom=-3309.00, width=1432.00, height=977.00 }, -- WinterVeilVale
[603] = { pfqAreaId=2437, mapId=389, left=452.87, right=-285.99, top=39.62, bottom=-452.95, width=738.86, height=492.57 }, -- Ragefire
[605] = { pfqAreaId=1176, mapId=209, left=1625.00, right=241.67, top=2052.08, bottom=1129.17, width=1383.33, height=922.91 }, -- ZulFarrak
[607] = { pfqAreaId=1477, mapId=109, left=442.76, right=-252.27, top=-255.17, bottom=-718.52, width=695.03, height=463.35 }, -- TheTempleOfAtalHakkar
[609] = { pfqAreaId=719, mapId=48, left=485.41, right=-736.46, top=-107.91, bottom=-914.33, width=1221.87, height=806.42 }, -- BlackFathomDeeps
[611] = { pfqAreaId=717, mapId=34, left=189.82, right=-188.33, top=220.63, bottom=-31.47, width=378.15, height=252.10 }, -- TheStockade
[613] = { pfqAreaId=721, mapId=90, left=863.00, right=-262.00, top=-245.00, bottom=-985.00, width=1125.00, height=740.00 }, -- Gnomeregan
[615] = { pfqAreaId=1337, mapId=70, left=645.12, right=-248.55, top=204.31, bottom=-391.47, width=893.67, height=595.78 }, -- Uldaman
[617] = { pfqAreaId=2717, mapId=409, left=-11.00, right=-1506.00, top=1439.00, bottom=456.00, width=1495.00, height=983.00 }, -- MoltenCore
[619] = { pfqAreaId=1977, mapId=309, left=-612.50, right=-2733.33, top=-11225.00, bottom=-12639.58, width=2120.83, height=1414.58 }, -- ZulGurub
[621] = { pfqAreaId=2557, mapId=429, left=1007.00, right=-912.00, top=955.00, bottom=-295.00, width=1919.00, height=1250.00 }, -- DireMaul
[623] = { pfqAreaId=1584, mapId=230, left=875.00, right=-1110.00, top=1513.00, bottom=245.00, width=1985.00, height=1268.00 }, -- BlackrockDepths
[625] = { pfqAreaId=3429, mapId=509, left=3035.42, right=522.92, top=-8233.33, bottom=-9908.33, width=2512.50, height=1675.00 }, -- RuinsofAhnQiraj
[627] = { pfqAreaId=2159, mapId=249, left=155.00, right=-366.00, top=86.00, bottom=-262.00, width=521.00, height=348.00 }, -- OnyxiasLair
[629] = { pfqAreaId=1583, mapId=229, left=10.59, right=-876.25, top=304.40, bottom=-286.83, width=886.84, height=591.23 }, -- BlackrockSpire
[631] = { pfqAreaId=718, mapId=43, left=790.00, right=-380.00, top=215.00, bottom=-570.00, width=1170.00, height=785.00 }, -- WailingCaverns
[633] = { pfqAreaId=2100, mapId=349, left=485.41, right=-1626.68, top=1199.76, bottom=-211.13, width=2112.09, height=1410.89 }, -- Maraudon
[635] = { pfqAreaId=2677, mapId=469, left=-645.00, right=-1422.00, top=-7255.00, bottom=-7760.00, width=777.00, height=505.00 }, -- BlackwingLair
[637] = { pfqAreaId=5138, mapId=36, left=-322.94, right=-979.53, top=36.93, bottom=-398.04, width=656.59, height=434.97 }, -- TheDeadmines
[639] = { pfqAreaId=722, mapId=129, left=1271.00, right=390.00, top=2683.00, bottom=2094.00, width=881.00, height=589.00 }, -- RazorfenDowns
[641] = { pfqAreaId=491, mapId=47, left=2058.92, right=1322.47, top=2349.64, bottom=1858.68, width=736.45, height=490.96 }, -- RazorfenKraul
[643] = { pfqAreaId=5136, mapId=189, left=1567.97, right=947.99, top=2030.18, bottom=1616.86, width=619.98, height=413.32 }, -- ScarletMonastery
[644] = { pfqAreaId=5135, mapId=189, left=-162.27, right=-482.46, top=307.37, bottom=93.91, width=320.19, height=213.46 }, -- ScarletMonastery2f
[645] = { pfqAreaId=5153, mapId=189, left=50.27, right=-562.42, top=2009.10, bottom=1600.64, width=612.69, height=408.46 }, -- ScarletMonastery3f
[646] = { pfqAreaId=5163, mapId=189, left=1743.99, right=1040.69, top=1281.29, bottom=812.42, width=703.30, height=468.87 }, -- ScarletMonastery4f
[648] = { pfqAreaId=2057, mapId=289, left=251.41, right=-68.64, top=317.70, bottom=104.33, width=320.05, height=213.37 }, -- Scholomance
[650] = { pfqAreaId=209, mapId=33, left=2436.00, right=2055.00, top=-61.00, bottom=-315.00, width=381.00, height=254.00 }, -- ShadowfangKeep
[652] = { pfqAreaId=2017, mapId=329, left=-2639.83, right=-3825.18, top=4163.90, bottom=3374.04, width=1185.35, height=789.86 }, -- Stratholme
[654] = { pfqAreaId=3428, mapId=531, left=2515.63, right=1538.07, top=-8051.80, bottom=-8703.50, width=977.56, height=651.70 }, -- AhnQiraj
[655] = { pfqAreaId=5147, mapId=531, left=2915.62, right=138.08, top=-7659.29, bottom=-9510.98, width=2777.54, height=1851.69 }, -- AhnQiraj2f
[657] = { pfqAreaId=5723, mapId=532, left=-1546.00, right=-2165.00, top=-10789.00, bottom=-11199.00, width=619.00, height=410.00 }, -- Karazhan
[659] = { pfqAreaId=2257, mapId=369, left=2623.50, right=2311.50, top=95.50, bottom=-112.50, width=312.00, height=208.00 }, -- DeeprunTram
[662] = { pfqAreaId=5204, mapId=269, left=7338.47, right=6066.48, top=-1247.55, bottom=-2093.03, width=1271.99, height=845.48 }, -- BlackMorass
[663] = { pfqAreaId=2366, mapId=269, left=7651.85, right=6565.99, top=-1500.47, bottom=-2227.08, width=1085.86, height=726.61 }, -- BlackMorass2f
[665] = { pfqAreaId=5208, mapId=815, left=3290.32, right=2040.14, top=-760.72, bottom=-1598.16, width=1250.18, height=837.44 }, -- GilneasCity
[667] = { pfqAreaId=3456, mapId=533, left=-2375.27, right=-4366.96, top=3656.70, bottom=2338.28, width=1991.69, height=1318.42 }, -- Naxxramas
[668] = { pfqAreaId=5148, mapId=533, left=-4869.36, right=-5521.46, top=3816.56, bottom=3376.89, width=652.10, height=439.67 }, -- Naxxramas2f
[670] = { pfqAreaId=5077, mapId=802, left=1207.72, right=-1435.49, top=882.98, bottom=-868.18, width=2643.21, height=1751.16 }, -- CrescentGrove
[672] = { pfqAreaId=5103, mapId=808, left=-3024.33, right=-3776.45, top=-7888.28, bottom=-8398.61, width=752.12, height=510.33 }, -- HateforgeQuarry
[674] = { pfqAreaId=5086, mapId=800, left=-1302.51, right=-1849.26, top=-10916.17, bottom=-11308.14, width=546.75, height=391.97 }, -- KarazhanCrypt
[676] = { pfqAreaId=5087, mapId=35, left=314.34, right=-40.16, top=89.30, bottom=-145.44, width=354.50, height=234.74 }, -- StormwindVault
[678] = { pfqAreaId=5097, mapId=807, left=3939.10, right=2666.00, top=3519.72, bottom=2666.00, width=1273.10, height=853.72 }, -- EmeraldSanctum
[680] = { pfqAreaId=5053, mapId=801, left=17296.30, right=16288.62, top=17158.52, bottom=16486.73, width=1007.68, height=671.79 }, -- Moomoo
[682] = { pfqAreaId=3457, mapId=814, left=-1378.00, right=-2201.00, top=-10887.00, bottom=-11436.00, width=823.00, height=549.00 }, -- UpperKarazhan
[683] = { pfqAreaId=5557, mapId=814, left=-1483.00, right=-4283.00, top=-5800.00, bottom=-7668.00, width=2800.00, height=1868.00 }, -- UpperKarazhan2f
[684] = { pfqAreaId=5602, mapId=0, left=-2072.00, right=-7459.00, top=-2904.00, bottom=-6488.00, width=5387.00, height=3584.00 }, -- GrimReaches
[685] = { pfqAreaId=5561, mapId=0, left=4728.00, right=1630.00, top=-7577.00, bottom=-9645.00, width=3098.00, height=2068.00 }, -- Balor
[686] = { pfqAreaId=5581, mapId=0, left=2258.00, right=-983.00, top=-6327.00, bottom=-8484.00, width=3241.00, height=2157.00 }, -- Northwind
[689] = { pfqAreaId=2557, mapId=1, left=2014.00, right=690.00, top=-3401.00, bottom=-4270.00, width=1324.00, height=869.00 }, -- DireMaulEntrance
[691] = { pfqAreaId=5601, mapId=816, left=-3428.00, right=-5062.00, top=-5599.00, bottom=-6672.00, width=1634.00, height=1073.00 }, -- DragonmawRetreat
[693] = { pfqAreaId=5628, mapId=818, left=-3365.00, right=-5345.00, top=-5424.00, bottom=-6774.00, width=1980.00, height=1350.00 }, -- StormwroughtRuins
[694] = { pfqAreaId=0, mapId=0, left=0.00, right=0.00, top=0.00, bottom=0.00, width=0.00, height=0.00 }, -- World
[696] = { pfqAreaId=5640, mapId=819, left=-2991.00, right=-4416.00, top=-7195.00, bottom=-8157.00, width=1425.00, height=962.00 }, -- Timbermaw
[698] = { pfqAreaId=5641, mapId=820, left=-3184.00, right=-4418.00, top=-7163.00, bottom=-7992.00, width=1234.00, height=829.00 }, -- WindhornCanyon
[699] = { pfqAreaId=5642, mapId=1, left=-1354.00, right=-9210.00, top=10204.00, bottom=4963.00, width=7856.00, height=5241.00 }, -- Moonwhisper
[700] = { pfqAreaId=1769, mapId=1, left=-1862.00, right=-2723.00, top=7395.00, bottom=6788.00, width=861.00, height=607.00 }, -- TimbermawTunnels
[701] = { pfqAreaId=5640, mapId=1, left=-4646.00, right=-5993.00, top=5175.00, bottom=4204.00, width=1347.00, height=971.00 }, -- TimbermawEntrance
[702] = { pfqAreaId=5722, mapId=821, left=2105.00, right=1058.00, top=2522.00, bottom=1828.00, width=1047.00, height=694.00 }, -- ThornGorge
[704] = { pfqAreaId=5734, mapId=822, left=-3157.00, right=-4168.00, top=-7453.00, bottom=-8106.00, width=1011.00, height=653.00 }, -- FrostmaneHollow
[705] = { pfqAreaId=5731, mapId=1, left=-3231.00, right=-3671.00, top=-5053.00, bottom=-5332.00, width=440.00, height=279.00 }, -- WindhornCanyonEntrance
}
+5
View File
@@ -56,6 +56,11 @@ local function MTH_DS_ApplyCapturedProjectileQualities()
[18042] = 2,
[19316] = 2,
[19317] = 2,
[42198] = 2,
[42199] = 2,
[42200] = 2,
[42201] = 3,
[42202] = 3,
}
for itemId, quality in pairs(capturedQualityByItemId) do
+4 -1
View File
@@ -1,7 +1,6 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Include file="..\api\constants.lua"/>
<Include file="..\api\debug-frame.lua"/>
<Include file="..\api\minimap-button.lua"/>
<Include file="..\api\AutoStrip.xml"/>
<Include file="..\api\AutoStrip.lua"/>
@@ -17,6 +16,7 @@
<Include file="..\api\options-autobuy.lua"/>
<Include file="..\api\options-autoquest.lua"/>
<Include file="..\api\options-icu.lua"/>
<Include file="..\api\options-expammo.lua"/>
<Include file="..\api\profile.lua"/>
<Include file="..\api\options-profiles.lua"/>
<Include file="..\api\options-shell.lua"/>
@@ -33,6 +33,7 @@
<Include file="..\api\hunterbook-tab-pethistory.lua"/>
<Include file="..\api\hunterbook-model-viewer.lua"/>
<Include file="..\api\map-markers.lua"/>
<Include file="..\api\debug-frame.lua"/>
<Include file="..\api\core-framework.lua"/>
<Include file="..\api\core-scan-stablemaster.lua"/>
<Include file="..\api\pets-service-lifecycle.lua"/>
@@ -41,6 +42,8 @@
<Include file="..\api\pets-service-stablescan.lua"/>
<Include file="..\api\core-scan-beasttraining.lua"/>
<Include file="..\api\core-scan-spellbookpet.lua"/>
<Include file="..\api\beastlore-scan.lua"/>
<Include file="..\api\core-scan-huntertalents.lua"/>
<Include file="..\api\core.lua"/>
<Include file="..\api\version-check.lua"/>
<Include file="..\api\localization.lua"/>
+3
View File
@@ -26,4 +26,7 @@ MetaHunt Module Loader
<!-- ICU Module - ENABLED (runtime default: disabled) -->
<Include file="..\modules\icu\loader.xml"/>
<!-- Experimental Ammunition Module - ENABLED -->
<Include file="..\modules\expammo\loader.xml"/>
</Ui>
+5
View File
@@ -2,6 +2,11 @@ MTH_LocaleData = MTH_LocaleData or {}
MTH_LocaleData.spells = MTH_LocaleData.spells or {}
MTH_LocaleData.spells.deDE = {
["Aimed Shot"] = "Gezielter Schuss",
["Kill Command"] = "Todesbefehl",
["Lock and Load"] = "Lock and Load",
["Scent of Blood"] = "Blutgeruch",
["Aspect of the Viper"] = "Aspekt der Viper",
["Banish"] = "Verbannen",
["Bestial Wrath"] = "Zorn des Wildtiers",
["Concussive Shot"] = "Erschütternder Schuss",
+5
View File
@@ -2,6 +2,11 @@ MTH_LocaleData = MTH_LocaleData or {}
MTH_LocaleData.spells = MTH_LocaleData.spells or {}
MTH_LocaleData.spells.enUS = {
["Aimed Shot"] = "Aimed Shot",
["Kill Command"] = "Kill Command",
["Lock and Load"] = "Lock and Load",
["Scent of Blood"] = "Scent of Blood",
["Aspect of the Viper"] = "Aspect of the Viper",
["Banish"] = "Banish",
["Bestial Wrath"] = "Bestial Wrath",
["Concussive Shot"] = "Concussive Shot",
+5
View File
@@ -2,6 +2,11 @@ MTH_LocaleData = MTH_LocaleData or {}
MTH_LocaleData.spells = MTH_LocaleData.spells or {}
MTH_LocaleData.spells.esES = {
["Aimed Shot"] = "Aimed Shot",
["Aspect of the Viper"] = "Aspect of the Viper",
["Kill Command"] = "Kill Command",
["Lock and Load"] = "Lock and Load",
["Scent of Blood"] = "Scent of Blood",
["Banish"] = "Banish",
["Bestial Wrath"] = "Bestial Wrath",
["Concussive Shot"] = "Concussive Shot",
+5
View File
@@ -2,6 +2,11 @@ MTH_LocaleData = MTH_LocaleData or {}
MTH_LocaleData.spells = MTH_LocaleData.spells or {}
MTH_LocaleData.spells.ptBR = {
["Aimed Shot"] = "Aimed Shot",
["Aspect of the Viper"] = "Aspect of the Viper",
["Kill Command"] = "Kill Command",
["Lock and Load"] = "Lock and Load",
["Scent of Blood"] = "Scent of Blood",
["Banish"] = "Banish",
["Bestial Wrath"] = "Bestial Wrath",
["Concussive Shot"] = "Concussive Shot",
+5
View File
@@ -2,6 +2,11 @@ MTH_LocaleData = MTH_LocaleData or {}
MTH_LocaleData.spells = MTH_LocaleData.spells or {}
MTH_LocaleData.spells.ruRU = {
["Aimed Shot"] = "Прицельный выстрел",
["Aspect of the Viper"] = "Аспект гадюки",
["Kill Command"] = "Приказ убивать",
["Lock and Load"] = "Lock and Load",
["Scent of Blood"] = "Запах крови",
["Banish"] = "Изгнание",
["Bestial Wrath"] = "Звериный гнев",
["Concussive Shot"] = "Контузящий выстрел",
+5
View File
@@ -2,6 +2,11 @@ MTH_LocaleData = MTH_LocaleData or {}
MTH_LocaleData.spells = MTH_LocaleData.spells or {}
MTH_LocaleData.spells.zhCN = {
["Aimed Shot"] = "瞄准射击",
["Aspect of the Viper"] = "毒蛇图腾",
["Kill Command"] = "猎杀命令",
["Lock and Load"] = "Lock and Load",
["Scent of Blood"] = "血腥气息",
["Banish"] = "放逐术",
["Bestial Wrath"] = "狂野怒火",
["Concussive Shot"] = "震荡射击",
-25
View File
@@ -9,9 +9,6 @@ local Engine = MTH_AutoBuyEngine
local AB_AMMO_BY_NAME = nil
local AB_FOOD_DIET_BY_ITEM_ID = nil
local function AB_Trace(message)
return
end
local function AB_ParseItemIdFromLink(link)
if type(link) ~= "string" then
@@ -1180,7 +1177,6 @@ end
function Engine:ExecutePlan(plan)
if type(plan) ~= "table" or type(plan.actions) ~= "table" then
AB_Trace("ExecutePlan skipped: invalid plan table")
return 0, 0
end
local executedActions = 0
@@ -1189,10 +1185,6 @@ function Engine:ExecutePlan(plan)
if type(action) == "table" and action.index then
local stacksToBuy = math.floor(tonumber(action.quantityStacks) or 0)
if stacksToBuy > 0 then
AB_Trace("ExecutePlan action index=" .. tostring(action.index)
.. " itemId=" .. tostring(action.itemId)
.. " stacks=" .. tostring(stacksToBuy)
.. " reason=" .. tostring(plan.reason or ""))
for i = 1, stacksToBuy do
BuyMerchantItem(action.index)
end
@@ -1201,7 +1193,6 @@ function Engine:ExecutePlan(plan)
end
end
end
AB_Trace("ExecutePlan done actions=" .. tostring(executedActions) .. " stacks=" .. tostring(requestedStacks) .. " reason=" .. tostring(plan.reason or ""))
return executedActions, requestedStacks
end
@@ -1264,42 +1255,30 @@ local function AB_AnnouncePurchases(actions)
end
function Engine:OnMerchantEvent(eventName)
AB_Trace("OnMerchantEvent start event=" .. tostring(eventName)
.. " sessionExecuted=" .. tostring(self._merchantSessionExecuted and true or false)
.. " engineEnabled=" .. tostring(self:IsEnabled() and true or false))
if eventName == "MERCHANT_SHOW" then
self._merchantSessionExecuted = false
AB_Trace("MERCHANT_SHOW resets session execution flag")
elseif eventName == "MERCHANT_UPDATE" and self._merchantSessionExecuted then
AB_Trace("MERCHANT_UPDATE ignored: already executed this merchant session")
return
end
if not self:IsEnabled() then
AB_Trace("event ignored: autobuy module disabled")
return
end
local snapshot = self:ScanMerchant()
AB_Trace("snapshot rows=" .. tostring(snapshot and snapshot.count or 0))
local foodPlan = self:BuildFoodPlan(snapshot)
local ammoPlan = self:BuildAmmoPlan(snapshot)
AB_Trace("foodPlan reason=" .. tostring(foodPlan.reason) .. " actions=" .. tostring(table.getn(foodPlan.actions or {})))
for i = 1, table.getn(foodPlan.debugLines or {}) do
AB_Trace("food#" .. tostring(i) .. " " .. tostring(foodPlan.debugLines[i]))
end
AB_Trace("ammoPlan reason=" .. tostring(ammoPlan.reason) .. " actions=" .. tostring(table.getn(ammoPlan.actions or {})))
for i = 1, table.getn(ammoPlan.debugLines or {}) do
AB_Trace("ammo#" .. tostring(i) .. " " .. tostring(ammoPlan.debugLines[i]))
end
local totalRequestedStacks = 0
if table.getn(foodPlan.actions or {}) > 0 then
local _, requestedStacks = self:ExecutePlan(foodPlan)
totalRequestedStacks = totalRequestedStacks + requestedStacks
AB_Trace("food plan executed requestedStacks=" .. tostring(requestedStacks))
if requestedStacks > 0 then
AB_AnnouncePurchases(foodPlan.actions)
end
@@ -1308,19 +1287,15 @@ function Engine:OnMerchantEvent(eventName)
if table.getn(ammoPlan.actions or {}) > 0 then
local _, requestedStacks = self:ExecutePlan(ammoPlan)
totalRequestedStacks = totalRequestedStacks + requestedStacks
AB_Trace("ammo plan executed requestedStacks=" .. tostring(requestedStacks))
if requestedStacks > 0 then
local moved = AB_MoveAmmoStacksToSpecialBags(300)
AB_Trace("ammo restack moved=" .. tostring(moved))
AB_AnnouncePurchases(ammoPlan.actions)
end
end
if totalRequestedStacks > 0 then
self._merchantSessionExecuted = true
AB_Trace("session marked executed requestedStacks=" .. tostring(totalRequestedStacks))
else
AB_Trace("no purchases requested in this event")
end
end
+2 -27
View File
@@ -6,7 +6,7 @@
local MTH_AutoBuy = {
name = "autobuy",
enabled = false,
version = "1.3.0",
version = "1.4.1",
events = {
"VARIABLES_LOADED",
"MERCHANT_SHOW",
@@ -24,9 +24,6 @@ end
local AB_Engine
local function AB_Trace(message)
return
end
local function AB_EnsureBridgeFrame(moduleRef)
if MTH_AutoBuy._bridgeFrame then
@@ -46,15 +43,12 @@ local function AB_EnsureBridgeFrame(moduleRef)
local eventName = event
local engine = AB_Engine()
if not engine then
AB_Trace("bridge event=" .. tostring(eventName) .. " engine missing")
return
end
if eventName == "MERCHANT_SHOW" or eventName == "MERCHANT_UPDATE" then
AB_Trace("bridge " .. tostring(eventName) .. " -> engine")
engine:OnMerchantEvent(eventName)
elseif eventName == "MERCHANT_CLOSED" then
AB_Trace("bridge MERCHANT_CLOSED -> engine")
if engine.OnMerchantClosed then
engine:OnMerchantClosed()
end
@@ -77,10 +71,8 @@ local function AB_SetBridgeActive(active)
frame:RegisterEvent("MERCHANT_UPDATE")
frame:RegisterEvent("MERCHANT_CLOSED")
MTH_AutoBuy._bridgeActive = true
AB_Trace("bridge active=true")
else
MTH_AutoBuy._bridgeActive = false
AB_Trace("bridge active=false (frame missing)")
end
return
end
@@ -91,7 +83,6 @@ local function AB_SetBridgeActive(active)
frame:UnregisterEvent("MERCHANT_CLOSED")
end
MTH_AutoBuy._bridgeActive = false
AB_Trace("bridge active=false")
end
AB_Engine = function()
@@ -102,15 +93,12 @@ function MTH_AutoBuy:init()
local engine = AB_Engine()
if not engine then
AB_Log("init failed: engine missing", "error")
AB_Trace("init failed: engine missing")
return
end
engine:Init()
self.initialized = true
AB_SetBridgeActive(self.enabled and true or false)
AB_Trace("init done")
if self.enabled then
AB_Log("module initialized", "debug")
end
end
@@ -120,20 +108,16 @@ function MTH_AutoBuy:setEnabled(enabled)
end
local engine = AB_Engine()
if not engine then
AB_Trace("setEnabled ignored: engine missing")
return
end
local store = engine:EnsureDefaults()
store.enabled = enabled and true or false
AB_SetBridgeActive(store.enabled and true or false)
AB_Trace("setEnabled store.enabled=" .. tostring(store.enabled))
end
function MTH_AutoBuy:onEvent(event)
local engine = AB_Engine()
if not engine then
AB_Log("onEvent ignored: engine missing, event=" .. tostring(event), "debug")
AB_Trace("engine missing, event=" .. tostring(event))
return
end
if self._bridgeActive and (event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" or event == "MERCHANT_CLOSED") then
@@ -143,27 +127,19 @@ function MTH_AutoBuy:onEvent(event)
if event == "VARIABLES_LOADED" then
engine:Init()
AB_SetBridgeActive(self.enabled and true or false)
local store = engine:EnsureDefaults()
AB_Trace("VARIABLES_LOADED module.enabled=" .. tostring(self.enabled)
.. " store.enabled=" .. tostring(store and store.enabled)
.. " projectiles.enabled=" .. tostring(store and store.projectiles and store.projectiles.enabled))
engine:EnsureDefaults()
return
end
if not self.enabled then
AB_Log("onEvent ignored: module disabled", "debug")
if event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" then
AB_Trace(tostring(event) .. " ignored: module disabled")
end
return
end
if event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" then
AB_Log("onEvent merchant event forwarded: " .. tostring(event), "debug")
AB_Trace("forwarding " .. tostring(event) .. " to engine")
engine:OnMerchantEvent(event)
elseif event == "MERCHANT_CLOSED" then
AB_Trace("forwarding MERCHANT_CLOSED to engine")
if engine.OnMerchantClosed then
engine:OnMerchantClosed()
end
@@ -171,7 +147,6 @@ function MTH_AutoBuy:onEvent(event)
end
function MTH_AutoBuy:cleanup()
AB_Log("module cleanup", "debug")
end
MTH:RegisterModule("autobuy", MTH_AutoBuy)
+1 -1
View File
@@ -6,7 +6,7 @@
local MTH_AutoQuest = {
name = "autoquest",
enabled = false,
version = "1.3.0",
version = "1.4.1",
events = {
"GOSSIP_SHOW",
"QUEST_GREETING",
+16 -4
View File
@@ -28,6 +28,8 @@ function MTH_ChronometerHunterInstallData(engine)
engine:AddTimer(engine.SPELL, BS["Flare"], 30, 0, 0, 0, { cr = "YELLOW", rc = true })
engine:AddTimer(engine.SPELL, BS["Hunter's Mark"], 120, 1, 0, 0, { cr = "RED", rc = true })
engine:AddTimer(engine.SPELL, BS["Immolation Trap"], 60, 0, 0, 0, { gr = 1, cr = "ORANGE", ea = { [BS["Immolation Trap Effect"]] = 60 } })
engine:AddTimer(engine.SPELL, BS["Aimed Shot"], 20, 0, 0, 0, { cr = "RED", rc = true, d = { tn = BS["Swiftshot"], tb = -2, ts = -2 } }) -- base 20s; Swiftshot reduces by 2s/rank (max -6s at rank 3)
engine:AddTimer(engine.SPELL, BS["Kill Command"], 12, 0, 0, 0, { cr = "RED", rc = true })
engine:AddTimer(engine.SPELL, BS["Rapid Fire"], 15, 0, 1, 1, { cr = "RED" })
engine:AddTimer(engine.SPELL, BS["Scare Beast"], 10, 1, 0, 0, { cr = "BLUE", rc = true, d = { rs = 5 } })
engine:AddTimer(engine.SPELL, BS["Scatter Shot"], 4, 1, 0, 0, { cr = "MAROON" })
@@ -38,16 +40,26 @@ 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["Feed Pet"], 20, 0, 0, 0, { cr = "MAROON" })
engine:AddTimer(engine.EVENT, BS["Explosive Trap Effect"], 20, 1, 0, 1, { gr = 1, cr = "ORANGE", a = 1, xn = BS["Explosive Trap"] })
engine:AddTimer(engine.EVENT, BS["Freezing Trap Effect"], 10, 1, 0, 1, { gr = 1, cr = "CYAN", a = 1, d = { rs = 5, tn = BS["Clever Traps"], tb = 0.15, tp = 1 }, xn = BS["Freezing Trap"] })
engine:AddTimer(engine.EVENT, BS["Frost Trap Aura"], 30, 0, 0, 0, { gr = 1, cr = "CYAN", a = 1, d = { tn = BS["Clever Traps"], tb = 0.15, tp = 1 }, xn = BS["Frost Trap"] })
engine:AddTimer(engine.EVENT, BS["Immolation Trap Effect"], 15, 1, 0, 1, { gr = 1, cr = "ORANGE", a = 1, xn = BS["Immolation Trap"] })
-- Trap effects: no "a=1" here — primed by the SPELL timer's "ea" chain (cast hook sets timer.v
-- and timer.t). Using "a=1" would trigger on any hunter's affliction message since
-- CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS never embeds a caster name.
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 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["Scent of Blood"], 8, 0, 1, 1, { a = 1, cr = "RED" })
engine:AddTimer(engine.EVENT, BS["Piercing Shot"], 8, 1, 0, 1, { a = 1, cr = "PURPLE", tx = "Interface\\Icons\\Ability_Hunter_DisarmingShot" })
engine:AddTimer(engine.EVENT, BS["Entrapment"], 5, 1, 0, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\Spell_Nature_StrangleVines" })
engine:AddTimer(engine.EVENT, BS["Quick Shots"], 12, 0, 1, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\Ability_Warrior_InnerRage" })
engine:AddTimer(engine.EVENT, BS["Wing Clip"], 10, 1, 0, 1, { a = 1, cr = "YELLOW" })
-- Experimental Ammunition: target-side debuffs (from consumed ammo state)
-- Poisonous Ammunition consumed: reduces target armor 15s (Nature)
engine:AddTimer(engine.EVENT, BS["Poisonous Ammunition"], 15, 1, 0, 1, { a = 1, cr = "GREEN", tx = "Interface\\Icons\\Ability_PoisonArrow" })
-- Enchanted Ammunition consumed: magic resist debuff 6s (Arcane)
engine:AddTimer(engine.EVENT, BS["Enchanted Ammunition"], 6, 1, 0, 1, { a = 1, cr = "PURPLE", tx = "Interface\\Icons\\Ability_TheBlackArrow" })
engine:AddTimer(engine.EVENT, BS["Scorpid Poison"], 10, 1, 0, 0, { gr = 3, cr = "PURPLE", a = 1, dn = 1 })
engine:AddTimer(engine.EVENT, BS["Devilsaur Fury"], 20, 0, 1, 1, { a = 1, cr = "PURPLE", xn = BS["Devilsaur Eye"], tx = "Interface\\Icons\\Ability_Hunter_Pet_Raptor" })
engine:AddTimer(engine.EVENT, BS["Restless Strength"], 20, 0, 1, 1, { a = 1, cr = "PURPLE", xn = BS["Zandalarian Hero Medallion"], tx = "Interface\\Icons\\INV_Jewelry_Necklace_13" })
+43 -48
View File
@@ -59,18 +59,7 @@ Chronometer.dataSetup = {}
local latins = { I = 1, II = 2, III = 3, IV = 4, V = 5, VI = 6, VII = 7, VIII = 8, IX = 9, X = 10, XI = 11, XII = 12, XIII = 13, XIV = 14 }
local BAR_GROUP = "MTHChronometer"
local PARSER_OWNER = "MTHChronometerHunter"
local MTH_CHRON_TRACE_ENABLED = false
local function MTH_CHRON_Trace(msg)
if not MTH_CHRON_TRACE_ENABLED then
return
end
if MTH and MTH.Print then
MTH:Print("[CHRONTRACE] " .. tostring(msg), "debug")
elseif DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
DEFAULT_CHAT_FRAME:AddMessage("[CHRONTRACE] " .. tostring(msg))
end
end
local function MTH_CHRON_FormatBarPosition(profile)
local bp = profile and profile.barposition
@@ -195,13 +184,11 @@ end
local function ensureProfile()
if not MTH or not MTH.GetModuleCharSavedVariables then
MTH_CHRON_Trace("ensureProfile fallback defaults (no MTH store)")
return shallowCopy(DEFAULTS)
end
local store = MTH:GetModuleCharSavedVariables("chronometer")
if type(store) ~= "table" then
MTH_CHRON_Trace("ensureProfile fallback defaults (invalid store)")
return shallowCopy(DEFAULTS)
end
if type(store.profile) ~= "table"
@@ -211,10 +198,8 @@ local function ensureProfile()
local legacyChar = MTH_CharSavedVariables.chronometer
if type(legacyChar.profile) == "table" then
store.profile = deepCopyValue(legacyChar.profile)
MTH_CHRON_Trace("ensureProfile migrated legacy MTH_CharSavedVariables.chronometer.profile")
elseif type(legacyChar.barposition) == "table" then
store.profile = { barposition = deepCopyValue(legacyChar.barposition) }
MTH_CHRON_Trace("ensureProfile migrated legacy MTH_CharSavedVariables.chronometer.barposition")
end
end
if type(store.profile) ~= "table"
@@ -224,17 +209,14 @@ local function ensureProfile()
local legacyAccount = MTH_SavedVariables.chronometer
if type(legacyAccount.profile) == "table" then
store.profile = deepCopyValue(legacyAccount.profile)
MTH_CHRON_Trace("ensureProfile migrated legacy MTH_SavedVariables.chronometer.profile")
elseif type(legacyAccount.barposition) == "table" then
store.profile = { barposition = deepCopyValue(legacyAccount.barposition) }
MTH_CHRON_Trace("ensureProfile migrated legacy MTH_SavedVariables.chronometer.barposition")
end
end
if type(store.profile) ~= "table" and MTH.GetModuleSavedVariables then
local accountStore = MTH:GetModuleSavedVariables("chronometer")
if type(accountStore) == "table" and type(accountStore.profile) == "table" then
store.profile = deepCopyValue(accountStore.profile)
MTH_CHRON_Trace("ensureProfile copied account profile into char store")
end
end
if type(store.profile) ~= "table" then
@@ -242,17 +224,14 @@ local function ensureProfile()
end
if type(store.profile.barposition) ~= "table" and type(store.barposition) == "table" then
store.profile.barposition = deepCopyValue(store.barposition)
MTH_CHRON_Trace("ensureProfile migrated legacy char barposition -> profile.barposition")
end
if type(store.profile.barposition) ~= "table" and MTH.GetModuleSavedVariables then
local accountStore = MTH:GetModuleSavedVariables("chronometer")
if type(accountStore) == "table" then
if type(accountStore.barposition) == "table" then
store.profile.barposition = deepCopyValue(accountStore.barposition)
MTH_CHRON_Trace("ensureProfile migrated legacy account barposition -> profile.barposition")
elseif type(accountStore.profile) == "table" and type(accountStore.profile.barposition) == "table" then
store.profile.barposition = deepCopyValue(accountStore.profile.barposition)
MTH_CHRON_Trace("ensureProfile copied account profile.barposition -> char profile.barposition")
end
end
end
@@ -282,7 +261,6 @@ local function ensureProfile()
profile.disabledSpells.HUNTER = {}
end
MTH_CHRON_Trace("ensureProfile result barposition=" .. MTH_CHRON_FormatBarPosition(profile))
return profile
end
@@ -309,8 +287,6 @@ local function MTH_CHRON_PersistAnchorPosition(self, reason)
self.profile.barposition.relativePoint = relPoint
self.profile.barposition.x = x
self.profile.barposition.y = y
MTH_CHRON_Trace("persist-anchor reason=" .. tostring(reason or "")
.. " profile=" .. MTH_CHRON_FormatBarPosition(self.profile))
return true
end
@@ -330,8 +306,6 @@ local function MTH_CHRON_RestoreAnchorFromProfile(self, reason)
local ppoint = tostring(bp.point or "")
local prelpoint = tostring(bp.relativePoint or "")
if not (px and py and ppoint ~= "") then
MTH_CHRON_Trace("restore-anchor skipped reason=" .. tostring(reason or "")
.. " profile=" .. MTH_CHRON_FormatBarPosition(self.profile))
return false
end
if prelpoint == "" then
@@ -339,8 +313,6 @@ local function MTH_CHRON_RestoreAnchorFromProfile(self, reason)
end
self.anchor:ClearAllPoints()
self.anchor:SetPoint(ppoint, UIParent, prelpoint, px, py)
MTH_CHRON_Trace("restore-anchor applied reason=" .. tostring(reason or "")
.. " frame=" .. MTH_CHRON_DescribePoint(self.anchor))
return true
end
@@ -527,7 +499,6 @@ function Chronometer:MTH_Initialize()
end
self.profile = ensureProfile()
MTH_CHRON_Trace("MTH_Initialize profile=" .. MTH_CHRON_FormatBarPosition(self.profile))
self.parser = ParserLib:GetInstance("1.1")
self.COLOR_MAP = {
@@ -538,7 +509,6 @@ function Chronometer:MTH_Initialize()
}
self.anchor = self:CreateAnchor("MetaHunt Chronometer", 0, 1, 0)
MTH_CHRON_Trace("MTH_Initialize anchor-created point=" .. MTH_CHRON_DescribePoint(self.anchor))
self:RegisterCandyBarGroup(BAR_GROUP)
self:SetCandyBarGroupPoint(BAR_GROUP, "TOP", self.anchor, "BOTTOM", 0, 0)
@@ -547,19 +517,16 @@ end
function Chronometer:MTH_Enable()
self._mth_explicitEnable = true
MTH_CHRON_Trace("MTH_Enable called")
self:MTH_Initialize()
self:OnEnable()
self._mth_explicitEnable = nil
end
function Chronometer:MTH_Disable()
MTH_CHRON_Trace("MTH_Disable called")
self:OnDisable()
end
function Chronometer:OnEnable()
MTH_CHRON_Trace("OnEnable begin enabled=" .. tostring(self._mth_enabled and true or false))
if self._mth_enabled then
return
end
@@ -589,11 +556,9 @@ function Chronometer:OnEnable()
self._mth_enabled = true
self.profile = ensureProfile()
MTH_CHRON_Trace("OnEnable profile-after-ensure=" .. MTH_CHRON_FormatBarPosition(self.profile))
self:SetCandyBarGroupGrowth(BAR_GROUP, self.profile.growup and true or false)
self:SetCandyBarGroupVerticalSpacing(BAR_GROUP, self.profile.spacing or 0)
if self.anchor then
MTH_CHRON_Trace("OnEnable anchor-current-point=" .. MTH_CHRON_DescribePoint(self.anchor))
end
MTH_CHRON_RestoreAnchorFromProfile(self, "OnEnable")
@@ -615,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_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_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_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
for _, timer in pairs(self.timers[self.SPELL] or {}) do
@@ -701,9 +670,7 @@ function Chronometer:OnDisable()
if not self._mth_enabled then
return
end
MTH_CHRON_Trace("OnDisable begin profile=" .. MTH_CHRON_FormatBarPosition(self.profile))
if self.anchor then
MTH_CHRON_Trace("OnDisable anchor-point=" .. MTH_CHRON_DescribePoint(self.anchor))
end
MTH_CHRON_PersistAnchorPosition(self, "OnDisable")
self._mth_enabled = false
@@ -1209,7 +1176,6 @@ function Chronometer:CreateAnchor(text, r, g, b)
local py = tonumber(self.profile and self.profile.barposition and self.profile.barposition.y)
local ppoint = tostring(self.profile and self.profile.barposition and self.profile.barposition.point or "")
local prelpoint = tostring(self.profile and self.profile.barposition and self.profile.barposition.relativePoint or "")
MTH_CHRON_Trace("CreateAnchor saved-in profile=" .. MTH_CHRON_FormatBarPosition(self.profile))
if px ~= nil and py ~= nil then
if ppoint == "" then
ppoint = "TOPLEFT"
@@ -1219,17 +1185,14 @@ function Chronometer:CreateAnchor(text, r, g, b)
end
frame:ClearAllPoints()
frame:SetPoint(ppoint, UIParent, prelpoint, px, py)
MTH_CHRON_Trace("CreateAnchor restored point=" .. MTH_CHRON_DescribePoint(frame))
else
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 50)
MTH_CHRON_Trace("CreateAnchor default point=" .. MTH_CHRON_DescribePoint(frame))
end
frame:SetScript("OnDragStart", function()
if not this or not this.StartMoving then
return
end
MTH_CHRON_Trace("anchor drag-start point=" .. MTH_CHRON_DescribePoint(this))
this:StartMoving()
end)
frame:SetScript("OnDragStop", function()
@@ -1258,8 +1221,6 @@ function Chronometer:CreateAnchor(text, r, g, b)
this.owner.profile.barposition.relativePoint = point or "TOPLEFT"
this.owner.profile.barposition.x = x
this.owner.profile.barposition.y = y
MTH_CHRON_Trace("anchor drag-stop saved profile=" .. MTH_CHRON_FormatBarPosition(this.owner.profile)
.. " frame=" .. MTH_CHRON_DescribePoint(this))
end
end)
@@ -1305,9 +1266,11 @@ function Chronometer:SPELL_FADE(event, info)
if not self.profile.fadeonfade then return end
if info.skill == BS["Banish"] then return end
if info.type == "fade" then
-- Only act when the fade is on the player or on their target, not on other players
if info.victim == ParserLib_SELF then
return self:KillBar(info.skill)
end
if info.source and info.source ~= ParserLib_SELF then return end
return self:KillBar(info.skill, info.victim)
end
end
@@ -1315,8 +1278,20 @@ end
function Chronometer:SPELL_PERIODIC(event, info)
local aura, rank, unit, isgain
-- Primary filter: explicit non-self source → always ignore (other player's confirmed event)
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
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
isgain = nil
elseif not info.isDOT then
@@ -1344,7 +1319,27 @@ function Chronometer:SPELL_PERIODIC(event, info)
if timer.k.t then
if not unit then unit = UnitName("player") end
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
if not UnitExists("target") or unit ~= UnitName("target") then return end
end
+1 -19
View File
@@ -1,28 +1,15 @@
local MTH_ChronometerModule = {
name = "chronometer",
enabled = true,
version = "1.3.0",
version = "1.4.1",
events = {},
initialized = false,
}
local MTH_CHRON_MODULE_TRACE_ENABLED = false
local function MTH_CHRON_ModuleTrace(msg)
if not MTH_CHRON_MODULE_TRACE_ENABLED then
return
end
if MTH and MTH.Print then
MTH:Print("[CHRONTRACE] " .. tostring(msg), "debug")
elseif DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
DEFAULT_CHAT_FRAME:AddMessage("[CHRONTRACE] " .. tostring(msg))
end
end
local function MTH_CHRON_ApplyRuntimeEnabledState(enabled)
MTH_CHRON_ModuleTrace("module apply runtime enabled=" .. tostring(enabled and true or false))
if not MTH_ChronometerHunter then
MTH_CHRON_ModuleTrace("module apply runtime skipped (engine unavailable)")
return
end
if enabled then
@@ -37,18 +24,14 @@ local function MTH_CHRON_ApplyRuntimeEnabledState(enabled)
end
function MTH_ChronometerModule:init()
MTH_CHRON_ModuleTrace("module init begin enabled=" .. tostring(self.enabled and true or false))
if MTH_ChronometerHunter and MTH_ChronometerHunter.MTH_Initialize then
MTH_ChronometerHunter:MTH_Initialize()
end
MTH_CHRON_ApplyRuntimeEnabledState(self.enabled and true or false)
self.initialized = true
MTH_CHRON_ModuleTrace("module init end initialized=true")
end
function MTH_ChronometerModule:setEnabled(enabled)
MTH_CHRON_ModuleTrace("module setEnabled enabled=" .. tostring(enabled and true or false)
.. " initialized=" .. tostring(self.initialized and true or false))
if not self.initialized then
self:init()
end
@@ -56,7 +39,6 @@ function MTH_ChronometerModule:setEnabled(enabled)
end
function MTH_ChronometerModule:cleanup()
MTH_CHRON_ModuleTrace("module cleanup")
if MTH_ChronometerHunter and MTH_ChronometerHunter.MTH_Disable then
MTH_ChronometerHunter:MTH_Disable()
end
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
<!--
MetaHunt: Experimental Ammunition Module Loader
-->
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Include file="engine.lua"/>
</Ui>
+25 -253
View File
@@ -56,12 +56,7 @@ FOM_LastChoiceReason = nil;
FOM_RealmPlayer = nil;
FOM_LastPetName = nil;
FOM_LastFeedAttempt = nil;
FOM_TRACE_ENABLED = false;
local FOM_CORE_ATTEMPT_TRACKING_ENABLED = true;
local FOM_PERF_TRACE_ENABLED = false;
local FOM_PERF_TRACE_HISTORY_LIMIT = 80;
local FOM_PERF_TRACE_SPIKE_MS = 12;
local FOM_PERF_TRACE_HISTORY = {};
local FOM_LAST_SETUP_AT = 0;
local FOM_LAST_SETUP_PET = nil;
local FOM_LAST_QUEST_SCAN_AT = 0;
@@ -125,82 +120,10 @@ FOM_FamilyToLegacyMap = {
["Wolves"] = WOLF,
};
local function FOM_Trace(message)
if not FOM_TRACE_ENABLED then return; end
if type(DEFAULT_CHAT_FRAME) == "table" and DEFAULT_CHAT_FRAME.AddMessage then
DEFAULT_CHAT_FRAME:AddMessage("|cffffff00[FOM-Trace]|r " .. tostring(message));
end
end
local function FOM_PerfNowMs()
if (type(debugprofilestop) == "function") then
local raw = tonumber(debugprofilestop()) or 0;
return raw / 1000;
end
if (type(GetTime) == "function") then
return (tonumber(GetTime()) or 0) * 1000;
end
return 0;
end
local function FOM_PerfOut(message, forceShow)
local text = tostring(message or "");
if (text == "") then
return;
end
if (type(MTH_DebugFrame) == "table" and type(MTH_DebugFrame.AddInfo) == "function") then
if (forceShow and type(MTH_DebugFrame.Show) == "function") then
MTH_DebugFrame:Show();
end
MTH_DebugFrame:AddInfo(text);
return;
end
if (MTH and type(MTH.Print) == "function") then
MTH:Print(text, "debug");
return;
end
if (type(GFWUtils) == "table" and type(GFWUtils.Print) == "function") then
GFWUtils.Print(text);
end
end
local function FOM_PerfRecord(label, elapsedMs, detail, forcePrint)
if (not FOM_PERF_TRACE_ENABLED) then
return;
end
local numericElapsed = tonumber(elapsedMs) or 0;
if (numericElapsed > 10000) then
numericElapsed = numericElapsed / 1000;
end
local row = {
ts = time and time() or 0,
label = tostring(label or "unknown"),
ms = numericElapsed,
detail = tostring(detail or ""),
};
table.insert(FOM_PERF_TRACE_HISTORY, row);
if (table.getn(FOM_PERF_TRACE_HISTORY) > FOM_PERF_TRACE_HISTORY_LIMIT) then
table.remove(FOM_PERF_TRACE_HISTORY, 1);
end
return;
end
local function FOM_PerfDump()
if (table.getn(FOM_PERF_TRACE_HISTORY) <= 0) then
FOM_PerfOut("[FOM PERF] no samples.", true);
return;
end
FOM_PerfOut("[FOM PERF] recent samples: " .. tostring(table.getn(FOM_PERF_TRACE_HISTORY)), true);
for i = 1, table.getn(FOM_PERF_TRACE_HISTORY) do
local row = FOM_PERF_TRACE_HISTORY[i];
if (type(row) == "table") then
FOM_PerfOut("[FOM PERF] #" .. tostring(i)
.. " " .. tostring(row.label)
.. " " .. string.format("%.2f", tonumber(row.ms) or 0) .. "ms"
.. (tostring(row.detail or "") ~= "" and (" | " .. tostring(row.detail)) or ""), false);
end
end
end
local function FOM_GetServerProfile()
return FOM_ServerProfiles[FOM_SERVER_PROFILE] or {};
@@ -291,9 +214,6 @@ local function FOM_RegisterNoBuffQuarantine(itemID, petInfo)
end
row.lastObservedAt = time and time() or 0;
row.reason = "no-buff";
FOM_Trace("quarantine add family='" .. tostring(familyKey)
.. "' itemId=" .. tostring(numericItem)
.. " minRejectPetLevel=" .. tostring(row.minRejectPetLevel));
end
local function FOM_IsQuarantined(itemID, petLevel, familyKey)
@@ -349,29 +269,6 @@ local function FOM_IsItemPetLevelCompatible(itemID, petLevel)
return true;
end
function FOM_CommandTrace(mode)
local arg = string.lower(tostring(mode or ""));
if (arg == "perf on") then
FOM_PERF_TRACE_ENABLED = true;
FOM_PerfOut("[FOM PERF] enabled.", true);
return;
end
if (arg == "perf off") then
FOM_PERF_TRACE_ENABLED = false;
FOM_PerfOut("[FOM PERF] disabled.", true);
return;
end
if (arg == "perf clear") then
FOM_PERF_TRACE_HISTORY = {};
FOM_PerfOut("[FOM PERF] cleared.", true);
return;
end
if (arg == "perf dump") then
FOM_PerfDump();
return;
end
FOM_PerfOut("Usage: /fomtrace perf on|off|dump|clear", true);
end
local function FOM_CoreFeedReady()
if (not FOM_CORE_ATTEMPT_TRACKING_ENABLED) then
@@ -457,7 +354,7 @@ function FOM_BuildFamilyAliasMap()
FOM_AddFamilyAlias("Carrion Bird", "Carrion Birds");
FOM_AddFamilyAlias("Wind Serpent", "Wind Serpents");
FOM_AddFamilyAlias("Serpent", "Serpents (Cobra)");
FOM_AddFamilyAlias("Serpent", "Serpents");
end
function FOM_GetCanonicalPetFamily(rawFamily)
@@ -642,7 +539,6 @@ local function FOM_PruneUnknownFoodNoise(force)
if (type(time) == "function") then
store.updatedAt = time();
end
FOM_Trace("pruned unknown vendor-only non-food rows=" .. tostring(removed));
end
return removed;
@@ -688,7 +584,6 @@ local function FOM_PruneExceptionNoise()
if (removed > 0 and store ~= nil and type(time) == "function") then
store.updatedAt = time();
FOM_Trace("pruned inert exception rows=" .. tostring(removed));
end
return removed;
end
@@ -827,10 +722,6 @@ function FOM_OnLoad()
SLASH_FEEDOMATIC3 = "/feed";
SLASH_FEEDOMATIC4 = "/petfeed"; -- Rauen's PetFeed compatibility
SLASH_FEEDOMATIC5 = "/pf";
SLASH_FOMTRACE1 = "/fomtrace";
SlashCmdList["FOMTRACE"] = function(msg)
FOM_CommandTrace(msg);
end
SlashCmdList["FEEDOMATIC"] = function(msg)
if MTH_IsModuleEnabled and not MTH_IsModuleEnabled("feedomatic", false) then
if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
@@ -1035,7 +926,7 @@ function FOM_OnEvent(event, arg1)
end
if (foodID) then
FOM_LastFood = GFWUtils.ItemLink(foodID);
GFWUtils.DebugLog("Manually fed "..FOM_LastFood);
FOM_DebugLog("Manually fed "..FOM_LastFood);
end
end
return;
@@ -1075,8 +966,6 @@ function FOM_OnEvent(event, arg1)
elseif ( event == "UI_ERROR_MESSAGE" ) then
local lowerError = string.lower(tostring(arg1 or ""));
if (FOM_LastFood) then
FOM_Trace("ui error while feeding message='" .. tostring(arg1 or "")
.. "' lower='" .. tostring(lowerError) .. "'")
end
local isLowLevelError = (arg1 and SPELL_FAILED_FOOD_LOWLEVEL and string.find(arg1, SPELL_FAILED_FOOD_LOWLEVEL))
or string.find(lowerError, "low level")
@@ -1086,13 +975,8 @@ function FOM_OnEvent(event, arg1)
or string.find(lowerError, "wrong pet food")
or string.find(lowerError, "doesn't like")
or string.find(lowerError, "does not like")
FOM_Trace("ui error classify lowLevel=" .. tostring(isLowLevelError and true or false)
.. " wrongFood=" .. tostring(isWrongFoodError and true or false)
.. " hasAttempt=" .. tostring(type(FOM_LastFeedAttempt) == "table" and true or false)
.. " lastFood='" .. tostring(FOM_LastFood or "") .. "'")
if (isLowLevelError) then
FOM_Trace("reject reason=low-level")
if (type(FOM_LastFeedAttempt) == "table") then
FOM_CoreRecordReject(FOM_LastFeedAttempt.coreAttemptId, "low-level", arg1);
FOM_CoreFinalizeAttempt(FOM_LastFeedAttempt.coreAttemptId, "rejected", "low-level");
@@ -1110,7 +994,6 @@ function FOM_OnEvent(event, arg1)
end
elseif (isWrongFoodError) then
FOM_Trace("reject reason=wrong-food")
if (type(FOM_LastFeedAttempt) == "table") then
FOM_CoreRecordReject(FOM_LastFeedAttempt.coreAttemptId, "wrong-food", arg1);
FOM_CoreFinalizeAttempt(FOM_LastFeedAttempt.coreAttemptId, "rejected", "wrong-food");
@@ -1119,9 +1002,6 @@ function FOM_OnEvent(event, arg1)
if (FOM_LastFood) then
local alertPetName = MTH_FOM_GetTrackedPetName() or "Your pet";
local itemID = FOM_IDFromLink(FOM_LastFood);
FOM_Trace("learn reject wrongfood pet='" .. tostring(FOM_LastPetName or alertPetName)
.. "' itemId=" .. tostring(itemID)
.. " link='" .. tostring(FOM_LastFood) .. "'")
if ( FOM_Config.Alert == "chat") then
GFWUtils.Print(string.format(FOM_FEEDING_EAT_ANOTHER, alertPetName));
@@ -1281,10 +1161,6 @@ function FOM_OnUpdate(elapsed)
local elapsedSinceFeed = now - startedAt;
if (elapsedSinceFeed >= 0.10 and not FOM_LastFeedAttempt.loggedFirstCheck) then
FOM_LastFeedAttempt.loggedFirstCheck = true;
FOM_Trace("feed outcome check itemId=" .. tostring(FOM_LastFeedAttempt.itemId)
.. " pet='" .. tostring(FOM_LastFeedAttempt.petName or "")
.. "' hasFeedBuff=" .. tostring(FOM_HasFeedEffect() and true or false)
.. " elapsed=" .. string.format("%.2f", elapsedSinceFeed));
end
if (FOM_HasFeedEffect()) then
@@ -1300,9 +1176,6 @@ function FOM_OnUpdate(elapsed)
SendChatMessage(string.format(FOM_FEEDING_FEED, confirmedPetName, confirmedFoodLink).. FOM_RandomEmote(), "EMOTE");
end
FOM_CoreFinalizeAttempt(FOM_LastFeedAttempt.coreAttemptId, "accepted", "accepted");
FOM_Trace("feed outcome accepted-with-buff itemId=" .. tostring(FOM_LastFeedAttempt.itemId)
.. " pet='" .. tostring(FOM_LastFeedAttempt.petName or "")
.. "' elapsed=" .. string.format("%.2f", elapsedSinceFeed));
FOM_LastFeedAttempt = nil;
FOM_LastFood = nil;
elseif (elapsedSinceFeed >= 2.50) then
@@ -1320,10 +1193,6 @@ function FOM_OnUpdate(elapsed)
tonumber(currentPetInfo and currentPetInfo.level) or nil,
"no-buff");
end
FOM_Trace("feed outcome no-eating-buff itemId=" .. tostring(FOM_LastFeedAttempt.itemId)
.. " pet='" .. tostring(FOM_LastFeedAttempt.petName or "")
.. "' elapsed=" .. string.format("%.2f", elapsedSinceFeed)
.. " (likely not accepted by pet)");
FOM_LastFood = nil;
FOM_LastFeedAttempt = nil;
@@ -1350,8 +1219,6 @@ function FOM_OnUpdate(elapsed)
excludedCount = excludedCount + 1;
end
end
FOM_Trace("feed retry scheduled after no-buff retry=" .. tostring(retryCount + 1)
.. " excludedCount=" .. tostring(excludedCount));
FOM_Feed(nil, {
retryCount = retryCount + 1,
excludedItemIds = excludedItemIds,
@@ -1378,31 +1245,31 @@ end
function FOM_CanFeed()
local petInfo = MTH_FOM_GetCorePetInfo();
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;
end
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;
end
if ( UnitHealth("player") <= 0 ) then
GFWUtils.DebugLog("Can't feed; I'm dead.");
FOM_DebugLog("Can't feed; I'm dead.");
return false;
end
if ( CastingBarFrameStatusBar:IsVisible() ) then
GFWUtils.DebugLog("Can't feed; casting a spell / tradeksill.");
FOM_DebugLog("Can't feed; casting a spell / tradeksill.");
return false;
end
if ( UnitOnTaxi("player") ) then
GFWUtils.DebugLog("Can't feed; flying.");
FOM_DebugLog("Can't feed; flying.");
return false;
end
if ( FOM_State.InCombat ) or ( PlayerFrame.inCombat ) then
GFWUtils.DebugLog("Can't feed; in combat.");
FOM_DebugLog("Can't feed; in combat.");
return false;
end
if ( LootFrame:IsVisible() ) then
GFWUtils.DebugLog("Shouldn't feed; loot window is open.");
FOM_DebugLog("Shouldn't feed; loot window is open.");
return false;
end
@@ -1423,7 +1290,7 @@ function FOM_CanFeed()
if ( buff ~= nil) then
for _, buffTexture in dontFeedBuffTextures do
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;
end
end
@@ -1436,7 +1303,7 @@ function FOM_CanFeed()
msg = string.lower(msg);
for _, mountName in FOM_MOUNT_NAME_SUBSTRINGS do
if (string.find(msg, mountName)) then
GFWUtils.DebugLog("Can't feed; mounted.");
FOM_DebugLog("Can't feed; mounted.");
return false;
end
end
@@ -1989,13 +1856,13 @@ end
function FOM_AddFood(diet, food)
if (FOM_Foods[diet] == nil) then
GFWUtils.DebugLog("FOM_Foods[diet] == nil");
FOM_DebugLog("FOM_Foods[diet] == nil");
end
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
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
if ( GFWTable.IndexOf(FOM_Foods[diet], food) == 0 ) then
if (FOM_AddedFoods == nil) then
@@ -2031,13 +1898,13 @@ end
function FOM_RemoveFood(diet, food)
if (FOM_Foods[diet] == nil) then
GFWUtils.DebugLog("FOM_Foods[diet] == nil");
FOM_DebugLog("FOM_Foods[diet] == nil");
end
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
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
if ( GFWTable.IndexOf(FOM_Foods[diet], food) ~= 0 ) then
if (FOM_RemovedFoods == nil) then
@@ -2333,7 +2200,6 @@ local function FOM_TryPickSinglePrecomputedFood(foodList, excludedItemIds, allow
end
function FOM_Feed(aFood, options)
local feedStartMs = FOM_PerfNowMs();
options = options or {};
local retryCount = tonumber(options.retryCount) or 0;
local excludedItemIds = FOM_CloneSet(options.excludedItemIds);
@@ -2342,7 +2208,6 @@ function FOM_Feed(aFood, options)
if MTH_IsModuleEnabled and not MTH_IsModuleEnabled("feedomatic", false) then
if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
MTH:Print("[FOM WRAP] FOM_Feed blocked: module disabled", "debug")
end
return false;
end
@@ -2368,19 +2233,9 @@ function FOM_Feed(aFood, options)
-- Assign Variable
local pet = (MTH_FOM_IsValidPetName(petInfo.name) and petInfo.name) or "Your pet";
FOM_Trace("feed request pet='" .. tostring(pet)
.. "' level=" .. tostring(petInfo.level)
.. " happiness=" .. tostring(petInfo.happiness)
.. " manualFood='" .. tostring(aFood or "") .. "'"
.. " retry=" .. tostring(retryCount)
.. " excluded=" .. tostring(FOM_CountSetEntries(excludedItemIds)))
local checkSetupStartMs = FOM_PerfNowMs();
FOM_CheckSetup();
FOM_PerfRecord("FOM_CheckSetup", FOM_PerfNowMs() - checkSetupStartMs, "retry=" .. tostring(retryCount), false);
if (FOM_LastPetName == nil or FOM_LastPetName == "") then
GFWUtils.DebugLog("Can't get pet info.");
FOM_PerfRecord("FOM_Feed total", FOM_PerfNowMs() - feedStartMs, "result=no-pet-name", true);
return false;
end
@@ -2404,24 +2259,18 @@ function FOM_Feed(aFood, options)
if ( foodBag == nil) then
-- No Food Could be Found
GFWUtils.Print(string.format(FOM_ERROR_FOOD_NOT_FOUND, pet, aFood));
FOM_PerfRecord("FOM_Feed total", FOM_PerfNowMs() - feedStartMs, "result=manual-not-found", true);
return false;
end
FOM_LastChoiceReason = "manual selection";
else
local cachedChoiceStartMs = FOM_PerfNowMs();
local cachedBag, cachedSlot, cachedItemId = FOM_GetCachedAutoChoice(excludedItemIds);
if (cachedBag ~= nil and cachedSlot ~= nil) then
foodBag, foodItem = cachedBag, cachedSlot;
FOM_LastChoiceReason = "cached previous food";
FOM_PerfRecord("FOM_AutoChoice cache", FOM_PerfNowMs() - cachedChoiceStartMs,
"hit itemId=" .. tostring(cachedItemId), false);
else
FOM_PerfRecord("FOM_AutoChoice cache", FOM_PerfNowMs() - cachedChoiceStartMs, "miss", false);
end
if (foodBag == nil) then
local precomputeStartMs = FOM_PerfNowMs();
local cacheNow = (type(GetTime) == "function") and (GetTime() or 0) or 0;
if (retryCount <= 0
and type(FOM_FEED_SCAN_CACHE) == "table"
@@ -2429,8 +2278,6 @@ function FOM_Feed(aFood, options)
and type(FOM_FEED_SCAN_CACHE.foods) == "table") then
precomputedFoodList = FOM_CloneFoodList(FOM_FEED_SCAN_CACHE.foods);
openSlots = tonumber(FOM_FEED_SCAN_CACHE.openSlots) or 0;
FOM_PerfRecord("FOM_Feed precompute", FOM_PerfNowMs() - precomputeStartMs,
"cache-hit foods=" .. tostring(table.getn(precomputedFoodList)) .. " openSlots=" .. tostring(openSlots), false);
else
precomputedFoodList = FOM_FlatFoodList();
openSlots = FOM_NumOpenBagSlots();
@@ -2440,32 +2287,23 @@ function FOM_Feed(aFood, options)
foods = FOM_CloneFoodList(precomputedFoodList),
openSlots = openSlots,
};
FOM_PerfRecord("FOM_Feed precompute", FOM_PerfNowMs() - precomputeStartMs,
"cache-miss foods=" .. tostring(table.getn(precomputedFoodList)) .. " openSlots=" .. tostring(openSlots), false);
end
local fastPickStartMs = FOM_PerfNowMs();
foodBag, foodItem = FOM_TryPickSinglePrecomputedFood(precomputedFoodList, excludedItemIds, (FOM_Config.AvoidUsefulFood and false or true));
if (foodBag ~= nil) then
FOM_LastChoiceReason = "single candidate fast-path";
FOM_PerfRecord("FOM_SingleCandidate", FOM_PerfNowMs() - fastPickStartMs, "hit", false);
else
FOM_PerfRecord("FOM_SingleCandidate", FOM_PerfNowMs() - fastPickStartMs, "miss", false);
end
if (foodBag == nil) then
local findStartMs = FOM_PerfNowMs();
foodBag, foodItem = FOM_NewFindFood(nil, excludedItemIds, precomputedFoodList, openSlots);
FOM_PerfRecord("FOM_NewFindFood primary", FOM_PerfNowMs() - findStartMs, "found=" .. tostring(foodBag ~= nil), false);
end
end
end
local fallbackBag, fallbackItem = nil, nil;
if (not manualFood and foodBag == nil and FOM_Config.Fallback) then
local fallbackStartMs = FOM_PerfNowMs();
fallbackBag, fallbackItem = FOM_NewFindFood(1, excludedItemIds, precomputedFoodList, openSlots);
FOM_PerfRecord("FOM_NewFindFood fallback", FOM_PerfNowMs() - fallbackStartMs, "found=" .. tostring(fallbackBag ~= nil), false);
end
if ( foodBag == nil) then
@@ -2480,12 +2318,10 @@ function FOM_Feed(aFood, options)
-- No Food Could be Found
GFWUtils.Print(string.format(FOM_ERROR_NO_FOOD, pet));
FOM_LastChoiceReason = nil;
FOM_PerfRecord("FOM_Feed total", FOM_PerfNowMs() - feedStartMs, "result=no-food", true);
return false;
end
end
local prepareStartMs = FOM_PerfNowMs();
FOM_LastFood = GetContainerItemLink(foodBag, foodItem);
local selectedId = FOM_IDFromLink(FOM_LastFood)
FOM_SetCachedAutoChoice(foodBag, foodItem, selectedId)
@@ -2504,26 +2340,15 @@ function FOM_Feed(aFood, options)
petLevel = tonumber(petInfo and petInfo.level) or nil,
foodLevel = selectedFoodLevel,
})
FOM_PerfRecord("FOM_Feed prepare", FOM_PerfNowMs() - prepareStartMs, "itemId=" .. tostring(selectedId), false);
FOM_Trace("selected food link='" .. tostring(FOM_LastFood)
.. "' itemId=" .. tostring(selectedId)
.. " bag=" .. tostring(foodBag)
.. " slot=" .. tostring(foodItem)
.. " reason='" .. tostring(FOM_LastChoiceReason or "") .. "'")
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
-- don't actually feed anything, just show what we would choose
FOM_PerfRecord("FOM_Feed total", FOM_PerfNowMs() - feedStartMs, "result=debug", true);
return false;
end
-- Actually feed the item to the pet
local dropStartMs = FOM_PerfNowMs();
PickupContainerItem(foodBag, foodItem);
FOM_Trace("feed execute pickup bag=" .. tostring(foodBag)
.. " slot=" .. tostring(foodItem)
.. " cursorHasItem=" .. tostring(CursorHasItem() and true or false))
if ( CursorHasItem() ) then
MTH_FEED_SuppressChatUntil = (GetTime() or 0) + 2.0;
MTH_FEED_SuppressChatFoodName = FOM_NameFromLink(FOM_LastFood);
@@ -2531,26 +2356,19 @@ function FOM_Feed(aFood, options)
local ok = pcall(DropItemOnUnit, "pet");
MTH_FEED_SuppressCoreDropHook = nil;
if (not ok) then
FOM_Trace("feed execute drop on pet failed during protected call");
end
FOM_Trace("feed execute drop on pet cursorHasItemAfterDrop=" .. tostring(CursorHasItem() and true or false))
end
FOM_PerfRecord("FOM_Feed drop", FOM_PerfNowMs() - dropStartMs, "cursor=" .. tostring(CursorHasItem() and true or false), false);
if (coreAttemptId and type(MTH_FEED_RecordClientDropResult) == "function") then
pcall(MTH_FEED_RecordClientDropResult, coreAttemptId, {
consumedFromCursor = (CursorHasItem() and false or true),
})
end
if ( CursorHasItem() ) then
FOM_Trace("feed execute immediate-fail item stayed on cursor; likely rejected before combat log/error parse")
PickupContainerItem(foodBag, foodItem);
FOM_CoreRecordReject(coreAttemptId, "client-drop-fail", nil);
FOM_CoreFinalizeAttempt(coreAttemptId, "rejected", "client-drop-fail");
FOM_Trace("feed execute returned item to bag")
FOM_PerfRecord("FOM_Feed total", FOM_PerfNowMs() - feedStartMs, "result=cursor-fail", true);
return false;
else
FOM_Trace("feed execute accepted by client (item consumed from cursor)")
if (selectedId ~= nil) then
excludedItemIds[selectedId] = true;
end
@@ -2568,10 +2386,6 @@ function FOM_Feed(aFood, options)
loggedFirstCheck = false,
}
FOM_State.ShouldFeed = nil;
FOM_Trace("feed alert deferred until confirmation itemId=" .. tostring(selectedId)
.. " pet='" .. tostring(pet or "")
.. "' mode='" .. tostring(FOM_Config.Alert or "") .. "'")
FOM_PerfRecord("FOM_Feed total", FOM_PerfNowMs() - feedStartMs, "result=ok itemId=" .. tostring(selectedId), true);
return true;
end
end
@@ -2656,7 +2470,6 @@ local function FOM_EnsureQuestScanFresh(maxAgeSeconds)
end
function FOM_FlatFoodList()
local flatStartMs = FOM_PerfNowMs();
local foodList = {};
local overflowFoodList = {};
local scanned = 0;
@@ -2746,27 +2559,10 @@ function FOM_FlatFoodList()
if (table.getn(foodList) == 0 and table.getn(overflowFoodList) > 0) then
foodList = overflowFoodList;
end
FOM_Trace("flat food scan scanned=" .. tostring(scanned)
.. " inDiet=" .. tostring(inDiet)
.. " compatible=" .. tostring(compatibleCount)
.. " overflowCompatible=" .. tostring(overflowCompatibleCount)
.. " exceptionRejects=" .. tostring(rejectedByException)
.. " levelOverrideRejects=" .. tostring(rejectedByLevelOverride)
.. " quarantineRejects=" .. tostring(rejectedByQuarantine)
.. " unknownLevel=" .. tostring(unknownLevelCandidates)
.. " candidates=" .. tostring(table.getn(foodList)))
if (FOM_PERF_TRACE_ENABLED) then
FOM_PerfRecord("FOM_FlatFoodList", FOM_PerfNowMs() - flatStartMs,
"scanned=" .. tostring(scanned)
.. " inDiet=" .. tostring(inDiet)
.. " candidates=" .. tostring(table.getn(foodList)),
false);
end
return foodList;
end
function FOM_NewFindFood(fallback, excludedItemIds, precomputedFoodList, openSlotsOverride)
local findStartMs = FOM_PerfNowMs();
local FlatFoodList = nil;
if (type(precomputedFoodList) == "table") then
FlatFoodList = FOM_CloneFoodList(precomputedFoodList);
@@ -2777,12 +2573,6 @@ function FOM_NewFindFood(fallback, excludedItemIds, precomputedFoodList, openSlo
local reasonParts = {};
if (initialCount <= 0) then
FOM_LastChoiceReason = nil;
if (FOM_PERF_TRACE_ENABLED) then
FOM_PerfRecord("FOM_NewFindFood", FOM_PerfNowMs() - findStartMs,
"fallback=" .. tostring(fallback and true or false)
.. " initial=0 final=0",
false);
end
return nil;
end
local petInfo = MTH_FOM_GetCorePetInfo();
@@ -2869,18 +2659,6 @@ function FOM_NewFindFood(fallback, excludedItemIds, precomputedFoodList, openSlo
table.insert(reasonParts, "fallback allows useful food");
end
end
FOM_Trace("find food fallback=" .. tostring(fallback and true or false)
.. " initial=" .. tostring(initialCount)
.. " postConjured=" .. tostring(postConjuredCount)
.. " postFilters=" .. tostring(table.getn(FlatFoodList))
.. " reasons='" .. tostring(table.concat(reasonParts, ", ")) .. "'")
if (FOM_PERF_TRACE_ENABLED) then
FOM_PerfRecord("FOM_NewFindFood", FOM_PerfNowMs() - findStartMs,
"fallback=" .. tostring(fallback and true or false)
.. " initial=" .. tostring(initialCount)
.. " final=" .. tostring(table.getn(FlatFoodList)),
false);
end
for _, foodInfo in FlatFoodList do
if (foodInfo.overflow) then
@@ -2894,15 +2672,9 @@ function FOM_NewFindFood(fallback, excludedItemIds, precomputedFoodList, openSlo
else
FOM_LastChoiceReason = nil;
end
FOM_Trace("find food result bag=" .. tostring(foodInfo.bag)
.. " slot=" .. tostring(foodInfo.slot)
.. " quality=" .. tostring(foodInfo.quality)
.. " useful=" .. tostring(foodInfo.useful and true or false)
.. " temp=" .. tostring(foodInfo.temp and true or false))
return foodInfo.bag, foodInfo.slot;
end
FOM_LastChoiceReason = nil;
FOM_Trace("find food result: none")
return nil;
end
@@ -2936,12 +2708,12 @@ end
function FOM_IsUsefulFood(itemID, quantity)
local foodName = GetItemInfo(itemID);
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;
end
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
GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; is good for cooking.");
FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; is good for cooking.");
return true;
end
end
@@ -2953,19 +2725,19 @@ function FOM_IsUsefulFood(itemID, quantity)
FOM_Quantity[foodName] = FOM_Quantity[foodName] + quantity;
end
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;
else
GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; is needed for quest.");
FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; is needed for quest.");
return true;
end
end
end
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;
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;
end
@@ -3003,7 +2775,7 @@ function FOM_IsInDiet(food, dietList)
diet = "";
end
if (FOM_Foods[diet] == nil) then
GFWUtils.DebugLog("FOM_Foods[diet] == nil");
FOM_DebugLog("FOM_Foods[diet] == nil");
end
if (FOM_RemovedFoods ~= nil and FOM_RemovedFoods[diet] ~= nil and GFWTable.IndexOf(FOM_RemovedFoods[diet], food) ~= 0) then
return false;
+1 -1
View File
@@ -80,7 +80,7 @@ FOM_Emotes = {
["Foxes"] = {
"Clever fox, clever snack choice.",
},
["Serpents (Cobra)"] = {
["Serpents"] = {
"No hissing with your mouth full.",
},
};
-13
View File
@@ -53,16 +53,6 @@ function GFWUtils_temp_PrintOnce(message, interval, r, g, b)
GFWUtils.PrintOnceCache[message] = GetTime();
end
-- Prints a message to the chat frame only if Debug is set
function GFWUtils_temp_DebugLog(message)
if (GFWUtils.Debug) then
if MTH and MTH.Print then
MTH:Print(message, "debug")
else
DEFAULT_CHAT_FRAME:AddMessage(message, GFW_DEBUG_COLOR.r, GFW_DEBUG_COLOR.g, GFW_DEBUG_COLOR.b);
end
end
end
-- Prints a message in yellow to the floating messages frame
function GFWUtils_temp_Note(message)
@@ -177,8 +167,6 @@ if (G.Version == nil or (tonumber(G.Version) ~= nil and G.Version < GFWUTILS_THI
-- Constants
GFW_FONT_COLOR = {r=0.25, g=1.0, b=1.0};
GFW_DEBUG_COLOR = {r=1.0, g=0.75, b=0.25};
G.Debug = false;
-- Functions
G.Hilite = GFWUtils_temp_HiliteText;
@@ -187,7 +175,6 @@ if (G.Version == nil or (tonumber(G.Version) ~= nil and G.Version < GFWUTILS_THI
G.LtY = GFWUtils_temp_LightYellowText;
G.Print = GFWUtils_temp_Print;
G.PrintOnce = GFWUtils_temp_PrintOnce;
G.DebugLog = GFWUtils_temp_DebugLog;
G.Note = GFWUtils_temp_Note;
G.FormatToPattern = GFWUtils_temp_FormatToPattern;
G.Split = GFWUtils_temp_Split;
+2 -12
View File
@@ -6,7 +6,7 @@
local MTH_FeedOMatic = {
name = "feedomatic",
enabled = false,
version = "1.3.0",
version = "1.4.1",
events = {
"VARIABLES_LOADED",
"MERCHANT_SHOW",
@@ -112,10 +112,6 @@ local function MTH_FeedOMatic_CallLegacyOnEvent(evt, a1, a2, a3, a4, a5, a6, a7,
event = oldEvent
arg1, arg2, arg3, arg4, arg5 = oldArg1, oldArg2, oldArg3, oldArg4, oldArg5
arg6, arg7, arg8, arg9 = oldArg6, oldArg7, oldArg8, oldArg9
if not ok and MTH and MTH.DebugPrint then
MTH:DebugPrint("FeedOMatic legacy OnEvent call failed for event: " .. tostring(evt))
end
end
local function MTH_FeedOMatic_EnsureVariablesLoaded(module)
@@ -166,8 +162,7 @@ end
local function MTH_FeedOMatic_Log(message, severity)
if type(MTH_Log) == "function" then
local logSeverity = severity or "debug"
MTH_Log("[FeedOMatic] " .. tostring(message or ""), logSeverity)
MTH_Log("[FeedOMatic] " .. tostring(message or ""), severity)
end
end
@@ -198,10 +193,8 @@ local function MTH_FeedOMatic_DebugMerchantScan(sourceEvent)
if type(rows) == "table" then
dietCount = table.getn(rows)
end
MTH_FeedOMatic_Log("diet " .. tostring(dietName) .. ": " .. tostring(dietCount) .. " item(s)", "debug")
if type(rows) == "table" then
for _, row in rows do
MTH_FeedOMatic_Log(" - [" .. tostring(row.id) .. "] " .. tostring(row.name) .. " (slot=" .. tostring(row.index) .. ")", "debug")
end
end
end
@@ -209,7 +202,6 @@ local function MTH_FeedOMatic_DebugMerchantScan(sourceEvent)
if unknownCount > 0 and type(merchantFoods.unknown) == "table" then
for _, row in merchantFoods.unknown do
MTH_FeedOMatic_Log("unknown map: [" .. tostring(row.id) .. "] " .. tostring(row.name) .. " (slot=" .. tostring(row.index) .. ")", "debug")
end
end
end
@@ -228,7 +220,6 @@ local function MTH_FeedOMatic_SetMerchantProbeEnabled(enabled)
MTH_FOM_MerchantProbe:SetScript("OnEvent", function()
local evt = event
if evt == "MERCHANT_SHOW" or evt == "MERCHANT_UPDATE" then
MTH_FeedOMatic_Log("probe event received: " .. tostring(evt), "debug")
MTH_FeedOMatic_DebugMerchantScan(evt)
end
end)
@@ -236,7 +227,6 @@ local function MTH_FeedOMatic_SetMerchantProbeEnabled(enabled)
MTH_FOM_MerchantProbe:RegisterEvent("MERCHANT_SHOW")
MTH_FOM_MerchantProbe:RegisterEvent("MERCHANT_UPDATE")
MTH_FeedOMatic_Log("merchant probe enabled", "debug")
end
function MTH_FeedOMatic:init()
+1 -1
View File
@@ -6,7 +6,7 @@
local MTH_ICU = {
name = "icu",
enabled = false,
version = "1.3.0",
version = "1.4.1",
events = {
"VARIABLES_LOADED",
},
+21
View File
@@ -48,10 +48,25 @@ end
local MTHSmartAmmo_InitializeHooks
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)
local saved = MTHSmartAmmo_GetSaved()
if enabled then
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
MTHSmartAmmo_InitializeHooks()
end
@@ -63,6 +78,12 @@ function MTHSmartAmmo_SetSmartEnabled(enabled, silent)
end
else
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
MTH_SA_Print("Smart Ammo Disabled.")
end
+1 -1
View File
@@ -7,7 +7,7 @@ MTH_SA_MANAGED_HOOKS = true
local MTH_SmartAmmo = {
name = "smartammo",
enabled = true,
version = "1.3.0",
version = "1.4.1",
events = {
"VARIABLES_LOADED",
-- PLAYER_ENTERING_WORLD handled by engine's own frame
+26 -9
View File
@@ -6,7 +6,7 @@
local MTH_Tooltips = {
name = "tooltips",
enabled = true,
version = "1.3.0",
version = "1.4.1",
events = {
"UPDATE_MOUSEOVER_UNIT",
"UNIT_NAME_UPDATE",
@@ -1389,7 +1389,6 @@ local function MTH_TT_AddPetActionNotLearnedHint()
return
end
local ownerName = MTH_TT_GetTooltipOwnerName()
local ownerMatch = MTH_TT_IsPetActionTooltipOwner()
local barMatch = MTH_TT_IsSpellOnPetActionBar(spellName)
if not ownerMatch and not barMatch then
@@ -1406,11 +1405,13 @@ local function MTH_TT_AddPetActionNotLearnedHint()
end
local canonicalLower = MTH_TT_Lower(canonical)
local known = MTH_TT_HunterKnowsAbility(canonicalLower, rankNumber)
if not known then
known = MTH_TT_CurrentPetKnowsAbility(canonicalLower, rankNumber)
end
if known then
local hunterKnown = MTH_TT_HunterKnowsAbility(canonicalLower, rankNumber)
-- Only fall back to petKnown for ranked abilities: rankless abilities have no rank
-- filter in CurrentPetKnowsAbility, so they always match on name alone -> false positive.
local petKnown = (not hunterKnown)
and MTH_TT_AbilityHasPositiveRanks(canonical)
and MTH_TT_CurrentPetKnowsAbility(canonicalLower, rankNumber)
if hunterKnown or petKnown then
return
end
@@ -1485,8 +1486,11 @@ local function MTH_TT_AddTooltip(unit)
local ammoVendorTooltipsEnabled = MTH_TT_IsAmmoVendorTooltipsEnabled()
local vendorInfo = ammoVendorTooltipsEnabled and MTH_TT_FindVendorInfo(name) or nil
local row = beastTooltipsEnabled and MTH_TT_FindBeastRow(name) or nil
local savedEntry = beastTooltipsEnabled
and (type(MTH_BLS_FindSavedBeastByName) == "function")
and MTH_BLS_FindSavedBeastByName(name) or nil
local scorpokAdded = MTH_TT_AddScorpokTargetsTooltip(unit, name)
if not row and not vendorInfo and not scorpokAdded then
if not row and not vendorInfo and not scorpokAdded and not savedEntry then
state.lookupMiss = (state.lookupMiss or 0) + 1
MTH_TT_StateSet("lookup-miss", name, normalized)
MTH_TT_Log("lookup miss: unit='" .. tostring(name) .. "' normalized='" .. tostring(normalized) .. "'")
@@ -1510,8 +1514,16 @@ local function MTH_TT_AddTooltip(unit)
MTH_TT_Log("vendor tooltip added: unit='" .. tostring(name) .. "'")
end
-- Determine which abilities source to display.
local abilitiesSource = nil
if row then
local abilities = MTH_TT_ParseAbilities(row.abilities)
abilitiesSource = row.abilities
elseif savedEntry and savedEntry.abilities and savedEntry.abilities ~= "" then
abilitiesSource = savedEntry.abilities
end
if abilitiesSource then
local abilities = MTH_TT_ParseAbilities(abilitiesSource)
if table.getn(abilities) == 0 then
MTH_TT_StateSet("skip-no-abilities", name, normalized)
MTH_TT_Log("skip: beast has no abilities ('" .. tostring(name) .. "')")
@@ -1534,6 +1546,11 @@ local function MTH_TT_AddTooltip(unit)
end
end
if savedEntry then
GameTooltip:AddLine("Beast recorded by you", 1.0, 0.85, 0.0)
addedAnything = 1
end
if addedAnything then
GameTooltip:Show()
state.added = (state.added or 0) + 1
+1 -18
View File
@@ -37,13 +37,6 @@ local function ZHunterMod_RunButtonInit(frame, onEventFunc)
event = oldEvent
end
local function ZHunterMod_LogDeferred(msg)
local deferredDebug = _G and _G["MTH_ZH_DEFERRED_DEBUG"]
if not (MTH and MTH.debug and deferredDebug) then
return
end
MTH_ZH_Print("[ZHUNTER] " .. tostring(msg), "error")
end
local function ZHunterMod_EnsureButtonFrame(buttonName)
local frame = getglobal(buttonName)
@@ -77,7 +70,6 @@ local function ZHunterMod_EnsureButtonFrame(buttonName)
else
created:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
end
ZHunterMod_LogDeferred("DeferredInit: created missing frame " .. tostring(buttonName))
end
return created
end
@@ -94,15 +86,6 @@ function ZHunterMod_DeferredInit()
local companions = ZHunterMod_EnsureButtonFrame("zButtonCompanions")
local toys = ZHunterMod_EnsureButtonFrame("zButtonToys")
ZHunterMod_LogDeferred("DeferredInit: Pet=" .. tostring(pet ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Aspect=" .. tostring(aspect ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Track=" .. tostring(track ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Trap=" .. tostring(trap ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Ranged=" .. tostring(ranged ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Ammo=" .. tostring(ammo ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Mounts=" .. tostring(mounts ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Companions=" .. tostring(companions ~= nil))
ZHunterMod_LogDeferred("DeferredInit: Toys=" .. tostring(toys ~= nil))
-- Continue with all frames that exist; do not hard-abort when one optional frame is missing.
local missing = {}
@@ -202,7 +185,7 @@ function ZHunterMod_DeferredInit()
if type(MTH_ZH_OnDeferredInitComplete) == "function" then
local ok, err = pcall(MTH_ZH_OnDeferredInitComplete)
if not ok and MTH_DebugFrame and MTH_DebugFrame.AddError then
if not ok then
MTH_ZH_Print("[ZHUNTER] DeferredInit callback error: " .. tostring(err), "error")
end
end
+1
View File
@@ -86,6 +86,7 @@ ZHUNTER_TRACK_GIANTS = "Track Giants"
ZHUNTER_TRACK_MINERALS = "Find Minerals"
ZHUNTER_TRACK_HERBS = "Find Herbs"
ZHUNTER_TRACK_TREASURE = "Find Treasure"
ZHUNTER_TRACK_TREES = "Find Trees"
ZHUNTER_TRAP_FREEZING = "Freezing Trap"
ZHUNTER_TRAP_FROST = "Frost Trap"
-46
View File
@@ -14,7 +14,6 @@ BINDING_HEADER_ZToysHeader = "ZToys Buttons"
ZHunterModTooltip = CreateFrame("GameTooltip", "MTH_ZH_AbilityProbe", nil, "GameTooltipTemplate")
ZHunterModTooltipTextLeft1 = getglobal("MTH_ZH_AbilityProbeTextLeft1")
MTH_ZH_TRACE_ENABLED = false
local function MTH_ZH_DescribePoint(frame)
if not (frame and frame.GetPoint) then
@@ -33,51 +32,8 @@ local function MTH_ZH_DescribePoint(frame)
.. " @(" .. tostring(x) .. "," .. tostring(y) .. ")"
end
function MTH_ZH_Trace(msg)
if not MTH_ZH_TRACE_ENABLED then
return
end
if MTH and MTH.Print then
MTH:Print("[ZHTRACE] " .. tostring(msg), "debug")
elseif DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
DEFAULT_CHAT_FRAME:AddMessage("[ZHTRACE] " .. tostring(msg))
end
end
function MTH_ZH_TraceButtonPoint(frame, reason)
if not MTH_ZH_TRACE_ENABLED then
return
end
if not frame then
MTH_ZH_Trace("point " .. tostring(reason or "") .. " frame=nil")
return
end
local name = frame.GetName and frame:GetName() or "<unnamed>"
MTH_ZH_Trace("point " .. tostring(reason or "") .. " " .. tostring(name) .. " " .. MTH_ZH_DescribePoint(frame))
end
function MTH_ZH_TraceAllButtonPoints(reason)
if not MTH_ZH_TRACE_ENABLED then
return
end
local names = {
"zButtonAspect",
"zButtonAmmo",
"zButtonTrack",
"zButtonTrap",
"zButtonRanged",
"zButtonPet",
"zButtonMounts",
"zButtonCompanions",
"zButtonToys",
}
MTH_ZH_Trace("snapshot begin reason=" .. tostring(reason or ""))
for i = 1, table.getn(names) do
local frame = getglobal(names[i])
MTH_ZH_TraceButtonPoint(frame, tostring(reason or "") .. ":" .. tostring(names[i]))
end
MTH_ZH_Trace("snapshot end reason=" .. tostring(reason or ""))
end
function MTH_ZH_IsModuleEnabled()
if not (MTH and MTH.IsModuleEnabled) then
@@ -170,7 +126,6 @@ function MTH_ZH_HandleDisabledSlash(message, tableKey, fieldKey)
end
function ZHunterMod_AlignButtons()
MTH_ZH_TraceAllButtonPoints("AlignButtons:before")
zButtonAmmo:ClearAllPoints()
zButtonAmmo:SetPoint("TOP", zButtonAspect, "BOTTOM", 0, -15)
zButtonTrack:ClearAllPoints()
@@ -189,7 +144,6 @@ function ZHunterMod_AlignButtons()
AutoStripDisplay:ClearAllPoints()
AutoStripDisplay:SetPoint("TOP", zButtonToys, "BOTTOM", 0, -10)
end
MTH_ZH_TraceAllButtonPoints("AlignButtons:after")
end
function ZMarkTarget()
-23
View File
@@ -536,13 +536,6 @@ local function ZSpellButton_SaveParentPosition(parent)
saved["parent"]["relativePoint"] = tostring(relPoint)
saved["parent"]["x"] = math.floor(x + 0.5)
saved["parent"]["y"] = math.floor(y + 0.5)
if type(MTH_ZH_Trace) == "function" then
MTH_ZH_Trace("persist-parent-position key=" .. tostring(key)
.. " point=" .. tostring(saved["parent"]["point"])
.. " rel=" .. tostring(saved["parent"]["relativePoint"])
.. " x=" .. tostring(saved["parent"]["x"])
.. " y=" .. tostring(saved["parent"]["y"]))
end
end
local function ZSpellButton_RestoreParentPosition(parent)
@@ -580,13 +573,6 @@ local function ZSpellButton_RestoreParentPosition(parent)
parent:ClearAllPoints()
parent:SetPoint(point, UIParent, relPoint, px, py)
if type(MTH_ZH_Trace) == "function" then
MTH_ZH_Trace("restore-parent-position key=" .. tostring(key)
.. " point=" .. tostring(point)
.. " rel=" .. tostring(relPoint)
.. " x=" .. tostring(px)
.. " y=" .. tostring(py))
end
return true
end
@@ -697,9 +683,6 @@ function ZSpellButtonParent_OnLoad()
if this.SetScript then
this:SetScript("OnDragStart", function()
if IsAltKeyDown() then
if type(MTH_ZH_TraceButtonPoint) == "function" then
MTH_ZH_TraceButtonPoint(this, "drag-start")
end
this:StartMoving()
this.isMoving = true
end
@@ -713,9 +696,6 @@ function ZSpellButtonParent_OnLoad()
end
ZSpellButton_SaveParentPosition(this)
this.isMoving = false
if type(MTH_ZH_TraceButtonPoint) == "function" then
MTH_ZH_TraceButtonPoint(this, "drag-stop")
end
end)
this:SetScript("OnMouseUp", function()
if this and this.isMoving then
@@ -724,9 +704,6 @@ function ZSpellButtonParent_OnLoad()
end
ZSpellButton_SaveParentPosition(this)
this.isMoving = false
if type(MTH_ZH_TraceButtonPoint) == "function" then
MTH_ZH_TraceButtonPoint(this, "mouse-up-stop")
end
end
end)
end
+1 -46
View File
@@ -8,7 +8,7 @@ MTH_ZH_MANAGED_HOOKS = true
local MTH_ZHunter = {
name = "zhunter",
enabled = true,
version = "1.3.0",
version = "1.4.1",
events = {
"VARIABLES_LOADED",
-- PLAYER_ENTERING_WORLD handled by bootstrap frame + adjustment frames
@@ -24,19 +24,6 @@ local MTH_ZHunter = {
}
}
local function MTH_ZH_Log(msg)
if not (MTH and MTH.debug) then
return
end
MTH:Print("[ZH MODULE] " .. tostring(msg), "debug")
end
local function MTH_ZH_TraceLocal(msg)
if type(MTH_ZH_Trace) == "function" then
MTH_ZH_Trace(msg)
end
end
local MTH_ZH_PostLoginRestore = nil
local MTH_ZH_BootstrapFrame = nil
local MTH_ZH_SyncSavedVariables
@@ -80,7 +67,6 @@ local function MTH_ZH_ApplyDefaultWidgetSpawnLayoutOnce()
local orderedCount = table.getn(orderedButtons)
for i = 1, orderedCount do
if not getglobal(orderedButtons[i]) then
MTH_ZH_Log("skipped one-time default widget spawn layout (missing frame: " .. tostring(orderedButtons[i]) .. ")")
return false
end
end
@@ -95,7 +81,6 @@ local function MTH_ZH_ApplyDefaultWidgetSpawnLayoutOnce()
end
savedRoot["_mth_widget_spawn_layout_v1"] = 1
MTH_ZH_Log("applied one-time default widget spawn layout")
return true
end
@@ -107,7 +92,6 @@ function MTH_ZH_OnDeferredInitComplete()
if MTH_ZH_SetAuxFramesVisible then
MTH_ZH_SetAuxFramesVisible(false)
end
MTH_ZH_Log("deferred init applied disabled-state hide")
return
end
MTH_ZH_SyncSavedVariables()
@@ -137,10 +121,6 @@ MTH_ZH_QueuePostLoginRestore = function(tag)
MTH_ZH_SyncSavedVariables()
MTH_ZH_RestoreRuntimeFeatureFlags()
if type(MTH_ZH_TraceAllButtonPoints) == "function" then
MTH_ZH_TraceAllButtonPoints("post-login-restore:" .. tostring(tag))
end
MTH_ZH_Log("post-login restore applied: " .. tostring(tag))
end)
end
@@ -178,17 +158,10 @@ local function MTH_ZH_EnsureBootstrapRestoreFrame()
end
MTH_ZH_ApplyEnabledRuntimeState = function(source)
MTH_ZH_TraceLocal("apply-enabled-runtime-state source=" .. tostring(source or ""))
if type(MTH_ZH_TraceAllButtonPoints) == "function" then
MTH_ZH_TraceAllButtonPoints("apply-enabled:before:" .. tostring(source or ""))
end
MTH_ZH_SyncSavedVariables()
MTH_ZH_SetButtonsVisible(true)
MTH_ZH_SetAuxFramesVisible(true)
MTH_ZH_RestoreRuntimeFeatureFlags()
if type(MTH_ZH_TraceAllButtonPoints) == "function" then
MTH_ZH_TraceAllButtonPoints("apply-enabled:after:" .. tostring(source or ""))
end
end
MTH_ZH_SyncSavedVariables = function()
@@ -197,22 +170,17 @@ MTH_ZH_SyncSavedVariables = function()
end
local moduleStore = MTH:GetModuleCharSavedVariables("zhunter")
MTH_ZH_TraceLocal("sync-saved begin zhuntermod_saved=" .. tostring(type(ZHunterMod_Saved)))
if type(ZHunterMod_Saved) == "table" then
if MTH_CharSavedVariables and MTH_CharSavedVariables.modules then
MTH_CharSavedVariables.modules.zhunter = ZHunterMod_Saved
MTH_ZH_TraceLocal("sync-saved wrote ZHunterMod_Saved -> MTH_CharSavedVariables.modules.zhunter")
end
elseif type(moduleStore) == "table" then
ZHunterMod_Saved = moduleStore
MTH_ZH_TraceLocal("sync-saved loaded moduleStore -> ZHunterMod_Saved")
end
MTH_ZH_TraceLocal("sync-saved end")
end
MTH_ZH_SetButtonsVisible = function(visible)
MTH_ZH_TraceLocal("set-buttons-visible visible=" .. tostring(visible and true or false))
local buttonNames = {
"zButtonAspect",
"zButtonTrack",
@@ -294,9 +262,6 @@ MTH_ZH_SetButtonsVisible = function(visible)
for _, buttonName in ipairs(buttonNames) do
local button = getglobal(buttonName)
if button then
if type(MTH_ZH_TraceButtonPoint) == "function" then
MTH_ZH_TraceButtonPoint(button, "set-buttons-visible:before:" .. tostring(buttonName))
end
if visible then
-- Respect per-button enabled state
local getterName = buttonName .. "_GetSaved"
@@ -319,9 +284,6 @@ MTH_ZH_SetButtonsVisible = function(visible)
MTH_ZH_SetChildButtonsVisible(button, buttonName, false)
button:Hide()
end
if type(MTH_ZH_TraceButtonPoint) == "function" then
MTH_ZH_TraceButtonPoint(button, "set-buttons-visible:after:" .. tostring(buttonName))
end
end
end
end
@@ -400,7 +362,6 @@ function MTH_ZHunter:init()
end
function MTH_ZHunter:setEnabled(enabled)
MTH_ZH_TraceLocal("module setEnabled enabled=" .. tostring(enabled and true or false))
MTH_ZH_SyncSavedVariables()
if enabled then
MTH_ZH_EnsureBootstrapRestoreFrame()
@@ -409,14 +370,8 @@ function MTH_ZHunter:setEnabled(enabled)
else
MTH_ZH_ClearRuntimeFeatureFlags()
MTH_ZH_SetAdjustmentHandlersActive(false)
if type(MTH_ZH_TraceAllButtonPoints) == "function" then
MTH_ZH_TraceAllButtonPoints("setEnabled:false:before-hide")
end
MTH_ZH_SetButtonsVisible(false)
MTH_ZH_SetAuxFramesVisible(false)
if type(MTH_ZH_TraceAllButtonPoints) == "function" then
MTH_ZH_TraceAllButtonPoints("setEnabled:false:after-hide")
end
end
end
+5
View File
@@ -121,9 +121,13 @@ local zButtonAmmo_ShortArrowLabels = {
[ARROWS_ROUGH] = "Rough",
[ARROWS_SHARP] = "Sharp",
[ARROWS_RAZOR] = "Razor",
[ARROWS_BRIGHT] = "Bright",
[ARROWS_JAGGED] = "Jagged",
[ARROWS_SHADE] = "Shade",
[ARROWS_ICETHREADED] = "Ice",
[ARROWS_SMOOTH] = "Smooth",
[ARROWS_THORIUM] = "Thorium",
[ARROWS_STAR] = "Star",
[ARROWS_DOOMSHOT] = "Doom",
}
@@ -143,6 +147,7 @@ local zButtonAmmo_ShortBulletLabels = {
[BULLETS_ACCURATE] = "Accur",
[BULLETS_GYROSHOT] = "Gyro",
[BULLETS_THORIUM] = "Thorium",
[BULLETS_CRAFTEDTHORIUM] = "Ench",
[BULLETS_ICETHREADED] = "Ice",
}
+3 -2
View File
@@ -5,7 +5,7 @@ end
local root = zButtonAspect_GetRoot()
if not root["zButtonAspect"] then
root["zButtonAspect"] = {}
root["zButtonAspect"]["spells"] = {1, 2, 3, 4, 5, 6, 7}
root["zButtonAspect"]["spells"] = {1, 2, 3, 4, 5, 6, 7, 8}
root["zButtonAspect"]["rows"] = 1
root["zButtonAspect"]["horizontal"] = nil
root["zButtonAspect"]["vertical"] = nil
@@ -28,7 +28,8 @@ ZHunterMod_Aspect_Spells = {
ZHUNTER_ASPECT_CHEETAH,
ZHUNTER_ASPECT_PACK,
ZHUNTER_ASPECT_WILD,
ZHUNTER_ASPECT_BEAST
ZHUNTER_ASPECT_BEAST,
ZHUNTER_ASPECT_VIPER
}
local ZHUNTER_ASPECT_MAX = table.getn(ZHunterMod_Aspect_Spells)
+5 -2
View File
@@ -249,7 +249,8 @@ end
function zButtonMounts_SetupSizeAndPosition()
local saved = zButtonMounts_GetSaved()
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)
end
if zButtonMounts and zButtonMounts.Hide then
@@ -257,7 +258,9 @@ function zButtonMounts_SetupSizeAndPosition()
end
return
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)
end
local displayCount = zButtonMounts.found or 0
+10 -2
View File
@@ -235,7 +235,8 @@ end
function zButtonPet_SetupSizeAndPosition()
local saved = zButtonPet_GetSaved()
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)
end
if zButtonPet and zButtonPet.Hide then
@@ -243,7 +244,14 @@ function zButtonPet_SetupSizeAndPosition()
end
return
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)
end
local displayCount = zButtonPet.found or ZHUNTER_PET_MAX
-4
View File
@@ -97,10 +97,6 @@ local function zButtonRanged_IsRangedItem(subtype, equipLoc)
if subtypeText == tostring(MTH_WEAPON_BOWS or "Bows") then return true end
if subtypeText == tostring(MTH_WEAPON_GUNS or "Guns") then return true end
if subtypeText == tostring(MTH_WEAPON_CROSSBOWS or "Crossbows") then return true end
if subtypeText == "Thrown" then return true end
if equipLoc == "INVTYPE_RANGED" or equipLoc == "INVTYPE_RANGEDRIGHT" or equipLoc == "INVTYPE_THROWN" then
return true
end
return false
end
+5 -2
View File
@@ -249,7 +249,8 @@ end
function zButtonToys_SetupSizeAndPosition()
local saved = zButtonToys_GetSaved()
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)
end
if zButtonToys and zButtonToys.Hide then
@@ -257,7 +258,9 @@ function zButtonToys_SetupSizeAndPosition()
end
return
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)
end
local displayCount = zButtonToys.found or 0
+11 -4
View File
@@ -5,7 +5,7 @@ end
local root = zButtonTrack_GetRoot()
if not root["zButtonTrack"] then
root["zButtonTrack"] = {}
root["zButtonTrack"]["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
root["zButtonTrack"]["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
root["zButtonTrack"]["rows"] = 1
root["zButtonTrack"]["horizontal"] = nil
root["zButtonTrack"]["vertical"] = nil
@@ -32,7 +32,8 @@ ZHunterMod_Track_Spells = {
ZHUNTER_TRACK_GIANTS,
ZHUNTER_TRACK_MINERALS,
ZHUNTER_TRACK_HERBS,
ZHUNTER_TRACK_TREASURE
ZHUNTER_TRACK_TREASURE,
ZHUNTER_TRACK_TREES
}
local ZHUNTER_TRACK_MAX = table.getn(ZHunterMod_Track_Spells)
@@ -311,7 +312,8 @@ function zButtonTrack_SetupSizeAndPosition()
zButtonTrack_EnsureConfig()
local saved = zButtonTrack_GetSaved()
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)
end
if zButtonTrack and zButtonTrack.Hide then
@@ -319,7 +321,12 @@ function zButtonTrack_SetupSizeAndPosition()
end
return
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)
end
local displayCount = zButtonTrack.found or ZHUNTER_TRACK_MAX
+8 -2
View File
@@ -154,7 +154,8 @@ function zButtonTrap_SetupSizeAndPosition()
zButtonTrap_EnsureConfig()
local saved = zButtonTrap_GetSaved()
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)
end
if zButtonTrap and zButtonTrap.Hide then
@@ -162,7 +163,12 @@ function zButtonTrap_SetupSizeAndPosition()
end
return
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)
end
local displayCount = zButtonTrap.found or ZHUNTER_TRAP_MAX