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/ tools/
LOC*.md LOC*.md
LOCALIZATION*.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"> <Binding name="ZPet 6" header="ZPetHeader">
zButtonPet_KeyBinding(6) zButtonPet_KeyBinding(6)
</Binding> </Binding>
<!-- ExpAmmo Action Button -->
<Binding name="ExpAmmo Action" header="ExpAmmoHeader">
MTH_EA_CastActionSpell();
</Binding>
</Ui> </Ui>
+68
View File
@@ -2,6 +2,74 @@
All notable changes to MetaHunt will be documented in this file. All notable changes to MetaHunt will be documented in this file.
## [1.4.1] - 2026-03-24
### Added
- **zTrack**: added `Find Trees` in tracking spells.
### Changed
- **Performance — MM Widget / ExpAmmo**: Replaced tooltip-based aura scanning (which triggered hidden tooltip rendering on every aura check) with direct texture/icon comparison via `UnitBuff`/`UnitDebuff`. Added a 150 ms throttle on `PLAYER_AURAS_CHANGED`, which fires 10–50+ times per second in combat. Lock and Load detection and ammo cycle recovery after `/reload` both updated to use the new zero-cost texture path.
- **Performance — event frame leaks**: Some addon features were registering WoW game events at load time and never unregistering them when the feature was disabled from the options, causing their `OnEvent` handlers to fire even with the option turned off. Fixed for: Auto-Strip (`PLAYER_REGEN_*`), Smart Ammo (`SPELLCAST_*`, `START/STOP_AUTOREPEAT_SPELL`), and some zButton frames (Pet, Mounts, Track, Trap, Toys). Events are now properly registered on enable and unregistered on disable.
- **Chronometer — trap effects from other hunters**: Trap effect bars (`Immolation Trap Effect`, `Explosive Trap Effect`, `Freezing Trap Effect`, `Frost Trap Aura`) were incorrectly appearing when another hunter's trap triggered on a mob you were also targeting. .
- **Version check broadcast interval**: Increased update notification broadcast cooldown from 10 minutes to 1 hour to reduce channel traffic now that the user base has grown.
- **Profile snapshot memory**: The auto `BuildSnapshot` (called on every `/reload` via `PLAYER_LOGOUT`) was deep-copying `feedomatic.legacy`, a large migration table mirroring `FOM_Cooking`, `FOM_QuestFood`, `FOM_AddedFoods` etc. These are runtime/operational blobs, not user configuration settings, and should never be included in a profile. Introduced `MTH_Profile_CopyModules` which skips `legacy` and `history` keys, reducing the snapshot allocation from ~1 MB to a few KB.
## [1.4.0] - 2026-03-23
### 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 ## [1.3.0] - 2026-03-19
+9
View File
@@ -2,6 +2,15 @@
-- MetaHunt: Hunter's Toolkit Addon -- MetaHunt: Hunter's Toolkit Addon
-- A unified addon merging FeedOMatic, Tooltips, and zhunter -- A unified addon merging FeedOMatic, Tooltips, and zhunter
-- Modern modular architecture with legacy addon support -- 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 -- Initialize beast database after all files loaded
+4 -3
View File
@@ -1,5 +1,5 @@
## Interface: 11200 ## Interface: 11200
## Version: 1.3.0 ## Version: 1.4.1
## Title: MetaHunt - |cff00ff00Hunter ## Title: MetaHunt - |cff00ff00Hunter
## Author: Metasploit and his Copilot ;) ## Author: Metasploit and his Copilot ;)
## Notes: Unified addon suite for huntards making old addons compatible with TurtleWoW, and adding an arsenal of never seen Hunter's utilities. ## Notes: Unified addon suite for huntards making old addons compatible with TurtleWoW, and adding an arsenal of never seen Hunter's utilities.
@@ -20,8 +20,6 @@ init\skins.xml
## Load database files (DB files must come before data\init.lua) ## Load database files (DB files must come before data\init.lua)
data\ds-beasts.lua data\ds-beasts.lua
data\ds-beasts-extra.lua
data\ds-beasts-html-enrichment.lua
data\ds-vendors.lua data\ds-vendors.lua
data\ds-vendors-extra.lua data\ds-vendors-extra.lua
data\ds-items.lua data\ds-items.lua
@@ -31,6 +29,7 @@ data\ds-bags.lua
data\ds-items-atlas-sources.lua data\ds-items-atlas-sources.lua
data\ds-zones.lua data\ds-zones.lua
data\ds-zones-fallback.lua data\ds-zones-fallback.lua
data\ds-zones-wma.lua
data\ds-minimap-sizes.lua data\ds-minimap-sizes.lua
data\ds-unit-coords.lua data\ds-unit-coords.lua
data\ds-creature-coords.lua data\ds-creature-coords.lua
@@ -39,6 +38,8 @@ data\ds-beasts-families-dbc.lua
data\ds-beasts-skins.lua data\ds-beasts-skins.lua
data\ds-pet-spells.lua data\ds-pet-spells.lua
data\ds-pet-spells-trainer.lua data\ds-pet-spells-trainer.lua
data\ds-hunter-spells.lua
data\ds-hunter-spells-dbc.lua
data\ds-racial.lua data\ds-racial.lua
data\init.lua data\init.lua
+11 -9
View File
@@ -1,14 +1,14 @@
# MetaHunt # MetaHunt
MetaHunt is a Turtle WoW Hunter toolkit. MetaHunt is a Turtle WoW Hunter toolkit.
It is a modern modular addon that combines never-seen features, and improves/fixes a few old hunter add-ons. It is a modern modular addon compiling brand new features, and improving a few old hunter add-ons, that were broken on twow.
It provides a bunch useful tools for all huntards, wheter they are still levelling, lone-wolf, or HL raider. It provides a bunch of useful tools for all huntards, wheter they are still levelling, lone-wolf, or HL raider.
## Twow Data ## Twow Data
MetaHunt ships with large up-to-date datastores for all Turtle WOW data a hunter needs : MetaHunt ships with large Turtle WOW datastores :
- 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 families, their abilities and their diet
- All pet abilities ranks - All pet abilities ranks
- All Ammo (Arrows and Bullets) - 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 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. - 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 ## 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. - Vendors : Shows if a vendor sells Arrows and/or Bullets.
- Your pet : Shows your pet's XP, loyalty, happiness and how much you fed it this session. - Your pet : Shows your pet's XP, loyalty, happiness and how much you fed it this session.
## zBouttons ## zButtons
Old zHunterMod addon on steroids. Fully compatible with Twow, and enhanced with new functionalities Old zHunterMod addon on steroids. Fully compatible with Twow, and enhanced with new functionalities
@@ -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. Just spam SHIFT-click on the NPC to validate quests Scorpok and Thorium arrows. Additionally you can have an enhanced tooltip that display your actual Scorpok-related items when you mouseover the mobs involved.
## Beast model Viewer
Display the model of all beasts in the world. Always know what you are going to tame exactly before running there ! You can also browse all skin models of the same pet family to find the best-looking pet according to your tastes.
## The Great Book of Huntards ## The Great Book of Huntards
The Book is the main GUI of MetaHunt, it allows to display the data constantly collected about you and your pet, and browse the addon's data to find anything a Hunter needs. The Book is the main GUI of MetaHunt, it allows to display the data constantly collected about you and your pet, and browse the addon's data to find anything a Hunter needs.
- Browse the MetaHunt datastores of NPCs (Beast, vendors, masters) and open the map to locate them like in pfQuest - Browse the MetaHunt datastores of NPCs (Beast, vendors, masters) and open the map to locate them like in pfQuest
- Model viewer of all beasts in the game.
- Track all info about the pet abilities that you know and don't know yet - Track all info about the pet abilities that you know and don't know yet
- Track all info about your stabled pets - Track all info about your stabled pets
- Keep an history of all your pets after you abandon them or if they run away. - Keep an history of all your pets after you abandon them or if they run away.
## 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 if enabled then
saved["autostrip"] = 1 saved["autostrip"] = 1
AutoStrip_On = 1 AutoStrip_On = 1
if AutoStrip_Frame then
AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_DISABLED")
AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_ENABLED")
end
if AutoStripDisplay and AutoStripDisplay:IsVisible() and AutoStripDisplayAutoCast then if AutoStripDisplay and AutoStripDisplay:IsVisible() and AutoStripDisplayAutoCast then
AutoStripDisplayAutoCast:Show() AutoStripDisplayAutoCast:Show()
end end
@@ -159,6 +163,10 @@ function AutoStrip_SetAutoStripToggle(enabled, silent)
else else
saved["autostrip"] = nil saved["autostrip"] = nil
AutoStrip_On = nil AutoStrip_On = nil
if AutoStrip_Frame then
AutoStrip_Frame:UnregisterEvent("PLAYER_REGEN_DISABLED")
AutoStrip_Frame:UnregisterEvent("PLAYER_REGEN_ENABLED")
end
if AutoStripDisplayAutoCast then if AutoStripDisplayAutoCast then
AutoStripDisplayAutoCast:Hide() AutoStripDisplayAutoCast:Hide()
end end
@@ -252,10 +260,12 @@ function AutoStrip_UnequipAll(weaponsOnly)
end end
local function AutoStrip_OnEvent() local function AutoStrip_OnEvent()
AutoStrip_Trace("OnEvent evt=" .. tostring(event or "") if AutoStrip_TraceEnabled then
.. " runtime=" .. tostring(AutoStrip_On and 1 or 0) AutoStrip_Trace("OnEvent evt=" .. tostring(event or "")
.. " wasInCombat=" .. tostring(AutoStrip_WasInCombat and 1 or 0) .. " runtime=" .. tostring(AutoStrip_On and 1 or 0)
.. " playerInCombat=" .. tostring((type(UnitAffectingCombat) == "function" and UnitAffectingCombat("player")) and 1 or 0)) .. " wasInCombat=" .. tostring(AutoStrip_WasInCombat and 1 or 0)
.. " playerInCombat=" .. tostring((type(UnitAffectingCombat) == "function" and UnitAffectingCombat("player")) and 1 or 0))
end
if event == "VARIABLES_LOADED" then if event == "VARIABLES_LOADED" then
local saved = AutoStrip_GetSaved() local saved = AutoStrip_GetSaved()
AutoStrip_Trace("VARIABLES_LOADED saved.autostrip=" .. tostring(saved["autostrip"] and 1 or 0) AutoStrip_Trace("VARIABLES_LOADED saved.autostrip=" .. tostring(saved["autostrip"] and 1 or 0)
@@ -318,9 +328,11 @@ end
AutoStrip_Frame = CreateFrame("Frame", "MTH_AutoStripEvent") AutoStrip_Frame = CreateFrame("Frame", "MTH_AutoStripEvent")
if AutoStrip_Frame then if AutoStrip_Frame then
-- PLAYER_REGEN_DISABLED / PLAYER_REGEN_ENABLED are intentionally NOT registered here.
-- They are registered only when the feature is enabled via AutoStrip_SetAutoStripToggle(true),
-- and unregistered when it is disabled. This prevents any combat event overhead when the
-- feature is off.
AutoStrip_Frame:RegisterEvent("VARIABLES_LOADED") AutoStrip_Frame:RegisterEvent("VARIABLES_LOADED")
AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_DISABLED")
AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_ENABLED")
AutoStrip_Frame:RegisterEvent("PLAYER_ENTERING_WORLD") AutoStrip_Frame:RegisterEvent("PLAYER_ENTERING_WORLD")
AutoStrip_Frame:RegisterEvent("PLAYER_LOGOUT") AutoStrip_Frame:RegisterEvent("PLAYER_LOGOUT")
AutoStrip_Frame:SetScript("OnEvent", AutoStrip_OnEvent) AutoStrip_Frame:SetScript("OnEvent", AutoStrip_OnEvent)
+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 = 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 = { MTH_CONST.WEAPON_TYPES = {
BOWS = "Bows", BOWS = "Bows",
@@ -24,6 +24,7 @@ MTH_CONST.AMMO = {
ICETHREADED = "Ice Threaded Bullet", ICETHREADED = "Ice Threaded Bullet",
THORIUM = "Thorium Shells", THORIUM = "Thorium Shells",
ROCKSHARD = "Rockshard Pellets", ROCKSHARD = "Rockshard Pellets",
CRAFTEDTHORIUM = "Enchanted Thorium Shells",
CANNONBALL = "Miniature Cannon Balls", CANNONBALL = "Miniature Cannon Balls",
}, },
ARROWS = { ARROWS = {
@@ -32,16 +33,19 @@ MTH_CONST.AMMO = {
RAZOR = "Razor Arrow", RAZOR = "Razor Arrow",
FEATHER = "Feathered Arrow", FEATHER = "Feathered Arrow",
PRECISION = "Precision Arrow", PRECISION = "Precision Arrow",
BRIGHT = "Bright Wood Arrows",
JAGGED = "Jagged Arrow", JAGGED = "Jagged Arrow",
SHADE = "Shade Wood Arrows",
ICETHREADED = "Ice Threaded Arrow", ICETHREADED = "Ice Threaded Arrow",
SMOOTH = "Smooth Ironfeather Arrows",
THORIUM = "Thorium Headed Arrow", THORIUM = "Thorium Headed Arrow",
STAR = "Starfeather Arrows",
DOOMSHOT = "Doomshot", DOOMSHOT = "Doomshot",
}, },
JUNKSHOTS = { JUNKSHOTS = {
SERPENT = "Serpent Sting", SERPENT = "Serpent Sting",
SCORPID = "Scorpid Sting", SCORPID = "Scorpid Sting",
VIPER = "Viper Sting", VIPER = "Viper Sting",
ARCANE = "Arcane Shot",
CONCUSSIVE = "Concussive Shot", CONCUSSIVE = "Concussive Shot",
DISTRACTING = "Distracting Shot", DISTRACTING = "Distracting Shot",
BAITED = "Baited Shot", BAITED = "Baited Shot",
@@ -69,6 +73,7 @@ BULLETS_ICETHREADED = MTH_CONST.AMMO.BULLETS.ICETHREADED
BULLETS_THORIUM = MTH_CONST.AMMO.BULLETS.THORIUM BULLETS_THORIUM = MTH_CONST.AMMO.BULLETS.THORIUM
BULLETS_ROCKSHARD = MTH_CONST.AMMO.BULLETS.ROCKSHARD BULLETS_ROCKSHARD = MTH_CONST.AMMO.BULLETS.ROCKSHARD
BULLETS_CANNONBALL = MTH_CONST.AMMO.BULLETS.CANNONBALL BULLETS_CANNONBALL = MTH_CONST.AMMO.BULLETS.CANNONBALL
BULLETS_CRAFTEDTHORIUM = MTH_CONST.AMMO.BULLETS.CRAFTEDTHORIUM
ARROWS_ROUGH = MTH_CONST.AMMO.ARROWS.ROUGH ARROWS_ROUGH = MTH_CONST.AMMO.ARROWS.ROUGH
ARROWS_SHARP = MTH_CONST.AMMO.ARROWS.SHARP 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_PRECISION = MTH_CONST.AMMO.ARROWS.PRECISION
ARROWS_JAGGED = MTH_CONST.AMMO.ARROWS.JAGGED ARROWS_JAGGED = MTH_CONST.AMMO.ARROWS.JAGGED
ARROWS_ICETHREADED = MTH_CONST.AMMO.ARROWS.ICETHREADED 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_THORIUM = MTH_CONST.AMMO.ARROWS.THORIUM
ARROWS_STAR = MTH_CONST.AMMO.ARROWS.STAR
ARROWS_DOOMSHOT = MTH_CONST.AMMO.ARROWS.DOOMSHOT ARROWS_DOOMSHOT = MTH_CONST.AMMO.ARROWS.DOOMSHOT
JUNKSHOT_SERPENT = MTH_CONST.AMMO.JUNKSHOTS.SERPENT JUNKSHOT_SERPENT = MTH_CONST.AMMO.JUNKSHOTS.SERPENT
JUNKSHOT_SCORPID = MTH_CONST.AMMO.JUNKSHOTS.SCORPID JUNKSHOT_SCORPID = MTH_CONST.AMMO.JUNKSHOTS.SCORPID
JUNKSHOT_VIPER = MTH_CONST.AMMO.JUNKSHOTS.VIPER JUNKSHOT_VIPER = MTH_CONST.AMMO.JUNKSHOTS.VIPER
JUNKSHOT_ARCANE = MTH_CONST.AMMO.JUNKSHOTS.ARCANE
JUNKSHOT_CONCUSSIVE = MTH_CONST.AMMO.JUNKSHOTS.CONCUSSIVE JUNKSHOT_CONCUSSIVE = MTH_CONST.AMMO.JUNKSHOTS.CONCUSSIVE
JUNKSHOT_DISTRACTING = MTH_CONST.AMMO.JUNKSHOTS.DISTRACTING JUNKSHOT_DISTRACTING = MTH_CONST.AMMO.JUNKSHOTS.DISTRACTING
JUNKSHOT_BAITED = MTH_CONST.AMMO.JUNKSHOTS.BAITED JUNKSHOT_BAITED = MTH_CONST.AMMO.JUNKSHOTS.BAITED
@@ -105,6 +113,7 @@ MTH_AMMO_BULLETS = {
BULLETS_ICETHREADED, BULLETS_ICETHREADED,
BULLETS_THORIUM, BULLETS_THORIUM,
BULLETS_ROCKSHARD, BULLETS_ROCKSHARD,
BULLETS_CRAFTEDTHORIUM,
BULLETS_CANNONBALL, BULLETS_CANNONBALL,
} }
@@ -114,9 +123,13 @@ MTH_AMMO_ARROWS = {
ARROWS_RAZOR, ARROWS_RAZOR,
ARROWS_FEATHER, ARROWS_FEATHER,
ARROWS_PRECISION, ARROWS_PRECISION,
ARROWS_BRIGHT,
ARROWS_JAGGED, ARROWS_JAGGED,
ARROWS_SHADE,
ARROWS_ICETHREADED, ARROWS_ICETHREADED,
ARROWS_SMOOTH,
ARROWS_THORIUM, ARROWS_THORIUM,
ARROWS_STAR,
ARROWS_DOOMSHOT, ARROWS_DOOMSHOT,
} }
@@ -124,7 +137,6 @@ MTH_AMMO_JUNKSHOTS = {
JUNKSHOT_SERPENT, JUNKSHOT_SERPENT,
JUNKSHOT_SCORPID, JUNKSHOT_SCORPID,
JUNKSHOT_VIPER, JUNKSHOT_VIPER,
JUNKSHOT_ARCANE,
JUNKSHOT_CONCUSSIVE, JUNKSHOT_CONCUSSIVE,
JUNKSHOT_DISTRACTING, JUNKSHOT_DISTRACTING,
JUNKSHOT_BAITED, JUNKSHOT_BAITED,
+7 -32
View File
@@ -1,5 +1,5 @@
MTH = MTH or { MTH = MTH or {
version = "1.3.0", version = "1.4.1",
name = "MetaHunt", name = "MetaHunt",
modules = {}, modules = {},
config = {}, config = {},
@@ -266,15 +266,6 @@ if type(MTH_CharSavedVariables.modules) ~= "table" then
MTH_CharSavedVariables.modules = {} MTH_CharSavedVariables.modules = {}
end 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 function MTH_IsPetUiFrameName(frameName)
local name = tostring(frameName or "") local name = tostring(frameName or "")
if name == "" then if name == "" then
@@ -423,7 +414,6 @@ end
local function MTH_GetPersistedModuleEnabled(name, defaultEnabled) local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
if type(name) ~= "string" or name == "" then 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 return defaultEnabled and true or false
end end
@@ -461,7 +451,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
local resolved = hardDefault and true or false local resolved = hardDefault and true or false
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
MTH_CharSavedVariables.modules[resolvedName].enabled = resolved MTH_CharSavedVariables.modules[resolvedName].enabled = resolved
MTH_ModuleStateDebug("read " .. tostring(name) .. " seeded char default=" .. tostring(resolved))
return resolved return resolved
end end
end end
@@ -472,7 +461,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
local key = candidates[i] local key = candidates[i]
if MTH_CharSavedVariables.moduleStates[key] ~= nil then if MTH_CharSavedVariables.moduleStates[key] ~= nil then
local resolved = MTH_CharSavedVariables.moduleStates[key] and true or false 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 MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
return resolved return resolved
end end
@@ -484,7 +472,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
local key = candidates[i] local key = candidates[i]
if MTH_SavedVariables.moduleStates[key] ~= nil then if MTH_SavedVariables.moduleStates[key] ~= nil then
local resolved = MTH_SavedVariables.moduleStates[key] and true or false 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 MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then
MTH_CharSavedVariables.modules[resolvedName] = {} MTH_CharSavedVariables.modules[resolvedName] = {}
@@ -500,7 +487,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
local key = candidates[i] local key = candidates[i]
if type(MTH_SavedVariables.modules[key]) == "table" and MTH_SavedVariables.modules[key].enabled ~= nil then 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 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 MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then
MTH_CharSavedVariables.modules[resolvedName] = {} MTH_CharSavedVariables.modules[resolvedName] = {}
@@ -515,7 +501,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
local key = candidates[i] local key = candidates[i]
if type(MTH_SavedVariables[key]) == "table" and MTH_SavedVariables[key].enabled ~= nil then if type(MTH_SavedVariables[key]) == "table" and MTH_SavedVariables[key].enabled ~= nil then
local resolved = MTH_SavedVariables[key].enabled and true or false 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 MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then
MTH_CharSavedVariables.modules[resolvedName] = {} MTH_CharSavedVariables.modules[resolvedName] = {}
@@ -525,7 +510,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
end end
end end
MTH_ModuleStateDebug("read " .. tostring(name) .. " no-persisted-value fallback-default=" .. tostring(defaultEnabled and true or false))
return defaultEnabled and true or false return defaultEnabled and true or false
end end
@@ -555,7 +539,6 @@ local function MTH_SetPersistedModuleEnabled(name, enabled)
enabled = enabled and true or false enabled = enabled and true or false
MTH_CharSavedVariables.moduleStates[name] = enabled MTH_CharSavedVariables.moduleStates[name] = enabled
MTH_CharSavedVariables.modules[name].enabled = enabled MTH_CharSavedVariables.modules[name].enabled = enabled
MTH_ModuleStateDebug("write " .. tostring(name) .. " enabled=" .. tostring(enabled))
end end
function MTH:InitEventRouter() function MTH:InitEventRouter()
@@ -669,7 +652,6 @@ function MTH:RegisterModule(name, module)
end end
if self.modules[name] then if self.modules[name] then
if self.debug then print("|cFFFFAA00MetaHunt|r: Module '" .. name .. "' already registered") end
return false return false
end end
@@ -684,8 +666,6 @@ function MTH:RegisterModule(name, module)
local initialEnabled = MTH_GetPersistedModuleEnabled(name, defaultEnabled) local initialEnabled = MTH_GetPersistedModuleEnabled(name, defaultEnabled)
module.enabled = initialEnabled and true or false module.enabled = initialEnabled and true or false
MTH_ModuleStateDebug("register " .. tostring(name) .. " default=" .. tostring(defaultEnabled) .. " initial=" .. tostring(module.enabled))
self.modules[name] = module self.modules[name] = module
self:RegisterModuleEvents(name, module.events) self:RegisterModuleEvents(name, module.events)
@@ -709,7 +689,6 @@ function MTH:RegisterModule(name, module)
self:_SetModuleEventSubscriptions(name, true) self:_SetModuleEventSubscriptions(name, true)
end end
if self.debug then print("|cFF00AA00MetaHunt|r: Module '" .. name .. "' registered") end
return true return true
end end
@@ -774,7 +753,6 @@ function MTH:SetModuleEnabled(name, enabled)
if self.SetConfig then if self.SetConfig then
self:SetConfig(name, "enabled", enabled) self:SetConfig(name, "enabled", enabled)
end end
MTH_ModuleStateDebug("request " .. tostring(name) .. " no-op runtime=" .. tostring(module.enabled) .. " persisted-synced")
return true return true
end end
@@ -796,7 +774,6 @@ function MTH:SetModuleEnabled(name, enabled)
if self.SetConfig then if self.SetConfig then
self:SetConfig(name, "enabled", enabled) self:SetConfig(name, "enabled", enabled)
end end
MTH_ModuleStateDebug("request " .. tostring(name) .. " applied runtime=" .. tostring(module.enabled))
return true return true
end end
@@ -1035,6 +1012,12 @@ function MTH:Log(msg, severity)
return chatText return chatText
end end
function MTH:DebugPrint(msg)
if self.debug then
self:Print("[DEBUG] " .. tostring(msg), "debug")
end
end
function MTH:Print(msg, severity) function MTH:Print(msg, severity)
return self:Log(msg, severity) return self:Log(msg, severity)
end end
@@ -1083,12 +1066,6 @@ function MTH:SetMessageEnabled(key, enabled)
return true return true
end end
function MTH:DebugPrint(msg)
if self.debug then
self:Print("[DEBUG] " .. tostring(msg), "debug")
end
end
function MTH_Log(message, severity) function MTH_Log(message, severity)
if MTH and MTH.Log then if MTH and MTH.Log then
return MTH:Log(message, severity) return MTH:Log(message, severity)
@@ -1270,12 +1247,10 @@ function MTH:ApplyPersistedModuleStates(source)
end end
local persistedEnabled = MTH_GetPersistedModuleEnabled(name, defaultEnabled) 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 if module.enabled ~= persistedEnabled then
local ok, err = self:SetModuleEnabled(name, persistedEnabled) local ok, err = self:SetModuleEnabled(name, persistedEnabled)
if not ok then if not ok then
MTH_ModuleStateDebug("bootstrap apply failed " .. tostring(name) .. ": " .. tostring(err))
end end
else else
MTH_SetPersistedModuleEnabled(name, persistedEnabled) 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)." 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 if MTH_PT_IsScanMessageEnabled() then
MTH:Print(msg) MTH:Print(msg)
MTH:Print("INFO: " .. msg, "debug")
end end
else 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)." 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 if MTH_PT_IsScanMessageEnabled() then
MTH:Print(msg) MTH:Print(msg)
MTH:Print("INFO: " .. msg, "debug")
end end
end 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 return
end end
local function MTH_PETS_LogTame(line) local function MTH_PETS_LogTame(_) end
return
end
local function MTH_PETS_FormatRowConsistency(row) local function MTH_PETS_FormatRowConsistency(row)
if type(row) ~= "table" then if type(row) ~= "table" then
@@ -856,11 +854,21 @@ local function MTH_PETS_ParseCreatureIdFromGuid(guid)
return nil return nil
end end
-- TBC-style string GUID: "Creature-realm-map-inst-?-ENTRY-spawn"
local _, _, creatureIdText = string.find(guidText, "^Creature%-%d+%-%d+%-%d+%-%d+%-(%d+)%-%d+$") local _, _, creatureIdText = string.find(guidText, "^Creature%-%d+%-%d+%-%d+%-%d+%-(%d+)%-%d+$")
if creatureIdText then if creatureIdText then
return tonumber(creatureIdText) return tonumber(creatureIdText)
end 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 return nil
end end
@@ -2553,7 +2561,6 @@ function MTH_PETS_RunSavedVarCleanup(pets)
pets._betaFreshStoreApplied = nil pets._betaFreshStoreApplied = nil
if purged > 0 and MTH and MTH.Print then if purged > 0 and MTH and MTH.Print then
MTH:Print("Cleaned up " .. tostring(purged) .. " stale pet-update records from SavedVariables.", "debug")
end end
end end
@@ -3400,7 +3407,6 @@ end
local function MTH_ST_DebugDumpLine(line) local function MTH_ST_DebugDumpLine(line)
if MTH and MTH.Print then if MTH and MTH.Print then
MTH:Print(tostring(line or ""), "debug")
end end
end end
@@ -3543,7 +3549,6 @@ function MTH_CommandPetsState()
.. " petTrainingLastScan=" .. tostring(petTraining and petTraining.lastScan or 0) .. " petTrainingLastScan=" .. tostring(petTraining and petTraining.lastScan or 0)
.. " hasCompletedPetScan=" .. tostring(petTraining and petTraining.hasCompletedPetScan or nil) .. " hasCompletedPetScan=" .. tostring(petTraining and petTraining.hasCompletedPetScan or nil)
MTH:Print(summary) MTH:Print(summary)
MTH:Print("[PETSSTATE] " .. summary, "debug")
end end
function MTH_CommandPetsReset() function MTH_CommandPetsReset()
@@ -3628,7 +3633,6 @@ function MTH_CommandPetsReset()
.. " preservedHistory=" .. tostring(historyCount) .. " preservedHistory=" .. tostring(historyCount)
.. " nextId=" .. tostring(store.nextId) .. " nextId=" .. tostring(store.nextId)
MTH:Print(line) MTH:Print(line)
MTH:Print("[PETSRESET] " .. line, "debug")
return true return true
end end
@@ -3784,9 +3788,8 @@ function MTH_ST_HandleSpellcastEvent(evt, eventArg1, eventArg2)
if evt == "SPELLCAST_START" or evt == "SPELLCAST_CHANNEL_START" if evt == "SPELLCAST_START" or evt == "SPELLCAST_CHANNEL_START"
or evt == "UNIT_SPELLCAST_START" or evt == "UNIT_SPELLCAST_CHANNEL_START" then or evt == "UNIT_SPELLCAST_START" or evt == "UNIT_SPELLCAST_CHANNEL_START" then
if not MTH_PETS_IsTameBeastSpellName(castSpellName) then -- For vanilla SPELLCAST_* events arg1 is a duration (ms), not spell name.
return true -- Always forward to RecordTameAttempt — it has all the fallback/heuristic logic.
end
MTH_PETS_RecordTameAttempt(evt, castSpellName) MTH_PETS_RecordTameAttempt(evt, castSpellName)
return true return true
end end
@@ -4156,6 +4159,12 @@ function MTH_ST_InitService()
MTH_PetLifecycleEventFrame:RegisterEvent("UNIT_PET") MTH_PetLifecycleEventFrame:RegisterEvent("UNIT_PET")
MTH_PetLifecycleEventFrame:RegisterEvent("PET_BAR_UPDATE") MTH_PetLifecycleEventFrame:RegisterEvent("PET_BAR_UPDATE")
MTH_PetLifecycleEventFrame:RegisterEvent("UNIT_HAPPINESS") 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("CHAT_MSG_COMBAT_XP_GAIN")
MTH_PetLifecycleEventFrame:RegisterEvent("PLAYER_XP_UPDATE") MTH_PetLifecycleEventFrame:RegisterEvent("PLAYER_XP_UPDATE")
MTH_PetLifecycleEventFrame:RegisterEvent("CHAT_MSG_SYSTEM") MTH_PetLifecycleEventFrame:RegisterEvent("CHAT_MSG_SYSTEM")
@@ -4172,7 +4181,6 @@ function MTH_ST_InitService()
MTH_PETS_InstallCoreRenameHook() MTH_PETS_InstallCoreRenameHook()
MTH_PETS_EmitLiveState("service:init", true) MTH_PETS_EmitLiveState("service:init", true)
if MTH_PETS_TRACE_CONSISTENCY and MTH and MTH.Print then if MTH_PETS_TRACE_CONSISTENCY and MTH and MTH.Print then
MTH:Print("[PETCONSIST] trace enabled", "debug")
end end
end end
+114 -50
View File
@@ -301,46 +301,6 @@ if type(MTH_CommandPetSpellScan) ~= "function" then
end end
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) function SlashCmdList.MTH(msg, editbox)
if MTH and MTH.ApplyClassGate and MTH:ApplyClassGate("slash") then if MTH and MTH.ApplyClassGate and MTH:ApplyClassGate("slash") then
return return
@@ -352,24 +312,128 @@ function SlashCmdList.MTH(msg, editbox)
local lowerMsg = string.lower(msg) local lowerMsg = string.lower(msg)
local _, _, lowerCmd, lowerArg = string.find(lowerMsg, "^(%S+)%s*(.-)%s*$") local _, _, lowerCmd, lowerArg = string.find(lowerMsg, "^(%S+)%s*(.-)%s*$")
if msg == "" then if msg == "" then
MTH:Print("Available: /mth options, /mth book, /mth diag, /mth err") MTH:Print("Available: /mth options, /mth book")
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()
elseif lowerMsg == "err" or lowerMsg == "errors" or lowerMsg == "debug" then elseif lowerMsg == "err" or lowerMsg == "errors" or lowerMsg == "debug" then
if MTH_DebugFrame and MTH_DebugFrame.Toggle then if MTH_DebugFrame and MTH_DebugFrame.Toggle then
MTH_DebugFrame:Toggle() MTH_DebugFrame:Toggle()
else else
MTH:Print("Debug frame is not available.") MTH:Print("Debug frame is not available.")
end 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 else
MTH:Print("Unknown command: " .. tostring(msg)) 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
end end
+4 -30
View File
@@ -6,18 +6,6 @@
-- Uses MTH_DS_BeastSkins[familyName] generated by .tools/generators/gen_beast_skins.py -- Uses MTH_DS_BeastSkins[familyName] generated by .tools/generators/gen_beast_skins.py
-- Skin rendering: PlayerModel:SetUnit(CreatureDisplayInfo.ID) -- 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 = { local MTH_MV = {
inited = false, inited = false,
family = nil, family = nil,
@@ -45,10 +33,8 @@ local MTH_MV = {
local function MTH_MV_ApplyModel(model, skinId) local function MTH_MV_ApplyModel(model, skinId)
if not model or not skinId then if not model or not skinId then
mv_err("ApplyModel: nil model or skinId model="..tostring(model).." id="..tostring(skinId))
return return
end end
mv_log("ApplyModel id="..tostring(skinId))
model:SetUnit(skinId) model:SetUnit(skinId)
model:SetPosition(0, 0, 0) model:SetPosition(0, 0, 0)
model:SetModelScale(1) model:SetModelScale(1)
@@ -106,14 +92,11 @@ MTH_MV_BuildSkinBeastList = function(skinId)
end end
local function MTH_MV_Init() local function MTH_MV_Init()
if MTH_MV.inited then mv_log("Init: already done") return end if MTH_MV.inited then return end
mv_log("Init: starting")
local backdrop = getglobal("MTH_BOOK_DetailBackdrop") local backdrop = getglobal("MTH_BOOK_DetailBackdrop")
if not backdrop then if not backdrop then
mv_err("Init: MTH_BOOK_DetailBackdrop not found")
return return
end end
mv_log("Init: backdrop found, creating previewFrame")
MTH_MV.inited = true 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:SetBackdropBorderColor(0.35, 0.35, 0.35, 0.8)
MTH_MV.previewFrame:Hide() MTH_MV.previewFrame:Hide()
mv_log("Init: previewFrame created, creating PlayerModel")
-- PlayerModel fills the inner area -- PlayerModel fills the inner area
MTH_MV.previewModel = CreateFrame("PlayerModel", nil, MTH_MV.previewFrame) MTH_MV.previewModel = CreateFrame("PlayerModel", nil, MTH_MV.previewFrame)
MTH_MV.previewModel:SetPoint("TOPLEFT", MTH_MV.previewFrame, "TOPLEFT", 3, -3) MTH_MV.previewModel:SetPoint("TOPLEFT", MTH_MV.previewFrame, "TOPLEFT", 3, -3)
@@ -158,7 +140,6 @@ local function MTH_MV_Init()
GameTooltip:Hide() GameTooltip:Hide()
end) end)
mv_log("Init: previewModel created, creating popup")
-- ---------------------------------------------------------------- -- ----------------------------------------------------------------
-- Popup frame (wider: left side = model viewer, right = beast list) -- Popup frame (wider: left side = model viewer, right = beast list)
-- ---------------------------------------------------------------- -- ----------------------------------------------------------------
@@ -343,7 +324,6 @@ local function MTH_MV_Init()
end end
MTH_MV.popup = popup MTH_MV.popup = popup
mv_log("Init: complete")
end end
-- --------------------------------------------------------------------------- -- ---------------------------------------------------------------------------
@@ -351,12 +331,10 @@ end
-- --------------------------------------------------------------------------- -- ---------------------------------------------------------------------------
function MTH_BOOK_ModelViewer_SetFamily(family, skinId) function MTH_BOOK_ModelViewer_SetFamily(family, skinId)
mv_log("SetFamily: "..tostring(family).." skinId="..tostring(skinId))
MTH_MV_Init() 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] 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 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() MTH_BOOK_ModelViewer_Clear()
return return
end end
@@ -380,7 +358,6 @@ function MTH_BOOK_ModelViewer_SetFamily(family, skinId)
MTH_BOOK_ModelViewer_Clear() MTH_BOOK_ModelViewer_Clear()
return return
end end
mv_log("SetFamily: "..table.getn(filteredSkins).." tameable skins (filtered from "..table.getn(skins)..")")
MTH_MV.family = family MTH_MV.family = family
MTH_MV.skins = filteredSkins MTH_MV.skins = filteredSkins
@@ -392,7 +369,6 @@ function MTH_BOOK_ModelViewer_SetFamily(family, skinId)
for i = 1, table.getn(filteredSkins) do for i = 1, table.getn(filteredSkins) do
if filteredSkins[i].id == skinId then if filteredSkins[i].id == skinId then
MTH_MV.index = i MTH_MV.index = i
mv_log("SetFamily: skinId "..skinId.." matched skin index "..i)
break break
end end
end end
@@ -409,7 +385,6 @@ function MTH_BOOK_ModelViewer_SetFamily(family, skinId)
end end
function MTH_BOOK_ModelViewer_Clear() function MTH_BOOK_ModelViewer_Clear()
mv_log("Clear")
if MTH_MV.previewFrame then MTH_MV.previewFrame:Hide() end if MTH_MV.previewFrame then MTH_MV.previewFrame:Hide() end
if not MTH_MV.keepPopup then if not MTH_MV.keepPopup then
if MTH_MV.popup and MTH_MV.popup:IsShown() then MTH_MV.popup:Hide() end 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 end
function MTH_BOOK_ModelViewer_OpenPopup() function MTH_BOOK_ModelViewer_OpenPopup()
mv_log("OpenPopup skins="..table.getn(MTH_MV.skins))
MTH_MV_Init() MTH_MV_Init()
if not MTH_MV.popup then mv_err("OpenPopup: no popup frame") return end if not MTH_MV.popup then return end
if table.getn(MTH_MV.skins) == 0 then mv_log("OpenPopup: no skins") return end if table.getn(MTH_MV.skins) == 0 then return end
MTH_MV.popup:Show() MTH_MV.popup:Show()
MTH_MV.popup:Raise() MTH_MV.popup:Raise()
MTH_MV_DisplayCurrent() MTH_MV_DisplayCurrent()
+98 -8
View File
@@ -29,13 +29,31 @@ function MTH_BOOK_GetBeastZoneSummary(beast)
return "-" return "-"
end end
local seen = {} -- Count coords per WMA zone ID to find the dominant zone.
local zoneNames = {} local coordCount = {}
for i = 1, table.getn(beast.coords) do for i = 1, table.getn(beast.coords) do
local c = beast.coords[i] local c = beast.coords[i]
if c and c[3] and not seen[c[3]] then if c and c[3] then
seen[c[3]] = true local zid = c[3]
table.insert(zoneNames, MTH_BOOK_GetZoneName(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
end end
@@ -68,6 +86,69 @@ function MTH_BOOK_SplitAbilities(text)
return out return out
end 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) function MTH_BOOK_HasUsableAbilities(beast)
if not beast then return false end if not beast then return false end
local abilities = MTH_BOOK_SplitAbilities(beast.abilities) local abilities = MTH_BOOK_SplitAbilities(beast.abilities)
@@ -232,8 +313,11 @@ function MTH_BOOK_BeastMatches(beastId, beast)
end end
if MTH_BOOK_STATE.petInZoneOnly then if MTH_BOOK_STATE.petInZoneOnly then
local currentZoneId = MTH_BOOK_GetCurrentZoneId() -- Use the zone ID cached once per BuildResults call (avoids N calls to
if currentZoneId and not MTH_BOOK_BeastHasZoneId(beast, currentZoneId) then -- 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 return false
end end
end end
@@ -251,6 +335,12 @@ function MTH_BOOK_BeastMatches(beastId, beast)
end end
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 return true
end end
@@ -258,7 +348,7 @@ function MTH_BOOK_BeastSort(a, b)
local beasts = MTH_DS_Beasts local beasts = MTH_DS_Beasts
local ba = beasts and beasts[a] local ba = beasts and beasts[a]
local bb = beasts and beasts[b] 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 la = MTH_BOOK_ParseLevel(ba.lvl) or 0
local lb = MTH_BOOK_ParseLevel(bb.lvl) or 0 local lb = MTH_BOOK_ParseLevel(bb.lvl) or 0
if la ~= lb then return la < lb end if la ~= lb then return la < lb end
+346 -51
View File
@@ -69,6 +69,8 @@ local MTH_BOOK_STATE = {
petOnlyMyLevel = true, petOnlyMyLevel = true,
itemOnlyMyLevel = false, itemOnlyMyLevel = false,
petInZoneOnly = false, petInZoneOnly = false,
petContinent = "all",
petZoneFilter = "all",
itemSubtype = "all", itemSubtype = "all",
npcFunction = "all", npcFunction = "all",
npcZone = "all", npcZone = "all",
@@ -274,7 +276,7 @@ local MTH_BOOK_CONTENT_LAYOUT_FAMILIES = {
listX = 16, listX = 16,
listY = -74, listY = -74,
listW = 728, listW = 728,
listH = 376, listH = 456,
detailX = 748, detailX = 748,
detailY = -74, detailY = -74,
detailW = 1, detailW = 1,
@@ -364,7 +366,7 @@ local function MTH_BOOK_UpdateCheckboxLayoutByMode()
getglobal("MTH_BOOK_HideNoAbilities"), getglobal("MTH_BOOK_HideNoAbilities"),
getglobal("MTH_BOOK_HideUnknown"), getglobal("MTH_BOOK_HideUnknown"),
} }
local xOffsets = { 18, 86, 154, 232, 372 } local xOffsets = { 18, 86, 154, 232, 345 }
local yOffset = -140 local yOffset = -140
if MTH_BOOK_STATE.mode == "npcs" then if MTH_BOOK_STATE.mode == "npcs" then
yOffset = -116 yOffset = -116
@@ -754,12 +756,15 @@ local function MTH_BOOK_ShowAllFilteredBeastsOnMap()
end end
local nodes = {} local nodes = {}
local firstZoneId = nil
for i = 1, table.getn(MTH_BOOK_STATE.results or {}) do for i = 1, table.getn(MTH_BOOK_STATE.results or {}) do
local beastId = tonumber(MTH_BOOK_STATE.results[i]) local beastId = tonumber(MTH_BOOK_STATE.results[i])
local beast = beastId and MTH_DS_Beasts and MTH_DS_Beasts[beastId] local beast = beastId and MTH_DS_Beasts and MTH_DS_Beasts[beastId]
if beast and beast.coords then if beast and beast.coords then
local beastDisplayName = (MTH and MTH.GetLocalizedBeastName and MTH:GetLocalizedBeastName(beastId, beast.name)) or beast.name or "Unknown" 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 for j = 1, table.getn(beast.coords) do
local c = beast.coords[j] local c = beast.coords[j]
if c and c[1] and c[2] and c[3] then 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 y = tonumber(c[2])
local zoneId = tonumber(c[3]) local zoneId = tonumber(c[3])
if x and y and zoneId then 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") local details = string.format("Family: %s\nLevel: %s\nAbilities: %s", beast.family or "?", beast.lvl or "?", beast.abilities or "None")
table.insert(nodes, { table.insert(nodes, {
zoneId = zoneId, zoneId = zoneId,
@@ -778,7 +780,7 @@ local function MTH_BOOK_ShowAllFilteredBeastsOnMap()
title = string.format("%s (%d)", beastDisplayName, beastId), title = string.format("%s (%d)", beastDisplayName, beastId),
detail = details, detail = details,
beastId = beastId, beastId = beastId,
color = { 0.95, 0.82, 0.10 }, color = { cr, cg, cb },
}) })
end end
end end
@@ -794,8 +796,11 @@ local function MTH_BOOK_ShowAllFilteredBeastsOnMap()
if not MTH_Map:SetSource("focus") then if not MTH_Map:SetSource("focus") then
return return
end end
if firstZoneId and MTH_Map.OpenWorldMapForZone then -- Navigate to the player's current (filter) zone, not the first coord's zone ID
MTH_Map:OpenWorldMapForZone(firstZoneId) -- 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 end
MTH_Map:UpdateWorldMap() MTH_Map:UpdateWorldMap()
MTH_Map:UpdateMinimap() MTH_Map:UpdateMinimap()
@@ -1076,11 +1081,17 @@ end
MTH_BOOK_GetZoneName = function(zoneId) MTH_BOOK_GetZoneName = function(zoneId)
local normalizedId = tonumber(zoneId) or zoneId local normalizedId = tonumber(zoneId) or zoneId
if not normalizedId then return "Zone " .. tostring(zoneId or "?") end if not normalizedId then return "Zone " .. tostring(zoneId or "?") end
if MTH_DS_ZoneNamesFallback and MTH_DS_ZoneNamesFallback[normalizedId] then -- Beast coords use WMA IDs. Always translate WMA→pfQ first so that e.g.
return MTH_DS_ZoneNamesFallback[normalizedId] -- 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 end
if not MTH_DS_Zones then return "Zone " .. tostring(zoneId or "?") end if MTH_DS_ZoneNamesFallback and MTH_DS_ZoneNamesFallback[pfqId] then
local row = MTH_DS_Zones[normalizedId] or MTH_DS_Zones[tostring(normalizedId)] 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 if not row then return "Zone " .. tostring(normalizedId) end
local names = row.names local names = row.names
if not names then return "Zone " .. tostring(normalizedId) end 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 if MTH_Map and type(MTH_Map.GetMapIDByName) == "function" then
local mapId = MTH_Map:GetMapIDByName(zoneName) local mapId = MTH_Map:GetMapIDByName(zoneName)
if mapId then 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
end end
@@ -1123,7 +1139,11 @@ function MTH_BOOK_GetCurrentZoneId()
if row and row.names then if row and row.names then
for _, value in pairs(row.names) do for _, value in pairs(row.names) do
if MTH_BOOK_NormalizeZoneLookupName(value) == normalized then 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 end
end end
@@ -1432,12 +1452,25 @@ local function MTH_BOOK_BuildResults()
local results = {} local results = {}
if MTH_BOOK_STATE.mode == "pets" then if MTH_BOOK_STATE.mode == "pets" then
if not MTH_DS_Beasts then return results end -- Cache zone info once for this build pass (avoids calling GetCurrentZoneId
for beastId, beast in pairs(MTH_DS_Beasts) do -- once per beast, which is expensive and causes freezes on large datasets).
if MTH_BOOK_BeastMatches(beastId, beast) then if MTH_BOOK_STATE.petInZoneOnly then
table.insert(results, beastId) 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
end end
table.sort(results, MTH_BOOK_BeastSort) table.sort(results, MTH_BOOK_BeastSort)
MTH_BOOK_ApplyActiveSort(results) MTH_BOOK_ApplyActiveSort(results)
return results return results
@@ -2054,6 +2087,77 @@ local function MTH_BOOK_UpdatePetLearnSourceDropdownText()
MTH_BOOK_DropdownSetText(sourceDropdown, MTH_BOOK_GetPetLearnSourceLabel(MTH_BOOK_STATE.petLearnSource)) MTH_BOOK_DropdownSetText(sourceDropdown, MTH_BOOK_GetPetLearnSourceLabel(MTH_BOOK_STATE.petLearnSource))
end 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 function MTH_BOOK_GetItemSubtypeLabelByValue(value)
local options = MTH_BOOK_GetItemSubtypeOptions() local options = MTH_BOOK_GetItemSubtypeOptions()
for i = 1, table.getn(options) do for i = 1, table.getn(options) do
@@ -2089,7 +2193,7 @@ local function MTH_BOOK_UpdateQuickFilterControls()
if MTH_BOOK_IsItemMode() then if MTH_BOOK_IsItemMode() then
MTH_BOOK_STATE.pageSize = 18 MTH_BOOK_STATE.pageSize = 18
elseif MTH_BOOK_STATE.mode == "families" then 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 elseif MTH_BOOK_STATE.mode == "stable" then
MTH_BOOK_STATE.pageSize = 5 MTH_BOOK_STATE.pageSize = 5
elseif MTH_BOOK_STATE.mode == "pethistory" then elseif MTH_BOOK_STATE.mode == "pethistory" then
@@ -2102,6 +2206,9 @@ local function MTH_BOOK_UpdateQuickFilterControls()
local abilityDropdown = getglobal("MTH_BOOK_AbilityDropdown") local abilityDropdown = getglobal("MTH_BOOK_AbilityDropdown")
local rankDropdown = getglobal("MTH_BOOK_RankDropdown") local rankDropdown = getglobal("MTH_BOOK_RankDropdown")
local petLearnSourceDropdown = getglobal("MTH_BOOK_PetLearnSourceDropdown") 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 itemSubtypeDropdown = getglobal("MTH_BOOK_ItemSubtypeDropdown")
local npcFunctionDropdown = getglobal("MTH_BOOK_NPCFunctionDropdown") local npcFunctionDropdown = getglobal("MTH_BOOK_NPCFunctionDropdown")
local npcZoneDropdown = getglobal("MTH_BOOK_NPCZoneDropdown") local npcZoneDropdown = getglobal("MTH_BOOK_NPCZoneDropdown")
@@ -2222,6 +2329,19 @@ local function MTH_BOOK_UpdateQuickFilterControls()
end end
end end
if petLearnSourceDropdown then petLearnSourceDropdown:Hide() 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 itemSubtypeDropdown then itemSubtypeDropdown:Hide() end
if npcFunctionDropdown then npcFunctionDropdown:Hide() end if npcFunctionDropdown then npcFunctionDropdown:Hide() end
if npcZoneDropdown then npcZoneDropdown:Hide() end if npcZoneDropdown then npcZoneDropdown:Hide() end
@@ -2257,6 +2377,9 @@ local function MTH_BOOK_UpdateQuickFilterControls()
petLearnSourceDropdown:Show() petLearnSourceDropdown:Show()
MTH_BOOK_UpdatePetLearnSourceDropdownText() MTH_BOOK_UpdatePetLearnSourceDropdownText()
end 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 itemSubtypeDropdown then itemSubtypeDropdown:Hide() end
if petOnlyMyLevel then if petOnlyMyLevel then
petOnlyMyLevel:ClearAllPoints() petOnlyMyLevel:ClearAllPoints()
@@ -2313,6 +2436,9 @@ local function MTH_BOOK_UpdateQuickFilterControls()
if abilityDropdown then abilityDropdown:Hide() end if abilityDropdown then abilityDropdown:Hide() end
if rankDropdown then rankDropdown:Hide() end if rankDropdown then rankDropdown:Hide() end
if petLearnSourceDropdown then petLearnSourceDropdown: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 itemSubtypeDropdown then itemSubtypeDropdown:Hide() end
if npcFunctionDropdown then npcFunctionDropdown:Show() end if npcFunctionDropdown then npcFunctionDropdown:Show() end
if npcZoneDropdown then npcZoneDropdown:Hide() end if npcZoneDropdown then npcZoneDropdown:Hide() end
@@ -2367,6 +2493,9 @@ local function MTH_BOOK_UpdateQuickFilterControls()
if abilityDropdown then abilityDropdown:Hide() end if abilityDropdown then abilityDropdown:Hide() end
if rankDropdown then rankDropdown:Hide() end if rankDropdown then rankDropdown:Hide() end
if petLearnSourceDropdown then petLearnSourceDropdown: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 if itemSubtypeDropdown then
itemSubtypeDropdown:ClearAllPoints() itemSubtypeDropdown:ClearAllPoints()
itemSubtypeDropdown:SetPoint("TOPLEFT", itemSubtypeDropdown:GetParent(), "TOPLEFT", 238, -80) 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 if MTH_BOOK_STATE.mode ~= "pets" and petInZoneOnly then
petInZoneOnly:Hide() petInZoneOnly:Hide()
end 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 if MTH_BOOK_STATE.mode ~= "npcs" and npcInZoneOnly then
npcInZoneOnly:Hide() npcInZoneOnly:Hide()
end end
@@ -2609,6 +2747,7 @@ local function MTH_BOOK_InitRankDropdown()
MTH_BOOK_UpdateRankDropdownText() MTH_BOOK_UpdateRankDropdownText()
end end
local function MTH_BOOK_InitPetLearnSourceDropdown() local function MTH_BOOK_InitPetLearnSourceDropdown()
local sourceDropdown = getglobal("MTH_BOOK_PetLearnSourceDropdown") local sourceDropdown = getglobal("MTH_BOOK_PetLearnSourceDropdown")
if not sourceDropdown then return end 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") table.insert(lines, "|cff9a9a9a" .. tostring(label or "") .. ":|r |cffffffff" .. tostring(value or "-") .. "|r")
end 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 function MTH_BOOK_FormatDateTimeValue(value)
local ts = tonumber(value) local ts = tonumber(value)
if not ts or ts <= 0 then if not ts or ts <= 0 then
@@ -2943,7 +3132,7 @@ end
function MTH_BOOK_SetDetailText(detail, text) function MTH_BOOK_SetDetailText(detail, text)
if not detail then return end if not detail then return end
local wrapped = tostring(text or "") 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) wrapped = MTH_BOOK_WrapDetailText(wrapped)
end end
detail._mthLocking = true detail._mthLocking = true
@@ -2996,6 +3185,7 @@ end
function MTH_BOOK_UpdateDetail() function MTH_BOOK_UpdateDetail()
local detail = getglobal("MTH_BOOK_DetailBackdropDetailText") local detail = getglobal("MTH_BOOK_DetailBackdropDetailText")
if not detail then return end if not detail then return end
MTH_BOOK_HideDetailTitle()
-- Hide model skin preview when not in a beast-list mode -- 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_STATE.mode ~= "pets" and MTH_BOOK_STATE.mode ~= "abilities" then
if MTH_BOOK_ModelViewer_Clear then MTH_BOOK_ModelViewer_Clear() end if MTH_BOOK_ModelViewer_Clear then MTH_BOOK_ModelViewer_Clear() end
@@ -3074,28 +3264,50 @@ function MTH_BOOK_UpdateDetail()
return return
end end
local beastId = selected.beastId local beastId = selected.beastId
local beast = MTH_DS_Beasts and MTH_DS_Beasts[beastId] local beast = MTH_DS_Beasts and MTH_DS_Beasts[beastId]
if not beast then 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_SetDetailText(detail, "|cFFFFD100Inspector|r\n\nSelect an entry from the list to view identity, stats, sources and locations.")
MTH_BOOK_UpdateOpenMapButton() MTH_BOOK_UpdateOpenMapButton()
return return
end end
local lines = {}
local beastDisplayName = (MTH and MTH.GetLocalizedBeastName and MTH:GetLocalizedBeastName(beastId, beast.name)) or beast.name 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_ShowDetailTitle("|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_AddDetailSection(lines, "Stats") local lines = {}
MTH_BOOK_AddDetailKV(lines, "Level", beast.lvl or "?") -- Identity block
MTH_BOOK_AddDetailKV(lines, "Attack Speed", beast.attackSpeed or "?") MTH_BOOK_AddStableStyleKV(lines, "ID", beastId)
local respawnWindow = MTH_BOOK_FormatRespawnWindow(beast) MTH_BOOK_AddStableStyleKV(lines, "Family", beast.family or "?")
if respawnWindow then local rankLabel = beast.rank
MTH_BOOK_AddDetailKV(lines, "Respawn", respawnWindow) 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 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 if MTH_BOOK_ModelViewer_SetFamily then MTH_BOOK_ModelViewer_SetFamily(beast.family, beast.skinId) end
MTH_BOOK_SetDetailText(detail, table.concat(lines, "\n")) MTH_BOOK_SetDetailText(detail, table.concat(lines, "\n"))
@@ -3116,22 +3328,36 @@ function MTH_BOOK_UpdateDetail()
MTH_BOOK_UpdateOpenMapButton() MTH_BOOK_UpdateOpenMapButton()
return return
end end
MTH_BOOK_ShowDetailTitle("|cFFFFFF00" .. tostring(entry.abilityToken) .. "|r")
local lines = {} 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 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_AddStableStyleKV(lines, "Level", beast.lvl or "?")
MTH_BOOK_AddDetailKV(lines, "Beast", tostring(beastDisplayName or "Unknown") .. " (ID " .. tostring(entry.beastId) .. ")") MTH_BOOK_AddStableStyleKV(lines, "Atk Speed", beast.attackSpeed or "?")
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 "?")
local respawnWindow = MTH_BOOK_FormatRespawnWindow(beast) local respawnWindow = MTH_BOOK_FormatRespawnWindow(beast)
if respawnWindow then if respawnWindow then MTH_BOOK_AddStableStyleKV(lines, "Respawn", respawnWindow) end
MTH_BOOK_AddDetailKV(lines, "Respawn", respawnWindow) 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 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 if MTH_BOOK_ModelViewer_SetFamily then MTH_BOOK_ModelViewer_SetFamily(beast.family, beast.skinId) end
MTH_BOOK_SetDetailText(detail, table.concat(lines, "\n")) MTH_BOOK_SetDetailText(detail, table.concat(lines, "\n"))
@@ -3659,6 +3885,7 @@ end
local function MTH_BOOK_GetRowValues(entry) local function MTH_BOOK_GetRowValues(entry)
if MTH_BOOK_STATE.mode == "pets" then if MTH_BOOK_STATE.mode == "pets" then
-- MetaHunt DB entry
local beast = MTH_DS_Beasts and MTH_DS_Beasts[entry] local beast = MTH_DS_Beasts and MTH_DS_Beasts[entry]
if not beast then return { "", "", "", "", "", "", "", "", "", "" } end if not beast then return { "", "", "", "", "", "", "", "", "", "" } end
local beastDisplayName = (MTH and MTH.GetLocalizedBeastName and MTH:GetLocalizedBeastName(entry, beast.name)) or beast.name 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"), npcFunctionDropdown = getglobal("MTH_BOOK_NPCFunctionDropdown"),
npcZoneDropdown = getglobal("MTH_BOOK_NPCZoneDropdown"), npcZoneDropdown = getglobal("MTH_BOOK_NPCZoneDropdown"),
petLearnSourceDropdown = getglobal("MTH_BOOK_PetLearnSourceDropdown"), petLearnSourceDropdown = getglobal("MTH_BOOK_PetLearnSourceDropdown"),
beastContinentDropdown = getglobal("MTH_BOOK_BeastContinentDropdown"),
beastZoneDropdown = getglobal("MTH_BOOK_BeastZoneDropdown"),
itemSubtypeDropdown = getglobal("MTH_BOOK_ItemSubtypeDropdown"), itemSubtypeDropdown = getglobal("MTH_BOOK_ItemSubtypeDropdown"),
petOnlyMyLevel = getglobal("MTH_BOOK_PetOnlyMyLevel"), petOnlyMyLevel = getglobal("MTH_BOOK_PetOnlyMyLevel"),
petInZoneOnly = getglobal("MTH_BOOK_PetInZoneOnly"), petInZoneOnly = getglobal("MTH_BOOK_PetInZoneOnly"),
@@ -4528,6 +4757,8 @@ local function MTH_BOOK_ResetStateForMode(mode)
MTH_BOOK_STATE.petOnlyMyLevel = false MTH_BOOK_STATE.petOnlyMyLevel = false
MTH_BOOK_STATE.itemOnlyMyLevel = false MTH_BOOK_STATE.itemOnlyMyLevel = false
MTH_BOOK_STATE.petInZoneOnly = false MTH_BOOK_STATE.petInZoneOnly = false
MTH_BOOK_STATE.petContinent = "all"
MTH_BOOK_STATE.petZoneFilter = "all"
MTH_BOOK_STATE.itemSubtype = "all" MTH_BOOK_STATE.itemSubtype = "all"
MTH_BOOK_STATE.npcFunction = "all" MTH_BOOK_STATE.npcFunction = "all"
MTH_BOOK_STATE.npcZone = "all" MTH_BOOK_STATE.npcZone = "all"
@@ -4591,6 +4822,8 @@ local function MTH_BOOK_ApplyStateToWidgets(widgets)
if widgets.petInZoneOnly then if widgets.petInZoneOnly then
widgets.petInZoneOnly:SetChecked(MTH_BOOK_STATE.mode == "pets" and MTH_BOOK_STATE.petInZoneOnly and 1 or nil) widgets.petInZoneOnly:SetChecked(MTH_BOOK_STATE.mode == "pets" and MTH_BOOK_STATE.petInZoneOnly and 1 or nil)
end end
if widgets.beastContinentDropdown then MTH_BOOK_UpdateBeastContinentDropdownText() end
if widgets.beastZoneDropdown then MTH_BOOK_UpdateBeastZoneDropdownText() end
if widgets.npcInZoneOnly then if widgets.npcInZoneOnly then
widgets.npcInZoneOnly:SetChecked(MTH_BOOK_STATE.mode == "npcs" and MTH_BOOK_STATE.npcInZoneOnly and 1 or nil) widgets.npcInZoneOnly:SetChecked(MTH_BOOK_STATE.mode == "npcs" and MTH_BOOK_STATE.npcInZoneOnly and 1 or nil)
end end
@@ -4840,6 +5073,8 @@ local function MTH_BOOK_ResetAllFiltersAndRefresh()
if widgets.abilityDropdown then MTH_BOOK_UpdateAbilityDropdownText() end if widgets.abilityDropdown then MTH_BOOK_UpdateAbilityDropdownText() end
if widgets.rankDropdown then MTH_BOOK_UpdateRankDropdownText() end if widgets.rankDropdown then MTH_BOOK_UpdateRankDropdownText() end
if widgets.petLearnSourceDropdown then MTH_BOOK_UpdatePetLearnSourceDropdownText() 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.itemSubtypeDropdown then MTH_BOOK_UpdateItemSubtypeDropdownText() end
if widgets.npcFunctionDropdown or widgets.npcZoneDropdown then MTH_BOOK_UpdateNPCDropdownTexts() end if widgets.npcFunctionDropdown or widgets.npcZoneDropdown then MTH_BOOK_UpdateNPCDropdownTexts() end
@@ -4847,6 +5082,71 @@ local function MTH_BOOK_ResetAllFiltersAndRefresh()
MTH_BOOK_RefreshFilter() MTH_BOOK_RefreshFilter()
end 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) local function MTH_BOOK_WireUI(frame)
if frame and frame.SetBackdropColor then if frame and frame.SetBackdropColor then
frame:SetBackdropColor(0.05, 0.05, 0.05, 1.00) 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 requireVendor = getglobal("MTH_BOOK_RequireVendor")
local requireDrop = getglobal("MTH_BOOK_RequireDrop") local requireDrop = getglobal("MTH_BOOK_RequireDrop")
local requireObject = getglobal("MTH_BOOK_RequireObject") 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 petBookScanButton = getglobal("MTH_BOOK_PetBookScanButton")
local hideNoAbilities = getglobal("MTH_BOOK_HideNoAbilities") local hideNoAbilities = getglobal("MTH_BOOK_HideNoAbilities")
local hideUnknown = getglobal("MTH_BOOK_HideUnknown") local hideUnknown = getglobal("MTH_BOOK_HideUnknown")
@@ -4934,6 +5228,7 @@ local function MTH_BOOK_WireUI(frame)
MTH_BOOK_InitFamilyDropdown() MTH_BOOK_InitFamilyDropdown()
MTH_BOOK_InitAbilityDropdown() MTH_BOOK_InitAbilityDropdown()
MTH_BOOK_InitRankDropdown() MTH_BOOK_InitRankDropdown()
MTH_BOOK_WireBeastDropdowns()
MTH_BOOK_InitPetLearnSourceDropdown() MTH_BOOK_InitPetLearnSourceDropdown()
MTH_BOOK_InitItemSubtypeDropdown() MTH_BOOK_InitItemSubtypeDropdown()
MTH_BOOK_InitNPCFunctionDropdown() MTH_BOOK_InitNPCFunctionDropdown()
+21 -2
View File
@@ -57,6 +57,14 @@
</Anchors> </Anchors>
</FontString> </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> </Layer>
</Layers> </Layers>
@@ -265,7 +273,7 @@
</Frame> </Frame>
<CheckButton name="$parentPetInZoneOnly" inherits="UICheckButtonTemplate" hidden="true"> <CheckButton name="$parentPetInZoneOnly" inherits="UICheckButtonTemplate" hidden="true">
<Anchors> <Anchors>
<Anchor point="TOPLEFT"><Offset><AbsDimension x="488" y="-112"/></Offset></Anchor> <Anchor point="TOPLEFT"><Offset><AbsDimension x="526" y="-106"/></Offset></Anchor>
</Anchors> </Anchors>
</CheckButton> </CheckButton>
<Button name="$parentShowAllOnMapButton" inherits="UIPanelButtonTemplate" text="Show all on map" hidden="true"> <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> <Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="232" y="-140"/></Offset></Anchor></Anchors>
</CheckButton> </CheckButton>
<CheckButton name="$parentHideUnknown" inherits="UICheckButtonTemplate"> <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> </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"> <Frame name="$parentListSliderBackdrop">
<Size><AbsDimension x="22" y="322"/></Size> <Size><AbsDimension x="22" y="322"/></Size>
+46 -22
View File
@@ -12,6 +12,7 @@ MTH_Map = {
mapZoneCache = {}, mapZoneCache = {},
focusNodes = {}, focusNodes = {},
pendingZoneOpenId = nil, pendingZoneOpenId = nil,
pendingZoneOpenPfqId = nil,
pendingZoneOpenSourceId = nil, pendingZoneOpenSourceId = nil,
pendingZoneOpenAttempts = 0, pendingZoneOpenAttempts = 0,
pendingZoneOpenNextAttemptAt = 0, pendingZoneOpenNextAttemptAt = 0,
@@ -60,11 +61,6 @@ local function MTH_Map_Mod(a, b)
return 0 return 0
end 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) local function MTH_Map_NormalizeName(name)
if not name then return "" end if not name then return "" end
@@ -130,12 +126,18 @@ local function MTH_Map_GetZoneNameById(zoneId)
local normalizedId = tonumber(zoneId) or zoneId local normalizedId = tonumber(zoneId) or zoneId
if not normalizedId then return nil end if not normalizedId then return nil end
if MTH_DS_ZoneNamesFallback and MTH_DS_ZoneNamesFallback[normalizedId] then -- Translate WMA→pfQ first so WMA IDs don't accidentally hit wrong pfQ entries.
return MTH_DS_ZoneNamesFallback[normalizedId] 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 end
if not MTH_DS_Zones then return nil 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 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 return row.names.enUS or row.names[GetLocale()] or row.names.deDE or row.names.frFR
end end
@@ -327,7 +329,6 @@ function MTH_Map:BuildZoneLookup()
for _ in pairs(self.zoneNameNormToId) do for _ in pairs(self.zoneNameNormToId) do
count = count + 1 count = count + 1
end end
MTH_Map_Log("Zone lookup rebuilt: " .. tostring(count) .. " entries")
end end
function MTH_Map:GetMapIDByName(name) function MTH_Map:GetMapIDByName(name)
@@ -418,6 +419,15 @@ function MTH_Map:ResolveZoneHierarchy(zoneId)
return resolved return resolved
end 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() function MTH_Map:GetCurrentMapID()
local continent = GetCurrentMapContinent and GetCurrentMapContinent() or nil local continent = GetCurrentMapContinent and GetCurrentMapContinent() or nil
local zone = GetCurrentMapZone and GetCurrentMapZone() or nil local zone = GetCurrentMapZone and GetCurrentMapZone() or nil
@@ -434,6 +444,7 @@ function MTH_Map:GetCurrentMapID()
if mapId then if mapId then
local resolved = self:ResolveZoneHierarchy(mapId) local resolved = self:ResolveZoneHierarchy(mapId)
local normalized = resolved.zoneId or 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)) 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 return normalized
end end
@@ -449,6 +460,7 @@ function MTH_Map:GetCurrentMapID()
mapId = self:GetMapIDByName(real) mapId = self:GetMapIDByName(real)
local resolved = self:ResolveZoneHierarchy(mapId) local resolved = self:ResolveZoneHierarchy(mapId)
local normalized = resolved.zoneId or 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)) 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 return normalized
end end
@@ -467,6 +479,7 @@ end
local function MTH_Map_ClearPendingZoneOpen() local function MTH_Map_ClearPendingZoneOpen()
MTH_Map.pendingZoneOpenId = nil MTH_Map.pendingZoneOpenId = nil
MTH_Map.pendingZoneOpenPfqId = nil
MTH_Map.pendingZoneOpenSourceId = nil MTH_Map.pendingZoneOpenSourceId = nil
MTH_Map.pendingZoneOpenAttempts = 0 MTH_Map.pendingZoneOpenAttempts = 0
MTH_Map.pendingZoneOpenNextAttemptAt = 0 MTH_Map.pendingZoneOpenNextAttemptAt = 0
@@ -532,8 +545,12 @@ end
function MTH_Map:OpenWorldMapForZone(zoneId) function MTH_Map:OpenWorldMapForZone(zoneId)
local zid = tonumber(zoneId) local zid = tonumber(zoneId)
if not zid then return false end if not zid then return false end
local resolved = self:ResolveZoneHierarchy(zid) -- Translate WMA ID → pfQ so game map APIs (pfMap, SetMapZoom) work correctly.
local targetZoneId = tonumber(resolved.zoneId or zid) or zid 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 ToggleWorldMap then
if not WorldMapFrame or not WorldMapFrame:IsShown() then if not WorldMapFrame or not WorldMapFrame:IsShown() then
@@ -546,34 +563,39 @@ function MTH_Map:OpenWorldMapForZone(zoneId)
if pfMap and pfMap.SetMapByID then if pfMap and pfMap.SetMapByID then
pfMap:SetMapByID(targetZoneId) pfMap:SetMapByID(targetZoneId)
local currentAfterPF = self:GetCurrentMapID() local currentAfterPF = self:GetCurrentMapID()
if tonumber(currentAfterPF) == tonumber(targetZoneId) then if tonumber(currentAfterPF) == tonumber(targetWmaId) then
MTH_Map_ClearPendingZoneOpen() MTH_Map_ClearPendingZoneOpen()
return true return true
end end
end end
local zoomApplied = MTH_Map_ApplyWorldMapZone(targetZoneId, zid) local zoomApplied = MTH_Map_ApplyWorldMapZone(zid, zid)
if zoomApplied then if zoomApplied then
local currentAfterZoom = self:GetCurrentMapID() local currentAfterZoom = self:GetCurrentMapID()
if tonumber(currentAfterZoom) == tonumber(targetZoneId) then if tonumber(currentAfterZoom) == tonumber(targetWmaId) then
MTH_Map_ClearPendingZoneOpen() MTH_Map_ClearPendingZoneOpen()
return true return true
end end
end end
local nowMapId = self:GetCurrentMapID() local nowMapId = self:GetCurrentMapID()
if tonumber(nowMapId) == tonumber(targetZoneId) then if tonumber(nowMapId) == tonumber(targetWmaId) then
MTH_Map_ClearPendingZoneOpen() MTH_Map_ClearPendingZoneOpen()
return true return true
end end
self.pendingZoneOpenId = targetZoneId self.pendingZoneOpenId = targetWmaId
self.pendingZoneOpenSourceId = zid self.pendingZoneOpenPfqId = targetZoneId
self.pendingZoneOpenSourceId = pfqZid
self.pendingZoneOpenAttempts = 8 self.pendingZoneOpenAttempts = 8
self.pendingZoneOpenNextAttemptAt = (GetTime and GetTime() or 0) + 0.25 self.pendingZoneOpenNextAttemptAt = (GetTime and GetTime() or 0) + 0.25
return true return true
end end
function MTH_Map:GetFamilyColor(family)
return MTH_Map_GetFamilyColor(family)
end
function MTH_Map:FocusBeast(beastId, beast) function MTH_Map:FocusBeast(beastId, beast)
local id = tonumber(beastId) local id = tonumber(beastId)
if not id then return false end if not id then return false end
@@ -890,7 +912,6 @@ function MTH_Map:RebuildNodes()
end end
end end
MTH_Map_Log("Rebuilt nodes for source '" .. tostring(self.activeSource) .. "'")
end end
function MTH_Map:UpdateWorldMap() function MTH_Map:UpdateWorldMap()
@@ -1019,6 +1040,11 @@ function MTH_Map:UpdateMinimap()
local minimapSizes = MTH_DS_MinimapSizes or (pfDB and pfDB["minimap"]) local minimapSizes = MTH_DS_MinimapSizes or (pfDB and pfDB["minimap"])
local mapSize = minimapSizes and minimapSizes[mapId] 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 if not mapSize then
self.lastMiniReason = self.verboseMiniReasons and "missing-minimap-size" or "missing-size" self.lastMiniReason = self.verboseMiniReasons and "missing-minimap-size" or "missing-size"
self._lastMiniState = nil self._lastMiniState = nil
@@ -1227,7 +1253,6 @@ function MTH_Map:RegisterDefaultProviders()
end end
if unresolvedCount > 0 then if unresolvedCount > 0 then
MTH_Map_Log("drops source: " .. tostring(unresolvedCount) .. " drop-creature links have no loaded coordinates (sample IDs: " .. table.concat(unresolvedSamples, ", ") .. ")")
end end
return nodes return nodes
@@ -1274,9 +1299,9 @@ function MTH_Map:Init()
if WorldMapFrame and WorldMapFrame:IsShown() then if WorldMapFrame and WorldMapFrame:IsShown() then
if pfMap and pfMap.SetMapByID then if pfMap and pfMap.SetMapByID then
pfMap:SetMapByID(MTH_Map.pendingZoneOpenId) pfMap:SetMapByID(MTH_Map.pendingZoneOpenPfqId or MTH_Map.pendingZoneOpenId)
end 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() local nowMapId = MTH_Map:GetCurrentMapID()
if tonumber(nowMapId) == tonumber(MTH_Map.pendingZoneOpenId) then if tonumber(nowMapId) == tonumber(MTH_Map.pendingZoneOpenId) then
MTH_Map_ClearPendingZoneOpen() MTH_Map_ClearPendingZoneOpen()
@@ -1318,5 +1343,4 @@ function MTH_Map:Init()
end) end)
end end
MTH_Map_Log("Map system initialized")
end 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 = MTH_OPTIONS_CONST or {}
MTH_OPTIONS_CONST.NAV_DEFAULT_WIDTH = MTH_OPTIONS_CONST.NAV_DEFAULT_WIDTH or 120 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.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_TOP_OFFSET = MTH_OPTIONS_CONST.CONTENT_TOP_OFFSET or -58
MTH_OPTIONS_CONST.CONTENT_HEIGHT = MTH_OPTIONS_CONST.CONTENT_HEIGHT or 540 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_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_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 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_SetupAutoQuestOptions()
MTH_OPTIONS_SETUP["AutoQuest"] = true MTH_OPTIONS_SETUP["AutoQuest"] = true
end 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 elseif tabKey == "ICU" then
if type(MTH_SetupICUOptions) == "function" then if type(MTH_SetupICUOptions) == "function" then
MTH_SetupICUOptions() MTH_SetupICUOptions()
+2
View File
@@ -44,6 +44,7 @@ MTH_OPTIONS_TABS = MTH_OPTIONS_TABS or {
{ key = "AutoBuy", label = "Auto Buy", frame = "MetaHuntOptionsAutoBuy" }, { key = "AutoBuy", label = "Auto Buy", frame = "MetaHuntOptionsAutoBuy" },
{ key = "AutoQuest", label = "Auto Quest", frame = "MetaHuntOptionsAutoQuest" }, { key = "AutoQuest", label = "Auto Quest", frame = "MetaHuntOptionsAutoQuest" },
{ key = "ICU", label = "ICU", frame = "MetaHuntOptionsICU" }, { key = "ICU", label = "ICU", frame = "MetaHuntOptionsICU" },
{ key = "ExpAmmo", label = "MM Widget", frame = "MetaHuntOptionsExpAmmo" },
{ key = "ChronometerGeneral", label = "General", frame = "MetaHuntOptionsChronometer" }, { key = "ChronometerGeneral", label = "General", frame = "MetaHuntOptionsChronometer" },
{ key = "ChronometerBar", label = "Bar", frame = "MetaHuntOptionsChronometer" }, { key = "ChronometerBar", label = "Bar", frame = "MetaHuntOptionsChronometer" },
{ key = "ChronometerClassSpells", label = "Hunter Spells", 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 = "Auto Quest", key = "AutoQuest" },
{ label = "Feed-O-Matic", key = "FeedOMatic" }, { label = "Feed-O-Matic", key = "FeedOMatic" },
{ label = "ICU", key = "ICU" }, { label = "ICU", key = "ICU" },
{ label = "MM Widget", key = "ExpAmmo" },
{ {
label = "zButtons", label = "zButtons",
node = "zButtons", node = "zButtons",
+3 -2
View File
@@ -46,12 +46,12 @@
<Frames> <Frames>
<Frame name="$parentNav" enableMouse="true"> <Frame name="$parentNav" enableMouse="true">
<Size> <Size>
<AbsDimension x="120" y="540"/> <AbsDimension x="120" y="566"/>
</Size> </Size>
<Anchors> <Anchors>
<Anchor point="TOPLEFT"> <Anchor point="TOPLEFT">
<Offset> <Offset>
<AbsDimension x="12" y="-72"/> <AbsDimension x="12" y="-58"/>
</Offset> </Offset>
</Anchor> </Anchor>
</Anchors> </Anchors>
@@ -82,6 +82,7 @@
<Frame name="$parentAutoBuy" hidden="true" enableMouse="true"/> <Frame name="$parentAutoBuy" hidden="true" enableMouse="true"/>
<Frame name="$parentAutoQuest" hidden="true" enableMouse="true"/> <Frame name="$parentAutoQuest" hidden="true" enableMouse="true"/>
<Frame name="$parentICU" 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="$parentChronometer" hidden="true" enableMouse="true"/>
<Frame name="$parentCredits" 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 if type(MTH_ST_HandlePlayerEnteringWorld) == "function" and MTH_ST_HandlePlayerEnteringWorld(evt) then
return true, "lifecycle-enter-world" return true, "lifecycle-enter-world"
end 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 type(MTH_ST_HandleUnitPetEvent) == "function" and MTH_ST_HandleUnitPetEvent(evt, eventArg1) then
if evt == "UNIT_PET" then if evt == "UNIT_PET" then
if eventArg1 == "player" then if eventArg1 == "player" then
+26 -2
View File
@@ -19,6 +19,30 @@ local function MTH_Profile_DeepCopy(orig)
return copy return copy
end end
-- Shallow-copy a module's saved data, skipping keys that hold large operational
-- blobs (e.g. feedomatic's "legacy" table which mirrors FOM_Cooking, FOM_QuestFood
-- etc.) — those are runtime migration artifacts, not user configuration settings.
local MTH_PROFILE_SKIP_KEYS = { legacy = true, history = true }
local function MTH_Profile_CopyModules(src)
if type(src) ~= "table" then return {} end
local out = {}
for modName, modData in src do
if type(modData) == "table" then
local modCopy = {}
for k, v in modData do
if not MTH_PROFILE_SKIP_KEYS[k] then
modCopy[MTH_Profile_DeepCopy(k)] = MTH_Profile_DeepCopy(v)
end
end
out[modName] = modCopy
else
out[modName] = modData
end
end
return out
end
local function MTH_Profile_EnsureStore() local function MTH_Profile_EnsureStore()
if type(MTH_SavedVariables) ~= "table" then if type(MTH_SavedVariables) ~= "table" then
MTH_SavedVariables = {} MTH_SavedVariables = {}
@@ -47,13 +71,13 @@ local function MTH_Profile_BuildSnapshot()
-- Account-wide module option values (e.g. feedomatic) -- Account-wide module option values (e.g. feedomatic)
snap.config = (type(MTH_SavedVariables) == "table" snap.config = (type(MTH_SavedVariables) == "table"
and type(MTH_SavedVariables.modules) == "table") and type(MTH_SavedVariables.modules) == "table")
and MTH_Profile_DeepCopy(MTH_SavedVariables.modules) and MTH_Profile_CopyModules(MTH_SavedVariables.modules)
or {} or {}
-- Per-character module option values (ICU, Chronometer, AutoBuy, SmartAmmo, etc.) -- Per-character module option values (ICU, Chronometer, AutoBuy, SmartAmmo, etc.)
snap.charConfig = (type(MTH_CharSavedVariables) == "table" snap.charConfig = (type(MTH_CharSavedVariables) == "table"
and type(MTH_CharSavedVariables.modules) == "table") and type(MTH_CharSavedVariables.modules) == "table")
and MTH_Profile_DeepCopy(MTH_CharSavedVariables.modules) and MTH_Profile_CopyModules(MTH_CharSavedVariables.modules)
or {} or {}
-- Per-character module enabled/disabled states -- Per-character module enabled/disabled states
+2 -2
View File
@@ -221,8 +221,8 @@ end
function VC:ResetPublishDelay() function VC:ResetPublishDelay()
local now = VC_GetTimeNow() local now = VC_GetTimeNow()
if self.lastPublishedAt and (now - self.lastPublishedAt) < 600 then if self.lastPublishedAt and (now - self.lastPublishedAt) < 3600 then
return -- 10-minute cooldown between publishes return -- 1-hour cooldown between publishes
end end
self.nextPublishAt = now + math.random(10, 20) self.nextPublishAt = now + math.random(10, 20)
end end
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) -- MetaHunt: Beast family DBC enrichment (scales, food validation)
-- AUTO-GENERATED by .tools — do not edit by hand. -- AUTO-GENERATED by .tools — do not edit by hand.
-- Source DBC(s): CreatureFamily.dbc, ItemPetFood.dbc -- 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 if not MTH_DS_Families then return end
@@ -295,14 +295,14 @@ if MTH_DS_Families["Wind Serpents"] then
end end
-- DBC ID=35 PetFoodMask=1009 scale=[0.60-0.80] -- DBC ID=35 PetFoodMask=1009 scale=[0.60-0.80]
if MTH_DS_Families["Serpents (Cobra)"] then if MTH_DS_Families["Serpents"] then
MTH_DS_Families["Serpents (Cobra)"]["dbcId"] = 35 MTH_DS_Families["Serpents"]["dbcId"] = 35
MTH_DS_Families["Serpents (Cobra)"]["minScale"] = 0.6 MTH_DS_Families["Serpents"]["minScale"] = 0.6
MTH_DS_Families["Serpents (Cobra)"]["maxScale"] = 0.8 MTH_DS_Families["Serpents"]["maxScale"] = 0.8
MTH_DS_Families["Serpents (Cobra)"]["minScaleLevel"] = 1 MTH_DS_Families["Serpents"]["minScaleLevel"] = 1
MTH_DS_Families["Serpents (Cobra)"]["maxScaleLevel"] = 60 MTH_DS_Families["Serpents"]["maxScaleLevel"] = 60
MTH_DS_Families["Serpents (Cobra)"]["foodMask"] = 1009 MTH_DS_Families["Serpents"]["foodMask"] = 1009
MTH_DS_Families["Serpents (Cobra)"]["foodDbc"] = { MTH_DS_Families["Serpents"]["foodDbc"] = {
"meat", "meat",
"fungus", "fungus",
"fruit", "fruit",
+18 -1
View File
@@ -233,7 +233,7 @@ MTH_DS_Families = {
"Scorpid Poison", "Scorpid Poison",
}, },
}, },
["Serpents (Cobra)"] = { ["Serpents"] = {
["icon"] = "Ability_Hunter_Pet_Serpent1", ["icon"] = "Ability_Hunter_Pet_Serpent1",
["named"] = 10, ["named"] = 10,
["coords"] = 13, ["coords"] = 13,
@@ -333,4 +333,21 @@ MTH_DS_Families = {
"Growl", "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 -- MetaHunt: Beast appearance skin variants per family
-- AUTO-GENERATED by .tools — do not edit by hand. -- AUTO-GENERATED by .tools — do not edit by hand.
-- Source DBC(s): CreatureDisplayInfo.dbc, CreatureModelData.dbc -- Source DBC(s): CreatureDisplayInfo.dbc, CreatureModelData.dbc
-- Generated: 2026-03-17 14:49 UTC -- Generated: 2026-03-23 15:09 UTC
-- Total skins: 244 across 19 families -- Total skins: 258 across 20 families
if not MTH_DS then MTH_DS = {} end 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=20635, tex="BearSkinBrownDiseased", unique=true, modelPath="Creature\\bear\\Bear.mdx"},
{id=20636, tex="BearSkinBlueDiseased", 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=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"] = { ["Boars"] = {
{id=193, tex="BoarSkinIvory", unique=false, modelPath="Creature\\Boar\\Boar.mdx"}, {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=2714, tex="HyenaSkinWhite", unique=false, modelPath="Creature\\Hyena\\Hyena.mdx"},
{id=2726, tex="HyenaSkinBlack", 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"] = { ["Owls"] = {
{id=4566, tex="OwlBrown", unique=false, modelPath="Creature\\Owl\\Owl.mdx"}, {id=4566, tex="OwlBrown", unique=false, modelPath="Creature\\Owl\\Owl.mdx"},
{id=4877, tex="OwlGrey", 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=18373, tex="SilithidScarabSkinGreen", unique=true, modelPath="Creature\\SILITHIDSCARAB\\SilithidScarab.mdx"},
{id=21268, tex="ScorpionskinDarkIron", unique=true, modelPath="Creature\\Scorpion\\Scorpion.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=1206, tex="SnakeSkinBlack", unique=false, modelPath="Creature\\snake\\snake.mdx"},
{id=1986, tex="SnakeSkinDarkGreenYellow", 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"}, {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=20511, tex="HawkstriderGreen", unique=true, modelPath="Creature\\Hawkstrider\\Hawkstrider.mdx"},
{id=20512, tex="HawkstriderRed", 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=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"] = { ["Turtles"] = {
{id=1244, tex="SeaTurtleSkin", unique=false, modelPath="Creature\\SeaTurtle\\SeaTurtle.mdx"}, {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, }, [9426] = {["boss"] = true, },
[9456] = {["boss"] = true, }, [9456] = {["boss"] = true, },
[9487] = {["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 for itemId, sourceMap in pairs(MTH_DS_AtlasSources) do
+26
View File
@@ -6308,6 +6308,13 @@ MTH_DS_ItemOrigins = {
["level"] = 25, ["level"] = 25,
["classification"] = 0, ["classification"] = 0,
}, },
{
["id"] = 62906,
["name"] = "Elendon Truebough",
["tag"] = "Weapons",
["level"] = 44,
["classification"] = 0,
},
}, },
}, },
}, },
@@ -11066,6 +11073,12 @@ MTH_DS_ItemOrigins = {
["level"] = 40, ["level"] = 40,
["classification"] = 0, ["classification"] = 0,
}, },
{
["id"] = 62843,
["name"] = "Ornala",
["level"] = 53,
["classification"] = 0,
},
}, },
}, },
}, },
@@ -11747,6 +11760,19 @@ MTH_DS_ItemOrigins = {
["level"] = 25, ["level"] = 25,
["classification"] = 0, ["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, [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 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 = { MTH_DS_MinimapSizes = {
[0] = { 0, 0 }, [0] = { 0, 0 },
[1] = { 4925, 3283.34 }, [9] = { 5137.50, 3425.00 }, -- Mulgore
[3] = { 2487.5, 1658.34 }, [11] = { 2487.50, 1658.34 }, -- Barrens
[4] = { 3350, 2233.3 }, [15] = { 2170.84, 1447.90 }, -- Alterac
[8] = { 2293.75, 1529.17 }, [19] = { 5287.50, 3525.00 }, -- BlastedLands
[10] = { 2700, 1800.03 }, [20] = { 4518.75, 3012.50 }, -- Tirisfal
[11] = { 4135.42, 2756.25 }, [21] = { 4200.00, 2800.00 }, -- Silverpine
[12] = { 3470.84, 2314.62 }, [22] = { 2231.25, 1487.50 }, -- WesternPlaguelands
[14] = { 5287.5, 3525 }, [23] = { 3870.83, 2581.25 }, -- EasternPlaguelands
[15] = { 5250, 3500 }, [24] = { 3200.00, 2133.33 }, -- Hilsbrad
[16] = { 5070.84, 3381.25 }, [26] = { 3850.00, 2566.67 }, -- Hinterlands
[17] = { 10133.34, 6756.25 }, [27] = { 4925.00, 3283.34 }, -- DunMorogh
[25] = { 711.56, 468.68 }, [29] = { 2929.16, 1952.08 }, -- BurningSteppes
[28] = { 4300, 2866.67 }, [30] = { 3470.84, 2314.62 }, -- Elwynn
[33] = { 6381.25, 4254.1 }, [32] = { 5091.66, 3393.70 }, -- DeadwindPass
[36] = { 2800, 1866.67 }, [34] = { 2700.00, 1800.03 }, -- Duskwood
[38] = { 2758.33, 1839.58 }, [35] = { 2293.75, 1529.17 }, -- LochModan
[40] = { 3500, 2333.3 }, [37] = { 6381.25, 4254.10 }, -- Stranglethorn
[41] = { 2500, 1666.63 }, [39] = { 4135.42, 2756.25 }, -- Westfall
[44] = { 2170.84, 1447.9 }, [40] = { 10133.34, 6756.25 }, -- Wetlands
[45] = { 3600, 2400 }, [41] = { 5250.00, 3500.00 }, -- Teldrassil
[46] = { 2929.16, 1952.08 }, [42] = { 6550.00, 4366.66 }, -- Darkshore
[47] = { 3850, 2566.67 }, [43] = { 5766.67, 3843.75 }, -- Ashenvale
[51] = { 2231.25, 1487.5 }, [61] = { 4400.00, 2933.33 }, -- ThousandNeedles
[85] = { 4518.75, 3012.5 }, [81] = { 6018.00, 4010.00 }, -- StonetalonMountains
[130] = { 4200, 2800 }, [101] = { 4495.83, 2997.91 }, -- Desolace
[139] = { 3870.83, 2581.25 }, [121] = { 6950.00, 4633.33 }, -- Feralas
[141] = { 5091.66, 3393.7 }, [141] = { 2800.00, 1866.67 }, -- Dustwallow
[148] = { 6550, 4366.66 }, [161] = { 6900.00, 4600.00 }, -- Tanaris
[209] = { 381, 254 }, [181] = { 3600.00, 2400.00 }, -- Azshara
[215] = { 5137.5, 3425 }, [182] = { 5750.00, 3833.33 }, -- Felwood
[267] = { 3200, 2133.33 }, [201] = { 3700.00, 2466.66 }, -- UngoroCrater
[331] = { 5766.67, 3843.75 }, [241] = { 2308.33, 1539.59 }, -- Moonglade
[357] = { 6950, 4633.33 }, [261] = { 3483.33, 2322.92 }, -- Silithus
[361] = { 5750, 3833.33 }, [281] = { 7100.00, 4733.33 }, -- Winterspring
[400] = { 4400, 2933.33 }, [301] = { 1737.50, 1158.34 }, -- Stormwind
[405] = { 4495.83, 2997.91 }, [321] = { 1402.61, 935.42 }, -- Orgrimmar
[406] = { 6018, 4010 }, [341] = { 790.63, 527.61 }, -- Ironforge
[408] = { 3092.1, 2047 }, [362] = { 1043.75, 695.83 }, -- ThunderBluff
[409] = { 2901.45, 1915.9 }, [381] = { 1058.33, 705.71 }, -- Darnassus
[440] = { 6900, 4600 }, [382] = { 959.37, 640.11 }, -- Undercity
[490] = { 3700, 2466.66 }, [401] = { 4237.50, 2825.00 }, -- AlteracValley
[491] = { 736.45, 490.96 }, [443] = { 1145.84, 764.58 }, -- WarsongGulch
[493] = { 2308.33, 1539.59 }, [461] = { 1756.25, 1170.83 }, -- ArathiBasin
[616] = { 3206, 2142 }, [500] = { 828.00, 541.00 }, -- pfQ876
[618] = { 7100, 4733.33 }, [501] = { 3206.00, 2142.00 }, -- pfQ616
[717] = { 378.15, 252.1 }, [502] = { 3159.00, 2108.00 }, -- pfQ4012
[718] = { 572.78, 381.85 }, [503] = { 988.63, 1393.17 }, -- pfQ5023
[719] = { 1221.87, 806.42 }, [504] = { 2901.45, 1915.90 }, -- pfQ409
[721] = { 769.67, 513.11 }, [505] = { 3092.10, 2047.00 }, -- pfQ408
[722] = { 881, 589 }, [507] = { 3227.00, 2187.00 }, -- pfQ5121
[796] = { 203.66, 135.04 }, [509] = { 1468.00, 976.00 }, -- pfQ2040
[876] = { 828, 541 }, [510] = { 3666.00, 2442.00 }, -- pfQ5179
[1176] = { 1383.33, 922.91 }, [511] = { 1608.00, 1075.00 }, -- pfQ5024
[1337] = { 893.67, 595.78 }, [512] = { 2472.00, 1665.00 }, -- pfQ5536
[1377] = { 3483.33, 2322.92 }, [513] = { 3082.00, 2061.00 }, -- pfQ5225
[1477] = { 695.03, 463.35 }, [514] = { 449.89, 300.00 }, -- pfQ1581
[1497] = { 959.37, 640.11 }, [516] = { 572.78, 381.85 }, -- pfQ718
[1519] = { 1737.5, 1158.34 }, [517] = { 2112.09, 1410.89 }, -- pfQ2100
[1537] = { 790.63, 527.61 }, [518] = { 769.67, 513.11 }, -- pfQ721
[1581] = { 449.89, 300 }, [519] = { 711.56, 468.68 }, -- pfQ25
[1583] = { 886.84, 591.23 }, [520] = { 203.66, 135.04 }, -- pfQ796
[1584] = { 1985, 1268 }, [521] = { 893.67, 595.78 }, -- pfQ1337
[1637] = { 1402.61, 935.42 }, [522] = { 4139.02, 2946.00 }, -- pfQ3478
[1638] = { 1043.75, 695.83 }, [523] = { 1348.24, 888.09 }, -- pfQ1941
[1657] = { 1058.33, 705.71 }, [601] = { 1432.00, 977.00 }, -- pfQ5130
[1941] = { 1348.24, 888.09 }, [603] = { 738.86, 492.57 }, -- pfQ2437
[1977] = { 2120.83, 1414.6 }, [605] = { 1383.33, 922.91 }, -- pfQ1176
[2017] = { 1185.35, 789.86 }, [607] = { 695.03, 463.35 }, -- pfQ1477
[2040] = { 1468, 976 }, [609] = { 1221.87, 806.42 }, -- pfQ719
[2057] = { 320.05, 213.37 }, [611] = { 378.15, 252.10 }, -- pfQ717
[2100] = { 2112.09, 1410.89 }, [617] = { 1495.00, 983.00 }, -- pfQ2717
[2159] = { 483.11, 322.08 }, [619] = { 2120.83, 1414.60 }, -- pfQ1977
[2257] = { 312, 208 }, [623] = { 1985.00, 1268.00 }, -- pfQ1584
[2366] = { 1085.86, 726.61 }, [625] = { 2512.50, 1675.00 }, -- pfQ3429
[2437] = { 738.86, 492.57 }, [627] = { 483.11, 322.08 }, -- pfQ2159
[2557] = { 1324, 869 }, [629] = { 886.84, 591.23 }, -- pfQ1583
[2597] = { 4237.5, 2825 }, [635] = { 499.43, 332.95 }, -- pfQ2677
[2677] = { 499.43, 332.95 }, [637] = { 656.59, 434.97 }, -- pfQ5138
[2717] = { 1495, 983 }, [639] = { 881.00, 589.00 }, -- pfQ722
[3277] = { 1145.84, 764.58 }, [641] = { 736.45, 490.96 }, -- pfQ491
[3358] = { 1756.25, 1170.83 }, [643] = { 619.98, 413.32 }, -- pfQ5136
[3428] = { 977.56, 651.7 }, [644] = { 320.19, 213.46 }, -- pfQ5135
[3429] = { 2512.5, 1675 }, [645] = { 612.69, 408.46 }, -- pfQ5153
[3456] = { 1991.69, 1318.42 }, [646] = { 703.30, 468.87 }, -- pfQ5163
[3457] = { 823, 549 }, [648] = { 320.05, 213.37 }, -- pfQ2057
[3478] = { 4139.02, 2946 }, [650] = { 381.00, 254.00 }, -- pfQ209
[4012] = { 3159, 2108 }, [652] = { 1185.35, 789.86 }, -- pfQ2017
[5023] = { 988.63, 1393.17 }, [654] = { 977.56, 651.70 }, -- pfQ3428
[5024] = { 1608, 1075 }, [655] = { 2777.54, 1851.69 }, -- pfQ5147
[5053] = { 1007.7, 671.8 }, [657] = { 619.00, 410.00 }, -- pfQ5723
[5077] = { 2643.21, 1751.16 }, [659] = { 312.00, 208.00 }, -- pfQ2257
[5086] = { 546.75, 391.9 }, [662] = { 1271.99, 845.48 }, -- pfQ5204
[5087] = { 354.5, 234.74 }, [663] = { 1085.86, 726.61 }, -- pfQ2366
[5097] = { 1273.1, 853.72 }, [665] = { 1250.18, 837.44 }, -- pfQ5208
[5103] = { 752.12, 510.33 }, [667] = { 1991.69, 1318.42 }, -- pfQ3456
[5121] = { 3227, 2187 }, [668] = { 652.10, 439.67 }, -- pfQ5148
[5130] = { 1432, 977 }, [670] = { 2643.21, 1751.16 }, -- pfQ5077
[5135] = { 320.19, 213.46 }, [672] = { 752.12, 510.33 }, -- pfQ5103
[5136] = { 619.98, 413.32 }, [674] = { 546.75, 391.90 }, -- pfQ5086
[5138] = { 656.59, 434.97 }, [676] = { 354.50, 234.74 }, -- pfQ5087
[5144] = { 309, 208 }, [678] = { 1273.10, 853.72 }, -- pfQ5097
[5147] = { 2777.54, 1851.69 }, [680] = { 1007.70, 671.80 }, -- pfQ5053
[5148] = { 652.1, 439.67 }, [682] = { 823.00, 549.00 }, -- pfQ3457
[5153] = { 612.69, 408.46 }, [683] = { 2800.00, 1868.00 }, -- pfQ5557
[5163] = { 703.3, 468.87 }, [684] = { 5387.00, 3584.00 }, -- pfQ5602
[5179] = { 3666, 2442 }, [685] = { 3098.00, 2068.00 }, -- pfQ5561
[5204] = { 1271.99, 845.48 }, [686] = { 3241.00, 2157.00 }, -- pfQ5581
[5208] = { 1250.18, 837.44 }, [689] = { 1324.00, 869.00 }, -- pfQ2557
[5225] = { 3082, 2061 }, [691] = { 1634.00, 1073.00 }, -- pfQ5601
[5536] = { 2472, 1665 }, [693] = { 1980.00, 1350.00 }, -- pfQ5628
[5557] = { 2800, 1868 }, [698] = { 1234.00, 829.00 }, -- pfQ5641
[5561] = { 3098, 2068 }, [699] = { 7856.00, 5241.00 }, -- pfQ5642
[5581] = { 3241, 2157 }, [700] = { 861.00, 607.00 }, -- pfQ1769
[5601] = { 1634, 1073 }, [701] = { 1347.00, 971.00 }, -- pfQ5640
[5602] = { 5387, 3584 }, [702] = { 1047.00, 694.00 }, -- pfQ5722
[5628] = { 1980, 1350 }, [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) -- MetaHunt: Pet spell DBC acquire-method overlay (learnMethod, minRank, nextSpellId)
-- AUTO-GENERATED by .tools — do not edit by hand. -- AUTO-GENERATED by .tools — do not edit by hand.
-- Source DBC(s): SkillLineAbility.dbc, SkillLine.dbc -- 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 -- This file patches MTH_DS_PetSpells.allSpells entries with DBC-authoritative
-- learnMethod, minRank, and nextSpellId values. -- learnMethod, minRank, and nextSpellId values.
@@ -121,32 +121,9 @@ local _acquire = {
[26190] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 }, [26190] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
[26202] = { 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 }, [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 }, [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 }, [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 }, [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 }, [51154] = { learnMethod="trainer", minRank=0, nextSpellId=0, skillLineId=261 },
[51155] = { 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 }, [51157] = { learnMethod="trainer", minRank=0, nextSpellId=0, skillLineId=261 },
+45 -7
View File
@@ -25,6 +25,7 @@ MTH_DS_PetSpells = {
"Strider Presence", "Strider Presence",
"Thunderstomp", "Thunderstomp",
"Web", "Web",
"Pollen Burst",
}, },
["allSpells"] = { ["allSpells"] = {
{ {
@@ -1804,15 +1805,30 @@ MTH_DS_PetSpells = {
"(6) Apply Aura #26: Root", "(6) Apply Aura #26: Root",
}, },
["icon"] = "Ability_Ensnare", ["icon"] = "Ability_Ensnare",
["id"] = 4167, ["id"] = 36533,
["name"] = "Web", ["name"] = "Web",
["range"] = "20 yards (Short Range)", ["range"] = "20 yards (Short Range)",
["rank"] = "", ["rank"] = "",
["rankNumber"] = 0, ["rankNumber"] = 0,
["school"] = "Physical", ["school"] = "Physical",
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=4167", ["sourceUrl"] = "https://database.turtlecraft.gg/?spell=36533",
["trainLevel"] = 22, ["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"] = { ["byAbility"] = {
["Bite"] = { ["Bite"] = {
@@ -3744,17 +3760,39 @@ MTH_DS_PetSpells = {
"(6) Apply Aura #26: Root", "(6) Apply Aura #26: Root",
}, },
["icon"] = "Ability_Ensnare", ["icon"] = "Ability_Ensnare",
["id"] = 4167, ["id"] = 36533,
["name"] = "Web", ["name"] = "Web",
["range"] = "20 yards (Short Range)", ["range"] = "20 yards (Short Range)",
["rank"] = "", ["rank"] = "",
["rankNumber"] = 0, ["rankNumber"] = 0,
["school"] = "Physical", ["school"] = "Physical",
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=4167", ["sourceUrl"] = "https://database.turtlecraft.gg/?spell=36533",
["trainLevel"] = 22, ["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", ["cleanedBy"] = "post-process quality rules v2 hard-gate",
["droppedDuplicates"] = { ["droppedDuplicates"] = {
@@ -4293,14 +4331,14 @@ MTH_DS_PetSpells = {
{ {
["ability"] = "Web", ["ability"] = "Web",
["droppedId"] = 12023, ["droppedId"] = 12023,
["keptId"] = 4167, ["keptId"] = 36533,
["mode"] = "lower-score", ["mode"] = "lower-score",
["rankNumber"] = 0, ["rankNumber"] = 0,
}, },
{ {
["ability"] = "Web", ["ability"] = "Web",
["droppedId"] = 36533, ["droppedId"] = 4167,
["keptId"] = 4167, ["keptId"] = 36533,
["mode"] = "lower-score", ["mode"] = "lower-score",
["rankNumber"] = 0, ["rankNumber"] = 0,
}, },
+8 -4
View File
@@ -1,7 +1,7 @@
-- MetaHunt: Stable slot prices -- MetaHunt: Stable slot prices
-- AUTO-GENERATED by .tools — do not edit by hand. -- AUTO-GENERATED by .tools — do not edit by hand.
-- Source DBC(s): StableSlotPrices.dbc -- 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 if not MTH_DS then MTH_DS = {} end
@@ -12,6 +12,7 @@ MTH_DS_StableSlotPrices = {
["cost_silver"] = 5, ["cost_silver"] = 5,
["cost_copper_remainder"] = 0, ["cost_copper_remainder"] = 0,
["display"] = "0g 5s 0c", ["display"] = "0g 5s 0c",
["acquireMethod"] = "gold",
}, },
[2] = { [2] = {
["cost_copper"] = 50000, ["cost_copper"] = 50000,
@@ -19,6 +20,7 @@ MTH_DS_StableSlotPrices = {
["cost_silver"] = 0, ["cost_silver"] = 0,
["cost_copper_remainder"] = 0, ["cost_copper_remainder"] = 0,
["display"] = "5g 0s 0c", ["display"] = "5g 0s 0c",
["acquireMethod"] = "gold",
}, },
[3] = { [3] = {
["cost_copper"] = 2500000, ["cost_copper"] = 2500000,
@@ -26,12 +28,14 @@ MTH_DS_StableSlotPrices = {
["cost_silver"] = 0, ["cost_silver"] = 0,
["cost_copper_remainder"] = 0, ["cost_copper_remainder"] = 0,
["display"] = "250g 0s 0c", ["display"] = "250g 0s 0c",
["acquireMethod"] = "gold",
}, },
[4] = { [4] = {
["cost_copper"] = 1, ["cost_copper"] = 0,
["cost_gold"] = 0, ["cost_gold"] = 0,
["cost_silver"] = 0, ["cost_silver"] = 0,
["cost_copper_remainder"] = 1, ["cost_copper_remainder"] = 0,
["display"] = "0g 0s 1c", ["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) -- MetaHunt: Zone DBC enrichment (worldBounds, dbcAreaId, dbcMapId, dbcName)
-- AUTO-GENERATED by .tools — do not edit by hand. -- AUTO-GENERATED by .tools — do not edit by hand.
-- Source DBC(s): WorldMapArea.dbc, AreaTable.dbc -- 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 if not MTH_DS_Zones then return end
@@ -70,6 +70,19 @@ if MTH_DS_Zones[1497] then
} }
end 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' -- WMA ID=509 map=0 'AlahThalas'
if MTH_DS_Zones[2040] then if MTH_DS_Zones[2040] then
MTH_DS_Zones[2040]["dbcAreaId"] = 2040 MTH_DS_Zones[2040]["dbcAreaId"] = 2040
+2
View File
@@ -72,4 +72,6 @@ MTH_DS_ZoneNamesFallback = {
[5581] = "Northwind", [5581] = "Northwind",
[5601] = "Dragonmaw Retreat", [5601] = "Dragonmaw Retreat",
[5602] = "Grim Reaches", [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) -- MetaHunt: Zones present in DBC but not in MTH_DS_Zones (TWoW custom zones)
-- AUTO-GENERATED by .tools — do not edit by hand. -- AUTO-GENERATED by .tools — do not edit by hand.
-- Source DBC(s): WorldMapArea.dbc, AreaTable.dbc -- 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 if not MTH_DS_Zones then MTH_DS_Zones = {} end
@@ -14,7 +14,7 @@ if not MTH_DS_Zones[14] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Durotar", ["dbcName"] = "Durotar",
["worldBounds"] = { left=-1962.50, right=-7250.00, top=1808.33, bottom=-1716.67 }, ["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 end
@@ -27,7 +27,7 @@ if not MTH_DS_Zones[215] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Mulgore", ["dbcName"] = "Mulgore",
["worldBounds"] = { left=2047.92, right=-3089.58, top=-272.92, bottom=-3697.92 }, ["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 end
@@ -40,7 +40,7 @@ if not MTH_DS_Zones[17] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Barrens", ["dbcName"] = "Barrens",
["worldBounds"] = { left=2622.92, right=-7510.42, top=1612.50, bottom=-5143.75 }, ["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 end
@@ -79,7 +79,7 @@ if not MTH_DS_Zones[36] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Alterac", ["dbcName"] = "Alterac",
["worldBounds"] = { left=783.33, right=-2016.67, top=1500.00, bottom=-366.67 }, ["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 end
@@ -92,7 +92,7 @@ if not MTH_DS_Zones[45] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Arathi", ["dbcName"] = "Arathi",
["worldBounds"] = { left=-866.67, right=-4466.67, top=-133.33, bottom=-2533.33 }, ["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 end
@@ -105,7 +105,7 @@ if not MTH_DS_Zones[3] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Badlands", ["dbcName"] = "Badlands",
["worldBounds"] = { left=-2079.17, right=-4566.67, top=-5889.58, bottom=-7547.92 }, ["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 end
@@ -118,7 +118,7 @@ if not MTH_DS_Zones[4] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "BlastedLands", ["dbcName"] = "BlastedLands",
["worldBounds"] = { left=-1241.67, right=-4591.67, top=-10566.67, bottom=-12800.00 }, ["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 end
@@ -131,7 +131,7 @@ if not MTH_DS_Zones[85] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Tirisfal", ["dbcName"] = "Tirisfal",
["worldBounds"] = { left=3033.33, right=-1485.42, top=3837.50, bottom=825.00 }, ["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 end
@@ -144,7 +144,7 @@ if not MTH_DS_Zones[130] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Silverpine", ["dbcName"] = "Silverpine",
["worldBounds"] = { left=3450.00, right=-750.00, top=1666.67, bottom=-1133.33 }, ["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 end
@@ -157,7 +157,7 @@ if not MTH_DS_Zones[28] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "WesternPlaguelands", ["dbcName"] = "WesternPlaguelands",
["worldBounds"] = { left=416.67, right=-3883.33, top=3366.67, bottom=500.00 }, ["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 end
@@ -170,7 +170,7 @@ if not MTH_DS_Zones[139] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "EasternPlaguelands", ["dbcName"] = "EasternPlaguelands",
["worldBounds"] = { left=-2185.42, right=-6056.25, top=3800.00, bottom=1218.75 }, ["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 end
@@ -183,7 +183,7 @@ if not MTH_DS_Zones[267] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Hilsbrad", ["dbcName"] = "Hilsbrad",
["worldBounds"] = { left=1066.67, right=-2133.33, top=400.00, bottom=-1733.33 }, ["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 end
@@ -196,7 +196,7 @@ if not MTH_DS_Zones[47] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Hinterlands", ["dbcName"] = "Hinterlands",
["worldBounds"] = { left=-1575.00, right=-5425.00, top=1466.67, bottom=-1100.00 }, ["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 end
@@ -209,7 +209,7 @@ if not MTH_DS_Zones[1] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "DunMorogh", ["dbcName"] = "DunMorogh",
["worldBounds"] = { left=1802.08, right=-3122.92, top=-3877.08, bottom=-7160.42 }, ["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 end
@@ -222,7 +222,7 @@ if not MTH_DS_Zones[51] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "SearingGorge", ["dbcName"] = "SearingGorge",
["worldBounds"] = { left=-322.92, right=-2554.17, top=-6100.00, bottom=-7587.50 }, ["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 end
@@ -235,7 +235,7 @@ if not MTH_DS_Zones[46] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "BurningSteppes", ["dbcName"] = "BurningSteppes",
["worldBounds"] = { left=-266.67, right=-3195.83, top=-7031.25, bottom=-8983.33 }, ["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 end
@@ -248,7 +248,7 @@ if not MTH_DS_Zones[12] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Elwynn", ["dbcName"] = "Elwynn",
["worldBounds"] = { left=1535.42, right=-1935.42, top=-7939.58, bottom=-10254.17 }, ["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 end
@@ -261,7 +261,7 @@ if not MTH_DS_Zones[41] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "DeadwindPass", ["dbcName"] = "DeadwindPass",
["worldBounds"] = { left=-833.33, right=-3333.33, top=-9866.67, bottom=-11533.33 }, ["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 end
@@ -274,7 +274,7 @@ if not MTH_DS_Zones[10] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Duskwood", ["dbcName"] = "Duskwood",
["worldBounds"] = { left=833.33, right=-1866.67, top=-9716.67, bottom=-11516.67 }, ["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 end
@@ -287,7 +287,7 @@ if not MTH_DS_Zones[38] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "LochModan", ["dbcName"] = "LochModan",
["worldBounds"] = { left=-1993.75, right=-4752.08, top=-4487.50, bottom=-6327.08 }, ["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 end
@@ -300,7 +300,7 @@ if not MTH_DS_Zones[44] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Redridge", ["dbcName"] = "Redridge",
["worldBounds"] = { left=-1570.83, right=-3741.67, top=-8575.00, bottom=-10022.92 }, ["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 end
@@ -313,7 +313,7 @@ if not MTH_DS_Zones[33] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Stranglethorn", ["dbcName"] = "Stranglethorn",
["worldBounds"] = { left=2220.83, right=-4160.42, top=-11168.75, bottom=-15422.92 }, ["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 end
@@ -326,7 +326,7 @@ if not MTH_DS_Zones[8] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "SwampOfSorrows", ["dbcName"] = "SwampOfSorrows",
["worldBounds"] = { left=-2222.92, right=-4516.67, top=-9620.83, bottom=-11150.00 }, ["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 end
@@ -339,7 +339,7 @@ if not MTH_DS_Zones[40] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Westfall", ["dbcName"] = "Westfall",
["worldBounds"] = { left=3016.67, right=-483.33, top=-9400.00, bottom=-11733.33 }, ["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 end
@@ -352,7 +352,7 @@ if not MTH_DS_Zones[11] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Wetlands", ["dbcName"] = "Wetlands",
["worldBounds"] = { left=-389.58, right=-4525.00, top=-2147.92, bottom=-4904.17 }, ["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 end
@@ -365,7 +365,7 @@ if not MTH_DS_Zones[141] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Teldrassil", ["dbcName"] = "Teldrassil",
["worldBounds"] = { left=3814.58, right=-1277.08, top=11831.25, bottom=8437.50 }, ["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 end
@@ -378,7 +378,7 @@ if not MTH_DS_Zones[148] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Darkshore", ["dbcName"] = "Darkshore",
["worldBounds"] = { left=2941.67, right=-3608.33, top=8333.33, bottom=3966.67 }, ["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 end
@@ -391,7 +391,7 @@ if not MTH_DS_Zones[331] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Ashenvale", ["dbcName"] = "Ashenvale",
["worldBounds"] = { left=1700.00, right=-4066.67, top=4672.92, bottom=829.17 }, ["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 end
@@ -404,7 +404,7 @@ if not MTH_DS_Zones[400] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "ThousandNeedles", ["dbcName"] = "ThousandNeedles",
["worldBounds"] = { left=-433.33, right=-4833.33, top=-3966.67, bottom=-6900.00 }, ["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 end
@@ -416,8 +416,8 @@ if not MTH_DS_Zones[406] then
["dbcAreaId"] = 406, ["dbcAreaId"] = 406,
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "StonetalonMountains", ["dbcName"] = "StonetalonMountains",
["worldBounds"] = { left=3949.00, right=-2069.00, top=3441.00, bottom=-569.00 }, ["worldBounds"] = { left=3245.83, right=-1637.50, top=2916.67, bottom=-339.58 },
["names"] = { ["deDE"] = "Steinkrallengebirge", ["enUS"] = "Stonetalon Mountains", ["esES"] = "Sierra Espolón", ["ptBR"] = "Cordilheira das Torres de Pedra", ["ruRU"] = "Когтистые Горы", ["zhCN"] = "石爪山脉" }, ["names"] = { ["enUS"] = "Stonetalon Mountains", ["esES"] = "Montañas de Colina Roca", ["ptBR"] = "Montanhas Stonetalon", ["zhCN"] = "石爪山脉" },
} }
end end
@@ -430,7 +430,7 @@ if not MTH_DS_Zones[405] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Desolace", ["dbcName"] = "Desolace",
["worldBounds"] = { left=4233.33, right=-262.50, top=452.08, bottom=-2545.83 }, ["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 end
@@ -443,7 +443,7 @@ if not MTH_DS_Zones[357] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Feralas", ["dbcName"] = "Feralas",
["worldBounds"] = { left=5441.67, right=-1508.33, top=-2366.67, bottom=-7000.00 }, ["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 end
@@ -456,7 +456,7 @@ if not MTH_DS_Zones[15] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Dustwallow", ["dbcName"] = "Dustwallow",
["worldBounds"] = { left=-975.00, right=-6225.00, top=-2033.33, bottom=-5533.33 }, ["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 end
@@ -469,7 +469,7 @@ if not MTH_DS_Zones[440] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Tanaris", ["dbcName"] = "Tanaris",
["worldBounds"] = { left=-218.75, right=-7118.75, top=-5875.00, bottom=-10475.00 }, ["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 end
@@ -482,7 +482,7 @@ if not MTH_DS_Zones[16] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Aszhara", ["dbcName"] = "Aszhara",
["worldBounds"] = { left=-3277.08, right=-8347.92, top=5341.67, bottom=1960.42 }, ["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 end
@@ -495,7 +495,7 @@ if not MTH_DS_Zones[361] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Felwood", ["dbcName"] = "Felwood",
["worldBounds"] = { left=1641.67, right=-4108.33, top=7133.33, bottom=3300.00 }, ["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 end
@@ -508,7 +508,7 @@ if not MTH_DS_Zones[490] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "UngoroCrater", ["dbcName"] = "UngoroCrater",
["worldBounds"] = { left=533.33, right=-3166.67, top=-5966.67, bottom=-8433.33 }, ["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 end
@@ -521,7 +521,7 @@ if not MTH_DS_Zones[493] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Moonglade", ["dbcName"] = "Moonglade",
["worldBounds"] = { left=-1381.25, right=-3689.58, top=8491.67, bottom=6952.08 }, ["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 end
@@ -534,7 +534,7 @@ if not MTH_DS_Zones[1377] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Silithus", ["dbcName"] = "Silithus",
["worldBounds"] = { left=2537.50, right=-945.83, top=-5958.33, bottom=-8281.25 }, ["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 end
@@ -547,7 +547,7 @@ if not MTH_DS_Zones[618] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Winterspring", ["dbcName"] = "Winterspring",
["worldBounds"] = { left=-316.67, right=-7416.67, top=8533.33, bottom=3800.00 }, ["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 end
@@ -560,7 +560,7 @@ if not MTH_DS_Zones[1537] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Ironforge", ["dbcName"] = "Ironforge",
["worldBounds"] = { left=-713.59, right=-1504.22, top=-4569.24, bottom=-5096.85 }, ["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 end
@@ -573,7 +573,7 @@ if not MTH_DS_Zones[2597] then
["dbcMapId"] = 30, ["dbcMapId"] = 30,
["dbcName"] = "AlteracValley", ["dbcName"] = "AlteracValley",
["worldBounds"] = { left=1781.25, right=-2456.25, top=1085.42, bottom=-1739.58 }, ["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 end
@@ -586,7 +586,7 @@ if not MTH_DS_Zones[3277] then
["dbcMapId"] = 489, ["dbcMapId"] = 489,
["dbcName"] = "WarsongGulch", ["dbcName"] = "WarsongGulch",
["worldBounds"] = { left=2041.67, right=895.83, top=1627.08, bottom=862.50 }, ["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 end
@@ -599,7 +599,7 @@ if not MTH_DS_Zones[3358] then
["dbcMapId"] = 529, ["dbcMapId"] = 529,
["dbcName"] = "ArathiBasin", ["dbcName"] = "ArathiBasin",
["worldBounds"] = { left=1858.33, right=102.08, top=1508.33, bottom=337.50 }, ["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 end
@@ -612,7 +612,7 @@ if not MTH_DS_Zones[876] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "GMIsland", ["dbcName"] = "GMIsland",
["worldBounds"] = { left=16748.00, right=15920.00, top=16525.00, bottom=15984.00 }, ["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 end
@@ -625,7 +625,7 @@ if not MTH_DS_Zones[616] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Hyjal", ["dbcName"] = "Hyjal",
["worldBounds"] = { left=-1080.00, right=-4286.00, top=6125.00, bottom=3983.00 }, ["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 end
@@ -638,7 +638,7 @@ if not MTH_DS_Zones[4012] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "ScarletEnclave", ["dbcName"] = "ScarletEnclave",
["worldBounds"] = { left=-4050.00, right=-7209.00, top=3087.00, bottom=979.00 }, ["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 end
@@ -651,7 +651,7 @@ if not MTH_DS_Zones[5023] then
["dbcMapId"] = 27, ["dbcMapId"] = 27,
["dbcName"] = "Sunnyglade", ["dbcName"] = "Sunnyglade",
["worldBounds"] = { left=719.47, right=-269.16, top=2000.77, bottom=607.60 }, ["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 end
@@ -664,7 +664,7 @@ if not MTH_DS_Zones[409] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Lapidis", ["dbcName"] = "Lapidis",
["worldBounds"] = { left=4933.33, right=2031.88, top=-11043.48, bottom=-12959.42 }, ["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 end
@@ -677,7 +677,20 @@ if not MTH_DS_Zones[408] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Gillijim", ["dbcName"] = "Gillijim",
["worldBounds"] = { left=4436.22, right=1344.12, top=-12528.71, bottom=-14575.72 }, ["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 end
@@ -690,7 +703,7 @@ if not MTH_DS_Zones[5121] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "TelAbim", ["dbcName"] = "TelAbim",
["worldBounds"] = { left=-5179.00, right=-8406.00, top=-7184.00, bottom=-9371.00 }, ["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 end
@@ -703,7 +716,7 @@ if not MTH_DS_Zones[5179] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "Gilneas", ["dbcName"] = "Gilneas",
["worldBounds"] = { left=3253.00, right=-413.00, top=-359.00, bottom=-2801.00 }, ["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 end
@@ -716,7 +729,7 @@ if not MTH_DS_Zones[5024] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "Icepoint", ["dbcName"] = "Icepoint",
["worldBounds"] = { left=-5595.00, right=-7203.00, top=14405.00, bottom=13330.00 }, ["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 end
@@ -729,7 +742,7 @@ if not MTH_DS_Zones[5536] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "BlackstoneIsland", ["dbcName"] = "BlackstoneIsland",
["worldBounds"] = { left=-6274.00, right=-8746.00, top=799.00, bottom=-866.00 }, ["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 end
@@ -742,7 +755,7 @@ if not MTH_DS_Zones[5225] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "ThalassianHighlands", ["dbcName"] = "ThalassianHighlands",
["worldBounds"] = { left=-1005.00, right=-4087.00, top=4952.00, bottom=2891.00 }, ["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 end
@@ -755,7 +768,7 @@ if not MTH_DS_Zones[1581] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "DeadminesEntrance", ["dbcName"] = "DeadminesEntrance",
["worldBounds"] = { left=1793.18, right=1343.29, top=-11054.94, bottom=-11354.86 }, ["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 end
@@ -768,7 +781,7 @@ if not MTH_DS_Zones[718] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "WailingCavernsEntrance", ["dbcName"] = "WailingCavernsEntrance",
["worldBounds"] = { left=-1900.87, right=-2473.65, top=-488.64, bottom=-870.49 }, ["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 end
@@ -781,7 +794,7 @@ if not MTH_DS_Zones[2100] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "MaraudonEntrance", ["dbcName"] = "MaraudonEntrance",
["worldBounds"] = { left=3208.00, right=2384.00, top=-1096.00, bottom=-1646.00 }, ["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 end
@@ -794,7 +807,7 @@ if not MTH_DS_Zones[721] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "GnomereganEntrance", ["dbcName"] = "GnomereganEntrance",
["worldBounds"] = { left=1027.64, right=456.45, top=-4806.32, bottom=-5185.46 }, ["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 end
@@ -807,7 +820,7 @@ if not MTH_DS_Zones[25] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "BlackrockMountain", ["dbcName"] = "BlackrockMountain",
["worldBounds"] = { left=-760.94, right=-1472.50, top=-7327.82, bottom=-7796.50 }, ["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 end
@@ -820,7 +833,7 @@ if not MTH_DS_Zones[796] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "ScarletMonasteryEntrance", ["dbcName"] = "ScarletMonasteryEntrance",
["worldBounds"] = { left=-659.96, right=-863.62, top=2947.37, bottom=2812.33 }, ["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 end
@@ -833,7 +846,7 @@ if not MTH_DS_Zones[1337] then
["dbcMapId"] = 0, ["dbcMapId"] = 0,
["dbcName"] = "UldamanEntrance", ["dbcName"] = "UldamanEntrance",
["worldBounds"] = { left=-2747.15, right=-3310.46, top=-5953.41, bottom=-6329.51 }, ["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 end
@@ -846,7 +859,7 @@ if not MTH_DS_Zones[3478] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "AhnQirajEntrance", ["dbcName"] = "AhnQirajEntrance",
["worldBounds"] = { left=3932.67, right=-206.35, top=-8005.20, bottom=-10951.25 }, ["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 end
@@ -859,7 +872,7 @@ if not MTH_DS_Zones[1941] then
["dbcMapId"] = 1, ["dbcMapId"] = 1,
["dbcName"] = "CavernsOfTime", ["dbcName"] = "CavernsOfTime",
["worldBounds"] = { left=-3695.85, right=-5044.09, top=-8023.09, bottom=-8911.18 }, ["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 end
@@ -872,7 +885,7 @@ if not MTH_DS_Zones[5130] then
["dbcMapId"] = 813, ["dbcMapId"] = 813,
["dbcName"] = "WinterVeilVale", ["dbcName"] = "WinterVeilVale",
["worldBounds"] = { left=1916.00, right=484.00, top=-2332.00, bottom=-3309.00 }, ["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 end
@@ -885,7 +898,7 @@ if not MTH_DS_Zones[2437] then
["dbcMapId"] = 389, ["dbcMapId"] = 389,
["dbcName"] = "Ragefire", ["dbcName"] = "Ragefire",
["worldBounds"] = { left=452.87, right=-285.99, top=39.62, bottom=-452.95 }, ["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 end
@@ -898,7 +911,7 @@ if not MTH_DS_Zones[1176] then
["dbcMapId"] = 209, ["dbcMapId"] = 209,
["dbcName"] = "ZulFarrak", ["dbcName"] = "ZulFarrak",
["worldBounds"] = { left=1625.00, right=241.67, top=2052.08, bottom=1129.17 }, ["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 end
@@ -911,7 +924,7 @@ if not MTH_DS_Zones[1477] then
["dbcMapId"] = 109, ["dbcMapId"] = 109,
["dbcName"] = "TheTempleOfAtalHakkar", ["dbcName"] = "TheTempleOfAtalHakkar",
["worldBounds"] = { left=442.76, right=-252.27, top=-255.17, bottom=-718.52 }, ["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 end
@@ -924,7 +937,7 @@ if not MTH_DS_Zones[719] then
["dbcMapId"] = 48, ["dbcMapId"] = 48,
["dbcName"] = "BlackFathomDeeps", ["dbcName"] = "BlackFathomDeeps",
["worldBounds"] = { left=485.41, right=-736.46, top=-107.91, bottom=-914.33 }, ["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 end
@@ -937,7 +950,7 @@ if not MTH_DS_Zones[717] then
["dbcMapId"] = 34, ["dbcMapId"] = 34,
["dbcName"] = "TheStockade", ["dbcName"] = "TheStockade",
["worldBounds"] = { left=189.82, right=-188.33, top=220.63, bottom=-31.47 }, ["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 end
@@ -950,7 +963,7 @@ if not MTH_DS_Zones[721] then
["dbcMapId"] = 90, ["dbcMapId"] = 90,
["dbcName"] = "Gnomeregan", ["dbcName"] = "Gnomeregan",
["worldBounds"] = { left=491.90, right=-277.77, top=-180.89, bottom=-694.00 }, ["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 end
@@ -963,7 +976,7 @@ if not MTH_DS_Zones[1337] then
["dbcMapId"] = 70, ["dbcMapId"] = 70,
["dbcName"] = "Uldaman", ["dbcName"] = "Uldaman",
["worldBounds"] = { left=645.12, right=-248.55, top=204.31, bottom=-391.47 }, ["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 end
@@ -975,8 +988,8 @@ if not MTH_DS_Zones[2717] then
["dbcAreaId"] = 2717, ["dbcAreaId"] = 2717,
["dbcMapId"] = 409, ["dbcMapId"] = 409,
["dbcName"] = "MoltenCore", ["dbcName"] = "MoltenCore",
["worldBounds"] = { left=-11.00, right=-1506.00, top=1439.00, bottom=456.00 }, ["worldBounds"] = { left=-130.76, right=-1395.56, top=1303.06, bottom=459.86 },
["names"] = { ["deDE"] = "Geschmolzener Kern", ["enUS"] = "Molten Core", ["esES"] = "Núcleo de Magma", ["ptBR"] = "Núcleo Derretido", ["ruRU"] = "Огненные Недра", ["zhCN"] = "熔火之心" }, ["names"] = { ["enUS"] = "Molten Core", ["esES"] = "Núcleo de Magma", ["ptBR"] = "Núcleo Derretido", ["zhCN"] = "熔火之心" },
} }
end end
@@ -989,7 +1002,7 @@ if not MTH_DS_Zones[1977] then
["dbcMapId"] = 309, ["dbcMapId"] = 309,
["dbcName"] = "ZulGurub", ["dbcName"] = "ZulGurub",
["worldBounds"] = { left=-612.50, right=-2733.33, top=-11225.00, bottom=-12639.58 }, ["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 end
@@ -1002,7 +1015,7 @@ if not MTH_DS_Zones[2557] then
["dbcMapId"] = 429, ["dbcMapId"] = 429,
["dbcName"] = "DireMaul", ["dbcName"] = "DireMaul",
["worldBounds"] = { left=887.50, right=-387.50, top=1050.00, bottom=200.00 }, ["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 end
@@ -1014,8 +1027,8 @@ if not MTH_DS_Zones[1584] then
["dbcAreaId"] = 1584, ["dbcAreaId"] = 1584,
["dbcMapId"] = 230, ["dbcMapId"] = 230,
["dbcName"] = "BlackrockDepths", ["dbcName"] = "BlackrockDepths",
["worldBounds"] = { left=875.00, right=-1110.00, top=1513.00, bottom=245.00 }, ["worldBounds"] = { left=522.34, right=-884.72, top=1186.68, bottom=248.64 },
["names"] = { ["deDE"] = "Schwarzfelstiefen", ["enUS"] = "Blackrock Depths", ["esES"] = "Profundidades de Roca Negra", ["ptBR"] = "Abismo Rocha Negra", ["ruRU"] = "Глубины Черной Горы", ["zhCN"] = "黑石深渊" }, ["names"] = { ["enUS"] = "Blackrock Depths", ["esES"] = "Profundidades de Roca Negra", ["ptBR"] = "Abismo Rocha Negra", ["zhCN"] = "黑石深渊" },
} }
end end
@@ -1028,7 +1041,7 @@ if not MTH_DS_Zones[3429] then
["dbcMapId"] = 509, ["dbcMapId"] = 509,
["dbcName"] = "RuinsofAhnQiraj", ["dbcName"] = "RuinsofAhnQiraj",
["worldBounds"] = { left=3035.42, right=522.92, top=-8233.33, bottom=-9908.33 }, ["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 end
@@ -1041,7 +1054,7 @@ if not MTH_DS_Zones[2159] then
["dbcMapId"] = 249, ["dbcMapId"] = 249,
["dbcName"] = "OnyxiasLair", ["dbcName"] = "OnyxiasLair",
["worldBounds"] = { left=111.38, right=-371.73, top=98.25, bottom=-223.83 }, ["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 end
@@ -1054,7 +1067,7 @@ if not MTH_DS_Zones[1583] then
["dbcMapId"] = 229, ["dbcMapId"] = 229,
["dbcName"] = "BlackrockSpire", ["dbcName"] = "BlackrockSpire",
["worldBounds"] = { left=10.59, right=-876.25, top=304.40, bottom=-286.83 }, ["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 end
@@ -1067,7 +1080,7 @@ if not MTH_DS_Zones[718] then
["dbcMapId"] = 43, ["dbcMapId"] = 43,
["dbcName"] = "WailingCaverns", ["dbcName"] = "WailingCaverns",
["worldBounds"] = { left=790.00, right=-380.00, top=215.00, bottom=-570.00 }, ["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 end
@@ -1080,7 +1093,7 @@ if not MTH_DS_Zones[2100] then
["dbcMapId"] = 349, ["dbcMapId"] = 349,
["dbcName"] = "Maraudon", ["dbcName"] = "Maraudon",
["worldBounds"] = { left=485.41, right=-1626.68, top=1199.76, bottom=-211.13 }, ["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 end
@@ -1093,7 +1106,7 @@ if not MTH_DS_Zones[2677] then
["dbcMapId"] = 469, ["dbcMapId"] = 469,
["dbcName"] = "BlackwingLair", ["dbcName"] = "BlackwingLair",
["worldBounds"] = { left=-844.62, right=-1344.05, top=-7394.12, bottom=-7727.07 }, ["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 end
@@ -1106,7 +1119,7 @@ if not MTH_DS_Zones[5138] then
["dbcMapId"] = 36, ["dbcMapId"] = 36,
["dbcName"] = "TheDeadmines", ["dbcName"] = "TheDeadmines",
["worldBounds"] = { left=-322.94, right=-979.53, top=36.93, bottom=-398.04 }, ["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 end
@@ -1118,8 +1131,8 @@ if not MTH_DS_Zones[722] then
["dbcAreaId"] = 722, ["dbcAreaId"] = 722,
["dbcMapId"] = 129, ["dbcMapId"] = 129,
["dbcName"] = "RazorfenDowns", ["dbcName"] = "RazorfenDowns",
["worldBounds"] = { left=1271.00, right=390.00, top=2683.00, bottom=2094.00 }, ["worldBounds"] = { left=1279.94, right=570.89, top=2682.55, bottom=2209.85 },
["names"] = { ["deDE"] = "Hügel der Klingenhauer", ["enUS"] = "Razorfen Downs", ["esES"] = "Zahúrda Rajacieno", ["ptBR"] = "Urzal dos Mortos", ["ruRU"] = "Курганы Иглошкурых", ["zhCN"] = "剃刀高地" }, ["names"] = { ["enUS"] = "Razorfen Downs", ["esES"] = "Tierras Bajas de Rajacieno", ["ptBR"] = "Razorfen Downs", ["zhCN"] = "剃刀高地" },
} }
end end
@@ -1132,7 +1145,7 @@ if not MTH_DS_Zones[491] then
["dbcMapId"] = 47, ["dbcMapId"] = 47,
["dbcName"] = "RazorfenKraul", ["dbcName"] = "RazorfenKraul",
["worldBounds"] = { left=2058.92, right=1322.47, top=2349.64, bottom=1858.68 }, ["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 end
@@ -1145,7 +1158,7 @@ if not MTH_DS_Zones[5136] then
["dbcMapId"] = 189, ["dbcMapId"] = 189,
["dbcName"] = "ScarletMonastery", ["dbcName"] = "ScarletMonastery",
["worldBounds"] = { left=1567.97, right=947.99, top=2030.18, bottom=1616.86 }, ["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 end
@@ -1158,7 +1171,7 @@ if not MTH_DS_Zones[5135] then
["dbcMapId"] = 189, ["dbcMapId"] = 189,
["dbcName"] = "ScarletMonastery2f", ["dbcName"] = "ScarletMonastery2f",
["worldBounds"] = { left=-162.27, right=-482.46, top=307.37, bottom=93.91 }, ["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 end
@@ -1171,7 +1184,7 @@ if not MTH_DS_Zones[5153] then
["dbcMapId"] = 189, ["dbcMapId"] = 189,
["dbcName"] = "ScarletMonastery3f", ["dbcName"] = "ScarletMonastery3f",
["worldBounds"] = { left=50.27, right=-562.42, top=2009.10, bottom=1600.64 }, ["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 end
@@ -1184,7 +1197,7 @@ if not MTH_DS_Zones[5163] then
["dbcMapId"] = 189, ["dbcMapId"] = 189,
["dbcName"] = "ScarletMonastery4f", ["dbcName"] = "ScarletMonastery4f",
["worldBounds"] = { left=1743.99, right=1040.69, top=1281.29, bottom=812.42 }, ["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 end
@@ -1197,7 +1210,7 @@ if not MTH_DS_Zones[2057] then
["dbcMapId"] = 289, ["dbcMapId"] = 289,
["dbcName"] = "Scholomance", ["dbcName"] = "Scholomance",
["worldBounds"] = { left=251.41, right=-68.64, top=317.70, bottom=104.33 }, ["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 end
@@ -1210,7 +1223,7 @@ if not MTH_DS_Zones[209] then
["dbcMapId"] = 33, ["dbcMapId"] = 33,
["dbcName"] = "ShadowfangKeep", ["dbcName"] = "ShadowfangKeep",
["worldBounds"] = { left=2436.00, right=2055.00, top=-61.00, bottom=-315.00 }, ["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 end
@@ -1223,7 +1236,7 @@ if not MTH_DS_Zones[2017] then
["dbcMapId"] = 329, ["dbcMapId"] = 329,
["dbcName"] = "Stratholme", ["dbcName"] = "Stratholme",
["worldBounds"] = { left=-2639.83, right=-3825.18, top=4163.90, bottom=3374.04 }, ["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 end
@@ -1236,7 +1249,7 @@ if not MTH_DS_Zones[3428] then
["dbcMapId"] = 531, ["dbcMapId"] = 531,
["dbcName"] = "AhnQiraj", ["dbcName"] = "AhnQiraj",
["worldBounds"] = { left=2515.63, right=1538.07, top=-8051.80, bottom=-8703.50 }, ["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 end
@@ -1249,7 +1262,7 @@ if not MTH_DS_Zones[5147] then
["dbcMapId"] = 531, ["dbcMapId"] = 531,
["dbcName"] = "AhnQiraj2f", ["dbcName"] = "AhnQiraj2f",
["worldBounds"] = { left=2915.62, right=138.08, top=-7659.29, bottom=-9510.98 }, ["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 end
@@ -1262,7 +1275,7 @@ if not MTH_DS_Zones[3457] then
["dbcMapId"] = 532, ["dbcMapId"] = 532,
["dbcName"] = "Karazhan", ["dbcName"] = "Karazhan",
["worldBounds"] = { left=-1614.00, right=-2212.00, top=-10780.00, bottom=-11179.00 }, ["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 end
@@ -1275,7 +1288,7 @@ if not MTH_DS_Zones[2257] then
["dbcMapId"] = 369, ["dbcMapId"] = 369,
["dbcName"] = "DeeprunTram", ["dbcName"] = "DeeprunTram",
["worldBounds"] = { left=2623.50, right=2311.50, top=95.50, bottom=-112.50 }, ["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 end
@@ -1288,7 +1301,7 @@ if not MTH_DS_Zones[5144] then
["dbcMapId"] = 369, ["dbcMapId"] = 369,
["dbcName"] = "DeeprunTram2f", ["dbcName"] = "DeeprunTram2f",
["worldBounds"] = { left=187.50, right=-121.50, top=95.50, bottom=-112.50 }, ["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 end
@@ -1301,7 +1314,7 @@ if not MTH_DS_Zones[5204] then
["dbcMapId"] = 269, ["dbcMapId"] = 269,
["dbcName"] = "BlackMorass", ["dbcName"] = "BlackMorass",
["worldBounds"] = { left=7338.47, right=6066.48, top=-1247.55, bottom=-2093.03 }, ["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 end
@@ -1314,7 +1327,7 @@ if not MTH_DS_Zones[2366] then
["dbcMapId"] = 269, ["dbcMapId"] = 269,
["dbcName"] = "BlackMorass2f", ["dbcName"] = "BlackMorass2f",
["worldBounds"] = { left=7651.85, right=6565.99, top=-1500.47, bottom=-2227.08 }, ["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 end
@@ -1327,7 +1340,7 @@ if not MTH_DS_Zones[5208] then
["dbcMapId"] = 815, ["dbcMapId"] = 815,
["dbcName"] = "GilneasCity", ["dbcName"] = "GilneasCity",
["worldBounds"] = { left=3290.32, right=2040.14, top=-760.72, bottom=-1598.16 }, ["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 end
@@ -1340,7 +1353,7 @@ if not MTH_DS_Zones[3456] then
["dbcMapId"] = 533, ["dbcMapId"] = 533,
["dbcName"] = "Naxxramas", ["dbcName"] = "Naxxramas",
["worldBounds"] = { left=-2375.27, right=-4366.96, top=3656.70, bottom=2338.28 }, ["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 end
@@ -1353,7 +1366,7 @@ if not MTH_DS_Zones[5148] then
["dbcMapId"] = 533, ["dbcMapId"] = 533,
["dbcName"] = "Naxxramas2f", ["dbcName"] = "Naxxramas2f",
["worldBounds"] = { left=-4869.36, right=-5521.46, top=3816.56, bottom=3376.89 }, ["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 end
@@ -1366,7 +1379,7 @@ if not MTH_DS_Zones[5077] then
["dbcMapId"] = 802, ["dbcMapId"] = 802,
["dbcName"] = "CrescentGrove", ["dbcName"] = "CrescentGrove",
["worldBounds"] = { left=1207.72, right=-1435.49, top=882.98, bottom=-868.18 }, ["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 end
@@ -1379,7 +1392,7 @@ if not MTH_DS_Zones[5103] then
["dbcMapId"] = 808, ["dbcMapId"] = 808,
["dbcName"] = "HateforgeQuarry", ["dbcName"] = "HateforgeQuarry",
["worldBounds"] = { left=-3024.33, right=-3776.45, top=-7888.28, bottom=-8398.61 }, ["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 end
@@ -1392,7 +1405,7 @@ if not MTH_DS_Zones[5086] then
["dbcMapId"] = 800, ["dbcMapId"] = 800,
["dbcName"] = "KarazhanCrypt", ["dbcName"] = "KarazhanCrypt",
["worldBounds"] = { left=-1302.51, right=-1849.26, top=-10916.17, bottom=-11308.14 }, ["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 end
@@ -1405,7 +1418,7 @@ if not MTH_DS_Zones[5087] then
["dbcMapId"] = 35, ["dbcMapId"] = 35,
["dbcName"] = "StormwindVault", ["dbcName"] = "StormwindVault",
["worldBounds"] = { left=314.34, right=-40.16, top=89.30, bottom=-145.44 }, ["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 end
@@ -1418,7 +1431,7 @@ if not MTH_DS_Zones[5097] then
["dbcMapId"] = 807, ["dbcMapId"] = 807,
["dbcName"] = "EmeraldSanctum", ["dbcName"] = "EmeraldSanctum",
["worldBounds"] = { left=3939.10, right=2666.00, top=3519.72, bottom=2666.00 }, ["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 end
@@ -1431,7 +1444,7 @@ if not MTH_DS_Zones[5053] then
["dbcMapId"] = 801, ["dbcMapId"] = 801,
["dbcName"] = "Moomoo", ["dbcName"] = "Moomoo",
["worldBounds"] = { left=17296.30, right=16288.62, top=17158.52, bottom=16486.73 }, ["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 end
@@ -1444,7 +1457,7 @@ if not MTH_DS_Zones[3457] then
["dbcMapId"] = 814, ["dbcMapId"] = 814,
["dbcName"] = "UpperKarazhan", ["dbcName"] = "UpperKarazhan",
["worldBounds"] = { left=-1378.00, right=-2201.00, top=-10887.00, bottom=-11436.00 }, ["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 end
@@ -1457,84 +1470,6 @@ if not MTH_DS_Zones[5557] then
["dbcMapId"] = 814, ["dbcMapId"] = 814,
["dbcName"] = "UpperKarazhan2f", ["dbcName"] = "UpperKarazhan2f",
["worldBounds"] = { left=-1483.00, right=-4283.00, top=-5800.00, bottom=-7668.00 }, ["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"] = "荒芜巨岩" }, ["names"] = { ["enUS"] = "???", ["esES"] = "???", ["ptBR"] = "???", ["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"] = "风暴废墟" },
} }
end 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, [18042] = 2,
[19316] = 2, [19316] = 2,
[19317] = 2, [19317] = 2,
[42198] = 2,
[42199] = 2,
[42200] = 2,
[42201] = 3,
[42202] = 3,
} }
for itemId, quality in pairs(capturedQualityByItemId) do 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/ <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"> ..\FrameXML\UI.xsd">
<Include file="..\api\constants.lua"/> <Include file="..\api\constants.lua"/>
<Include file="..\api\debug-frame.lua"/>
<Include file="..\api\minimap-button.lua"/> <Include file="..\api\minimap-button.lua"/>
<Include file="..\api\AutoStrip.xml"/> <Include file="..\api\AutoStrip.xml"/>
<Include file="..\api\AutoStrip.lua"/> <Include file="..\api\AutoStrip.lua"/>
@@ -17,6 +16,7 @@
<Include file="..\api\options-autobuy.lua"/> <Include file="..\api\options-autobuy.lua"/>
<Include file="..\api\options-autoquest.lua"/> <Include file="..\api\options-autoquest.lua"/>
<Include file="..\api\options-icu.lua"/> <Include file="..\api\options-icu.lua"/>
<Include file="..\api\options-expammo.lua"/>
<Include file="..\api\profile.lua"/> <Include file="..\api\profile.lua"/>
<Include file="..\api\options-profiles.lua"/> <Include file="..\api\options-profiles.lua"/>
<Include file="..\api\options-shell.lua"/> <Include file="..\api\options-shell.lua"/>
@@ -33,6 +33,7 @@
<Include file="..\api\hunterbook-tab-pethistory.lua"/> <Include file="..\api\hunterbook-tab-pethistory.lua"/>
<Include file="..\api\hunterbook-model-viewer.lua"/> <Include file="..\api\hunterbook-model-viewer.lua"/>
<Include file="..\api\map-markers.lua"/> <Include file="..\api\map-markers.lua"/>
<Include file="..\api\debug-frame.lua"/>
<Include file="..\api\core-framework.lua"/> <Include file="..\api\core-framework.lua"/>
<Include file="..\api\core-scan-stablemaster.lua"/> <Include file="..\api\core-scan-stablemaster.lua"/>
<Include file="..\api\pets-service-lifecycle.lua"/> <Include file="..\api\pets-service-lifecycle.lua"/>
@@ -41,6 +42,8 @@
<Include file="..\api\pets-service-stablescan.lua"/> <Include file="..\api\pets-service-stablescan.lua"/>
<Include file="..\api\core-scan-beasttraining.lua"/> <Include file="..\api\core-scan-beasttraining.lua"/>
<Include file="..\api\core-scan-spellbookpet.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\core.lua"/>
<Include file="..\api\version-check.lua"/> <Include file="..\api\version-check.lua"/>
<Include file="..\api\localization.lua"/> <Include file="..\api\localization.lua"/>
+3
View File
@@ -26,4 +26,7 @@ MetaHunt Module Loader
<!-- ICU Module - ENABLED (runtime default: disabled) --> <!-- ICU Module - ENABLED (runtime default: disabled) -->
<Include file="..\modules\icu\loader.xml"/> <Include file="..\modules\icu\loader.xml"/>
<!-- Experimental Ammunition Module - ENABLED -->
<Include file="..\modules\expammo\loader.xml"/>
</Ui> </Ui>
+5
View File
@@ -2,6 +2,11 @@ MTH_LocaleData = MTH_LocaleData or {}
MTH_LocaleData.spells = MTH_LocaleData.spells or {} MTH_LocaleData.spells = MTH_LocaleData.spells or {}
MTH_LocaleData.spells.deDE = { 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", ["Banish"] = "Verbannen",
["Bestial Wrath"] = "Zorn des Wildtiers", ["Bestial Wrath"] = "Zorn des Wildtiers",
["Concussive Shot"] = "Erschütternder Schuss", ["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 = MTH_LocaleData.spells or {}
MTH_LocaleData.spells.enUS = { 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", ["Banish"] = "Banish",
["Bestial Wrath"] = "Bestial Wrath", ["Bestial Wrath"] = "Bestial Wrath",
["Concussive Shot"] = "Concussive Shot", ["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 = MTH_LocaleData.spells or {}
MTH_LocaleData.spells.esES = { 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", ["Banish"] = "Banish",
["Bestial Wrath"] = "Bestial Wrath", ["Bestial Wrath"] = "Bestial Wrath",
["Concussive Shot"] = "Concussive Shot", ["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 = MTH_LocaleData.spells or {}
MTH_LocaleData.spells.ptBR = { 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", ["Banish"] = "Banish",
["Bestial Wrath"] = "Bestial Wrath", ["Bestial Wrath"] = "Bestial Wrath",
["Concussive Shot"] = "Concussive Shot", ["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 = MTH_LocaleData.spells or {}
MTH_LocaleData.spells.ruRU = { MTH_LocaleData.spells.ruRU = {
["Aimed Shot"] = "Прицельный выстрел",
["Aspect of the Viper"] = "Аспект гадюки",
["Kill Command"] = "Приказ убивать",
["Lock and Load"] = "Lock and Load",
["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 = MTH_LocaleData.spells or {}
MTH_LocaleData.spells.zhCN = { MTH_LocaleData.spells.zhCN = {
["Aimed Shot"] = "瞄准射击",
["Aspect of the Viper"] = "毒蛇图腾",
["Kill Command"] = "猎杀命令",
["Lock and Load"] = "Lock and Load",
["Scent of Blood"] = "血腥气息",
["Banish"] = "放逐术", ["Banish"] = "放逐术",
["Bestial Wrath"] = "狂野怒火", ["Bestial Wrath"] = "狂野怒火",
["Concussive Shot"] = "震荡射击", ["Concussive Shot"] = "震荡射击",
-25
View File
@@ -9,9 +9,6 @@ local Engine = MTH_AutoBuyEngine
local AB_AMMO_BY_NAME = nil local AB_AMMO_BY_NAME = nil
local AB_FOOD_DIET_BY_ITEM_ID = nil local AB_FOOD_DIET_BY_ITEM_ID = nil
local function AB_Trace(message)
return
end
local function AB_ParseItemIdFromLink(link) local function AB_ParseItemIdFromLink(link)
if type(link) ~= "string" then if type(link) ~= "string" then
@@ -1180,7 +1177,6 @@ end
function Engine:ExecutePlan(plan) function Engine:ExecutePlan(plan)
if type(plan) ~= "table" or type(plan.actions) ~= "table" then if type(plan) ~= "table" or type(plan.actions) ~= "table" then
AB_Trace("ExecutePlan skipped: invalid plan table")
return 0, 0 return 0, 0
end end
local executedActions = 0 local executedActions = 0
@@ -1189,10 +1185,6 @@ function Engine:ExecutePlan(plan)
if type(action) == "table" and action.index then if type(action) == "table" and action.index then
local stacksToBuy = math.floor(tonumber(action.quantityStacks) or 0) local stacksToBuy = math.floor(tonumber(action.quantityStacks) or 0)
if stacksToBuy > 0 then 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 for i = 1, stacksToBuy do
BuyMerchantItem(action.index) BuyMerchantItem(action.index)
end end
@@ -1201,7 +1193,6 @@ function Engine:ExecutePlan(plan)
end end
end end
end end
AB_Trace("ExecutePlan done actions=" .. tostring(executedActions) .. " stacks=" .. tostring(requestedStacks) .. " reason=" .. tostring(plan.reason or ""))
return executedActions, requestedStacks return executedActions, requestedStacks
end end
@@ -1264,42 +1255,30 @@ local function AB_AnnouncePurchases(actions)
end end
function Engine:OnMerchantEvent(eventName) 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 if eventName == "MERCHANT_SHOW" then
self._merchantSessionExecuted = false self._merchantSessionExecuted = false
AB_Trace("MERCHANT_SHOW resets session execution flag")
elseif eventName == "MERCHANT_UPDATE" and self._merchantSessionExecuted then elseif eventName == "MERCHANT_UPDATE" and self._merchantSessionExecuted then
AB_Trace("MERCHANT_UPDATE ignored: already executed this merchant session")
return return
end end
if not self:IsEnabled() then if not self:IsEnabled() then
AB_Trace("event ignored: autobuy module disabled")
return return
end end
local snapshot = self:ScanMerchant() local snapshot = self:ScanMerchant()
AB_Trace("snapshot rows=" .. tostring(snapshot and snapshot.count or 0))
local foodPlan = self:BuildFoodPlan(snapshot) local foodPlan = self:BuildFoodPlan(snapshot)
local ammoPlan = self:BuildAmmoPlan(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 for i = 1, table.getn(foodPlan.debugLines or {}) do
AB_Trace("food#" .. tostring(i) .. " " .. tostring(foodPlan.debugLines[i]))
end end
AB_Trace("ammoPlan reason=" .. tostring(ammoPlan.reason) .. " actions=" .. tostring(table.getn(ammoPlan.actions or {})))
for i = 1, table.getn(ammoPlan.debugLines or {}) do for i = 1, table.getn(ammoPlan.debugLines or {}) do
AB_Trace("ammo#" .. tostring(i) .. " " .. tostring(ammoPlan.debugLines[i]))
end end
local totalRequestedStacks = 0 local totalRequestedStacks = 0
if table.getn(foodPlan.actions or {}) > 0 then if table.getn(foodPlan.actions or {}) > 0 then
local _, requestedStacks = self:ExecutePlan(foodPlan) local _, requestedStacks = self:ExecutePlan(foodPlan)
totalRequestedStacks = totalRequestedStacks + requestedStacks totalRequestedStacks = totalRequestedStacks + requestedStacks
AB_Trace("food plan executed requestedStacks=" .. tostring(requestedStacks))
if requestedStacks > 0 then if requestedStacks > 0 then
AB_AnnouncePurchases(foodPlan.actions) AB_AnnouncePurchases(foodPlan.actions)
end end
@@ -1308,19 +1287,15 @@ function Engine:OnMerchantEvent(eventName)
if table.getn(ammoPlan.actions or {}) > 0 then if table.getn(ammoPlan.actions or {}) > 0 then
local _, requestedStacks = self:ExecutePlan(ammoPlan) local _, requestedStacks = self:ExecutePlan(ammoPlan)
totalRequestedStacks = totalRequestedStacks + requestedStacks totalRequestedStacks = totalRequestedStacks + requestedStacks
AB_Trace("ammo plan executed requestedStacks=" .. tostring(requestedStacks))
if requestedStacks > 0 then if requestedStacks > 0 then
local moved = AB_MoveAmmoStacksToSpecialBags(300) local moved = AB_MoveAmmoStacksToSpecialBags(300)
AB_Trace("ammo restack moved=" .. tostring(moved))
AB_AnnouncePurchases(ammoPlan.actions) AB_AnnouncePurchases(ammoPlan.actions)
end end
end end
if totalRequestedStacks > 0 then if totalRequestedStacks > 0 then
self._merchantSessionExecuted = true self._merchantSessionExecuted = true
AB_Trace("session marked executed requestedStacks=" .. tostring(totalRequestedStacks))
else else
AB_Trace("no purchases requested in this event")
end end
end end
+2 -27
View File
@@ -6,7 +6,7 @@
local MTH_AutoBuy = { local MTH_AutoBuy = {
name = "autobuy", name = "autobuy",
enabled = false, enabled = false,
version = "1.3.0", version = "1.4.1",
events = { events = {
"VARIABLES_LOADED", "VARIABLES_LOADED",
"MERCHANT_SHOW", "MERCHANT_SHOW",
@@ -24,9 +24,6 @@ end
local AB_Engine local AB_Engine
local function AB_Trace(message)
return
end
local function AB_EnsureBridgeFrame(moduleRef) local function AB_EnsureBridgeFrame(moduleRef)
if MTH_AutoBuy._bridgeFrame then if MTH_AutoBuy._bridgeFrame then
@@ -46,15 +43,12 @@ local function AB_EnsureBridgeFrame(moduleRef)
local eventName = event local eventName = event
local engine = AB_Engine() local engine = AB_Engine()
if not engine then if not engine then
AB_Trace("bridge event=" .. tostring(eventName) .. " engine missing")
return return
end end
if eventName == "MERCHANT_SHOW" or eventName == "MERCHANT_UPDATE" then if eventName == "MERCHANT_SHOW" or eventName == "MERCHANT_UPDATE" then
AB_Trace("bridge " .. tostring(eventName) .. " -> engine")
engine:OnMerchantEvent(eventName) engine:OnMerchantEvent(eventName)
elseif eventName == "MERCHANT_CLOSED" then elseif eventName == "MERCHANT_CLOSED" then
AB_Trace("bridge MERCHANT_CLOSED -> engine")
if engine.OnMerchantClosed then if engine.OnMerchantClosed then
engine:OnMerchantClosed() engine:OnMerchantClosed()
end end
@@ -77,10 +71,8 @@ local function AB_SetBridgeActive(active)
frame:RegisterEvent("MERCHANT_UPDATE") frame:RegisterEvent("MERCHANT_UPDATE")
frame:RegisterEvent("MERCHANT_CLOSED") frame:RegisterEvent("MERCHANT_CLOSED")
MTH_AutoBuy._bridgeActive = true MTH_AutoBuy._bridgeActive = true
AB_Trace("bridge active=true")
else else
MTH_AutoBuy._bridgeActive = false MTH_AutoBuy._bridgeActive = false
AB_Trace("bridge active=false (frame missing)")
end end
return return
end end
@@ -91,7 +83,6 @@ local function AB_SetBridgeActive(active)
frame:UnregisterEvent("MERCHANT_CLOSED") frame:UnregisterEvent("MERCHANT_CLOSED")
end end
MTH_AutoBuy._bridgeActive = false MTH_AutoBuy._bridgeActive = false
AB_Trace("bridge active=false")
end end
AB_Engine = function() AB_Engine = function()
@@ -102,15 +93,12 @@ function MTH_AutoBuy:init()
local engine = AB_Engine() local engine = AB_Engine()
if not engine then if not engine then
AB_Log("init failed: engine missing", "error") AB_Log("init failed: engine missing", "error")
AB_Trace("init failed: engine missing")
return return
end end
engine:Init() engine:Init()
self.initialized = true self.initialized = true
AB_SetBridgeActive(self.enabled and true or false) AB_SetBridgeActive(self.enabled and true or false)
AB_Trace("init done")
if self.enabled then if self.enabled then
AB_Log("module initialized", "debug")
end end
end end
@@ -120,20 +108,16 @@ function MTH_AutoBuy:setEnabled(enabled)
end end
local engine = AB_Engine() local engine = AB_Engine()
if not engine then if not engine then
AB_Trace("setEnabled ignored: engine missing")
return return
end end
local store = engine:EnsureDefaults() local store = engine:EnsureDefaults()
store.enabled = enabled and true or false store.enabled = enabled and true or false
AB_SetBridgeActive(store.enabled and true or false) AB_SetBridgeActive(store.enabled and true or false)
AB_Trace("setEnabled store.enabled=" .. tostring(store.enabled))
end end
function MTH_AutoBuy:onEvent(event) function MTH_AutoBuy:onEvent(event)
local engine = AB_Engine() local engine = AB_Engine()
if not engine then if not engine then
AB_Log("onEvent ignored: engine missing, event=" .. tostring(event), "debug")
AB_Trace("engine missing, event=" .. tostring(event))
return return
end end
if self._bridgeActive and (event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" or event == "MERCHANT_CLOSED") then 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 if event == "VARIABLES_LOADED" then
engine:Init() engine:Init()
AB_SetBridgeActive(self.enabled and true or false) AB_SetBridgeActive(self.enabled and true or false)
local store = engine:EnsureDefaults() engine:EnsureDefaults()
AB_Trace("VARIABLES_LOADED module.enabled=" .. tostring(self.enabled)
.. " store.enabled=" .. tostring(store and store.enabled)
.. " projectiles.enabled=" .. tostring(store and store.projectiles and store.projectiles.enabled))
return return
end end
if not self.enabled then if not self.enabled then
AB_Log("onEvent ignored: module disabled", "debug")
if event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" then if event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" then
AB_Trace(tostring(event) .. " ignored: module disabled")
end end
return return
end end
if event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" then 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) engine:OnMerchantEvent(event)
elseif event == "MERCHANT_CLOSED" then elseif event == "MERCHANT_CLOSED" then
AB_Trace("forwarding MERCHANT_CLOSED to engine")
if engine.OnMerchantClosed then if engine.OnMerchantClosed then
engine:OnMerchantClosed() engine:OnMerchantClosed()
end end
@@ -171,7 +147,6 @@ function MTH_AutoBuy:onEvent(event)
end end
function MTH_AutoBuy:cleanup() function MTH_AutoBuy:cleanup()
AB_Log("module cleanup", "debug")
end end
MTH:RegisterModule("autobuy", MTH_AutoBuy) MTH:RegisterModule("autobuy", MTH_AutoBuy)
+1 -1
View File
@@ -6,7 +6,7 @@
local MTH_AutoQuest = { local MTH_AutoQuest = {
name = "autoquest", name = "autoquest",
enabled = false, enabled = false,
version = "1.3.0", version = "1.4.1",
events = { events = {
"GOSSIP_SHOW", "GOSSIP_SHOW",
"QUEST_GREETING", "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["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["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["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["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["Scare Beast"], 10, 1, 0, 0, { cr = "BLUE", rc = true, d = { rs = 5 } })
engine:AddTimer(engine.SPELL, BS["Scatter Shot"], 4, 1, 0, 0, { cr = "MAROON" }) engine:AddTimer(engine.SPELL, BS["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["Wyvern Sting"], 12, 1, 0, 0, { gr = 2, cr = "MAROON", rc = true })
engine:AddTimer(engine.SPELL, BS["Feed Pet"], 20, 0, 0, 0, { cr = "MAROON" }) engine:AddTimer(engine.SPELL, BS["Feed Pet"], 20, 0, 0, 0, { cr = "MAROON" })
engine:AddTimer(engine.EVENT, BS["Explosive Trap Effect"], 20, 1, 0, 1, { gr = 1, cr = "ORANGE", a = 1, xn = BS["Explosive Trap"] }) -- Trap effects: no "a=1" here — primed by the SPELL timer's "ea" chain (cast hook sets timer.v
engine:AddTimer(engine.EVENT, BS["Freezing Trap Effect"], 10, 1, 0, 1, { gr = 1, cr = "CYAN", a = 1, d = { rs = 5, tn = BS["Clever Traps"], tb = 0.15, tp = 1 }, xn = BS["Freezing Trap"] }) -- and timer.t). Using "a=1" would trigger on any hunter's affliction message since
engine:AddTimer(engine.EVENT, BS["Frost Trap Aura"], 30, 0, 0, 0, { gr = 1, cr = "CYAN", a = 1, d = { tn = BS["Clever Traps"], tb = 0.15, tp = 1 }, xn = BS["Frost Trap"] }) -- CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS never embeds a caster name.
engine:AddTimer(engine.EVENT, BS["Immolation Trap Effect"], 15, 1, 0, 1, { gr = 1, cr = "ORANGE", a = 1, xn = BS["Immolation Trap"] }) engine:AddTimer(engine.EVENT, BS["Explosive Trap Effect"], 20, 1, 0, 1, { gr = 1, cr = "ORANGE", xn = BS["Explosive Trap"] })
engine:AddTimer(engine.EVENT, BS["Freezing Trap Effect"], 10, 1, 0, 1, { gr = 1, cr = "CYAN", d = { rs = 5, tn = BS["Clever Traps"], tb = 0.15, tp = 1 }, xn = BS["Freezing Trap"] })
engine:AddTimer(engine.EVENT, BS["Frost Trap Aura"], 30, 0, 0, 0, { gr = 1, cr = "CYAN", d = { tn = BS["Clever Traps"], tb = 0.15, tp = 1 }, xn = BS["Frost Trap"] })
engine:AddTimer(engine.EVENT, BS["Immolation Trap Effect"], 15, 1, 0, 1, { gr = 1, cr = "ORANGE", xn = BS["Immolation Trap"] })
engine:AddTimer(engine.EVENT, BS["Improved Concussive Shot"], 3, 1, 0, 0, { a = 1, cr = "BLUE", xn = BS["Concussive Shot"] }) engine:AddTimer(engine.EVENT, BS["Improved Concussive Shot"], 3, 1, 0, 0, { a = 1, cr = "BLUE", xn = BS["Concussive Shot"] })
engine:AddTimer(engine.EVENT, BS["Improved Wing Clip"], 5, 1, 0, 0, { a = 1, cr = "MAROON", xn = BS["Wing Clip"] }) engine:AddTimer(engine.EVENT, BS["Improved Wing Clip"], 5, 1, 0, 0, { a = 1, cr = "MAROON", xn = BS["Wing Clip"] })
engine:AddTimer(engine.EVENT, BS["Lock and Load"], 10, 0, 1, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\ability_hunter_lockandload" }) -- 10s (tooltip confirmed; expires on Aimed Shot cast)
engine:AddTimer(engine.EVENT, BS["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["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["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["Quick Shots"], 12, 0, 1, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\Ability_Warrior_InnerRage" })
engine:AddTimer(engine.EVENT, BS["Wing Clip"], 10, 1, 0, 1, { a = 1, cr = "YELLOW" }) engine:AddTimer(engine.EVENT, BS["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["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["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" }) 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 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 BAR_GROUP = "MTHChronometer"
local PARSER_OWNER = "MTHChronometerHunter" 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 function MTH_CHRON_FormatBarPosition(profile)
local bp = profile and profile.barposition local bp = profile and profile.barposition
@@ -195,13 +184,11 @@ end
local function ensureProfile() local function ensureProfile()
if not MTH or not MTH.GetModuleCharSavedVariables then if not MTH or not MTH.GetModuleCharSavedVariables then
MTH_CHRON_Trace("ensureProfile fallback defaults (no MTH store)")
return shallowCopy(DEFAULTS) return shallowCopy(DEFAULTS)
end end
local store = MTH:GetModuleCharSavedVariables("chronometer") local store = MTH:GetModuleCharSavedVariables("chronometer")
if type(store) ~= "table" then if type(store) ~= "table" then
MTH_CHRON_Trace("ensureProfile fallback defaults (invalid store)")
return shallowCopy(DEFAULTS) return shallowCopy(DEFAULTS)
end end
if type(store.profile) ~= "table" if type(store.profile) ~= "table"
@@ -211,10 +198,8 @@ local function ensureProfile()
local legacyChar = MTH_CharSavedVariables.chronometer local legacyChar = MTH_CharSavedVariables.chronometer
if type(legacyChar.profile) == "table" then if type(legacyChar.profile) == "table" then
store.profile = deepCopyValue(legacyChar.profile) store.profile = deepCopyValue(legacyChar.profile)
MTH_CHRON_Trace("ensureProfile migrated legacy MTH_CharSavedVariables.chronometer.profile")
elseif type(legacyChar.barposition) == "table" then elseif type(legacyChar.barposition) == "table" then
store.profile = { barposition = deepCopyValue(legacyChar.barposition) } store.profile = { barposition = deepCopyValue(legacyChar.barposition) }
MTH_CHRON_Trace("ensureProfile migrated legacy MTH_CharSavedVariables.chronometer.barposition")
end end
end end
if type(store.profile) ~= "table" if type(store.profile) ~= "table"
@@ -224,17 +209,14 @@ local function ensureProfile()
local legacyAccount = MTH_SavedVariables.chronometer local legacyAccount = MTH_SavedVariables.chronometer
if type(legacyAccount.profile) == "table" then if type(legacyAccount.profile) == "table" then
store.profile = deepCopyValue(legacyAccount.profile) store.profile = deepCopyValue(legacyAccount.profile)
MTH_CHRON_Trace("ensureProfile migrated legacy MTH_SavedVariables.chronometer.profile")
elseif type(legacyAccount.barposition) == "table" then elseif type(legacyAccount.barposition) == "table" then
store.profile = { barposition = deepCopyValue(legacyAccount.barposition) } store.profile = { barposition = deepCopyValue(legacyAccount.barposition) }
MTH_CHRON_Trace("ensureProfile migrated legacy MTH_SavedVariables.chronometer.barposition")
end end
end end
if type(store.profile) ~= "table" and MTH.GetModuleSavedVariables then if type(store.profile) ~= "table" and MTH.GetModuleSavedVariables then
local accountStore = MTH:GetModuleSavedVariables("chronometer") local accountStore = MTH:GetModuleSavedVariables("chronometer")
if type(accountStore) == "table" and type(accountStore.profile) == "table" then if type(accountStore) == "table" and type(accountStore.profile) == "table" then
store.profile = deepCopyValue(accountStore.profile) store.profile = deepCopyValue(accountStore.profile)
MTH_CHRON_Trace("ensureProfile copied account profile into char store")
end end
end end
if type(store.profile) ~= "table" then if type(store.profile) ~= "table" then
@@ -242,17 +224,14 @@ local function ensureProfile()
end end
if type(store.profile.barposition) ~= "table" and type(store.barposition) == "table" then if type(store.profile.barposition) ~= "table" and type(store.barposition) == "table" then
store.profile.barposition = deepCopyValue(store.barposition) store.profile.barposition = deepCopyValue(store.barposition)
MTH_CHRON_Trace("ensureProfile migrated legacy char barposition -> profile.barposition")
end end
if type(store.profile.barposition) ~= "table" and MTH.GetModuleSavedVariables then if type(store.profile.barposition) ~= "table" and MTH.GetModuleSavedVariables then
local accountStore = MTH:GetModuleSavedVariables("chronometer") local accountStore = MTH:GetModuleSavedVariables("chronometer")
if type(accountStore) == "table" then if type(accountStore) == "table" then
if type(accountStore.barposition) == "table" then if type(accountStore.barposition) == "table" then
store.profile.barposition = deepCopyValue(accountStore.barposition) 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 elseif type(accountStore.profile) == "table" and type(accountStore.profile.barposition) == "table" then
store.profile.barposition = deepCopyValue(accountStore.profile.barposition) store.profile.barposition = deepCopyValue(accountStore.profile.barposition)
MTH_CHRON_Trace("ensureProfile copied account profile.barposition -> char profile.barposition")
end end
end end
end end
@@ -282,7 +261,6 @@ local function ensureProfile()
profile.disabledSpells.HUNTER = {} profile.disabledSpells.HUNTER = {}
end end
MTH_CHRON_Trace("ensureProfile result barposition=" .. MTH_CHRON_FormatBarPosition(profile))
return profile return profile
end end
@@ -309,8 +287,6 @@ local function MTH_CHRON_PersistAnchorPosition(self, reason)
self.profile.barposition.relativePoint = relPoint self.profile.barposition.relativePoint = relPoint
self.profile.barposition.x = x self.profile.barposition.x = x
self.profile.barposition.y = y self.profile.barposition.y = y
MTH_CHRON_Trace("persist-anchor reason=" .. tostring(reason or "")
.. " profile=" .. MTH_CHRON_FormatBarPosition(self.profile))
return true return true
end end
@@ -330,8 +306,6 @@ local function MTH_CHRON_RestoreAnchorFromProfile(self, reason)
local ppoint = tostring(bp.point or "") local ppoint = tostring(bp.point or "")
local prelpoint = tostring(bp.relativePoint or "") local prelpoint = tostring(bp.relativePoint or "")
if not (px and py and ppoint ~= "") then 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 return false
end end
if prelpoint == "" then if prelpoint == "" then
@@ -339,8 +313,6 @@ local function MTH_CHRON_RestoreAnchorFromProfile(self, reason)
end end
self.anchor:ClearAllPoints() self.anchor:ClearAllPoints()
self.anchor:SetPoint(ppoint, UIParent, prelpoint, px, py) 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 return true
end end
@@ -527,7 +499,6 @@ function Chronometer:MTH_Initialize()
end end
self.profile = ensureProfile() self.profile = ensureProfile()
MTH_CHRON_Trace("MTH_Initialize profile=" .. MTH_CHRON_FormatBarPosition(self.profile))
self.parser = ParserLib:GetInstance("1.1") self.parser = ParserLib:GetInstance("1.1")
self.COLOR_MAP = { self.COLOR_MAP = {
@@ -538,7 +509,6 @@ function Chronometer:MTH_Initialize()
} }
self.anchor = self:CreateAnchor("MetaHunt Chronometer", 0, 1, 0) 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:RegisterCandyBarGroup(BAR_GROUP)
self:SetCandyBarGroupPoint(BAR_GROUP, "TOP", self.anchor, "BOTTOM", 0, 0) self:SetCandyBarGroupPoint(BAR_GROUP, "TOP", self.anchor, "BOTTOM", 0, 0)
@@ -547,19 +517,16 @@ end
function Chronometer:MTH_Enable() function Chronometer:MTH_Enable()
self._mth_explicitEnable = true self._mth_explicitEnable = true
MTH_CHRON_Trace("MTH_Enable called")
self:MTH_Initialize() self:MTH_Initialize()
self:OnEnable() self:OnEnable()
self._mth_explicitEnable = nil self._mth_explicitEnable = nil
end end
function Chronometer:MTH_Disable() function Chronometer:MTH_Disable()
MTH_CHRON_Trace("MTH_Disable called")
self:OnDisable() self:OnDisable()
end end
function Chronometer:OnEnable() function Chronometer:OnEnable()
MTH_CHRON_Trace("OnEnable begin enabled=" .. tostring(self._mth_enabled and true or false))
if self._mth_enabled then if self._mth_enabled then
return return
end end
@@ -589,11 +556,9 @@ function Chronometer:OnEnable()
self._mth_enabled = true self._mth_enabled = true
self.profile = ensureProfile() 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:SetCandyBarGroupGrowth(BAR_GROUP, self.profile.growup and true or false)
self:SetCandyBarGroupVerticalSpacing(BAR_GROUP, self.profile.spacing or 0) self:SetCandyBarGroupVerticalSpacing(BAR_GROUP, self.profile.spacing or 0)
if self.anchor then if self.anchor then
MTH_CHRON_Trace("OnEnable anchor-current-point=" .. MTH_CHRON_DescribePoint(self.anchor))
end end
MTH_CHRON_RestoreAnchorFromProfile(self, "OnEnable") 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_SELF", function(event, info) self:SPELL_FADE(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_AURA_GONE_OTHER", function(event, info) self:SPELL_FADE(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_AURA_GONE_OTHER", function(event, info) self:SPELL_FADE(event, info) end)
-- Registered events:
-- SELF_BUFFS / SELF_DAMAGE → our own procs & self-damage (source == ParserLib_SELF confirmed)
-- CREATURE_DAMAGE → DOT ticks on creatures ("from your X" embeds source; filtered in SPELL_PERIODIC)
-- CREATURE_BUFFS → debuff APPLICATION on creatures ("X is afflicted by Y"; no source embedded).
-- Needed for non-ticking debuffs: Poisonous/Enchanted Ammunition, Piercing Shot.
-- Foreign-bar risk is mitigated in SPELL_PERIODIC by requiring victim == target
-- when source is nil and no confirmed cast record exists.
-- FRIENDLYPLAYER_*, HOSTILEPLAYER_* are other players' events → intentionally NOT registered.
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end) self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS", function(event, info) self:SPELL_PERIODIC(event, info) end)
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE", function(event, info) self:SPELL_PERIODIC(event, info) end)
local enableRoM = false local enableRoM = false
for _, timer in pairs(self.timers[self.SPELL] or {}) do for _, timer in pairs(self.timers[self.SPELL] or {}) do
@@ -701,9 +670,7 @@ function Chronometer:OnDisable()
if not self._mth_enabled then if not self._mth_enabled then
return return
end end
MTH_CHRON_Trace("OnDisable begin profile=" .. MTH_CHRON_FormatBarPosition(self.profile))
if self.anchor then if self.anchor then
MTH_CHRON_Trace("OnDisable anchor-point=" .. MTH_CHRON_DescribePoint(self.anchor))
end end
MTH_CHRON_PersistAnchorPosition(self, "OnDisable") MTH_CHRON_PersistAnchorPosition(self, "OnDisable")
self._mth_enabled = false 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 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 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 "") 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 px ~= nil and py ~= nil then
if ppoint == "" then if ppoint == "" then
ppoint = "TOPLEFT" ppoint = "TOPLEFT"
@@ -1219,17 +1185,14 @@ function Chronometer:CreateAnchor(text, r, g, b)
end end
frame:ClearAllPoints() frame:ClearAllPoints()
frame:SetPoint(ppoint, UIParent, prelpoint, px, py) frame:SetPoint(ppoint, UIParent, prelpoint, px, py)
MTH_CHRON_Trace("CreateAnchor restored point=" .. MTH_CHRON_DescribePoint(frame))
else else
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 50) frame:SetPoint("CENTER", UIParent, "CENTER", 0, 50)
MTH_CHRON_Trace("CreateAnchor default point=" .. MTH_CHRON_DescribePoint(frame))
end end
frame:SetScript("OnDragStart", function() frame:SetScript("OnDragStart", function()
if not this or not this.StartMoving then if not this or not this.StartMoving then
return return
end end
MTH_CHRON_Trace("anchor drag-start point=" .. MTH_CHRON_DescribePoint(this))
this:StartMoving() this:StartMoving()
end) end)
frame:SetScript("OnDragStop", function() 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.relativePoint = point or "TOPLEFT"
this.owner.profile.barposition.x = x this.owner.profile.barposition.x = x
this.owner.profile.barposition.y = y 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
end) end)
@@ -1305,9 +1266,11 @@ function Chronometer:SPELL_FADE(event, info)
if not self.profile.fadeonfade then return end if not self.profile.fadeonfade then return end
if info.skill == BS["Banish"] then return end if info.skill == BS["Banish"] then return end
if info.type == "fade" then 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 if info.victim == ParserLib_SELF then
return self:KillBar(info.skill) return self:KillBar(info.skill)
end end
if info.source and info.source ~= ParserLib_SELF then return end
return self:KillBar(info.skill, info.victim) return self:KillBar(info.skill, info.victim)
end end
end end
@@ -1315,8 +1278,20 @@ end
function Chronometer:SPELL_PERIODIC(event, info) function Chronometer:SPELL_PERIODIC(event, info)
local aura, rank, unit, isgain local aura, rank, unit, isgain
-- 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 if info.type == "buff" then
isgain = 1 isgain = 1
-- Buff gained by someone other than self with no source confirmation → another player's proc
if not sourceIsConfirmedSelf and info.victim ~= nil and info.victim ~= ParserLib_SELF then
return
end
elseif info.type == "debuff" then elseif info.type == "debuff" then
isgain = nil isgain = nil
elseif not info.isDOT then elseif not info.isDOT then
@@ -1344,7 +1319,27 @@ function Chronometer:SPELL_PERIODIC(event, info)
if timer.k.t then if timer.k.t then
if not unit then unit = UnitName("player") end if not unit then unit = UnitName("player") end
if timer.k.s then if timer.k.s then
if timer.t and timer.t ~= unit then return end -- Selforselect: four-tier confirmation.
-- 1. Confirmed cast record (timer.t set by CastSpell hook): require target match.
-- 2. Confirmed self source (SELF_BUFFS / SELF_DAMAGE events, source == SELF): accept.
-- 3. Cast-window confirmed (timer.v fresh, timer.t nil): untargeted spells like traps
-- where the caster is known but the trigger victim cannot be predicted in advance.
-- Accept unconditionally — the mob that walked into the trap may not be our target.
-- 4. Source unconfirmed AND no cast record (CREATURE_BUFFS affliction messages never
-- embed a caster name): fall back to target-check. This lets non-ticking debuffs
-- (Poisonous Ammo, Enchanted Ammo, Piercing Shot…) show when applied to our current
-- target, while blocking the same debuff on a mob we are NOT targeting (i.e. another
-- player's debuff on a different dummy).
if timer.t then
if timer.t ~= unit then return end
elseif sourceIsConfirmedSelf then
-- source confirmed → accept unconditionally
elseif timer.v and timer.v > GetTime() then
-- cast-window confirmed, timer.t nil → untargeted cast (e.g. trap placed on ground)
-- victim unknown at cast time; accept whatever mob triggered it
elseif not UnitExists("target") or unit ~= UnitName("target") then
return
end
else else
if not UnitExists("target") or unit ~= UnitName("target") then return end if not UnitExists("target") or unit ~= UnitName("target") then return end
end end
+1 -19
View File
@@ -1,28 +1,15 @@
local MTH_ChronometerModule = { local MTH_ChronometerModule = {
name = "chronometer", name = "chronometer",
enabled = true, enabled = true,
version = "1.3.0", version = "1.4.1",
events = {}, events = {},
initialized = false, 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) local function MTH_CHRON_ApplyRuntimeEnabledState(enabled)
MTH_CHRON_ModuleTrace("module apply runtime enabled=" .. tostring(enabled and true or false))
if not MTH_ChronometerHunter then if not MTH_ChronometerHunter then
MTH_CHRON_ModuleTrace("module apply runtime skipped (engine unavailable)")
return return
end end
if enabled then if enabled then
@@ -37,18 +24,14 @@ local function MTH_CHRON_ApplyRuntimeEnabledState(enabled)
end end
function MTH_ChronometerModule:init() 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 if MTH_ChronometerHunter and MTH_ChronometerHunter.MTH_Initialize then
MTH_ChronometerHunter:MTH_Initialize() MTH_ChronometerHunter:MTH_Initialize()
end end
MTH_CHRON_ApplyRuntimeEnabledState(self.enabled and true or false) MTH_CHRON_ApplyRuntimeEnabledState(self.enabled and true or false)
self.initialized = true self.initialized = true
MTH_CHRON_ModuleTrace("module init end initialized=true")
end end
function MTH_ChronometerModule:setEnabled(enabled) 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 if not self.initialized then
self:init() self:init()
end end
@@ -56,7 +39,6 @@ function MTH_ChronometerModule:setEnabled(enabled)
end end
function MTH_ChronometerModule:cleanup() function MTH_ChronometerModule:cleanup()
MTH_CHRON_ModuleTrace("module cleanup")
if MTH_ChronometerHunter and MTH_ChronometerHunter.MTH_Disable then if MTH_ChronometerHunter and MTH_ChronometerHunter.MTH_Disable then
MTH_ChronometerHunter:MTH_Disable() MTH_ChronometerHunter:MTH_Disable()
end 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_RealmPlayer = nil;
FOM_LastPetName = nil; FOM_LastPetName = nil;
FOM_LastFeedAttempt = nil; FOM_LastFeedAttempt = nil;
FOM_TRACE_ENABLED = false;
local FOM_CORE_ATTEMPT_TRACKING_ENABLED = true; 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_AT = 0;
local FOM_LAST_SETUP_PET = nil; local FOM_LAST_SETUP_PET = nil;
local FOM_LAST_QUEST_SCAN_AT = 0; local FOM_LAST_QUEST_SCAN_AT = 0;
@@ -125,82 +120,10 @@ FOM_FamilyToLegacyMap = {
["Wolves"] = WOLF, ["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() local function FOM_GetServerProfile()
return FOM_ServerProfiles[FOM_SERVER_PROFILE] or {}; return FOM_ServerProfiles[FOM_SERVER_PROFILE] or {};
@@ -291,9 +214,6 @@ local function FOM_RegisterNoBuffQuarantine(itemID, petInfo)
end end
row.lastObservedAt = time and time() or 0; row.lastObservedAt = time and time() or 0;
row.reason = "no-buff"; row.reason = "no-buff";
FOM_Trace("quarantine add family='" .. tostring(familyKey)
.. "' itemId=" .. tostring(numericItem)
.. " minRejectPetLevel=" .. tostring(row.minRejectPetLevel));
end end
local function FOM_IsQuarantined(itemID, petLevel, familyKey) local function FOM_IsQuarantined(itemID, petLevel, familyKey)
@@ -349,29 +269,6 @@ local function FOM_IsItemPetLevelCompatible(itemID, petLevel)
return true; return true;
end 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() local function FOM_CoreFeedReady()
if (not FOM_CORE_ATTEMPT_TRACKING_ENABLED) then if (not FOM_CORE_ATTEMPT_TRACKING_ENABLED) then
@@ -457,7 +354,7 @@ function FOM_BuildFamilyAliasMap()
FOM_AddFamilyAlias("Carrion Bird", "Carrion Birds"); FOM_AddFamilyAlias("Carrion Bird", "Carrion Birds");
FOM_AddFamilyAlias("Wind Serpent", "Wind Serpents"); FOM_AddFamilyAlias("Wind Serpent", "Wind Serpents");
FOM_AddFamilyAlias("Serpent", "Serpents (Cobra)"); FOM_AddFamilyAlias("Serpent", "Serpents");
end end
function FOM_GetCanonicalPetFamily(rawFamily) function FOM_GetCanonicalPetFamily(rawFamily)
@@ -642,7 +539,6 @@ local function FOM_PruneUnknownFoodNoise(force)
if (type(time) == "function") then if (type(time) == "function") then
store.updatedAt = time(); store.updatedAt = time();
end end
FOM_Trace("pruned unknown vendor-only non-food rows=" .. tostring(removed));
end end
return removed; return removed;
@@ -688,7 +584,6 @@ local function FOM_PruneExceptionNoise()
if (removed > 0 and store ~= nil and type(time) == "function") then if (removed > 0 and store ~= nil and type(time) == "function") then
store.updatedAt = time(); store.updatedAt = time();
FOM_Trace("pruned inert exception rows=" .. tostring(removed));
end end
return removed; return removed;
end end
@@ -827,10 +722,6 @@ function FOM_OnLoad()
SLASH_FEEDOMATIC3 = "/feed"; SLASH_FEEDOMATIC3 = "/feed";
SLASH_FEEDOMATIC4 = "/petfeed"; -- Rauen's PetFeed compatibility SLASH_FEEDOMATIC4 = "/petfeed"; -- Rauen's PetFeed compatibility
SLASH_FEEDOMATIC5 = "/pf"; SLASH_FEEDOMATIC5 = "/pf";
SLASH_FOMTRACE1 = "/fomtrace";
SlashCmdList["FOMTRACE"] = function(msg)
FOM_CommandTrace(msg);
end
SlashCmdList["FEEDOMATIC"] = function(msg) SlashCmdList["FEEDOMATIC"] = function(msg)
if MTH_IsModuleEnabled and not MTH_IsModuleEnabled("feedomatic", false) then if MTH_IsModuleEnabled and not MTH_IsModuleEnabled("feedomatic", false) then
if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
@@ -1035,7 +926,7 @@ function FOM_OnEvent(event, arg1)
end end
if (foodID) then if (foodID) then
FOM_LastFood = GFWUtils.ItemLink(foodID); FOM_LastFood = GFWUtils.ItemLink(foodID);
GFWUtils.DebugLog("Manually fed "..FOM_LastFood); FOM_DebugLog("Manually fed "..FOM_LastFood);
end end
end end
return; return;
@@ -1075,8 +966,6 @@ function FOM_OnEvent(event, arg1)
elseif ( event == "UI_ERROR_MESSAGE" ) then elseif ( event == "UI_ERROR_MESSAGE" ) then
local lowerError = string.lower(tostring(arg1 or "")); local lowerError = string.lower(tostring(arg1 or ""));
if (FOM_LastFood) then if (FOM_LastFood) then
FOM_Trace("ui error while feeding message='" .. tostring(arg1 or "")
.. "' lower='" .. tostring(lowerError) .. "'")
end end
local isLowLevelError = (arg1 and SPELL_FAILED_FOOD_LOWLEVEL and string.find(arg1, SPELL_FAILED_FOOD_LOWLEVEL)) local isLowLevelError = (arg1 and SPELL_FAILED_FOOD_LOWLEVEL and string.find(arg1, SPELL_FAILED_FOOD_LOWLEVEL))
or string.find(lowerError, "low level") 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, "wrong pet food")
or string.find(lowerError, "doesn't like") or string.find(lowerError, "doesn't like")
or string.find(lowerError, "does not 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 if (isLowLevelError) then
FOM_Trace("reject reason=low-level")
if (type(FOM_LastFeedAttempt) == "table") then if (type(FOM_LastFeedAttempt) == "table") then
FOM_CoreRecordReject(FOM_LastFeedAttempt.coreAttemptId, "low-level", arg1); FOM_CoreRecordReject(FOM_LastFeedAttempt.coreAttemptId, "low-level", arg1);
FOM_CoreFinalizeAttempt(FOM_LastFeedAttempt.coreAttemptId, "rejected", "low-level"); FOM_CoreFinalizeAttempt(FOM_LastFeedAttempt.coreAttemptId, "rejected", "low-level");
@@ -1110,7 +994,6 @@ function FOM_OnEvent(event, arg1)
end end
elseif (isWrongFoodError) then elseif (isWrongFoodError) then
FOM_Trace("reject reason=wrong-food")
if (type(FOM_LastFeedAttempt) == "table") then if (type(FOM_LastFeedAttempt) == "table") then
FOM_CoreRecordReject(FOM_LastFeedAttempt.coreAttemptId, "wrong-food", arg1); FOM_CoreRecordReject(FOM_LastFeedAttempt.coreAttemptId, "wrong-food", arg1);
FOM_CoreFinalizeAttempt(FOM_LastFeedAttempt.coreAttemptId, "rejected", "wrong-food"); FOM_CoreFinalizeAttempt(FOM_LastFeedAttempt.coreAttemptId, "rejected", "wrong-food");
@@ -1119,9 +1002,6 @@ function FOM_OnEvent(event, arg1)
if (FOM_LastFood) then if (FOM_LastFood) then
local alertPetName = MTH_FOM_GetTrackedPetName() or "Your pet"; local alertPetName = MTH_FOM_GetTrackedPetName() or "Your pet";
local itemID = FOM_IDFromLink(FOM_LastFood); 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 if ( FOM_Config.Alert == "chat") then
GFWUtils.Print(string.format(FOM_FEEDING_EAT_ANOTHER, alertPetName)); GFWUtils.Print(string.format(FOM_FEEDING_EAT_ANOTHER, alertPetName));
@@ -1281,10 +1161,6 @@ function FOM_OnUpdate(elapsed)
local elapsedSinceFeed = now - startedAt; local elapsedSinceFeed = now - startedAt;
if (elapsedSinceFeed >= 0.10 and not FOM_LastFeedAttempt.loggedFirstCheck) then if (elapsedSinceFeed >= 0.10 and not FOM_LastFeedAttempt.loggedFirstCheck) then
FOM_LastFeedAttempt.loggedFirstCheck = true; 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 end
if (FOM_HasFeedEffect()) then if (FOM_HasFeedEffect()) then
@@ -1300,9 +1176,6 @@ function FOM_OnUpdate(elapsed)
SendChatMessage(string.format(FOM_FEEDING_FEED, confirmedPetName, confirmedFoodLink).. FOM_RandomEmote(), "EMOTE"); SendChatMessage(string.format(FOM_FEEDING_FEED, confirmedPetName, confirmedFoodLink).. FOM_RandomEmote(), "EMOTE");
end end
FOM_CoreFinalizeAttempt(FOM_LastFeedAttempt.coreAttemptId, "accepted", "accepted"); 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_LastFeedAttempt = nil;
FOM_LastFood = nil; FOM_LastFood = nil;
elseif (elapsedSinceFeed >= 2.50) then elseif (elapsedSinceFeed >= 2.50) then
@@ -1320,10 +1193,6 @@ function FOM_OnUpdate(elapsed)
tonumber(currentPetInfo and currentPetInfo.level) or nil, tonumber(currentPetInfo and currentPetInfo.level) or nil,
"no-buff"); "no-buff");
end 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_LastFood = nil;
FOM_LastFeedAttempt = nil; FOM_LastFeedAttempt = nil;
@@ -1350,8 +1219,6 @@ function FOM_OnUpdate(elapsed)
excludedCount = excludedCount + 1; excludedCount = excludedCount + 1;
end end
end end
FOM_Trace("feed retry scheduled after no-buff retry=" .. tostring(retryCount + 1)
.. " excludedCount=" .. tostring(excludedCount));
FOM_Feed(nil, { FOM_Feed(nil, {
retryCount = retryCount + 1, retryCount = retryCount + 1,
excludedItemIds = excludedItemIds, excludedItemIds = excludedItemIds,
@@ -1378,31 +1245,31 @@ end
function FOM_CanFeed() function FOM_CanFeed()
local petInfo = MTH_FOM_GetCorePetInfo(); local petInfo = MTH_FOM_GetCorePetInfo();
if ( not (petInfo and petInfo.liveExists) ) then if ( not (petInfo and petInfo.liveExists) ) then
GFWUtils.DebugLog("Can't feed; pet doesn't exist."); FOM_DebugLog("Can't feed; pet doesn't exist.");
return false; return false;
end end
if ( tonumber(petInfo.health) and tonumber(petInfo.health) <= 0 ) then if ( tonumber(petInfo.health) and tonumber(petInfo.health) <= 0 ) then
GFWUtils.DebugLog("Can't feed; pet is dead."); FOM_DebugLog("Can't feed; pet is dead.");
return false; return false;
end end
if ( UnitHealth("player") <= 0 ) then if ( UnitHealth("player") <= 0 ) then
GFWUtils.DebugLog("Can't feed; I'm dead."); FOM_DebugLog("Can't feed; I'm dead.");
return false; return false;
end end
if ( CastingBarFrameStatusBar:IsVisible() ) then if ( CastingBarFrameStatusBar:IsVisible() ) then
GFWUtils.DebugLog("Can't feed; casting a spell / tradeksill."); FOM_DebugLog("Can't feed; casting a spell / tradeksill.");
return false; return false;
end end
if ( UnitOnTaxi("player") ) then if ( UnitOnTaxi("player") ) then
GFWUtils.DebugLog("Can't feed; flying."); FOM_DebugLog("Can't feed; flying.");
return false; return false;
end end
if ( FOM_State.InCombat ) or ( PlayerFrame.inCombat ) then if ( FOM_State.InCombat ) or ( PlayerFrame.inCombat ) then
GFWUtils.DebugLog("Can't feed; in combat."); FOM_DebugLog("Can't feed; in combat.");
return false; return false;
end end
if ( LootFrame:IsVisible() ) then if ( LootFrame:IsVisible() ) then
GFWUtils.DebugLog("Shouldn't feed; loot window is open."); FOM_DebugLog("Shouldn't feed; loot window is open.");
return false; return false;
end end
@@ -1423,7 +1290,7 @@ function FOM_CanFeed()
if ( buff ~= nil) then if ( buff ~= nil) then
for _, buffTexture in dontFeedBuffTextures do for _, buffTexture in dontFeedBuffTextures do
if ( buff == buffTexture ) then if ( buff == buffTexture ) then
GFWUtils.DebugLog("Can't feed; currently, eating, drinking, or feigning death."); FOM_DebugLog("Can't feed; currently, eating, drinking, or feigning death.");
return false; return false;
end end
end end
@@ -1436,7 +1303,7 @@ function FOM_CanFeed()
msg = string.lower(msg); msg = string.lower(msg);
for _, mountName in FOM_MOUNT_NAME_SUBSTRINGS do for _, mountName in FOM_MOUNT_NAME_SUBSTRINGS do
if (string.find(msg, mountName)) then if (string.find(msg, mountName)) then
GFWUtils.DebugLog("Can't feed; mounted."); FOM_DebugLog("Can't feed; mounted.");
return false; return false;
end end
end end
@@ -1989,13 +1856,13 @@ end
function FOM_AddFood(diet, food) function FOM_AddFood(diet, food)
if (FOM_Foods[diet] == nil) then if (FOM_Foods[diet] == nil) then
GFWUtils.DebugLog("FOM_Foods[diet] == nil"); FOM_DebugLog("FOM_Foods[diet] == nil");
end end
if (FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil) then if (FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil) then
GFWUtils.DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil"); FOM_DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil");
end end
if (FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil) then if (FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil) then
GFWUtils.DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil"); FOM_DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil");
end end
if ( GFWTable.IndexOf(FOM_Foods[diet], food) == 0 ) then if ( GFWTable.IndexOf(FOM_Foods[diet], food) == 0 ) then
if (FOM_AddedFoods == nil) then if (FOM_AddedFoods == nil) then
@@ -2031,13 +1898,13 @@ end
function FOM_RemoveFood(diet, food) function FOM_RemoveFood(diet, food)
if (FOM_Foods[diet] == nil) then if (FOM_Foods[diet] == nil) then
GFWUtils.DebugLog("FOM_Foods[diet] == nil"); FOM_DebugLog("FOM_Foods[diet] == nil");
end end
if (FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil) then if (FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil) then
GFWUtils.DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil"); FOM_DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil");
end end
if (FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil) then if (FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil) then
GFWUtils.DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil"); FOM_DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil");
end end
if ( GFWTable.IndexOf(FOM_Foods[diet], food) ~= 0 ) then if ( GFWTable.IndexOf(FOM_Foods[diet], food) ~= 0 ) then
if (FOM_RemovedFoods == nil) then if (FOM_RemovedFoods == nil) then
@@ -2333,7 +2200,6 @@ local function FOM_TryPickSinglePrecomputedFood(foodList, excludedItemIds, allow
end end
function FOM_Feed(aFood, options) function FOM_Feed(aFood, options)
local feedStartMs = FOM_PerfNowMs();
options = options or {}; options = options or {};
local retryCount = tonumber(options.retryCount) or 0; local retryCount = tonumber(options.retryCount) or 0;
local excludedItemIds = FOM_CloneSet(options.excludedItemIds); 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 MTH_IsModuleEnabled and not MTH_IsModuleEnabled("feedomatic", false) then
if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
MTH:Print("[FOM WRAP] FOM_Feed blocked: module disabled", "debug")
end end
return false; return false;
end end
@@ -2368,19 +2233,9 @@ function FOM_Feed(aFood, options)
-- Assign Variable -- Assign Variable
local pet = (MTH_FOM_IsValidPetName(petInfo.name) and petInfo.name) or "Your pet"; 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_CheckSetup();
FOM_PerfRecord("FOM_CheckSetup", FOM_PerfNowMs() - checkSetupStartMs, "retry=" .. tostring(retryCount), false);
if (FOM_LastPetName == nil or FOM_LastPetName == "") then 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; return false;
end end
@@ -2404,24 +2259,18 @@ function FOM_Feed(aFood, options)
if ( foodBag == nil) then if ( foodBag == nil) then
-- No Food Could be Found -- No Food Could be Found
GFWUtils.Print(string.format(FOM_ERROR_FOOD_NOT_FOUND, pet, aFood)); 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; return false;
end end
FOM_LastChoiceReason = "manual selection"; FOM_LastChoiceReason = "manual selection";
else else
local cachedChoiceStartMs = FOM_PerfNowMs();
local cachedBag, cachedSlot, cachedItemId = FOM_GetCachedAutoChoice(excludedItemIds); local cachedBag, cachedSlot, cachedItemId = FOM_GetCachedAutoChoice(excludedItemIds);
if (cachedBag ~= nil and cachedSlot ~= nil) then if (cachedBag ~= nil and cachedSlot ~= nil) then
foodBag, foodItem = cachedBag, cachedSlot; foodBag, foodItem = cachedBag, cachedSlot;
FOM_LastChoiceReason = "cached previous food"; FOM_LastChoiceReason = "cached previous food";
FOM_PerfRecord("FOM_AutoChoice cache", FOM_PerfNowMs() - cachedChoiceStartMs,
"hit itemId=" .. tostring(cachedItemId), false);
else else
FOM_PerfRecord("FOM_AutoChoice cache", FOM_PerfNowMs() - cachedChoiceStartMs, "miss", false);
end end
if (foodBag == nil) then if (foodBag == nil) then
local precomputeStartMs = FOM_PerfNowMs();
local cacheNow = (type(GetTime) == "function") and (GetTime() or 0) or 0; local cacheNow = (type(GetTime) == "function") and (GetTime() or 0) or 0;
if (retryCount <= 0 if (retryCount <= 0
and type(FOM_FEED_SCAN_CACHE) == "table" 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 and type(FOM_FEED_SCAN_CACHE.foods) == "table") then
precomputedFoodList = FOM_CloneFoodList(FOM_FEED_SCAN_CACHE.foods); precomputedFoodList = FOM_CloneFoodList(FOM_FEED_SCAN_CACHE.foods);
openSlots = tonumber(FOM_FEED_SCAN_CACHE.openSlots) or 0; 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 else
precomputedFoodList = FOM_FlatFoodList(); precomputedFoodList = FOM_FlatFoodList();
openSlots = FOM_NumOpenBagSlots(); openSlots = FOM_NumOpenBagSlots();
@@ -2440,32 +2287,23 @@ function FOM_Feed(aFood, options)
foods = FOM_CloneFoodList(precomputedFoodList), foods = FOM_CloneFoodList(precomputedFoodList),
openSlots = openSlots, openSlots = openSlots,
}; };
FOM_PerfRecord("FOM_Feed precompute", FOM_PerfNowMs() - precomputeStartMs,
"cache-miss foods=" .. tostring(table.getn(precomputedFoodList)) .. " openSlots=" .. tostring(openSlots), false);
end end
local fastPickStartMs = FOM_PerfNowMs();
foodBag, foodItem = FOM_TryPickSinglePrecomputedFood(precomputedFoodList, excludedItemIds, (FOM_Config.AvoidUsefulFood and false or true)); foodBag, foodItem = FOM_TryPickSinglePrecomputedFood(precomputedFoodList, excludedItemIds, (FOM_Config.AvoidUsefulFood and false or true));
if (foodBag ~= nil) then if (foodBag ~= nil) then
FOM_LastChoiceReason = "single candidate fast-path"; FOM_LastChoiceReason = "single candidate fast-path";
FOM_PerfRecord("FOM_SingleCandidate", FOM_PerfNowMs() - fastPickStartMs, "hit", false);
else else
FOM_PerfRecord("FOM_SingleCandidate", FOM_PerfNowMs() - fastPickStartMs, "miss", false);
end end
if (foodBag == nil) then if (foodBag == nil) then
local findStartMs = FOM_PerfNowMs();
foodBag, foodItem = FOM_NewFindFood(nil, excludedItemIds, precomputedFoodList, openSlots); foodBag, foodItem = FOM_NewFindFood(nil, excludedItemIds, precomputedFoodList, openSlots);
FOM_PerfRecord("FOM_NewFindFood primary", FOM_PerfNowMs() - findStartMs, "found=" .. tostring(foodBag ~= nil), false);
end end
end end
end end
local fallbackBag, fallbackItem = nil, nil; local fallbackBag, fallbackItem = nil, nil;
if (not manualFood and foodBag == nil and FOM_Config.Fallback) then if (not manualFood and foodBag == nil and FOM_Config.Fallback) then
local fallbackStartMs = FOM_PerfNowMs();
fallbackBag, fallbackItem = FOM_NewFindFood(1, excludedItemIds, precomputedFoodList, openSlots); fallbackBag, fallbackItem = FOM_NewFindFood(1, excludedItemIds, precomputedFoodList, openSlots);
FOM_PerfRecord("FOM_NewFindFood fallback", FOM_PerfNowMs() - fallbackStartMs, "found=" .. tostring(fallbackBag ~= nil), false);
end end
if ( foodBag == nil) then if ( foodBag == nil) then
@@ -2480,12 +2318,10 @@ function FOM_Feed(aFood, options)
-- No Food Could be Found -- No Food Could be Found
GFWUtils.Print(string.format(FOM_ERROR_NO_FOOD, pet)); GFWUtils.Print(string.format(FOM_ERROR_NO_FOOD, pet));
FOM_LastChoiceReason = nil; FOM_LastChoiceReason = nil;
FOM_PerfRecord("FOM_Feed total", FOM_PerfNowMs() - feedStartMs, "result=no-food", true);
return false; return false;
end end
end end
local prepareStartMs = FOM_PerfNowMs();
FOM_LastFood = GetContainerItemLink(foodBag, foodItem); FOM_LastFood = GetContainerItemLink(foodBag, foodItem);
local selectedId = FOM_IDFromLink(FOM_LastFood) local selectedId = FOM_IDFromLink(FOM_LastFood)
FOM_SetCachedAutoChoice(foodBag, foodItem, selectedId) FOM_SetCachedAutoChoice(foodBag, foodItem, selectedId)
@@ -2504,26 +2340,15 @@ function FOM_Feed(aFood, options)
petLevel = tonumber(petInfo and petInfo.level) or nil, petLevel = tonumber(petInfo and petInfo.level) or nil,
foodLevel = selectedFoodLevel, 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 if (FOM_Config.Debug) then
-- don't actually feed anything, just show what we would choose -- don't actually feed anything, just show what we would choose
FOM_PerfRecord("FOM_Feed total", FOM_PerfNowMs() - feedStartMs, "result=debug", true);
return false; return false;
end end
-- Actually feed the item to the pet -- Actually feed the item to the pet
local dropStartMs = FOM_PerfNowMs();
PickupContainerItem(foodBag, foodItem); PickupContainerItem(foodBag, foodItem);
FOM_Trace("feed execute pickup bag=" .. tostring(foodBag)
.. " slot=" .. tostring(foodItem)
.. " cursorHasItem=" .. tostring(CursorHasItem() and true or false))
if ( CursorHasItem() ) then if ( CursorHasItem() ) then
MTH_FEED_SuppressChatUntil = (GetTime() or 0) + 2.0; MTH_FEED_SuppressChatUntil = (GetTime() or 0) + 2.0;
MTH_FEED_SuppressChatFoodName = FOM_NameFromLink(FOM_LastFood); MTH_FEED_SuppressChatFoodName = FOM_NameFromLink(FOM_LastFood);
@@ -2531,26 +2356,19 @@ function FOM_Feed(aFood, options)
local ok = pcall(DropItemOnUnit, "pet"); local ok = pcall(DropItemOnUnit, "pet");
MTH_FEED_SuppressCoreDropHook = nil; MTH_FEED_SuppressCoreDropHook = nil;
if (not ok) then if (not ok) then
FOM_Trace("feed execute drop on pet failed during protected call");
end end
FOM_Trace("feed execute drop on pet cursorHasItemAfterDrop=" .. tostring(CursorHasItem() and true or false))
end 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 if (coreAttemptId and type(MTH_FEED_RecordClientDropResult) == "function") then
pcall(MTH_FEED_RecordClientDropResult, coreAttemptId, { pcall(MTH_FEED_RecordClientDropResult, coreAttemptId, {
consumedFromCursor = (CursorHasItem() and false or true), consumedFromCursor = (CursorHasItem() and false or true),
}) })
end end
if ( CursorHasItem() ) then if ( CursorHasItem() ) then
FOM_Trace("feed execute immediate-fail item stayed on cursor; likely rejected before combat log/error parse")
PickupContainerItem(foodBag, foodItem); PickupContainerItem(foodBag, foodItem);
FOM_CoreRecordReject(coreAttemptId, "client-drop-fail", nil); FOM_CoreRecordReject(coreAttemptId, "client-drop-fail", nil);
FOM_CoreFinalizeAttempt(coreAttemptId, "rejected", "client-drop-fail"); 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; return false;
else else
FOM_Trace("feed execute accepted by client (item consumed from cursor)")
if (selectedId ~= nil) then if (selectedId ~= nil) then
excludedItemIds[selectedId] = true; excludedItemIds[selectedId] = true;
end end
@@ -2568,10 +2386,6 @@ function FOM_Feed(aFood, options)
loggedFirstCheck = false, loggedFirstCheck = false,
} }
FOM_State.ShouldFeed = nil; 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; return true;
end end
end end
@@ -2656,7 +2470,6 @@ local function FOM_EnsureQuestScanFresh(maxAgeSeconds)
end end
function FOM_FlatFoodList() function FOM_FlatFoodList()
local flatStartMs = FOM_PerfNowMs();
local foodList = {}; local foodList = {};
local overflowFoodList = {}; local overflowFoodList = {};
local scanned = 0; local scanned = 0;
@@ -2746,27 +2559,10 @@ function FOM_FlatFoodList()
if (table.getn(foodList) == 0 and table.getn(overflowFoodList) > 0) then if (table.getn(foodList) == 0 and table.getn(overflowFoodList) > 0) then
foodList = overflowFoodList; foodList = overflowFoodList;
end 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; return foodList;
end end
function FOM_NewFindFood(fallback, excludedItemIds, precomputedFoodList, openSlotsOverride) function FOM_NewFindFood(fallback, excludedItemIds, precomputedFoodList, openSlotsOverride)
local findStartMs = FOM_PerfNowMs();
local FlatFoodList = nil; local FlatFoodList = nil;
if (type(precomputedFoodList) == "table") then if (type(precomputedFoodList) == "table") then
FlatFoodList = FOM_CloneFoodList(precomputedFoodList); FlatFoodList = FOM_CloneFoodList(precomputedFoodList);
@@ -2777,12 +2573,6 @@ function FOM_NewFindFood(fallback, excludedItemIds, precomputedFoodList, openSlo
local reasonParts = {}; local reasonParts = {};
if (initialCount <= 0) then if (initialCount <= 0) then
FOM_LastChoiceReason = nil; 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; return nil;
end end
local petInfo = MTH_FOM_GetCorePetInfo(); local petInfo = MTH_FOM_GetCorePetInfo();
@@ -2869,18 +2659,6 @@ function FOM_NewFindFood(fallback, excludedItemIds, precomputedFoodList, openSlo
table.insert(reasonParts, "fallback allows useful food"); table.insert(reasonParts, "fallback allows useful food");
end end
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 for _, foodInfo in FlatFoodList do
if (foodInfo.overflow) then if (foodInfo.overflow) then
@@ -2894,15 +2672,9 @@ function FOM_NewFindFood(fallback, excludedItemIds, precomputedFoodList, openSlo
else else
FOM_LastChoiceReason = nil; FOM_LastChoiceReason = nil;
end 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; return foodInfo.bag, foodInfo.slot;
end end
FOM_LastChoiceReason = nil; FOM_LastChoiceReason = nil;
FOM_Trace("find food result: none")
return nil; return nil;
end end
@@ -2936,12 +2708,12 @@ end
function FOM_IsUsefulFood(itemID, quantity) function FOM_IsUsefulFood(itemID, quantity)
local foodName = GetItemInfo(itemID); local foodName = GetItemInfo(itemID);
if (foodName == nil) then if (foodName == nil) then
GFWUtils.DebugLog("Can't get info for item ID "..itemID..", assuming it's OK to eat."); FOM_DebugLog("Can't get info for item ID "..itemID..", assuming it's OK to eat.");
return false; return false;
end end
if (FOM_Cooking and FOM_Cooking[FOM_RealmPlayer] and FOM_Cooking[FOM_RealmPlayer][itemID]) then if (FOM_Cooking and FOM_Cooking[FOM_RealmPlayer] and FOM_Cooking[FOM_RealmPlayer][itemID]) then
if (FOM_Cooking[FOM_RealmPlayer][itemID] >= FOM_Config.SaveForCookingLevel) then if (FOM_Cooking[FOM_RealmPlayer][itemID] >= FOM_Config.SaveForCookingLevel) then
GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; is good for cooking."); FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; is good for cooking.");
return true; return true;
end end
end end
@@ -2953,19 +2725,19 @@ function FOM_IsUsefulFood(itemID, quantity)
FOM_Quantity[foodName] = FOM_Quantity[foodName] + quantity; FOM_Quantity[foodName] = FOM_Quantity[foodName] + quantity;
end end
if (FOM_Quantity[foodName] > FOM_QuestFood[FOM_RealmPlayer][foodName]) then if (FOM_Quantity[foodName] > FOM_QuestFood[FOM_RealmPlayer][foodName]) then
GFWUtils.DebugLog("Not skipping "..quantity.."x "..foodName.."; is needed for quest, but we have more than enough."); FOM_DebugLog("Not skipping "..quantity.."x "..foodName.."; is needed for quest, but we have more than enough.");
return false; return false;
else else
GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; is needed for quest."); FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; is needed for quest.");
return true; return true;
end end
end end
end end
if (FOM_Config.AvoidBonusFood and FOM_IsInDiet(itemID, FOM_DIET_BONUS)) then if (FOM_Config.AvoidBonusFood and FOM_IsInDiet(itemID, FOM_DIET_BONUS)) then
GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; has bonus effect when eaten by player."); FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; has bonus effect when eaten by player.");
return true; return true;
end end
--GFWUtils.DebugLog("Not skipping "..quantity.."x "..foodName.."; doesn't have other uses."); --FOM_DebugLog("Not skipping "..quantity.."x "..foodName.."; doesn't have other uses.");
return false; return false;
end end
@@ -3003,7 +2775,7 @@ function FOM_IsInDiet(food, dietList)
diet = ""; diet = "";
end end
if (FOM_Foods[diet] == nil) then if (FOM_Foods[diet] == nil) then
GFWUtils.DebugLog("FOM_Foods[diet] == nil"); FOM_DebugLog("FOM_Foods[diet] == nil");
end end
if (FOM_RemovedFoods ~= nil and FOM_RemovedFoods[diet] ~= nil and GFWTable.IndexOf(FOM_RemovedFoods[diet], food) ~= 0) then if (FOM_RemovedFoods ~= nil and FOM_RemovedFoods[diet] ~= nil and GFWTable.IndexOf(FOM_RemovedFoods[diet], food) ~= 0) then
return false; return false;
+1 -1
View File
@@ -80,7 +80,7 @@ FOM_Emotes = {
["Foxes"] = { ["Foxes"] = {
"Clever fox, clever snack choice.", "Clever fox, clever snack choice.",
}, },
["Serpents (Cobra)"] = { ["Serpents"] = {
"No hissing with your mouth full.", "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(); GFWUtils.PrintOnceCache[message] = GetTime();
end 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 -- Prints a message in yellow to the floating messages frame
function GFWUtils_temp_Note(message) function GFWUtils_temp_Note(message)
@@ -177,8 +167,6 @@ if (G.Version == nil or (tonumber(G.Version) ~= nil and G.Version < GFWUTILS_THI
-- Constants -- Constants
GFW_FONT_COLOR = {r=0.25, g=1.0, b=1.0}; 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 -- Functions
G.Hilite = GFWUtils_temp_HiliteText; 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.LtY = GFWUtils_temp_LightYellowText;
G.Print = GFWUtils_temp_Print; G.Print = GFWUtils_temp_Print;
G.PrintOnce = GFWUtils_temp_PrintOnce; G.PrintOnce = GFWUtils_temp_PrintOnce;
G.DebugLog = GFWUtils_temp_DebugLog;
G.Note = GFWUtils_temp_Note; G.Note = GFWUtils_temp_Note;
G.FormatToPattern = GFWUtils_temp_FormatToPattern; G.FormatToPattern = GFWUtils_temp_FormatToPattern;
G.Split = GFWUtils_temp_Split; G.Split = GFWUtils_temp_Split;
+2 -12
View File
@@ -6,7 +6,7 @@
local MTH_FeedOMatic = { local MTH_FeedOMatic = {
name = "feedomatic", name = "feedomatic",
enabled = false, enabled = false,
version = "1.3.0", version = "1.4.1",
events = { events = {
"VARIABLES_LOADED", "VARIABLES_LOADED",
"MERCHANT_SHOW", "MERCHANT_SHOW",
@@ -112,10 +112,6 @@ local function MTH_FeedOMatic_CallLegacyOnEvent(evt, a1, a2, a3, a4, a5, a6, a7,
event = oldEvent event = oldEvent
arg1, arg2, arg3, arg4, arg5 = oldArg1, oldArg2, oldArg3, oldArg4, oldArg5 arg1, arg2, arg3, arg4, arg5 = oldArg1, oldArg2, oldArg3, oldArg4, oldArg5
arg6, arg7, arg8, arg9 = oldArg6, oldArg7, oldArg8, oldArg9 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 end
local function MTH_FeedOMatic_EnsureVariablesLoaded(module) local function MTH_FeedOMatic_EnsureVariablesLoaded(module)
@@ -166,8 +162,7 @@ end
local function MTH_FeedOMatic_Log(message, severity) local function MTH_FeedOMatic_Log(message, severity)
if type(MTH_Log) == "function" then if type(MTH_Log) == "function" then
local logSeverity = severity or "debug" MTH_Log("[FeedOMatic] " .. tostring(message or ""), severity)
MTH_Log("[FeedOMatic] " .. tostring(message or ""), logSeverity)
end end
end end
@@ -198,10 +193,8 @@ local function MTH_FeedOMatic_DebugMerchantScan(sourceEvent)
if type(rows) == "table" then if type(rows) == "table" then
dietCount = table.getn(rows) dietCount = table.getn(rows)
end end
MTH_FeedOMatic_Log("diet " .. tostring(dietName) .. ": " .. tostring(dietCount) .. " item(s)", "debug")
if type(rows) == "table" then if type(rows) == "table" then
for _, row in rows do for _, row in rows do
MTH_FeedOMatic_Log(" - [" .. tostring(row.id) .. "] " .. tostring(row.name) .. " (slot=" .. tostring(row.index) .. ")", "debug")
end end
end end
end end
@@ -209,7 +202,6 @@ local function MTH_FeedOMatic_DebugMerchantScan(sourceEvent)
if unknownCount > 0 and type(merchantFoods.unknown) == "table" then if unknownCount > 0 and type(merchantFoods.unknown) == "table" then
for _, row in merchantFoods.unknown do 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 end
end end
@@ -228,7 +220,6 @@ local function MTH_FeedOMatic_SetMerchantProbeEnabled(enabled)
MTH_FOM_MerchantProbe:SetScript("OnEvent", function() MTH_FOM_MerchantProbe:SetScript("OnEvent", function()
local evt = event local evt = event
if evt == "MERCHANT_SHOW" or evt == "MERCHANT_UPDATE" then if evt == "MERCHANT_SHOW" or evt == "MERCHANT_UPDATE" then
MTH_FeedOMatic_Log("probe event received: " .. tostring(evt), "debug")
MTH_FeedOMatic_DebugMerchantScan(evt) MTH_FeedOMatic_DebugMerchantScan(evt)
end end
end) end)
@@ -236,7 +227,6 @@ local function MTH_FeedOMatic_SetMerchantProbeEnabled(enabled)
MTH_FOM_MerchantProbe:RegisterEvent("MERCHANT_SHOW") MTH_FOM_MerchantProbe:RegisterEvent("MERCHANT_SHOW")
MTH_FOM_MerchantProbe:RegisterEvent("MERCHANT_UPDATE") MTH_FOM_MerchantProbe:RegisterEvent("MERCHANT_UPDATE")
MTH_FeedOMatic_Log("merchant probe enabled", "debug")
end end
function MTH_FeedOMatic:init() function MTH_FeedOMatic:init()
+1 -1
View File
@@ -6,7 +6,7 @@
local MTH_ICU = { local MTH_ICU = {
name = "icu", name = "icu",
enabled = false, enabled = false,
version = "1.3.0", version = "1.4.1",
events = { events = {
"VARIABLES_LOADED", "VARIABLES_LOADED",
}, },
+21
View File
@@ -48,10 +48,25 @@ end
local MTHSmartAmmo_InitializeHooks local MTHSmartAmmo_InitializeHooks
MTHSmartAmmo_EnsureHooks = nil MTHSmartAmmo_EnsureHooks = nil
local MTH_SA_SPELL_EVENTS = {
"START_AUTOREPEAT_SPELL",
"STOP_AUTOREPEAT_SPELL",
"SPELLCAST_INTERRUPTED",
"SPELLCAST_FAILED",
"SPELLCAST_STOP",
"SPELLCAST_DELAYED",
}
function MTHSmartAmmo_SetSmartEnabled(enabled, silent) function MTHSmartAmmo_SetSmartEnabled(enabled, silent)
local saved = MTHSmartAmmo_GetSaved() local saved = MTHSmartAmmo_GetSaved()
if enabled then if enabled then
saved["enabled"] = 1 saved["enabled"] = 1
local evFrame = getglobal("MTH_SA_EventFrame")
if evFrame then
for _, ev in ipairs(MTH_SA_SPELL_EVENTS) do
evFrame:RegisterEvent(ev)
end
end
if MTHSmartAmmo_InitializeHooks then if MTHSmartAmmo_InitializeHooks then
MTHSmartAmmo_InitializeHooks() MTHSmartAmmo_InitializeHooks()
end end
@@ -63,6 +78,12 @@ function MTHSmartAmmo_SetSmartEnabled(enabled, silent)
end end
else else
saved["enabled"] = false saved["enabled"] = false
local evFrame = getglobal("MTH_SA_EventFrame")
if evFrame then
for _, ev in ipairs(MTH_SA_SPELL_EVENTS) do
evFrame:UnregisterEvent(ev)
end
end
if not silent and DEFAULT_CHAT_FRAME then if not silent and DEFAULT_CHAT_FRAME then
MTH_SA_Print("Smart Ammo Disabled.") MTH_SA_Print("Smart Ammo Disabled.")
end end
+1 -1
View File
@@ -7,7 +7,7 @@ MTH_SA_MANAGED_HOOKS = true
local MTH_SmartAmmo = { local MTH_SmartAmmo = {
name = "smartammo", name = "smartammo",
enabled = true, enabled = true,
version = "1.3.0", version = "1.4.1",
events = { events = {
"VARIABLES_LOADED", "VARIABLES_LOADED",
-- PLAYER_ENTERING_WORLD handled by engine's own frame -- PLAYER_ENTERING_WORLD handled by engine's own frame
+26 -9
View File
@@ -6,7 +6,7 @@
local MTH_Tooltips = { local MTH_Tooltips = {
name = "tooltips", name = "tooltips",
enabled = true, enabled = true,
version = "1.3.0", version = "1.4.1",
events = { events = {
"UPDATE_MOUSEOVER_UNIT", "UPDATE_MOUSEOVER_UNIT",
"UNIT_NAME_UPDATE", "UNIT_NAME_UPDATE",
@@ -1389,7 +1389,6 @@ local function MTH_TT_AddPetActionNotLearnedHint()
return return
end end
local ownerName = MTH_TT_GetTooltipOwnerName()
local ownerMatch = MTH_TT_IsPetActionTooltipOwner() local ownerMatch = MTH_TT_IsPetActionTooltipOwner()
local barMatch = MTH_TT_IsSpellOnPetActionBar(spellName) local barMatch = MTH_TT_IsSpellOnPetActionBar(spellName)
if not ownerMatch and not barMatch then if not ownerMatch and not barMatch then
@@ -1406,11 +1405,13 @@ local function MTH_TT_AddPetActionNotLearnedHint()
end end
local canonicalLower = MTH_TT_Lower(canonical) local canonicalLower = MTH_TT_Lower(canonical)
local known = MTH_TT_HunterKnowsAbility(canonicalLower, rankNumber) local hunterKnown = MTH_TT_HunterKnowsAbility(canonicalLower, rankNumber)
if not known then -- Only fall back to petKnown for ranked abilities: rankless abilities have no rank
known = MTH_TT_CurrentPetKnowsAbility(canonicalLower, rankNumber) -- filter in CurrentPetKnowsAbility, so they always match on name alone -> false positive.
end local petKnown = (not hunterKnown)
if known then and MTH_TT_AbilityHasPositiveRanks(canonical)
and MTH_TT_CurrentPetKnowsAbility(canonicalLower, rankNumber)
if hunterKnown or petKnown then
return return
end end
@@ -1485,8 +1486,11 @@ local function MTH_TT_AddTooltip(unit)
local ammoVendorTooltipsEnabled = MTH_TT_IsAmmoVendorTooltipsEnabled() local ammoVendorTooltipsEnabled = MTH_TT_IsAmmoVendorTooltipsEnabled()
local vendorInfo = ammoVendorTooltipsEnabled and MTH_TT_FindVendorInfo(name) or nil local vendorInfo = ammoVendorTooltipsEnabled and MTH_TT_FindVendorInfo(name) or nil
local row = beastTooltipsEnabled and MTH_TT_FindBeastRow(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) 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 state.lookupMiss = (state.lookupMiss or 0) + 1
MTH_TT_StateSet("lookup-miss", name, normalized) MTH_TT_StateSet("lookup-miss", name, normalized)
MTH_TT_Log("lookup miss: unit='" .. tostring(name) .. "' normalized='" .. tostring(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) .. "'") MTH_TT_Log("vendor tooltip added: unit='" .. tostring(name) .. "'")
end end
-- Determine which abilities source to display.
local abilitiesSource = nil
if row then 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 if table.getn(abilities) == 0 then
MTH_TT_StateSet("skip-no-abilities", name, normalized) MTH_TT_StateSet("skip-no-abilities", name, normalized)
MTH_TT_Log("skip: beast has no abilities ('" .. tostring(name) .. "')") MTH_TT_Log("skip: beast has no abilities ('" .. tostring(name) .. "')")
@@ -1534,6 +1546,11 @@ local function MTH_TT_AddTooltip(unit)
end end
end end
if savedEntry then
GameTooltip:AddLine("Beast recorded by you", 1.0, 0.85, 0.0)
addedAnything = 1
end
if addedAnything then if addedAnything then
GameTooltip:Show() GameTooltip:Show()
state.added = (state.added or 0) + 1 state.added = (state.added or 0) + 1
+1 -18
View File
@@ -37,13 +37,6 @@ local function ZHunterMod_RunButtonInit(frame, onEventFunc)
event = oldEvent event = oldEvent
end 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 function ZHunterMod_EnsureButtonFrame(buttonName)
local frame = getglobal(buttonName) local frame = getglobal(buttonName)
@@ -77,7 +70,6 @@ local function ZHunterMod_EnsureButtonFrame(buttonName)
else else
created:SetPoint("CENTER", UIParent, "CENTER", 0, 0) created:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
end end
ZHunterMod_LogDeferred("DeferredInit: created missing frame " .. tostring(buttonName))
end end
return created return created
end end
@@ -94,15 +86,6 @@ function ZHunterMod_DeferredInit()
local companions = ZHunterMod_EnsureButtonFrame("zButtonCompanions") local companions = ZHunterMod_EnsureButtonFrame("zButtonCompanions")
local toys = ZHunterMod_EnsureButtonFrame("zButtonToys") 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. -- Continue with all frames that exist; do not hard-abort when one optional frame is missing.
local missing = {} local missing = {}
@@ -202,7 +185,7 @@ function ZHunterMod_DeferredInit()
if type(MTH_ZH_OnDeferredInitComplete) == "function" then if type(MTH_ZH_OnDeferredInitComplete) == "function" then
local ok, err = pcall(MTH_ZH_OnDeferredInitComplete) 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") MTH_ZH_Print("[ZHUNTER] DeferredInit callback error: " .. tostring(err), "error")
end end
end end
+1
View File
@@ -86,6 +86,7 @@ ZHUNTER_TRACK_GIANTS = "Track Giants"
ZHUNTER_TRACK_MINERALS = "Find Minerals" ZHUNTER_TRACK_MINERALS = "Find Minerals"
ZHUNTER_TRACK_HERBS = "Find Herbs" ZHUNTER_TRACK_HERBS = "Find Herbs"
ZHUNTER_TRACK_TREASURE = "Find Treasure" ZHUNTER_TRACK_TREASURE = "Find Treasure"
ZHUNTER_TRACK_TREES = "Find Trees"
ZHUNTER_TRAP_FREEZING = "Freezing Trap" ZHUNTER_TRAP_FREEZING = "Freezing Trap"
ZHUNTER_TRAP_FROST = "Frost Trap" ZHUNTER_TRAP_FROST = "Frost Trap"
-46
View File
@@ -14,7 +14,6 @@ BINDING_HEADER_ZToysHeader = "ZToys Buttons"
ZHunterModTooltip = CreateFrame("GameTooltip", "MTH_ZH_AbilityProbe", nil, "GameTooltipTemplate") ZHunterModTooltip = CreateFrame("GameTooltip", "MTH_ZH_AbilityProbe", nil, "GameTooltipTemplate")
ZHunterModTooltipTextLeft1 = getglobal("MTH_ZH_AbilityProbeTextLeft1") ZHunterModTooltipTextLeft1 = getglobal("MTH_ZH_AbilityProbeTextLeft1")
MTH_ZH_TRACE_ENABLED = false
local function MTH_ZH_DescribePoint(frame) local function MTH_ZH_DescribePoint(frame)
if not (frame and frame.GetPoint) then if not (frame and frame.GetPoint) then
@@ -33,51 +32,8 @@ local function MTH_ZH_DescribePoint(frame)
.. " @(" .. tostring(x) .. "," .. tostring(y) .. ")" .. " @(" .. tostring(x) .. "," .. tostring(y) .. ")"
end 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() function MTH_ZH_IsModuleEnabled()
if not (MTH and MTH.IsModuleEnabled) then if not (MTH and MTH.IsModuleEnabled) then
@@ -170,7 +126,6 @@ function MTH_ZH_HandleDisabledSlash(message, tableKey, fieldKey)
end end
function ZHunterMod_AlignButtons() function ZHunterMod_AlignButtons()
MTH_ZH_TraceAllButtonPoints("AlignButtons:before")
zButtonAmmo:ClearAllPoints() zButtonAmmo:ClearAllPoints()
zButtonAmmo:SetPoint("TOP", zButtonAspect, "BOTTOM", 0, -15) zButtonAmmo:SetPoint("TOP", zButtonAspect, "BOTTOM", 0, -15)
zButtonTrack:ClearAllPoints() zButtonTrack:ClearAllPoints()
@@ -189,7 +144,6 @@ function ZHunterMod_AlignButtons()
AutoStripDisplay:ClearAllPoints() AutoStripDisplay:ClearAllPoints()
AutoStripDisplay:SetPoint("TOP", zButtonToys, "BOTTOM", 0, -10) AutoStripDisplay:SetPoint("TOP", zButtonToys, "BOTTOM", 0, -10)
end end
MTH_ZH_TraceAllButtonPoints("AlignButtons:after")
end end
function ZMarkTarget() function ZMarkTarget()
-23
View File
@@ -536,13 +536,6 @@ local function ZSpellButton_SaveParentPosition(parent)
saved["parent"]["relativePoint"] = tostring(relPoint) saved["parent"]["relativePoint"] = tostring(relPoint)
saved["parent"]["x"] = math.floor(x + 0.5) saved["parent"]["x"] = math.floor(x + 0.5)
saved["parent"]["y"] = math.floor(y + 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 end
local function ZSpellButton_RestoreParentPosition(parent) local function ZSpellButton_RestoreParentPosition(parent)
@@ -580,13 +573,6 @@ local function ZSpellButton_RestoreParentPosition(parent)
parent:ClearAllPoints() parent:ClearAllPoints()
parent:SetPoint(point, UIParent, relPoint, px, py) 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 return true
end end
@@ -697,9 +683,6 @@ function ZSpellButtonParent_OnLoad()
if this.SetScript then if this.SetScript then
this:SetScript("OnDragStart", function() this:SetScript("OnDragStart", function()
if IsAltKeyDown() then if IsAltKeyDown() then
if type(MTH_ZH_TraceButtonPoint) == "function" then
MTH_ZH_TraceButtonPoint(this, "drag-start")
end
this:StartMoving() this:StartMoving()
this.isMoving = true this.isMoving = true
end end
@@ -713,9 +696,6 @@ function ZSpellButtonParent_OnLoad()
end end
ZSpellButton_SaveParentPosition(this) ZSpellButton_SaveParentPosition(this)
this.isMoving = false this.isMoving = false
if type(MTH_ZH_TraceButtonPoint) == "function" then
MTH_ZH_TraceButtonPoint(this, "drag-stop")
end
end) end)
this:SetScript("OnMouseUp", function() this:SetScript("OnMouseUp", function()
if this and this.isMoving then if this and this.isMoving then
@@ -724,9 +704,6 @@ function ZSpellButtonParent_OnLoad()
end end
ZSpellButton_SaveParentPosition(this) ZSpellButton_SaveParentPosition(this)
this.isMoving = false this.isMoving = false
if type(MTH_ZH_TraceButtonPoint) == "function" then
MTH_ZH_TraceButtonPoint(this, "mouse-up-stop")
end
end end
end) end)
end end
+1 -46
View File
@@ -8,7 +8,7 @@ MTH_ZH_MANAGED_HOOKS = true
local MTH_ZHunter = { local MTH_ZHunter = {
name = "zhunter", name = "zhunter",
enabled = true, enabled = true,
version = "1.3.0", version = "1.4.1",
events = { events = {
"VARIABLES_LOADED", "VARIABLES_LOADED",
-- PLAYER_ENTERING_WORLD handled by bootstrap frame + adjustment frames -- PLAYER_ENTERING_WORLD handled by bootstrap frame + adjustment frames
@@ -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_PostLoginRestore = nil
local MTH_ZH_BootstrapFrame = nil local MTH_ZH_BootstrapFrame = nil
local MTH_ZH_SyncSavedVariables local MTH_ZH_SyncSavedVariables
@@ -80,7 +67,6 @@ local function MTH_ZH_ApplyDefaultWidgetSpawnLayoutOnce()
local orderedCount = table.getn(orderedButtons) local orderedCount = table.getn(orderedButtons)
for i = 1, orderedCount do for i = 1, orderedCount do
if not getglobal(orderedButtons[i]) then if not getglobal(orderedButtons[i]) then
MTH_ZH_Log("skipped one-time default widget spawn layout (missing frame: " .. tostring(orderedButtons[i]) .. ")")
return false return false
end end
end end
@@ -95,7 +81,6 @@ local function MTH_ZH_ApplyDefaultWidgetSpawnLayoutOnce()
end end
savedRoot["_mth_widget_spawn_layout_v1"] = 1 savedRoot["_mth_widget_spawn_layout_v1"] = 1
MTH_ZH_Log("applied one-time default widget spawn layout")
return true return true
end end
@@ -107,7 +92,6 @@ function MTH_ZH_OnDeferredInitComplete()
if MTH_ZH_SetAuxFramesVisible then if MTH_ZH_SetAuxFramesVisible then
MTH_ZH_SetAuxFramesVisible(false) MTH_ZH_SetAuxFramesVisible(false)
end end
MTH_ZH_Log("deferred init applied disabled-state hide")
return return
end end
MTH_ZH_SyncSavedVariables() MTH_ZH_SyncSavedVariables()
@@ -137,10 +121,6 @@ MTH_ZH_QueuePostLoginRestore = function(tag)
MTH_ZH_SyncSavedVariables() MTH_ZH_SyncSavedVariables()
MTH_ZH_RestoreRuntimeFeatureFlags() 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)
end end
@@ -178,17 +158,10 @@ local function MTH_ZH_EnsureBootstrapRestoreFrame()
end end
MTH_ZH_ApplyEnabledRuntimeState = function(source) 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_SyncSavedVariables()
MTH_ZH_SetButtonsVisible(true) MTH_ZH_SetButtonsVisible(true)
MTH_ZH_SetAuxFramesVisible(true) MTH_ZH_SetAuxFramesVisible(true)
MTH_ZH_RestoreRuntimeFeatureFlags() MTH_ZH_RestoreRuntimeFeatureFlags()
if type(MTH_ZH_TraceAllButtonPoints) == "function" then
MTH_ZH_TraceAllButtonPoints("apply-enabled:after:" .. tostring(source or ""))
end
end end
MTH_ZH_SyncSavedVariables = function() MTH_ZH_SyncSavedVariables = function()
@@ -197,22 +170,17 @@ MTH_ZH_SyncSavedVariables = function()
end end
local moduleStore = MTH:GetModuleCharSavedVariables("zhunter") local moduleStore = MTH:GetModuleCharSavedVariables("zhunter")
MTH_ZH_TraceLocal("sync-saved begin zhuntermod_saved=" .. tostring(type(ZHunterMod_Saved)))
if type(ZHunterMod_Saved) == "table" then if type(ZHunterMod_Saved) == "table" then
if MTH_CharSavedVariables and MTH_CharSavedVariables.modules then if MTH_CharSavedVariables and MTH_CharSavedVariables.modules then
MTH_CharSavedVariables.modules.zhunter = ZHunterMod_Saved MTH_CharSavedVariables.modules.zhunter = ZHunterMod_Saved
MTH_ZH_TraceLocal("sync-saved wrote ZHunterMod_Saved -> MTH_CharSavedVariables.modules.zhunter")
end end
elseif type(moduleStore) == "table" then elseif type(moduleStore) == "table" then
ZHunterMod_Saved = moduleStore ZHunterMod_Saved = moduleStore
MTH_ZH_TraceLocal("sync-saved loaded moduleStore -> ZHunterMod_Saved")
end end
MTH_ZH_TraceLocal("sync-saved end")
end end
MTH_ZH_SetButtonsVisible = function(visible) MTH_ZH_SetButtonsVisible = function(visible)
MTH_ZH_TraceLocal("set-buttons-visible visible=" .. tostring(visible and true or false))
local buttonNames = { local buttonNames = {
"zButtonAspect", "zButtonAspect",
"zButtonTrack", "zButtonTrack",
@@ -294,9 +262,6 @@ MTH_ZH_SetButtonsVisible = function(visible)
for _, buttonName in ipairs(buttonNames) do for _, buttonName in ipairs(buttonNames) do
local button = getglobal(buttonName) local button = getglobal(buttonName)
if button then if button then
if type(MTH_ZH_TraceButtonPoint) == "function" then
MTH_ZH_TraceButtonPoint(button, "set-buttons-visible:before:" .. tostring(buttonName))
end
if visible then if visible then
-- Respect per-button enabled state -- Respect per-button enabled state
local getterName = buttonName .. "_GetSaved" local getterName = buttonName .. "_GetSaved"
@@ -319,9 +284,6 @@ MTH_ZH_SetButtonsVisible = function(visible)
MTH_ZH_SetChildButtonsVisible(button, buttonName, false) MTH_ZH_SetChildButtonsVisible(button, buttonName, false)
button:Hide() button:Hide()
end end
if type(MTH_ZH_TraceButtonPoint) == "function" then
MTH_ZH_TraceButtonPoint(button, "set-buttons-visible:after:" .. tostring(buttonName))
end
end end
end end
end end
@@ -400,7 +362,6 @@ function MTH_ZHunter:init()
end end
function MTH_ZHunter:setEnabled(enabled) function MTH_ZHunter:setEnabled(enabled)
MTH_ZH_TraceLocal("module setEnabled enabled=" .. tostring(enabled and true or false))
MTH_ZH_SyncSavedVariables() MTH_ZH_SyncSavedVariables()
if enabled then if enabled then
MTH_ZH_EnsureBootstrapRestoreFrame() MTH_ZH_EnsureBootstrapRestoreFrame()
@@ -409,14 +370,8 @@ function MTH_ZHunter:setEnabled(enabled)
else else
MTH_ZH_ClearRuntimeFeatureFlags() MTH_ZH_ClearRuntimeFeatureFlags()
MTH_ZH_SetAdjustmentHandlersActive(false) 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_SetButtonsVisible(false)
MTH_ZH_SetAuxFramesVisible(false) MTH_ZH_SetAuxFramesVisible(false)
if type(MTH_ZH_TraceAllButtonPoints) == "function" then
MTH_ZH_TraceAllButtonPoints("setEnabled:false:after-hide")
end
end end
end end
+5
View File
@@ -121,9 +121,13 @@ local zButtonAmmo_ShortArrowLabels = {
[ARROWS_ROUGH] = "Rough", [ARROWS_ROUGH] = "Rough",
[ARROWS_SHARP] = "Sharp", [ARROWS_SHARP] = "Sharp",
[ARROWS_RAZOR] = "Razor", [ARROWS_RAZOR] = "Razor",
[ARROWS_BRIGHT] = "Bright",
[ARROWS_JAGGED] = "Jagged", [ARROWS_JAGGED] = "Jagged",
[ARROWS_SHADE] = "Shade",
[ARROWS_ICETHREADED] = "Ice", [ARROWS_ICETHREADED] = "Ice",
[ARROWS_SMOOTH] = "Smooth",
[ARROWS_THORIUM] = "Thorium", [ARROWS_THORIUM] = "Thorium",
[ARROWS_STAR] = "Star",
[ARROWS_DOOMSHOT] = "Doom", [ARROWS_DOOMSHOT] = "Doom",
} }
@@ -143,6 +147,7 @@ local zButtonAmmo_ShortBulletLabels = {
[BULLETS_ACCURATE] = "Accur", [BULLETS_ACCURATE] = "Accur",
[BULLETS_GYROSHOT] = "Gyro", [BULLETS_GYROSHOT] = "Gyro",
[BULLETS_THORIUM] = "Thorium", [BULLETS_THORIUM] = "Thorium",
[BULLETS_CRAFTEDTHORIUM] = "Ench",
[BULLETS_ICETHREADED] = "Ice", [BULLETS_ICETHREADED] = "Ice",
} }
+3 -2
View File
@@ -5,7 +5,7 @@ end
local root = zButtonAspect_GetRoot() local root = zButtonAspect_GetRoot()
if not root["zButtonAspect"] then if not root["zButtonAspect"] then
root["zButtonAspect"] = {} 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"]["rows"] = 1
root["zButtonAspect"]["horizontal"] = nil root["zButtonAspect"]["horizontal"] = nil
root["zButtonAspect"]["vertical"] = nil root["zButtonAspect"]["vertical"] = nil
@@ -28,7 +28,8 @@ ZHunterMod_Aspect_Spells = {
ZHUNTER_ASPECT_CHEETAH, ZHUNTER_ASPECT_CHEETAH,
ZHUNTER_ASPECT_PACK, ZHUNTER_ASPECT_PACK,
ZHUNTER_ASPECT_WILD, ZHUNTER_ASPECT_WILD,
ZHUNTER_ASPECT_BEAST ZHUNTER_ASPECT_BEAST,
ZHUNTER_ASPECT_VIPER
} }
local ZHUNTER_ASPECT_MAX = table.getn(ZHunterMod_Aspect_Spells) local ZHUNTER_ASPECT_MAX = table.getn(ZHunterMod_Aspect_Spells)
+5 -2
View File
@@ -249,7 +249,8 @@ end
function zButtonMounts_SetupSizeAndPosition() function zButtonMounts_SetupSizeAndPosition()
local saved = zButtonMounts_GetSaved() local saved = zButtonMounts_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then if saved["enabled"] == false or saved["enabled"] == 0 then
if MTH_ZH_MountsAdjust and MTH_ZH_MountsAdjust.SetScript then if MTH_ZH_MountsAdjust then
MTH_ZH_MountsAdjust:UnregisterAllEvents()
MTH_ZH_MountsAdjust:SetScript("OnEvent", nil) MTH_ZH_MountsAdjust:SetScript("OnEvent", nil)
end end
if zButtonMounts and zButtonMounts.Hide then if zButtonMounts and zButtonMounts.Hide then
@@ -257,7 +258,9 @@ function zButtonMounts_SetupSizeAndPosition()
end end
return return
end end
if MTH_ZH_MountsAdjust and MTH_ZH_MountsAdjust.SetScript then if MTH_ZH_MountsAdjust then
MTH_ZH_MountsAdjust:RegisterEvent("SPELLS_CHANGED")
MTH_ZH_MountsAdjust:RegisterEvent("PLAYER_ENTERING_WORLD")
MTH_ZH_MountsAdjust:SetScript("OnEvent", MTH_ZH_MountsAdjust_OnEvent) MTH_ZH_MountsAdjust:SetScript("OnEvent", MTH_ZH_MountsAdjust_OnEvent)
end end
local displayCount = zButtonMounts.found or 0 local displayCount = zButtonMounts.found or 0
+10 -2
View File
@@ -235,7 +235,8 @@ end
function zButtonPet_SetupSizeAndPosition() function zButtonPet_SetupSizeAndPosition()
local saved = zButtonPet_GetSaved() local saved = zButtonPet_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then if saved["enabled"] == false or saved["enabled"] == 0 then
if MTH_ZH_PetAdjust and MTH_ZH_PetAdjust.SetScript then if MTH_ZH_PetAdjust then
MTH_ZH_PetAdjust:UnregisterAllEvents()
MTH_ZH_PetAdjust:SetScript("OnEvent", nil) MTH_ZH_PetAdjust:SetScript("OnEvent", nil)
end end
if zButtonPet and zButtonPet.Hide then if zButtonPet and zButtonPet.Hide then
@@ -243,7 +244,14 @@ function zButtonPet_SetupSizeAndPosition()
end end
return return
end end
if MTH_ZH_PetAdjust and MTH_ZH_PetAdjust.SetScript then if MTH_ZH_PetAdjust then
MTH_ZH_PetAdjust:RegisterEvent("UNIT_HEALTH")
MTH_ZH_PetAdjust:RegisterEvent("UNIT_HAPPINESS")
MTH_ZH_PetAdjust:RegisterEvent("UNIT_PET")
MTH_ZH_PetAdjust:RegisterEvent("PET_BAR_UPDATE")
MTH_ZH_PetAdjust:RegisterEvent("PLAYER_ENTERING_WORLD")
MTH_ZH_PetAdjust:RegisterEvent("SPELLS_CHANGED")
MTH_ZH_PetAdjust:RegisterEvent("LEARNED_SPELL_IN_TAB")
MTH_ZH_PetAdjust:SetScript("OnEvent", MTH_ZH_PetAdjust_OnEvent) MTH_ZH_PetAdjust:SetScript("OnEvent", MTH_ZH_PetAdjust_OnEvent)
end end
local displayCount = zButtonPet.found or ZHUNTER_PET_MAX local displayCount = zButtonPet.found or ZHUNTER_PET_MAX
-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_BOWS or "Bows") then return true end
if subtypeText == tostring(MTH_WEAPON_GUNS or "Guns") 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 == 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 return false
end end
+5 -2
View File
@@ -249,7 +249,8 @@ end
function zButtonToys_SetupSizeAndPosition() function zButtonToys_SetupSizeAndPosition()
local saved = zButtonToys_GetSaved() local saved = zButtonToys_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then if saved["enabled"] == false or saved["enabled"] == 0 then
if MTH_ZH_ToysAdjust and MTH_ZH_ToysAdjust.SetScript then if MTH_ZH_ToysAdjust then
MTH_ZH_ToysAdjust:UnregisterAllEvents()
MTH_ZH_ToysAdjust:SetScript("OnEvent", nil) MTH_ZH_ToysAdjust:SetScript("OnEvent", nil)
end end
if zButtonToys and zButtonToys.Hide then if zButtonToys and zButtonToys.Hide then
@@ -257,7 +258,9 @@ function zButtonToys_SetupSizeAndPosition()
end end
return return
end end
if MTH_ZH_ToysAdjust and MTH_ZH_ToysAdjust.SetScript then if MTH_ZH_ToysAdjust then
MTH_ZH_ToysAdjust:RegisterEvent("SPELLS_CHANGED")
MTH_ZH_ToysAdjust:RegisterEvent("PLAYER_ENTERING_WORLD")
MTH_ZH_ToysAdjust:SetScript("OnEvent", MTH_ZH_ToysAdjust_OnEvent) MTH_ZH_ToysAdjust:SetScript("OnEvent", MTH_ZH_ToysAdjust_OnEvent)
end end
local displayCount = zButtonToys.found or 0 local displayCount = zButtonToys.found or 0
+11 -4
View File
@@ -5,7 +5,7 @@ end
local root = zButtonTrack_GetRoot() local root = zButtonTrack_GetRoot()
if not root["zButtonTrack"] then if not root["zButtonTrack"] then
root["zButtonTrack"] = {} root["zButtonTrack"] = {}
root["zButtonTrack"]["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} root["zButtonTrack"]["spells"] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
root["zButtonTrack"]["rows"] = 1 root["zButtonTrack"]["rows"] = 1
root["zButtonTrack"]["horizontal"] = nil root["zButtonTrack"]["horizontal"] = nil
root["zButtonTrack"]["vertical"] = nil root["zButtonTrack"]["vertical"] = nil
@@ -32,7 +32,8 @@ ZHunterMod_Track_Spells = {
ZHUNTER_TRACK_GIANTS, ZHUNTER_TRACK_GIANTS,
ZHUNTER_TRACK_MINERALS, ZHUNTER_TRACK_MINERALS,
ZHUNTER_TRACK_HERBS, ZHUNTER_TRACK_HERBS,
ZHUNTER_TRACK_TREASURE ZHUNTER_TRACK_TREASURE,
ZHUNTER_TRACK_TREES
} }
local ZHUNTER_TRACK_MAX = table.getn(ZHunterMod_Track_Spells) local ZHUNTER_TRACK_MAX = table.getn(ZHunterMod_Track_Spells)
@@ -311,7 +312,8 @@ function zButtonTrack_SetupSizeAndPosition()
zButtonTrack_EnsureConfig() zButtonTrack_EnsureConfig()
local saved = zButtonTrack_GetSaved() local saved = zButtonTrack_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then if saved["enabled"] == false or saved["enabled"] == 0 then
if MTH_ZH_TrackAdjust and MTH_ZH_TrackAdjust.SetScript then if MTH_ZH_TrackAdjust then
MTH_ZH_TrackAdjust:UnregisterAllEvents()
MTH_ZH_TrackAdjust:SetScript("OnEvent", nil) MTH_ZH_TrackAdjust:SetScript("OnEvent", nil)
end end
if zButtonTrack and zButtonTrack.Hide then if zButtonTrack and zButtonTrack.Hide then
@@ -319,7 +321,12 @@ function zButtonTrack_SetupSizeAndPosition()
end end
return return
end end
if MTH_ZH_TrackAdjust and MTH_ZH_TrackAdjust.SetScript then if MTH_ZH_TrackAdjust then
MTH_ZH_TrackAdjust:RegisterEvent("MINIMAP_UPDATE_TRACKING")
MTH_ZH_TrackAdjust:RegisterEvent("PLAYER_ENTERING_WORLD")
MTH_ZH_TrackAdjust:RegisterEvent("SPELLS_CHANGED")
MTH_ZH_TrackAdjust:RegisterEvent("CHARACTER_POINTS_CHANGED")
MTH_ZH_TrackAdjust:RegisterEvent("LEARNED_SPELL_IN_TAB")
MTH_ZH_TrackAdjust:SetScript("OnEvent", MTH_ZH_TrackAdjust_OnEvent) MTH_ZH_TrackAdjust:SetScript("OnEvent", MTH_ZH_TrackAdjust_OnEvent)
end end
local displayCount = zButtonTrack.found or ZHUNTER_TRACK_MAX local displayCount = zButtonTrack.found or ZHUNTER_TRACK_MAX
+8 -2
View File
@@ -154,7 +154,8 @@ function zButtonTrap_SetupSizeAndPosition()
zButtonTrap_EnsureConfig() zButtonTrap_EnsureConfig()
local saved = zButtonTrap_GetSaved() local saved = zButtonTrap_GetSaved()
if saved["enabled"] == false or saved["enabled"] == 0 then if saved["enabled"] == false or saved["enabled"] == 0 then
if MTH_ZH_TrapAdjust and MTH_ZH_TrapAdjust.SetScript then if MTH_ZH_TrapAdjust then
MTH_ZH_TrapAdjust:UnregisterAllEvents()
MTH_ZH_TrapAdjust:SetScript("OnEvent", nil) MTH_ZH_TrapAdjust:SetScript("OnEvent", nil)
end end
if zButtonTrap and zButtonTrap.Hide then if zButtonTrap and zButtonTrap.Hide then
@@ -162,7 +163,12 @@ function zButtonTrap_SetupSizeAndPosition()
end end
return return
end end
if MTH_ZH_TrapAdjust and MTH_ZH_TrapAdjust.SetScript then if MTH_ZH_TrapAdjust then
MTH_ZH_TrapAdjust:RegisterEvent("PLAYER_REGEN_ENABLED")
MTH_ZH_TrapAdjust:RegisterEvent("PLAYER_REGEN_DISABLED")
MTH_ZH_TrapAdjust:RegisterEvent("PLAYER_ENTERING_WORLD")
MTH_ZH_TrapAdjust:RegisterEvent("SPELLS_CHANGED")
MTH_ZH_TrapAdjust:RegisterEvent("CHARACTER_POINTS_CHANGED")
MTH_ZH_TrapAdjust:SetScript("OnEvent", MTH_ZH_TrapAdjust_OnEvent) MTH_ZH_TrapAdjust:SetScript("OnEvent", MTH_ZH_TrapAdjust_OnEvent)
end end
local displayCount = zButtonTrap.found or ZHUNTER_TRAP_MAX local displayCount = zButtonTrap.found or ZHUNTER_TRAP_MAX