mirror of
https://codeberg.org/Duvelcorp/MetaHunt.git
synced 2026-09-22 15:46:59 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8479607a13 | |||
| 23bb69d094 | |||
| b2060e0aab | |||
| 609a6bdd83 | |||
| c0c2c275eb | |||
| ab34946775 | |||
| d41703949d | |||
| 27d37564ce | |||
| 4aed1174dd | |||
| 233899b2a0 | |||
| 89fd8e079c |
@@ -9,3 +9,7 @@
|
||||
tools/
|
||||
LOC*.md
|
||||
LOCALIZATION*.md
|
||||
|
||||
# Dev tooling — Python generators, data processing scripts, scratch files
|
||||
# Not part of the addon, never ship this
|
||||
.tools/
|
||||
|
||||
@@ -118,4 +118,9 @@
|
||||
<Binding name="ZPet 6" header="ZPetHeader">
|
||||
zButtonPet_KeyBinding(6)
|
||||
</Binding>
|
||||
|
||||
<!-- ExpAmmo Action Button -->
|
||||
<Binding name="ExpAmmo Action" header="ExpAmmoHeader">
|
||||
MTH_EA_CastActionSpell();
|
||||
</Binding>
|
||||
</Ui>
|
||||
+131
@@ -2,6 +2,137 @@
|
||||
|
||||
All notable changes to MetaHunt will be documented in this file.
|
||||
|
||||
## [1.4.0] - 2026-03-23
|
||||
|
||||
### TWoW 1.18.1 "Nightmares of Ursol" support
|
||||
|
||||
- **Complete beast database overhaul**: The MTH beast datastore was reconstructed from scratch, based on a full (beasts) 1.18.1 extract from live DB, gladly provided by Twow staff (thanks @Haaxor!). The beast data should now be 100% accurate, and notably all spawn coordinates, respawn times and pet abilities learnable on all beasts in the world.
|
||||
|
||||
- The **Beast Lore** page of the Book now allows to filter the list by Zone. Additionaly, the beast inspector has been reformated and all meaningful beast's data is displayed nicely.
|
||||
|
||||
- All new and missing **Beasts Models** have been (re)scanned from MPQ game files and are viewable in the Beast Lore page, and browsable in the Family Model viewer.
|
||||
|
||||
- Added **MM widget** module: tracks the new 3-state of Experimental ammo cycle (Fire → Nature → Arcane), the Lock and Load procs, and has adynamic cell that shows either Aimed Shot availability or the right shot to use following the current Experimental ammo proc if any. Lets Make MM great again.
|
||||
|
||||
- Added 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 wasnt tall enough to display all famillies (wolves were hidden).
|
||||
|
||||
## [1.3.0] - 2026-03-19
|
||||
|
||||
|
||||
### Added
|
||||
- Added a **3D Model Viewer** to the Hunter Book Beast Lore inspector panel. Clicking a beast in the list shows its in-game model.
|
||||
- Added a standalone **3D Model Viewer** that is shown when cliking the model of a beast in the Beast lore. The model is rotatable with the mouse, and you can browse all models of the same pet family and shows all other beasts that share the same skin, with one-click to jump to any of them in the Beast Lore.
|
||||
- Added a **Family icon** column to the Beast Lore list, replacing the text family name with the pet family icon for a more compact view.
|
||||
- Added an **Attack Speed (AS)** column to the Beast Lore list.
|
||||
- Added `displayId` and `skinId` fields to **all ~1000 beasts** in the MetaHunt datastore. `displayId` was scraped from the Turtle WoW DB, and `skinId` derived from it following an extraction on MPQ game files. This is what powers the model viewer and skin-grouping.
|
||||
- Added per-family icons to all 19 pet families in the family data table.
|
||||
- Added missing food types (`raw meat`, `raw fish`) to all pet families that accept `meat` or `fish` respectively (sourced from MPQ data).
|
||||
- Added **Profile Management** panel (Options → Profiles): save the current addon configuration as a named profile and instantly load it on any character. Profiles cover all module settings (ICU, Chronometer, AutoBuy, AutoQuest, SmartAmmo, Feed-O-Matic, zButtons layout) and per-character module enabled/disabled states.
|
||||
- Added automatic per-character **config snapshots** saved on every logout (`CharName-RealmName`), visible in the "Copy from Character" section — import any character's snapshot as a loadable profile in one click.
|
||||
|
||||
|
||||
### Fixed
|
||||
- Fixed the pet feeding counter never incrementing: `MTH_FEED_Trace` was a no-op stub and `FOM_CORE_ATTEMPT_TRACKING_ENABLED` was `false`; both are now active.
|
||||
- Fixed `FOM_AddFood` not clearing a food from `FOM_RemovedFoods` when the item belongs to the base diet list, which permanently banned it even after an explicit `/fom add`.
|
||||
- Wired `FOM_ClearItemBans` into the `/fom add` command path: explicitly re-adding a food now clears it from `FOM_RemovedFoods`, FOM quarantine, and core exceptions in one step.
|
||||
- Removed debug messages forgotten when releasing 1.2.
|
||||
- Fixed SmartAmmo + **Quiver castbar conflict**: Quiver's castbar was disappearing when both addons were active. Root cause: MetaHunt SmartAmmo was re-installing its hooks every 0.5 seconds, constantly bumping Quiver off the top of the hook chain. Fixed by removing the repeated re-hook and adding a guard that only installs once (or when no other addon is on top).
|
||||
|
||||
|
||||
## [1.2.0] - 2026-03-10
|
||||
|
||||
### Added
|
||||
- Added keybinding text overlay on zButtons: parent and child buttons now display their bound key for the 5 bindable sets (Aspect, Track, Trap, Ammo, Pet).
|
||||
- Added "Expand on Hover" option for zButton children: when enabled, hovering over the parent button automatically expands children (instead of requiring right-click).
|
||||
- Added "Auto-Hide Timer" option for zButton children: a configurable 0–10 second timer that automatically collapses expanded children after the mouse leaves the button group. Timer resets while hovering any button in the group.
|
||||
|
||||
### Fixed
|
||||
- Fixed SavedVariables data loss on login caused by initialization race condition overwriting persisted data.
|
||||
- Fixed SavedVariables bloat by adding a migration that strips redundant default-valued keys on first load.
|
||||
- Fixed six performance issues including throttling high-frequency event handlers, caching repeated `getglobal` lookups, and reducing unnecessary table allocations in hot paths.
|
||||
- Cleaned up ICU module global variable leaks by properly scoping locals.
|
||||
- Standardized all remaining `SetScript` handler patterns to use the WoW 1.12 `this`-based convention consistently.
|
||||
|
||||
|
||||
## [1.1.0] - 2026-03-09
|
||||
|
||||
### Added
|
||||
- Added new `ICU` module with dedicated options panel.
|
||||
- Added ICU custom popup anchor mode with draggable anchor and direction toggle.
|
||||
- Added ICU popup hide delay options (`INSTANT`, 1..10 seconds).
|
||||
- Added new `Auto Quest` module for :
|
||||
- `Salt of the Scorpok` (`Bloodmage Drazial`)
|
||||
- `Arrows Are For Sissies` (`Artilleryman Sheldonore`)
|
||||
- Added a Food Feed learning feature to Feed-O-Matic.
|
||||
- Added Chronometer `Entrapment` effect tracking support.
|
||||
|
||||
### Changed
|
||||
- Loads of Frame/Handlers/Processes adjustments to optimize addon's CPU time and Memory usage.
|
||||
- Updated Chronometer Improved Wing Clip effect color to `MAROON` for clearer effect-bar distinction.
|
||||
- Reworked Stable Master processing to minimize swap-time overhead:
|
||||
- No auto-scan on `PET_STABLE_SHOW`.
|
||||
- Deferred stable scan moved to `PET_STABLE_CLOSED`.
|
||||
- Optional heavy workloads are skipped while stable UI is open.
|
||||
- Changed Hunter Book page order, and default opening page to `Beast Lore`.
|
||||
- Optimized `Pet History` result build/sort path using cached precomputed sort keys.
|
||||
- Modules Auto-Buy, Auto-Quest, ICU, Feed-O-Matic are by default disabled on first use on a character.
|
||||
|
||||
### Fixed
|
||||
- Fixed issues with zBouttons,Autostrp and Chronometer bar anchor not retaining their configured spawn position after the disabling/renabling of the Addon.
|
||||
- Fixed issues with options checkbox-state not always retaining their state on startup.
|
||||
- Fixed multiple issues in Feeed-O-Matic with some foods that were accepted by lvl 60 pets in Vanilla and are not anymore on Turtle.
|
||||
- Fixed Chronometer spell/event disable toggles in options so disabled entries now reliably block bar creation.
|
||||
- Fixed Chronometer `Feed Pet` bar missing trigger by adding `UNIT_AURA` fallback detection.
|
||||
- Fixed stable swap stutter/freezes by removing heavy processing from repeated `UNIT_PET` bursts during stable interactions.
|
||||
|
||||
|
||||
## [1.0.6] - 2026-03-05
|
||||
|
||||
### Fixed
|
||||
- Added missing abilities to all pet families.
|
||||
- Rescraped from Twow DB the previously in correct `Roar of Fortitude` pet-ability.
|
||||
- Fixed an issue with Tooltip on pet action bar abilities, that were falsely displayed as not learned yet for rankless abilities.
|
||||
- Restored visible Stable Master auto-scan feedback (`Stable scan complete: X slot(s).`) when opening the stable window.
|
||||
- Fixed stable scan icon persistence for active pets that were never stabled by capturing current-pet icon data during stable scans.
|
||||
- Hardened stable-scan bootstrap to initialize on both `PET_STABLE_SHOW` and `PET_STABLE_UPDATE` event paths.
|
||||
- Fixed issues with taming pet metadata that were not properly recorded since the last update.
|
||||
- Fixed issues with pet runaway interception that was broken since the last update.
|
||||
- Updated version-update notification text to include clearer upgrade guidance and plain GitHub URL text for updates.
|
||||
- Fixed an issue with `zTrack` buttons spells being incorrect after having respec the talents using brainwashing device.
|
||||
|
||||
|
||||
## [1.0.5] - 2026-03-01
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
-- MetaHunt: Hunter's Toolkit Addon
|
||||
-- A unified addon merging FeedOMatic, Tooltips, and zhunter
|
||||
-- Modern modular architecture with legacy addon support
|
||||
--
|
||||
-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
-- TARGET RUNTIME: LUA 5.0 (WoW 1.12 / Turtle-WoW)
|
||||
-- - Max 32 upvalues per function
|
||||
-- - No # operator (use table.getn)
|
||||
-- - No string.gmatch (use string.gfind)
|
||||
-- - NEVER validate with Lua 5.1+ tools (false passes)
|
||||
-- - Errors: check Logs/FrameXML.log first
|
||||
-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
------------------------------------------------------
|
||||
|
||||
-- Initialize beast database after all files loaded
|
||||
|
||||
+6
-3
@@ -1,5 +1,5 @@
|
||||
## Interface: 11200
|
||||
## Version: 1.0.5
|
||||
## Version: 1.4.0
|
||||
## Title: MetaHunt - |cff00ff00Hunter
|
||||
## Author: Metasploit and his Copilot ;)
|
||||
## Notes: Unified addon suite for huntards making old addons compatible with TurtleWoW, and adding an arsenal of never seen Hunter's utilities.
|
||||
@@ -20,8 +20,6 @@ init\skins.xml
|
||||
|
||||
## Load database files (DB files must come before data\init.lua)
|
||||
data\ds-beasts.lua
|
||||
data\ds-beasts-extra.lua
|
||||
data\ds-beasts-html-enrichment.lua
|
||||
data\ds-vendors.lua
|
||||
data\ds-vendors-extra.lua
|
||||
data\ds-items.lua
|
||||
@@ -31,12 +29,17 @@ data\ds-bags.lua
|
||||
data\ds-items-atlas-sources.lua
|
||||
data\ds-zones.lua
|
||||
data\ds-zones-fallback.lua
|
||||
data\ds-zones-wma.lua
|
||||
data\ds-minimap-sizes.lua
|
||||
data\ds-unit-coords.lua
|
||||
data\ds-creature-coords.lua
|
||||
data\ds-beasts-families.lua
|
||||
data\ds-beasts-families-dbc.lua
|
||||
data\ds-beasts-skins.lua
|
||||
data\ds-pet-spells.lua
|
||||
data\ds-pet-spells-trainer.lua
|
||||
data\ds-hunter-spells.lua
|
||||
data\ds-hunter-spells-dbc.lua
|
||||
data\ds-racial.lua
|
||||
data\init.lua
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# MetaHunt
|
||||
|
||||
MetaHunt is a Turtle WoW Hunter toolkit.
|
||||
It combines never-seen pet-centric and beast tracking features, and revives old broken hunter add-ons.
|
||||
It provides usefull tools for all hunters, wheter they are still leveling, lone-wolf, or HL raider.
|
||||
It is a modern modular addon that combines never-seen features, and improves/fixes a few old hunter add-ons.
|
||||
It provides a bunch useful tools for all huntards, wheter they are still levelling, lone-wolf, or HL raider.
|
||||
|
||||
## Twow Data
|
||||
|
||||
Metahunt ships with larges up-to-date datastores for all Turtle WOW data a hunter needs :
|
||||
MetaHunt ships with large up-to-date datastores for all Turtle WOW data a hunter needs :
|
||||
|
||||
- All beasts, their location, and the abilities they can learn you
|
||||
- 100% accurate beasts' data, their locations, and the abilities they can learn you
|
||||
- All Pet families, their abilities and their diet
|
||||
- All pet abilities ranks
|
||||
- All Ammo (Arrows and Bullets)
|
||||
@@ -21,6 +21,8 @@ Metahunt ships with larges up-to-date datastores for all Turtle WOW data a hunte
|
||||
- Auto equip another ammo instantly during combat whenever you get out of your current ammo.
|
||||
- Auto equip the right ammo when you swap from a box/xbow to a gun and the other way around.
|
||||
|
||||
## MM Widget
|
||||
Lets Make MM great again. Tracks the new 3-state of Experimental ammo cycle (Fire → Nature → Arcane), the Lock&Load procs, and has a dynamic cell that shows either Aimed Shot availability or the right shot to use following the current Experimental ammo proc if any.
|
||||
|
||||
## Tooltips
|
||||
|
||||
@@ -37,7 +39,7 @@ Old zHunterMod addon on steroids. Fully compatible with Twow, and enhanced with
|
||||
- zPet : Intelligent collapsible pet Bar regrouping all pet spells and providing an intelligent button that always show you the right spell to use depending on the situation
|
||||
- zTrack: All your trackings in one collapsible bar
|
||||
- zAspect: All your trackings in one collapsible bar
|
||||
- zRanged : All the rnaged weampons currently in your bags to swap them fast
|
||||
- zRanged : All the ranged weampons currently in your bags to swap them fast
|
||||
- But also zMounts, zToys and zCompanions.
|
||||
|
||||
## Feed-O-Matic
|
||||
@@ -48,16 +50,27 @@ Now compatible with Turtle, feed your pet with one key bind, it will always pick
|
||||
|
||||
The good old Chronometer addon, purged of non-necessary things and reconfigured for a pure hunter use.
|
||||
|
||||
## Autobuy
|
||||
## ICU (I see you)
|
||||
|
||||
Old addon used to display Targets' enhanced information when you click on your minimap tracking things. MetaHunt offers many more customization options for it.
|
||||
|
||||
|
||||
## Auto-Buy
|
||||
|
||||
Define your own simple rules for auto buy ammo and pet food when you open a vendor.
|
||||
|
||||
## The book of Hunters
|
||||
## Auto-Quest
|
||||
|
||||
The book of Hunters 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.
|
||||
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.
|
||||
|
||||
- Browse the Metahunt datastores of NPCs (Beast, vendors, masters) and open the map to locate them like in pfQuest
|
||||
|
||||
## The Great Book of Huntards
|
||||
|
||||
The Book is the main GUI of MetaHunt, it allows to display the data constantly collected about you and your pet, and browse the addon's data to find anything a Hunter needs.
|
||||
|
||||
- Browse the MetaHunt datastores of NPCs (Beast, vendors, masters) and open the map to locate them like in pfQuest
|
||||
- Track all info about the pet abilities that you know and don't know yet
|
||||
- Track all info about your stabled pets
|
||||
- Keep an history of all your pets after you abandon them or if they run away.
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -98,7 +98,7 @@ local function AntiDaze_CancelRelevantAspect(isSelfDazed)
|
||||
|
||||
AntiDazeTooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
||||
AntiDazeTooltip:SetPlayerBuff(i, "HELPFUL")
|
||||
local text = AntiDazeTooltipTextLeft1 and AntiDazeTooltipTextLeft1:GetText()
|
||||
local text = MTH_AntiDazeProbeTextLeft1 and MTH_AntiDazeProbeTextLeft1:GetText()
|
||||
if text == packName or (isSelfDazed and text == cheetahName) then
|
||||
CancelPlayerBuff(i)
|
||||
return 1
|
||||
@@ -112,8 +112,8 @@ local function AntiDaze_HandleSlash()
|
||||
AntiDaze_SetEnabled(not AntiDaze_IsEnabled())
|
||||
end
|
||||
|
||||
AntiDazeTooltip = CreateFrame("GameTooltip", "AntiDazeTooltip", nil, "GameTooltipTemplate")
|
||||
AntiDazeFrame = CreateFrame("Frame", "AntiDazeFrame")
|
||||
AntiDazeTooltip = CreateFrame("GameTooltip", "MTH_AntiDazeProbe", nil, "GameTooltipTemplate")
|
||||
AntiDazeFrame = CreateFrame("Frame", "MTH_AntiDazeEvent")
|
||||
if AntiDazeFrame then
|
||||
AntiDazeFrame:RegisterEvent("VARIABLES_LOADED")
|
||||
AntiDazeFrame:SetScript("OnEvent", function()
|
||||
|
||||
+153
-1
@@ -6,6 +6,29 @@ local function AutoStrip_Print(msg)
|
||||
end
|
||||
end
|
||||
|
||||
local AutoStrip_TraceEnabled = false
|
||||
|
||||
local function AutoStrip_Trace(msg)
|
||||
if not AutoStrip_TraceEnabled then
|
||||
return
|
||||
end
|
||||
AutoStrip_Print("[ASTRACE] " .. tostring(msg))
|
||||
end
|
||||
|
||||
function AutoStrip_CommandTrace(mode)
|
||||
local action = string.lower(tostring(mode or "status"))
|
||||
if action == "on" or action == "1" or action == "true" then
|
||||
AutoStrip_TraceEnabled = true
|
||||
AutoStrip_Trace("trace enabled")
|
||||
return
|
||||
elseif action == "off" or action == "0" or action == "false" then
|
||||
AutoStrip_Trace("trace disabled")
|
||||
AutoStrip_TraceEnabled = false
|
||||
return
|
||||
end
|
||||
AutoStrip_Print("[ASTRACE] status=" .. tostring(AutoStrip_TraceEnabled and true or false))
|
||||
end
|
||||
|
||||
function AutoStrip_GetSaved()
|
||||
if type(MTH_CharSavedVariables) ~= "table" then
|
||||
MTH_CharSavedVariables = {}
|
||||
@@ -20,6 +43,90 @@ local AUTO_STRIP_ORDER = {16, 17, 18, 5, 7, 1, 3, 10, 8, 6, 9}
|
||||
AutoStrip_On = nil
|
||||
AutoStrip_WasInCombat = nil
|
||||
AutoStrip_Frame = nil
|
||||
local AutoStrip_RestoreFrame = nil
|
||||
|
||||
local function AutoStrip_DescribePoint(frame)
|
||||
if not (frame and frame.GetPoint) then
|
||||
return "<no-frame>"
|
||||
end
|
||||
local point, relTo, relPoint, x, y = frame:GetPoint()
|
||||
local relName = "nil"
|
||||
if type(relTo) == "table" and relTo.GetName then
|
||||
relName = tostring(relTo:GetName() or "<anon>")
|
||||
elseif relTo then
|
||||
relName = tostring(relTo)
|
||||
end
|
||||
return tostring(point or "nil")
|
||||
.. "->" .. relName
|
||||
.. ":" .. tostring(relPoint or "nil")
|
||||
.. " @(" .. tostring(x) .. "," .. tostring(y) .. ")"
|
||||
end
|
||||
|
||||
function AutoStrip_SaveDisplayPosition(reason)
|
||||
if not (AutoStripDisplay and AutoStripDisplay.GetPoint) then
|
||||
return
|
||||
end
|
||||
local saved = AutoStrip_GetSaved()
|
||||
local point, _, relPoint, x, y = AutoStripDisplay:GetPoint()
|
||||
x = tonumber(x)
|
||||
y = tonumber(y)
|
||||
if not (point and relPoint and x and y) then
|
||||
return
|
||||
end
|
||||
saved["point"] = tostring(point)
|
||||
saved["relativePoint"] = tostring(relPoint)
|
||||
saved["x"] = math.floor(x + 0.5)
|
||||
saved["y"] = math.floor(y + 0.5)
|
||||
AutoStrip_Trace("persist-display-position reason=" .. tostring(reason or "")
|
||||
.. " point=" .. tostring(saved["point"])
|
||||
.. " rel=" .. tostring(saved["relativePoint"])
|
||||
.. " x=" .. tostring(saved["x"])
|
||||
.. " y=" .. tostring(saved["y"]))
|
||||
end
|
||||
|
||||
local function AutoStrip_RestoreDisplayPosition(reason)
|
||||
if not (AutoStripDisplay and AutoStripDisplay.ClearAllPoints and AutoStripDisplay.SetPoint) then
|
||||
return false
|
||||
end
|
||||
local saved = AutoStrip_GetSaved()
|
||||
local point = tostring(saved["point"] or "")
|
||||
local relPoint = tostring(saved["relativePoint"] or "")
|
||||
local x = tonumber(saved["x"])
|
||||
local y = tonumber(saved["y"])
|
||||
if point == "" or not x or not y then
|
||||
AutoStrip_Trace("restore-display-position skipped reason=" .. tostring(reason or "")
|
||||
.. " savedPoint=" .. tostring(saved["point"])
|
||||
.. " savedX=" .. tostring(saved["x"])
|
||||
.. " savedY=" .. tostring(saved["y"]))
|
||||
return false
|
||||
end
|
||||
if relPoint == "" then
|
||||
relPoint = point
|
||||
end
|
||||
AutoStripDisplay:ClearAllPoints()
|
||||
AutoStripDisplay:SetPoint(point, UIParent, relPoint, x, y)
|
||||
AutoStrip_Trace("restore-display-position reason=" .. tostring(reason or "")
|
||||
.. " frame=" .. AutoStrip_DescribePoint(AutoStripDisplay))
|
||||
return true
|
||||
end
|
||||
|
||||
local function AutoStrip_QueueDeferredRestore(reason)
|
||||
if not AutoStrip_RestoreFrame then
|
||||
AutoStrip_RestoreFrame = CreateFrame("Frame", "MTH_AutoStripRestore")
|
||||
if not AutoStrip_RestoreFrame then
|
||||
return
|
||||
end
|
||||
end
|
||||
AutoStrip_RestoreFrame._elapsed = 0
|
||||
AutoStrip_RestoreFrame:SetScript("OnUpdate", function()
|
||||
this._elapsed = (this._elapsed or 0) + (arg1 or 0)
|
||||
if this._elapsed < 0.2 then
|
||||
return
|
||||
end
|
||||
this:SetScript("OnUpdate", nil)
|
||||
AutoStrip_RestoreDisplayPosition("deferred:" .. tostring(reason or ""))
|
||||
end)
|
||||
end
|
||||
|
||||
function AutoStrip_SetDisplayIcon()
|
||||
local icon = getglobal("AutoStripDisplayIcon") or getglobal("AutoStripDisplayIconTexture")
|
||||
@@ -35,6 +142,11 @@ end
|
||||
|
||||
function AutoStrip_SetAutoStripToggle(enabled, silent)
|
||||
local saved = AutoStrip_GetSaved()
|
||||
AutoStrip_Trace("SetAutoStripToggle enabled=" .. tostring(enabled and true or false)
|
||||
.. " silent=" .. tostring(silent and true or false)
|
||||
.. " savedBefore=" .. tostring(saved["autostrip"] and 1 or 0)
|
||||
.. " runtimeBefore=" .. tostring(AutoStrip_On and 1 or 0)
|
||||
.. " castShownBefore=" .. tostring((AutoStripDisplayAutoCast and AutoStripDisplayAutoCast:IsVisible()) and 1 or 0))
|
||||
if enabled then
|
||||
saved["autostrip"] = 1
|
||||
AutoStrip_On = 1
|
||||
@@ -54,10 +166,17 @@ function AutoStrip_SetAutoStripToggle(enabled, silent)
|
||||
AutoStrip_Print("Auto-Strip disabled.")
|
||||
end
|
||||
end
|
||||
AutoStrip_Trace("SetAutoStripToggle savedAfter=" .. tostring(saved["autostrip"] and 1 or 0)
|
||||
.. " runtimeAfter=" .. tostring(AutoStrip_On and 1 or 0)
|
||||
.. " castShownAfter=" .. tostring((AutoStripDisplayAutoCast and AutoStripDisplayAutoCast:IsVisible()) and 1 or 0))
|
||||
end
|
||||
|
||||
function AutoStrip_SetDisplayToggle(enabled, silent)
|
||||
local saved = AutoStrip_GetSaved()
|
||||
AutoStrip_Trace("SetDisplayToggle enabled=" .. tostring(enabled and true or false)
|
||||
.. " silent=" .. tostring(silent and true or false)
|
||||
.. " savedDisplayBefore=" .. tostring(saved["display"] and 1 or 0)
|
||||
.. " frameShownBefore=" .. tostring((AutoStripDisplay and AutoStripDisplay:IsVisible()) and 1 or 0))
|
||||
if enabled then
|
||||
saved["display"] = 1
|
||||
if AutoStripDisplay then
|
||||
@@ -79,9 +198,15 @@ function AutoStrip_SetDisplayToggle(enabled, silent)
|
||||
AutoStrip_Print("AutoStrip button is now hidden.")
|
||||
end
|
||||
end
|
||||
AutoStrip_Trace("SetDisplayToggle savedDisplayAfter=" .. tostring(saved["display"] and 1 or 0)
|
||||
.. " frameShownAfter=" .. tostring((AutoStripDisplay and AutoStripDisplay:IsVisible()) and 1 or 0)
|
||||
.. " castShownAfter=" .. tostring((AutoStripDisplayAutoCast and AutoStripDisplayAutoCast:IsVisible()) and 1 or 0))
|
||||
end
|
||||
|
||||
function AutoStrip_UnequipAll(weaponsOnly)
|
||||
AutoStrip_Trace("UnequipAll called weaponsOnly=" .. tostring(weaponsOnly and 1 or 0)
|
||||
.. " runtimeBefore=" .. tostring(AutoStrip_On and 1 or 0)
|
||||
.. " wasInCombat=" .. tostring(AutoStrip_WasInCombat and 1 or 0))
|
||||
AutoStrip_On = nil
|
||||
if AutoStripDisplayAutoCast then
|
||||
AutoStripDisplayAutoCast:Hide()
|
||||
@@ -102,6 +227,7 @@ function AutoStrip_UnequipAll(weaponsOnly)
|
||||
|
||||
if not hasEmptySlot then
|
||||
AutoStrip_Print("You need at least one empty bag slot to auto-strip.")
|
||||
AutoStrip_Trace("UnequipAll aborted no-empty-slot")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -121,19 +247,36 @@ function AutoStrip_UnequipAll(weaponsOnly)
|
||||
end
|
||||
end
|
||||
end
|
||||
AutoStrip_Trace("UnequipAll completed runtimeAfter=" .. tostring(AutoStrip_On and 1 or 0)
|
||||
.. " castShownAfter=" .. tostring((AutoStripDisplayAutoCast and AutoStripDisplayAutoCast:IsVisible()) and 1 or 0))
|
||||
end
|
||||
|
||||
local function AutoStrip_OnEvent()
|
||||
AutoStrip_Trace("OnEvent evt=" .. tostring(event or "")
|
||||
.. " runtime=" .. tostring(AutoStrip_On and 1 or 0)
|
||||
.. " wasInCombat=" .. tostring(AutoStrip_WasInCombat and 1 or 0)
|
||||
.. " playerInCombat=" .. tostring((type(UnitAffectingCombat) == "function" and UnitAffectingCombat("player")) and 1 or 0))
|
||||
if event == "VARIABLES_LOADED" then
|
||||
local saved = AutoStrip_GetSaved()
|
||||
AutoStrip_Trace("VARIABLES_LOADED saved.autostrip=" .. tostring(saved["autostrip"] and 1 or 0)
|
||||
.. " saved.display=" .. tostring(saved["display"] and 1 or 0))
|
||||
AutoStrip_WasInCombat = UnitAffectingCombat("player") and 1 or nil
|
||||
AutoStrip_RestoreDisplayPosition("VARIABLES_LOADED")
|
||||
AutoStrip_SetDisplayToggle(saved["display"] and true or false, 1)
|
||||
AutoStrip_SetAutoStripToggle(saved["autostrip"] and true or false, 1)
|
||||
AutoStrip_QueueDeferredRestore("VARIABLES_LOADED")
|
||||
return
|
||||
end
|
||||
|
||||
if event == "PLAYER_ENTERING_WORLD" then
|
||||
AutoStrip_WasInCombat = UnitAffectingCombat("player") and 1 or nil
|
||||
AutoStrip_RestoreDisplayPosition("PLAYER_ENTERING_WORLD")
|
||||
AutoStrip_QueueDeferredRestore("PLAYER_ENTERING_WORLD")
|
||||
return
|
||||
end
|
||||
|
||||
if event == "PLAYER_LOGOUT" then
|
||||
AutoStrip_SaveDisplayPosition("PLAYER_LOGOUT")
|
||||
return
|
||||
end
|
||||
|
||||
@@ -144,6 +287,7 @@ local function AutoStrip_OnEvent()
|
||||
|
||||
if event == "PLAYER_REGEN_ENABLED" then
|
||||
if AutoStrip_On and AutoStrip_WasInCombat then
|
||||
AutoStrip_Trace("PLAYER_REGEN_ENABLED triggering auto strip")
|
||||
AutoStrip_UnequipAll()
|
||||
end
|
||||
AutoStrip_WasInCombat = nil
|
||||
@@ -152,6 +296,8 @@ end
|
||||
|
||||
local function AutoStrip_HandleSlash(msg)
|
||||
local saved = AutoStrip_GetSaved()
|
||||
AutoStrip_Trace("Slash msg='" .. tostring(msg or "") .. "' saved.autostrip=" .. tostring(saved["autostrip"] and 1 or 0)
|
||||
.. " runtime=" .. tostring(AutoStrip_On and 1 or 0))
|
||||
if msg == "display" then
|
||||
AutoStrip_SetDisplayToggle(not (saved["display"] and true or false))
|
||||
elseif msg == "toggle" then
|
||||
@@ -170,12 +316,13 @@ local function AutoStrip_HandleSlash(msg)
|
||||
end
|
||||
end
|
||||
|
||||
AutoStrip_Frame = CreateFrame("Frame", "AutoStripFrame")
|
||||
AutoStrip_Frame = CreateFrame("Frame", "MTH_AutoStripEvent")
|
||||
if AutoStrip_Frame then
|
||||
AutoStrip_Frame:RegisterEvent("VARIABLES_LOADED")
|
||||
AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_DISABLED")
|
||||
AutoStrip_Frame:RegisterEvent("PLAYER_REGEN_ENABLED")
|
||||
AutoStrip_Frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
AutoStrip_Frame:RegisterEvent("PLAYER_LOGOUT")
|
||||
AutoStrip_Frame:SetScript("OnEvent", AutoStrip_OnEvent)
|
||||
end
|
||||
|
||||
@@ -187,3 +334,8 @@ SLASH_AUTOSTRIP1 = "/autostrip"
|
||||
SlashCmdList["AUTOSTRIP"] = AutoStrip_HandleSlash
|
||||
SLASH_ZSTRIP1 = "/zstrip"
|
||||
SlashCmdList["ZSTRIP"] = AutoStrip_HandleSlash
|
||||
SLASH_AUTOSTRIPTRACE1 = "/autostriptrace"
|
||||
SLASH_AUTOSTRIPTRACE2 = "/astrace"
|
||||
SlashCmdList["AUTOSTRIPTRACE"] = function(msg)
|
||||
AutoStrip_CommandTrace(msg)
|
||||
end
|
||||
|
||||
@@ -68,6 +68,9 @@
|
||||
if ( this.isMoving ) then
|
||||
this:StopMovingOrSizing()
|
||||
this.isMoving = false
|
||||
if AutoStrip_SaveDisplayPosition then
|
||||
AutoStrip_SaveDisplayPosition("mouse-up-stop")
|
||||
end
|
||||
end
|
||||
</OnMouseUp>
|
||||
<OnDragStart>
|
||||
@@ -79,6 +82,9 @@
|
||||
<OnDragStop>
|
||||
this:StopMovingOrSizing()
|
||||
this.isMoving = false
|
||||
if AutoStrip_SaveDisplayPosition then
|
||||
AutoStrip_SaveDisplayPosition("drag-stop")
|
||||
end
|
||||
</OnDragStop>
|
||||
</Scripts>
|
||||
<NormalTexture name="$parentNormalTexture" file="Interface\Buttons\UI-Quickslot2">
|
||||
|
||||
@@ -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
@@ -1,5 +1,5 @@
|
||||
MTH_CONST = MTH_CONST or {}
|
||||
MTH_CONST.version = MTH_CONST.version or "1.0.5"
|
||||
MTH_CONST.version = MTH_CONST.version or "1.4.0"
|
||||
|
||||
MTH_CONST.WEAPON_TYPES = {
|
||||
BOWS = "Bows",
|
||||
@@ -24,6 +24,7 @@ MTH_CONST.AMMO = {
|
||||
ICETHREADED = "Ice Threaded Bullet",
|
||||
THORIUM = "Thorium Shells",
|
||||
ROCKSHARD = "Rockshard Pellets",
|
||||
CRAFTEDTHORIUM = "Enchanted Thorium Shells",
|
||||
CANNONBALL = "Miniature Cannon Balls",
|
||||
},
|
||||
ARROWS = {
|
||||
@@ -32,16 +33,19 @@ MTH_CONST.AMMO = {
|
||||
RAZOR = "Razor Arrow",
|
||||
FEATHER = "Feathered Arrow",
|
||||
PRECISION = "Precision Arrow",
|
||||
BRIGHT = "Bright Wood Arrows",
|
||||
JAGGED = "Jagged Arrow",
|
||||
SHADE = "Shade Wood Arrows",
|
||||
ICETHREADED = "Ice Threaded Arrow",
|
||||
SMOOTH = "Smooth Ironfeather Arrows",
|
||||
THORIUM = "Thorium Headed Arrow",
|
||||
STAR = "Starfeather Arrows",
|
||||
DOOMSHOT = "Doomshot",
|
||||
},
|
||||
JUNKSHOTS = {
|
||||
SERPENT = "Serpent Sting",
|
||||
SCORPID = "Scorpid Sting",
|
||||
VIPER = "Viper Sting",
|
||||
ARCANE = "Arcane Shot",
|
||||
CONCUSSIVE = "Concussive Shot",
|
||||
DISTRACTING = "Distracting Shot",
|
||||
BAITED = "Baited Shot",
|
||||
@@ -69,6 +73,7 @@ BULLETS_ICETHREADED = MTH_CONST.AMMO.BULLETS.ICETHREADED
|
||||
BULLETS_THORIUM = MTH_CONST.AMMO.BULLETS.THORIUM
|
||||
BULLETS_ROCKSHARD = MTH_CONST.AMMO.BULLETS.ROCKSHARD
|
||||
BULLETS_CANNONBALL = MTH_CONST.AMMO.BULLETS.CANNONBALL
|
||||
BULLETS_CRAFTEDTHORIUM = MTH_CONST.AMMO.BULLETS.CRAFTEDTHORIUM
|
||||
|
||||
ARROWS_ROUGH = MTH_CONST.AMMO.ARROWS.ROUGH
|
||||
ARROWS_SHARP = MTH_CONST.AMMO.ARROWS.SHARP
|
||||
@@ -77,13 +82,16 @@ ARROWS_FEATHER = MTH_CONST.AMMO.ARROWS.FEATHER
|
||||
ARROWS_PRECISION = MTH_CONST.AMMO.ARROWS.PRECISION
|
||||
ARROWS_JAGGED = MTH_CONST.AMMO.ARROWS.JAGGED
|
||||
ARROWS_ICETHREADED = MTH_CONST.AMMO.ARROWS.ICETHREADED
|
||||
ARROWS_BRIGHT = MTH_CONST.AMMO.ARROWS.BRIGHT
|
||||
ARROWS_SHADE = MTH_CONST.AMMO.ARROWS.SHADE
|
||||
ARROWS_SMOOTH = MTH_CONST.AMMO.ARROWS.SMOOTH
|
||||
ARROWS_THORIUM = MTH_CONST.AMMO.ARROWS.THORIUM
|
||||
ARROWS_STAR = MTH_CONST.AMMO.ARROWS.STAR
|
||||
ARROWS_DOOMSHOT = MTH_CONST.AMMO.ARROWS.DOOMSHOT
|
||||
|
||||
JUNKSHOT_SERPENT = MTH_CONST.AMMO.JUNKSHOTS.SERPENT
|
||||
JUNKSHOT_SCORPID = MTH_CONST.AMMO.JUNKSHOTS.SCORPID
|
||||
JUNKSHOT_VIPER = MTH_CONST.AMMO.JUNKSHOTS.VIPER
|
||||
JUNKSHOT_ARCANE = MTH_CONST.AMMO.JUNKSHOTS.ARCANE
|
||||
JUNKSHOT_CONCUSSIVE = MTH_CONST.AMMO.JUNKSHOTS.CONCUSSIVE
|
||||
JUNKSHOT_DISTRACTING = MTH_CONST.AMMO.JUNKSHOTS.DISTRACTING
|
||||
JUNKSHOT_BAITED = MTH_CONST.AMMO.JUNKSHOTS.BAITED
|
||||
@@ -105,6 +113,7 @@ MTH_AMMO_BULLETS = {
|
||||
BULLETS_ICETHREADED,
|
||||
BULLETS_THORIUM,
|
||||
BULLETS_ROCKSHARD,
|
||||
BULLETS_CRAFTEDTHORIUM,
|
||||
BULLETS_CANNONBALL,
|
||||
}
|
||||
|
||||
@@ -114,9 +123,13 @@ MTH_AMMO_ARROWS = {
|
||||
ARROWS_RAZOR,
|
||||
ARROWS_FEATHER,
|
||||
ARROWS_PRECISION,
|
||||
ARROWS_BRIGHT,
|
||||
ARROWS_JAGGED,
|
||||
ARROWS_SHADE,
|
||||
ARROWS_ICETHREADED,
|
||||
ARROWS_SMOOTH,
|
||||
ARROWS_THORIUM,
|
||||
ARROWS_STAR,
|
||||
ARROWS_DOOMSHOT,
|
||||
}
|
||||
|
||||
@@ -124,7 +137,6 @@ MTH_AMMO_JUNKSHOTS = {
|
||||
JUNKSHOT_SERPENT,
|
||||
JUNKSHOT_SCORPID,
|
||||
JUNKSHOT_VIPER,
|
||||
JUNKSHOT_ARCANE,
|
||||
JUNKSHOT_CONCUSSIVE,
|
||||
JUNKSHOT_DISTRACTING,
|
||||
JUNKSHOT_BAITED,
|
||||
|
||||
+174
-17
@@ -15,6 +15,7 @@ local MTH_FEED_TrackerFrame = nil
|
||||
local MTH_FEED_ActiveCoreAttemptId = nil
|
||||
local MTH_FEED_BootstrapFrame = nil
|
||||
local MTH_FEED_NameToItemCache = {}
|
||||
local MTH_FEED_InvalidateDietMapCache
|
||||
|
||||
local MTH_FEED_HARDCODED_LEVEL_RULES = {
|
||||
{ minPetLevel = 1, minFoodLevel = 1 },
|
||||
@@ -28,7 +29,10 @@ local MTH_FEED_HARDCODED_LEVEL_RULES = {
|
||||
MTH_FEED_TRACE = false
|
||||
|
||||
local function MTH_FEED_Trace(message)
|
||||
return
|
||||
if not MTH_FEED_TRACE then return end
|
||||
if type(DEFAULT_CHAT_FRAME) == "table" and DEFAULT_CHAT_FRAME.AddMessage then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff88aaff[MTH-FeedTrack]|r " .. tostring(message))
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_FEED_Now()
|
||||
@@ -460,6 +464,7 @@ local function MTH_FEED_CoreTrackerOnEvent()
|
||||
end
|
||||
elseif evt == "BAG_UPDATE" then
|
||||
MTH_FEED_IndexBagFoods()
|
||||
MTH_FEED_InvalidateDietMapCache()
|
||||
elseif evt == "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS" then
|
||||
if MTH_FEED_ActiveCoreAttemptId and MTH_FEED_HasPetFeedBuff() then
|
||||
MTH_FEED_Trace("Core tracker buff event confirms acceptance")
|
||||
@@ -468,7 +473,32 @@ local function MTH_FEED_CoreTrackerOnEvent()
|
||||
end
|
||||
end
|
||||
|
||||
local MTH_FEED_CoreTrackerUpdateElapsed = 0
|
||||
local MTH_FEED_LastStaleCleanupAt = 0
|
||||
|
||||
local function MTH_FEED_CoreTrackerOnUpdate()
|
||||
MTH_FEED_CoreTrackerUpdateElapsed = MTH_FEED_CoreTrackerUpdateElapsed + (arg1 or 0)
|
||||
if MTH_FEED_CoreTrackerUpdateElapsed < 0.10 then
|
||||
return
|
||||
end
|
||||
MTH_FEED_CoreTrackerUpdateElapsed = 0
|
||||
|
||||
-- Periodic stale attempt cleanup (every ~30 seconds)
|
||||
local now = GetTime() or 0
|
||||
if (now - MTH_FEED_LastStaleCleanupAt) >= 30 then
|
||||
MTH_FEED_LastStaleCleanupAt = now
|
||||
if MTH_FEED_Runtime and type(MTH_FEED_Runtime.attempts) == "table" then
|
||||
for id, row in pairs(MTH_FEED_Runtime.attempts) do
|
||||
if type(row) == "table" then
|
||||
local age = now - (tonumber(row.startedAt) or now)
|
||||
if age > 10 then
|
||||
MTH_FEED_Runtime.attempts[id] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local attemptId = MTH_FEED_ActiveCoreAttemptId
|
||||
if attemptId == nil then
|
||||
return
|
||||
@@ -499,7 +529,7 @@ local function MTH_FEED_EnsureTrackerFrame()
|
||||
if MTH_FEED_TrackerFrame then
|
||||
return MTH_FEED_TrackerFrame
|
||||
end
|
||||
local frame = CreateFrame("Frame", "MTH_FeedTrackingFrame")
|
||||
local frame = CreateFrame("Frame", "MTH_FeedTracking")
|
||||
if not frame then
|
||||
return nil
|
||||
end
|
||||
@@ -610,6 +640,7 @@ end
|
||||
|
||||
function MTH_FEED_ReinstallCoreTracking()
|
||||
local ok = MTH_FEED_InstallCoreHooks()
|
||||
MTH_FEED_EnsureTrackerFrame()
|
||||
return ok and true or false
|
||||
end
|
||||
|
||||
@@ -617,19 +648,17 @@ local function MTH_FEED_EnsureBootstrapFrame()
|
||||
if MTH_FEED_BootstrapFrame ~= nil then
|
||||
return MTH_FEED_BootstrapFrame
|
||||
end
|
||||
local frame = CreateFrame("Frame", "MTH_FeedTrackingBootstrapFrame")
|
||||
local frame = CreateFrame("Frame", "MTH_FeedTrackingBoot")
|
||||
if not frame then
|
||||
return nil
|
||||
end
|
||||
frame:RegisterEvent("VARIABLES_LOADED")
|
||||
frame:RegisterEvent("PLAYER_LOGIN")
|
||||
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
frame:SetScript("OnEvent", function(self)
|
||||
frame:SetScript("OnEvent", function()
|
||||
MTH_FEED_ReinstallCoreTracking()
|
||||
if self and self.UnregisterAllEvents then
|
||||
self:UnregisterAllEvents()
|
||||
self:SetScript("OnEvent", nil)
|
||||
end
|
||||
this:UnregisterAllEvents()
|
||||
this:SetScript("OnEvent", nil)
|
||||
end)
|
||||
MTH_FEED_BootstrapFrame = frame
|
||||
return frame
|
||||
@@ -826,7 +855,16 @@ local function MTH_FEED_NormalizeReason(reason, rawMessage)
|
||||
return "unknown"
|
||||
end
|
||||
|
||||
local MTH_FEED_DietMapCache = nil
|
||||
|
||||
MTH_FEED_InvalidateDietMapCache = function()
|
||||
MTH_FEED_DietMapCache = nil
|
||||
end
|
||||
|
||||
local function MTH_FEED_GetDietByItemIdMap()
|
||||
if MTH_FEED_DietMapCache then
|
||||
return MTH_FEED_DietMapCache
|
||||
end
|
||||
local map = {}
|
||||
if type(FOM_Foods) ~= "table" then
|
||||
return map
|
||||
@@ -841,6 +879,7 @@ local function MTH_FEED_GetDietByItemIdMap()
|
||||
end
|
||||
end
|
||||
end
|
||||
MTH_FEED_DietMapCache = map
|
||||
return map
|
||||
end
|
||||
|
||||
@@ -944,9 +983,6 @@ function MTH_FEED_BeginAttempt(payload)
|
||||
itemIcon = infoTexture
|
||||
end
|
||||
end
|
||||
if (not itemIcon or itemIcon == "") then
|
||||
itemIcon = MTH_FEED_FindItemIconInBags(itemId, payload and payload.itemName)
|
||||
end
|
||||
|
||||
MTH_FEED_Runtime.attempts[attemptId] = {
|
||||
id = attemptId,
|
||||
@@ -1117,7 +1153,7 @@ function MTH_FEED_IsFoodCompatible(petLevel, foodLevel)
|
||||
return true
|
||||
end
|
||||
|
||||
function MTH_FEED_IsExceptionReject(itemId)
|
||||
function MTH_FEED_IsExceptionReject(itemId, petLevel)
|
||||
local key = tonumber(itemId)
|
||||
if not key then
|
||||
return false
|
||||
@@ -1127,6 +1163,11 @@ function MTH_FEED_IsExceptionReject(itemId)
|
||||
if type(row) ~= "table" then
|
||||
return false
|
||||
end
|
||||
local numericPet = tonumber(petLevel)
|
||||
local blockedAtOrAbove = tonumber(row.blockAtOrAbovePetLevel)
|
||||
if blockedAtOrAbove and numericPet and numericPet >= blockedAtOrAbove then
|
||||
return true
|
||||
end
|
||||
if row.anomalyReject ~= true then
|
||||
return false
|
||||
end
|
||||
@@ -1141,6 +1182,17 @@ function MTH_FEED_IsExceptionReject(itemId)
|
||||
if not reasons then
|
||||
return false
|
||||
end
|
||||
local lowLevelCount = tonumber(reasons.lowLevel) or 0
|
||||
if lowLevelCount >= 1 then
|
||||
local maxPetLevel = tonumber(row.maxPetLevel)
|
||||
if numericPet and maxPetLevel then
|
||||
if numericPet > maxPetLevel then
|
||||
return true
|
||||
end
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
local wrongFoodCount = tonumber(reasons.wrongFood) or 0
|
||||
if wrongFoodCount < 2 then
|
||||
return false
|
||||
@@ -1148,6 +1200,49 @@ function MTH_FEED_IsExceptionReject(itemId)
|
||||
return true
|
||||
end
|
||||
|
||||
function MTH_FEED_BlockItemForPetLevel(itemId, petLevel, reason)
|
||||
local key = tonumber(itemId)
|
||||
local numericPet = tonumber(petLevel)
|
||||
if not key or not numericPet then
|
||||
return false
|
||||
end
|
||||
if numericPet < 1 then
|
||||
numericPet = 1
|
||||
end
|
||||
local store = MTH_FEED_EnsureStore()
|
||||
if type(store.exceptions.byItemId[key]) ~= "table" then
|
||||
store.exceptions.byItemId[key] = {
|
||||
anomalyReject = true,
|
||||
reasons = { noBuff = 0, wrongFood = 0, lowLevel = 0, unknown = 0 },
|
||||
lastObservedAt = 0,
|
||||
}
|
||||
end
|
||||
local row = store.exceptions.byItemId[key]
|
||||
if type(row.reasons) ~= "table" then
|
||||
row.reasons = { noBuff = 0, wrongFood = 0, lowLevel = 0, unknown = 0 }
|
||||
end
|
||||
row.anomalyReject = true
|
||||
row.lastObservedAt = MTH_FEED_Now()
|
||||
if tonumber(row.blockAtOrAbovePetLevel) == nil or numericPet < tonumber(row.blockAtOrAbovePetLevel) then
|
||||
row.blockAtOrAbovePetLevel = numericPet
|
||||
end
|
||||
local normalizedReason = MTH_FEED_NormalizeReason(reason, nil)
|
||||
if normalizedReason == "no-buff" then
|
||||
row.reasons.noBuff = (tonumber(row.reasons.noBuff) or 0) + 1
|
||||
elseif normalizedReason == "low-level" then
|
||||
row.reasons.lowLevel = (tonumber(row.reasons.lowLevel) or 0) + 1
|
||||
elseif normalizedReason == "wrong-food" then
|
||||
row.reasons.wrongFood = (tonumber(row.reasons.wrongFood) or 0) + 1
|
||||
else
|
||||
row.reasons.unknown = (tonumber(row.reasons.unknown) or 0) + 1
|
||||
end
|
||||
MTH_FEED_TouchStore(store)
|
||||
MTH_FEED_Trace("BlockItemForPetLevel itemId=" .. tostring(key)
|
||||
.. " blockAtOrAbove=" .. tostring(row.blockAtOrAbovePetLevel)
|
||||
.. " reason=" .. tostring(normalizedReason))
|
||||
return true
|
||||
end
|
||||
|
||||
function MTH_FEED_GetPetFeedStats(petId)
|
||||
local key = tostring(petId or "")
|
||||
if key == "" then
|
||||
@@ -1157,7 +1252,7 @@ function MTH_FEED_GetPetFeedStats(petId)
|
||||
return store.byPetId[key]
|
||||
end
|
||||
|
||||
local function MTH_FEED_UpsertException(store, itemId, reason)
|
||||
local function MTH_FEED_UpsertException(store, itemId, reason, petLevel)
|
||||
if not itemId then
|
||||
return
|
||||
end
|
||||
@@ -1179,6 +1274,16 @@ local function MTH_FEED_UpsertException(store, itemId, reason)
|
||||
row.reasons.wrongFood = (tonumber(row.reasons.wrongFood) or 0) + 1
|
||||
elseif reason == "low-level" then
|
||||
row.reasons.lowLevel = (tonumber(row.reasons.lowLevel) or 0) + 1
|
||||
local numericPetLevel = tonumber(petLevel)
|
||||
if numericPetLevel and numericPetLevel > 1 then
|
||||
local derivedMaxPetLevel = numericPetLevel - 1
|
||||
if derivedMaxPetLevel < 1 then
|
||||
derivedMaxPetLevel = 1
|
||||
end
|
||||
if tonumber(row.maxPetLevel) == nil or derivedMaxPetLevel < tonumber(row.maxPetLevel) then
|
||||
row.maxPetLevel = derivedMaxPetLevel
|
||||
end
|
||||
end
|
||||
else
|
||||
row.reasons.unknown = (tonumber(row.reasons.unknown) or 0) + 1
|
||||
end
|
||||
@@ -1186,6 +1291,36 @@ local function MTH_FEED_UpsertException(store, itemId, reason)
|
||||
row.lastObservedAt = MTH_FEED_Now()
|
||||
end
|
||||
|
||||
local function MTH_FEED_ClearStaleExceptionOnAccept(store, itemId)
|
||||
if not itemId or type(store) ~= "table" or type(store.exceptions) ~= "table" or type(store.exceptions.byItemId) ~= "table" then
|
||||
return
|
||||
end
|
||||
local key = tonumber(itemId) or itemId
|
||||
local row = store.exceptions.byItemId[key]
|
||||
if type(row) ~= "table" then
|
||||
return
|
||||
end
|
||||
if type(row.reasons) ~= "table" then
|
||||
store.exceptions.byItemId[key] = nil
|
||||
return
|
||||
end
|
||||
row.reasons.noBuff = 0
|
||||
row.lastObservedAt = MTH_FEED_Now()
|
||||
|
||||
local noBuff = tonumber(row.reasons.noBuff) or 0
|
||||
local lowLevel = tonumber(row.reasons.lowLevel) or 0
|
||||
local wrongFood = tonumber(row.reasons.wrongFood) or 0
|
||||
local unknown = tonumber(row.reasons.unknown) or 0
|
||||
if noBuff <= 0
|
||||
and lowLevel <= 0
|
||||
and wrongFood <= 0
|
||||
and unknown <= 0
|
||||
and tonumber(row.blockAtOrAbovePetLevel) == nil
|
||||
and tonumber(row.maxPetLevel) == nil then
|
||||
store.exceptions.byItemId[key] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_FEED_FinalizeAttempt(attemptId, payload)
|
||||
local row = MTH_FEED_Runtime.attempts[attemptId]
|
||||
if type(row) ~= "table" then
|
||||
@@ -1245,6 +1380,7 @@ function MTH_FEED_FinalizeAttempt(attemptId, payload)
|
||||
if itemRow then
|
||||
itemRow.accepted = itemRow.accepted + 1
|
||||
end
|
||||
MTH_FEED_ClearStaleExceptionOnAccept(store, row.itemId)
|
||||
local petKey = tostring((petRow and petRow.petId) or row.petId or "")
|
||||
if petKey ~= "" then
|
||||
MTH_FEED_Runtime.sessionFeedsByPetId[petKey] = (tonumber(MTH_FEED_Runtime.sessionFeedsByPetId[petKey]) or 0) + 1
|
||||
@@ -1261,7 +1397,7 @@ function MTH_FEED_FinalizeAttempt(attemptId, payload)
|
||||
if itemRow then
|
||||
itemRow.rejected = itemRow.rejected + 1
|
||||
end
|
||||
MTH_FEED_UpsertException(store, row.itemId, reason)
|
||||
MTH_FEED_UpsertException(store, row.itemId, reason, row.petLevel)
|
||||
end
|
||||
|
||||
if itemRow then
|
||||
@@ -1284,9 +1420,6 @@ function MTH_FEED_FinalizeAttempt(attemptId, payload)
|
||||
persistedIcon = directTexture
|
||||
end
|
||||
end
|
||||
if (not persistedIcon or persistedIcon == "") then
|
||||
persistedIcon = MTH_FEED_FindItemIconInBags(row.itemId, row.itemName)
|
||||
end
|
||||
if persistedIcon and persistedIcon ~= "" then
|
||||
itemRow.itemIcon = persistedIcon
|
||||
end
|
||||
@@ -1329,6 +1462,30 @@ function MTH_FEED_GetSessionFeedCount(petId)
|
||||
return tonumber(MTH_FEED_Runtime.sessionFeedsByPetId[petKey]) or 0
|
||||
end
|
||||
|
||||
function MTH_FEED_DebugSessionFeeds()
|
||||
local pet = MTH_FEED_GetCurrentPetContext()
|
||||
local petId = pet and pet.petId or "(none)"
|
||||
local count = MTH_FEED_GetSessionFeedCount(petId)
|
||||
local hookOk = MTH_FEED_IsCoreHookInstalled()
|
||||
local frameOk = MTH_FEED_TrackerFrame ~= nil
|
||||
local activeId = tostring(MTH_FEED_ActiveCoreAttemptId or "nil")
|
||||
if type(DEFAULT_CHAT_FRAME) == "table" and DEFAULT_CHAT_FRAME.AddMessage then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff88aaff[MTH-FeedTrack]|r petId=" .. tostring(petId)
|
||||
.. " feeds=" .. tostring(count)
|
||||
.. " hookOk=" .. tostring(hookOk)
|
||||
.. " frameOk=" .. tostring(frameOk)
|
||||
.. " activeAttempt=" .. activeId)
|
||||
local anyFeeds = false
|
||||
for k, v in pairs(MTH_FEED_Runtime.sessionFeedsByPetId) do
|
||||
anyFeeds = true
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff88aaff[MTH-FeedTrack]|r session petId='" .. tostring(k) .. "' count=" .. tostring(v))
|
||||
end
|
||||
if not anyFeeds then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff88aaff[MTH-FeedTrack]|r (no session feeds recorded)")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_FEED_RecordUnknownFoodCandidate(payload)
|
||||
local store = MTH_FEED_EnsureStore()
|
||||
local itemId = payload and tonumber(payload.itemId) or nil
|
||||
|
||||
+99
-67
@@ -1,5 +1,5 @@
|
||||
MTH = MTH or {
|
||||
version = "1.0.5",
|
||||
version = "1.4.0",
|
||||
name = "MetaHunt",
|
||||
modules = {},
|
||||
config = {},
|
||||
@@ -16,6 +16,14 @@ local MTH_MESSAGE_DEFAULTS = {
|
||||
spellbookScan = false,
|
||||
petRanAway = true,
|
||||
mapMarkers = true,
|
||||
stableScan = true,
|
||||
}
|
||||
|
||||
local MTH_MODULE_DEFAULT_STATES = {
|
||||
autoquest = false,
|
||||
autobuy = false,
|
||||
feedomatic = false,
|
||||
icu = false,
|
||||
}
|
||||
|
||||
local function MTH_ClassGateTrace(_step, _detail)
|
||||
@@ -36,7 +44,7 @@ local function MTH_ClassGateEnsureAnnounceFrame(self)
|
||||
if not self or self._classGateAnnounceFrame then
|
||||
return
|
||||
end
|
||||
local frame = CreateFrame("Frame", "MTH_ClassGateAnnounceFrame")
|
||||
local frame = CreateFrame("Frame", "MTH_ClassGateAnnounce")
|
||||
if not frame then
|
||||
return
|
||||
end
|
||||
@@ -47,12 +55,12 @@ local function MTH_ClassGateEnsureAnnounceFrame(self)
|
||||
end
|
||||
end)
|
||||
frame._mthElapsed = 0
|
||||
frame:SetScript("OnUpdate", function(self, elapsed)
|
||||
self._mthElapsed = (self._mthElapsed or 0) + (elapsed or arg1 or 0)
|
||||
if self._mthElapsed < 0.5 then
|
||||
frame:SetScript("OnUpdate", function()
|
||||
this._mthElapsed = (this._mthElapsed or 0) + (arg1 or 0)
|
||||
if this._mthElapsed < 0.5 then
|
||||
return
|
||||
end
|
||||
self._mthElapsed = 0
|
||||
this._mthElapsed = 0
|
||||
if MTH and MTH._classGateAnnouncedChat then
|
||||
MTH_ClassGateClearAnnounceFrame(MTH)
|
||||
return
|
||||
@@ -184,21 +192,19 @@ end
|
||||
MTH:ApplyClassGate("startup")
|
||||
|
||||
if not MTH._classGateLifecycleFrame then
|
||||
local classGateFrame = CreateFrame("Frame", "MTH_ClassGateLifecycleFrame")
|
||||
local classGateFrame = CreateFrame("Frame", "MTH_ClassGateLifecycle")
|
||||
if classGateFrame then
|
||||
classGateFrame:RegisterEvent("PLAYER_LOGIN")
|
||||
classGateFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
classGateFrame:SetScript("OnEvent", function(self, eventName)
|
||||
self = self or this
|
||||
eventName = eventName or event
|
||||
if MTH and eventName == "PLAYER_LOGIN" then
|
||||
classGateFrame:SetScript("OnEvent", function()
|
||||
if MTH and event == "PLAYER_LOGIN" then
|
||||
MTH._classGateAnnouncedChat = nil
|
||||
MTH._classGateAnnounced = nil
|
||||
MTH._classGateAnnouncePending = nil
|
||||
end
|
||||
if MTH and MTH.ApplyClassGate and MTH:ApplyClassGate(eventName) and MTH._classGateAnnouncedChat then
|
||||
self:UnregisterAllEvents()
|
||||
self:SetScript("OnEvent", nil)
|
||||
if MTH and MTH.ApplyClassGate and MTH:ApplyClassGate(event) and MTH._classGateAnnouncedChat then
|
||||
this:UnregisterAllEvents()
|
||||
this:SetScript("OnEvent", nil)
|
||||
end
|
||||
end)
|
||||
MTH._classGateLifecycleFrame = classGateFrame
|
||||
@@ -260,15 +266,6 @@ if type(MTH_CharSavedVariables.modules) ~= "table" then
|
||||
MTH_CharSavedVariables.modules = {}
|
||||
end
|
||||
|
||||
local function MTH_ModuleStateDebug(message)
|
||||
local text = "[MODULE STATE] " .. tostring(message or "")
|
||||
if MTH and MTH.debug and MTH.Log then
|
||||
MTH:Log(text, "debug")
|
||||
elseif MTH and MTH.debug and MTH.Print then
|
||||
MTH:Print(text, "debug")
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_IsPetUiFrameName(frameName)
|
||||
local name = tostring(frameName or "")
|
||||
if name == "" then
|
||||
@@ -417,7 +414,6 @@ end
|
||||
|
||||
local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
|
||||
if type(name) ~= "string" or name == "" then
|
||||
MTH_ModuleStateDebug("read <invalid-name> fallback-default=" .. tostring(defaultEnabled and true or false))
|
||||
return defaultEnabled and true or false
|
||||
end
|
||||
|
||||
@@ -433,6 +429,9 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
|
||||
if type(MTH_CharSavedVariables.modules) ~= "table" then
|
||||
MTH_CharSavedVariables.modules = {}
|
||||
end
|
||||
if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then
|
||||
MTH_CharSavedVariables.modules[resolvedName] = {}
|
||||
end
|
||||
|
||||
if type(MTH_SavedVariables) ~= "table" then
|
||||
MTH_SavedVariables = {}
|
||||
@@ -444,13 +443,24 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
|
||||
MTH_SavedVariables.modules = {}
|
||||
end
|
||||
|
||||
local hardDefault = MTH_MODULE_DEFAULT_STATES[resolvedName]
|
||||
if hardDefault ~= nil then
|
||||
local hasCharState = MTH_CharSavedVariables.moduleStates[resolvedName] ~= nil
|
||||
or MTH_CharSavedVariables.modules[resolvedName].enabled ~= nil
|
||||
if not hasCharState then
|
||||
local resolved = hardDefault and true or false
|
||||
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
|
||||
MTH_CharSavedVariables.modules[resolvedName].enabled = resolved
|
||||
return resolved
|
||||
end
|
||||
end
|
||||
|
||||
if type(MTH_CharSavedVariables.moduleStates) == "table"
|
||||
then
|
||||
for i = 1, table.getn(candidates) do
|
||||
local key = candidates[i]
|
||||
if MTH_CharSavedVariables.moduleStates[key] ~= nil then
|
||||
local resolved = MTH_CharSavedVariables.moduleStates[key] and true or false
|
||||
MTH_ModuleStateDebug("read " .. tostring(name) .. " from char.moduleStates." .. tostring(key) .. "=" .. tostring(resolved))
|
||||
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
|
||||
return resolved
|
||||
end
|
||||
@@ -462,7 +472,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
|
||||
local key = candidates[i]
|
||||
if MTH_SavedVariables.moduleStates[key] ~= nil then
|
||||
local resolved = MTH_SavedVariables.moduleStates[key] and true or false
|
||||
MTH_ModuleStateDebug("read " .. tostring(name) .. " from moduleStates." .. tostring(key) .. "=" .. tostring(resolved))
|
||||
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
|
||||
if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then
|
||||
MTH_CharSavedVariables.modules[resolvedName] = {}
|
||||
@@ -478,7 +487,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
|
||||
local key = candidates[i]
|
||||
if type(MTH_SavedVariables.modules[key]) == "table" and MTH_SavedVariables.modules[key].enabled ~= nil then
|
||||
local resolved = MTH_SavedVariables.modules[key].enabled and true or false
|
||||
MTH_ModuleStateDebug("read " .. tostring(name) .. " from modules." .. tostring(key) .. ".enabled=" .. tostring(resolved))
|
||||
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
|
||||
if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then
|
||||
MTH_CharSavedVariables.modules[resolvedName] = {}
|
||||
@@ -493,7 +501,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
|
||||
local key = candidates[i]
|
||||
if type(MTH_SavedVariables[key]) == "table" and MTH_SavedVariables[key].enabled ~= nil then
|
||||
local resolved = MTH_SavedVariables[key].enabled and true or false
|
||||
MTH_ModuleStateDebug("read " .. tostring(name) .. " from legacy-top-level." .. tostring(key) .. ".enabled=" .. tostring(resolved))
|
||||
MTH_CharSavedVariables.moduleStates[resolvedName] = resolved
|
||||
if type(MTH_CharSavedVariables.modules[resolvedName]) ~= "table" then
|
||||
MTH_CharSavedVariables.modules[resolvedName] = {}
|
||||
@@ -503,7 +510,6 @@ local function MTH_GetPersistedModuleEnabled(name, defaultEnabled)
|
||||
end
|
||||
end
|
||||
|
||||
MTH_ModuleStateDebug("read " .. tostring(name) .. " no-persisted-value fallback-default=" .. tostring(defaultEnabled and true or false))
|
||||
return defaultEnabled and true or false
|
||||
end
|
||||
|
||||
@@ -533,7 +539,6 @@ local function MTH_SetPersistedModuleEnabled(name, enabled)
|
||||
enabled = enabled and true or false
|
||||
MTH_CharSavedVariables.moduleStates[name] = enabled
|
||||
MTH_CharSavedVariables.modules[name].enabled = enabled
|
||||
MTH_ModuleStateDebug("write " .. tostring(name) .. " enabled=" .. tostring(enabled))
|
||||
end
|
||||
|
||||
function MTH:InitEventRouter()
|
||||
@@ -541,10 +546,10 @@ function MTH:InitEventRouter()
|
||||
return self._eventRouter.frame
|
||||
end
|
||||
|
||||
local frame = CreateFrame("Frame", "MTH_EventRouterFrame")
|
||||
frame:SetScript("OnEvent", function(self, evt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
|
||||
local frame = CreateFrame("Frame", "MTH_EventRouter")
|
||||
frame:SetScript("OnEvent", function()
|
||||
if MTH and MTH.DispatchEvent then
|
||||
MTH:DispatchEvent(evt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
|
||||
MTH:DispatchEvent(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -604,7 +609,7 @@ function MTH:_SetModuleEventSubscriptions(name, enabled)
|
||||
end
|
||||
end
|
||||
|
||||
function MTH:DispatchEvent(evt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
|
||||
function MTH:DispatchEvent(evt, ea1, ea2, ea3, ea4, ea5, ea6, ea7, ea8, ea9)
|
||||
for name, module in pairs(self.modules) do
|
||||
if module.enabled and module.onEvent then
|
||||
local allow = true
|
||||
@@ -613,11 +618,10 @@ function MTH:DispatchEvent(evt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
|
||||
end
|
||||
if allow then
|
||||
local ok, err = pcall(function()
|
||||
module:onEvent(evt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
|
||||
module:onEvent(evt, ea1, ea2, ea3, ea4, ea5, ea6, ea7, ea8, ea9)
|
||||
end)
|
||||
if not ok then
|
||||
self:Print("Module '" .. name .. "' event error on '" .. tostring(evt) .. "': " .. tostring(err))
|
||||
MTH:Print("[MTH] Module event error (" .. name .. ", " .. tostring(evt) .. "): " .. tostring(err), "error")
|
||||
MTH:Print("Module '" .. name .. "' event error on '" .. tostring(evt) .. "': " .. tostring(err), "error")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -648,7 +652,6 @@ function MTH:RegisterModule(name, module)
|
||||
end
|
||||
|
||||
if self.modules[name] then
|
||||
if self.debug then print("|cFFFFAA00MetaHunt|r: Module '" .. name .. "' already registered") end
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -663,8 +666,6 @@ function MTH:RegisterModule(name, module)
|
||||
|
||||
local initialEnabled = MTH_GetPersistedModuleEnabled(name, defaultEnabled)
|
||||
module.enabled = initialEnabled and true or false
|
||||
MTH_ModuleStateDebug("register " .. tostring(name) .. " default=" .. tostring(defaultEnabled) .. " initial=" .. tostring(module.enabled))
|
||||
|
||||
self.modules[name] = module
|
||||
self:RegisterModuleEvents(name, module.events)
|
||||
|
||||
@@ -688,7 +689,6 @@ function MTH:RegisterModule(name, module)
|
||||
self:_SetModuleEventSubscriptions(name, true)
|
||||
end
|
||||
|
||||
if self.debug then print("|cFF00AA00MetaHunt|r: Module '" .. name .. "' registered") end
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -753,7 +753,6 @@ function MTH:SetModuleEnabled(name, enabled)
|
||||
if self.SetConfig then
|
||||
self:SetConfig(name, "enabled", enabled)
|
||||
end
|
||||
MTH_ModuleStateDebug("request " .. tostring(name) .. " no-op runtime=" .. tostring(module.enabled) .. " persisted-synced")
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -775,7 +774,6 @@ function MTH:SetModuleEnabled(name, enabled)
|
||||
if self.SetConfig then
|
||||
self:SetConfig(name, "enabled", enabled)
|
||||
end
|
||||
MTH_ModuleStateDebug("request " .. tostring(name) .. " applied runtime=" .. tostring(module.enabled))
|
||||
|
||||
return true
|
||||
end
|
||||
@@ -1014,6 +1012,12 @@ function MTH:Log(msg, severity)
|
||||
return chatText
|
||||
end
|
||||
|
||||
function MTH:DebugPrint(msg)
|
||||
if self.debug then
|
||||
self:Print("[DEBUG] " .. tostring(msg), "debug")
|
||||
end
|
||||
end
|
||||
|
||||
function MTH:Print(msg, severity)
|
||||
return self:Log(msg, severity)
|
||||
end
|
||||
@@ -1062,12 +1066,6 @@ function MTH:SetMessageEnabled(key, enabled)
|
||||
return true
|
||||
end
|
||||
|
||||
function MTH:DebugPrint(msg)
|
||||
if self.debug then
|
||||
self:Print("[DEBUG] " .. tostring(msg), "debug")
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_Log(message, severity)
|
||||
if MTH and MTH.Log then
|
||||
return MTH:Log(message, severity)
|
||||
@@ -1249,12 +1247,10 @@ function MTH:ApplyPersistedModuleStates(source)
|
||||
end
|
||||
|
||||
local persistedEnabled = MTH_GetPersistedModuleEnabled(name, defaultEnabled)
|
||||
MTH_ModuleStateDebug("bootstrap " .. tostring(source or "") .. " " .. tostring(name) .. " persisted=" .. tostring(persistedEnabled) .. " runtime=" .. tostring(module.enabled and true or false))
|
||||
|
||||
if module.enabled ~= persistedEnabled then
|
||||
local ok, err = self:SetModuleEnabled(name, persistedEnabled)
|
||||
if not ok then
|
||||
MTH_ModuleStateDebug("bootstrap apply failed " .. tostring(name) .. ": " .. tostring(err))
|
||||
end
|
||||
else
|
||||
MTH_SetPersistedModuleEnabled(name, persistedEnabled)
|
||||
@@ -1271,24 +1267,22 @@ function MTH:EnsureModuleStateBootstrap()
|
||||
return self._moduleStateBootstrapFrame
|
||||
end
|
||||
|
||||
local frame = CreateFrame("Frame", "MTH_ModuleStateBootstrapFrame")
|
||||
local frame = CreateFrame("Frame", "MTH_ModuleBootstrap")
|
||||
if not frame then
|
||||
return nil
|
||||
end
|
||||
|
||||
frame:RegisterEvent("VARIABLES_LOADED")
|
||||
frame:SetScript("OnEvent", function(self, eventName)
|
||||
self = self or this
|
||||
eventName = eventName or event
|
||||
if eventName ~= "VARIABLES_LOADED" then
|
||||
frame:SetScript("OnEvent", function()
|
||||
if event ~= "VARIABLES_LOADED" then
|
||||
return
|
||||
end
|
||||
if MTH and MTH.ApplyPersistedModuleStates then
|
||||
MTH:ApplyPersistedModuleStates("VARIABLES_LOADED")
|
||||
end
|
||||
if not self then return end
|
||||
self:UnregisterAllEvents()
|
||||
self:SetScript("OnEvent", nil)
|
||||
if not this then return end
|
||||
this:UnregisterAllEvents()
|
||||
this:SetScript("OnEvent", nil)
|
||||
end)
|
||||
|
||||
self._moduleStateBootstrapFrame = frame
|
||||
@@ -1466,6 +1460,46 @@ function MTH:AnnounceLoadComplete()
|
||||
"Addon synced. Your threat meter just sent a stress signal.",
|
||||
"Loaded cleanly. Reputation with healers currently in freefall.",
|
||||
"Mission start: hit things from far away and deny everything in chat.",
|
||||
"Welcome back. Your pet missed you. Just kidding, it ran away.",
|
||||
"MetaHunt loaded. You're still a Huntard, but now you're an organized one.",
|
||||
"Aspects, traps, tracking... Don't worry, I'll handle the hard parts.",
|
||||
"Oh good, another hunter who needs an addon to remember their own spells.",
|
||||
"MetaHunt ready. Feign Death is not a personality trait.",
|
||||
"Loaded successfully. No, I can't fix your DPS.",
|
||||
"Welcome. Your pet's loyalty is higher than your raid attendance.",
|
||||
"MetaHunt online. Please don't Multishot the sheep.",
|
||||
"Greetings, hunter. I see you've chosen the 'easy' class and still need help.",
|
||||
"All systems go. Try not to pull the entire dungeon this time.",
|
||||
"MetaHunt activated. Reminder: Melee range is not your home.",
|
||||
"Welcome back. Your ammo count is almost as low as your situational awareness.",
|
||||
"Loaded. I'll manage your buttons since you clearly have too many.",
|
||||
"MetaHunt ready. Aspect of the Cheetah in dungeons is a choice, not a strategy.",
|
||||
"Oh look, a hunter that uses addons. There might be hope for you yet.",
|
||||
"Welcome. No, you cannot tame that. Or that. Stop asking.",
|
||||
"MetaHunt standing by. Unlike you during your last Feign Death.",
|
||||
"Initialized. Fun fact: your pet has more utility than you do.",
|
||||
"All buttons configured. Now if only I could configure your aim.",
|
||||
"MetaHunt loaded. Growl is off, right? ...RIGHT?",
|
||||
"MetaHunt loaded. Your Freezing Trap will still break early. That's on you.",
|
||||
"Welcome. Aspect of the Pack is ready. Your group is not.",
|
||||
"Initializing... unlike your pet, I actually come when called.",
|
||||
"MetaHunt online. Remember: Hunter loot is everything. Everything.",
|
||||
"Loaded. Concussive Shot the flag carrier, not the rogue vanishing.",
|
||||
"Welcome back. Eyes of the Beast is not a valid boss strategy.",
|
||||
"Ready. Your Aimed Shot takes longer to cast than this addon took to load.",
|
||||
"MetaHunt armed. Scatter Shot into Freezing Trap — you'll get it right someday.",
|
||||
"Online. Don't worry, I track your cooldowns since you clearly don't.",
|
||||
"Welcome. Wing Clip and run. It's what you do best.",
|
||||
"Loaded. Distracting Shot is for the boss, not for your ego.",
|
||||
"MetaHunt ready. Your quiver is full but your skill bar is empty.",
|
||||
"Initialized. Serpent Sting on every target doesn't make you a DoT class.",
|
||||
"Welcome, hunter. Viper Sting the healer. No, the OTHER healer.",
|
||||
"Ready to hunt. Mend Pet is not optional, it's a lifestyle.",
|
||||
"MetaHunt loaded. Tranquilizing Shot the enrage, not the warrior.",
|
||||
"Online. Rapid Fire is a cooldown, not your approach to pulling.",
|
||||
"Welcome. You have 28 arrows left. Should've checked before the raid.",
|
||||
"Loaded. Bestial Wrath does not make YOU immune. Learned that yet?",
|
||||
"MetaHunt standing by. Dead zone? What dead zone? Oh... that dead zone.",
|
||||
}
|
||||
|
||||
local welcomeIndex = 1
|
||||
@@ -1496,24 +1530,22 @@ function MTH:EnsureLoadCompleteAnnouncement()
|
||||
return self._loadCompleteFrame
|
||||
end
|
||||
|
||||
local frame = CreateFrame("Frame", "MTH_LoadCompleteAnnounceFrame")
|
||||
local frame = CreateFrame("Frame", "MTH_LoadAnnounce")
|
||||
if not frame then
|
||||
return nil
|
||||
end
|
||||
|
||||
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
frame:SetScript("OnEvent", function(self, eventName)
|
||||
self = self or this
|
||||
eventName = eventName or event
|
||||
if eventName ~= "PLAYER_ENTERING_WORLD" then
|
||||
frame:SetScript("OnEvent", function()
|
||||
if event ~= "PLAYER_ENTERING_WORLD" then
|
||||
return
|
||||
end
|
||||
if MTH and MTH.AnnounceLoadComplete then
|
||||
MTH:AnnounceLoadComplete()
|
||||
end
|
||||
if not self then return end
|
||||
self:UnregisterAllEvents()
|
||||
self:SetScript("OnEvent", nil)
|
||||
if not this then return end
|
||||
this:UnregisterAllEvents()
|
||||
this:SetScript("OnEvent", nil)
|
||||
end)
|
||||
|
||||
self._loadCompleteFrame = frame
|
||||
|
||||
@@ -623,13 +623,11 @@ function MTH_PT_ApplyScan(triggerReason)
|
||||
local msg = "New pet data recorded (" .. tostring(added) .. " new rank(s)): " .. detailsText .. ". Known totals for this character: " .. tostring(totalBaselines) .. " ability type(s), " .. tostring(totalRanks) .. " rank(s)."
|
||||
if MTH_PT_IsScanMessageEnabled() then
|
||||
MTH:Print(msg)
|
||||
MTH:Print("INFO: " .. msg, "debug")
|
||||
end
|
||||
else
|
||||
local msg = "New pet data recorded (" .. tostring(added) .. " new rank(s)). Known totals for this character: " .. tostring(totalBaselines) .. " ability type(s), " .. tostring(totalRanks) .. " rank(s)."
|
||||
if MTH_PT_IsScanMessageEnabled() then
|
||||
MTH:Print(msg)
|
||||
MTH:Print("INFO: " .. msg, "debug")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -802,7 +800,7 @@ function MTH_PT_InitService()
|
||||
if MTH_PetTrainingFrame then
|
||||
return
|
||||
end
|
||||
MTH_PetTrainingFrame = CreateFrame("Frame", "MTHPetTrainingScanFrame")
|
||||
MTH_PetTrainingFrame = CreateFrame("Frame", "MTH_PetTrainingScan")
|
||||
MTH_PetTrainingFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
MTH_PetTrainingFrame:RegisterEvent("LEARNED_SPELL_IN_TAB")
|
||||
MTH_PetTrainingFrame:RegisterEvent("PET_TRAINING_SHOW")
|
||||
@@ -813,9 +811,8 @@ function MTH_PT_InitService()
|
||||
MTH_PetTrainingFrame:RegisterEvent("CRAFT_SHOW")
|
||||
MTH_PetTrainingFrame:RegisterEvent("CRAFT_UPDATE")
|
||||
MTH_PetTrainingFrame:SetScript("OnEvent", MTH_PT_OnEvent)
|
||||
MTH_PetTrainingFrame:SetScript("OnUpdate", function(_, elapsed)
|
||||
elapsed = elapsed or arg1
|
||||
MTH_PT_PetBookPollElapsed = (MTH_PT_PetBookPollElapsed or 0) + (elapsed or 0)
|
||||
MTH_PetTrainingFrame:SetScript("OnUpdate", function()
|
||||
MTH_PT_PetBookPollElapsed = (MTH_PT_PetBookPollElapsed or 0) + (arg1 or 0)
|
||||
if MTH_PT_PetBookPollElapsed < 0.20 then
|
||||
return
|
||||
end
|
||||
@@ -861,19 +858,16 @@ function MTH_PT_InitBootstrap()
|
||||
end
|
||||
frame:RegisterEvent("PET_TRAINING_SHOW")
|
||||
frame:RegisterEvent("CRAFT_SHOW")
|
||||
frame:SetScript("OnEvent", function(self, evt)
|
||||
evt = evt or event
|
||||
if evt ~= "PET_TRAINING_SHOW" and evt ~= "CRAFT_SHOW" then
|
||||
frame:SetScript("OnEvent", function()
|
||||
if event ~= "PET_TRAINING_SHOW" and event ~= "CRAFT_SHOW" then
|
||||
return
|
||||
end
|
||||
MTH_PT_InitService()
|
||||
if type(MTH_PT_OnEvent) == "function" then
|
||||
MTH_PT_OnEvent(MTH_PetTrainingFrame, evt)
|
||||
end
|
||||
if self and self.UnregisterAllEvents then
|
||||
self:UnregisterAllEvents()
|
||||
self:SetScript("OnEvent", nil)
|
||||
MTH_PT_OnEvent(MTH_PetTrainingFrame, event)
|
||||
end
|
||||
this:UnregisterAllEvents()
|
||||
this:SetScript("OnEvent", nil)
|
||||
MTH_PT_BootstrapFrame = nil
|
||||
end)
|
||||
MTH_PT_BootstrapFrame = frame
|
||||
|
||||
@@ -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()
|
||||
@@ -8,6 +8,24 @@ local MTH_PS_VERBOSE_LOGS = false
|
||||
local MTH_PS_ForceScanUntil = 0
|
||||
local MTH_PS_ForceScanBudget = 0
|
||||
local MTH_PS_EventThrottle = {}
|
||||
local MTH_PS_LastNoPetScanAt = 0
|
||||
|
||||
local function MTH_PS_IsPlayerDeadOrGhost()
|
||||
if type(UnitIsDeadOrGhost) == "function" then
|
||||
return UnitIsDeadOrGhost("player") and true or false
|
||||
end
|
||||
if type(UnitIsDead) == "function" then
|
||||
return UnitIsDead("player") and true or false
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function MTH_PS_HasLivePet()
|
||||
if type(UnitExists) ~= "function" then
|
||||
return false
|
||||
end
|
||||
return UnitExists("pet") and true or false
|
||||
end
|
||||
|
||||
local function MTH_PS_ClearForceWindow()
|
||||
MTH_PS_ForceScanUntil = 0
|
||||
@@ -207,6 +225,41 @@ function MTH_PSP_RequestScan(trigger, minIntervalSeconds)
|
||||
local minInterval = tonumber(minIntervalSeconds) or 1
|
||||
local bypassThrottle = false
|
||||
local bypassReason = ""
|
||||
local deadOrGhost = MTH_PS_IsPlayerDeadOrGhost()
|
||||
local hasLivePet = MTH_PS_HasLivePet()
|
||||
|
||||
if deadOrGhost then
|
||||
if triggerText == "PET_BAR_UPDATE" or triggerText == "event:PET_BAR_UPDATE"
|
||||
or triggerText == "SPELLS_CHANGED" or triggerText == "event:SPELLS_CHANGED"
|
||||
or triggerText == "LEARNED_SPELL_IN_TAB" or triggerText == "event:LEARNED_SPELL_IN_TAB"
|
||||
then
|
||||
MTH_PS_TraceTrigger(triggerText, false, "dead-skip")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if not hasLivePet then
|
||||
if MTH_PS_IsFollowupEventTrigger(triggerText) then
|
||||
MTH_PS_TraceTrigger(triggerText, false, "no-pet-followup")
|
||||
return false
|
||||
end
|
||||
if triggerText ~= "manual"
|
||||
and triggerText ~= "PLAYER_ENTERING_WORLD"
|
||||
and triggerText ~= "event:PLAYER_ENTERING_WORLD"
|
||||
and triggerText ~= "UNIT_PET"
|
||||
and triggerText ~= "event:UNIT_PET"
|
||||
then
|
||||
MTH_PS_TraceTrigger(triggerText, false, "no-pet")
|
||||
return false
|
||||
end
|
||||
if (now - (tonumber(MTH_PS_LastNoPetScanAt) or 0)) < 5 then
|
||||
MTH_PS_TraceTrigger(triggerText, false, "no-pet-throttled")
|
||||
return false
|
||||
end
|
||||
MTH_PS_LastNoPetScanAt = now
|
||||
else
|
||||
MTH_PS_LastNoPetScanAt = 0
|
||||
end
|
||||
|
||||
if MTH_PS_IsPriorityTrigger(triggerText) then
|
||||
bypassThrottle = true
|
||||
@@ -256,16 +309,16 @@ local function MTH_PS_OnEvent(_, evt, eventArg1)
|
||||
if evt == "PLAYER_ENTERING_WORLD" or evt == "UNIT_PET" or evt == "PET_BAR_UPDATE" or evt == "SPELLS_CHANGED" or evt == "LEARNED_SPELL_IN_TAB" then
|
||||
local minInterval = 1
|
||||
if evt == "PET_BAR_UPDATE" then
|
||||
minInterval = 2
|
||||
minInterval = 4
|
||||
elseif evt == "SPELLS_CHANGED" then
|
||||
minInterval = 2.5
|
||||
minInterval = 4
|
||||
elseif evt == "LEARNED_SPELL_IN_TAB" then
|
||||
minInterval = 0.75
|
||||
minInterval = 1.5
|
||||
elseif evt == "UNIT_PET" then
|
||||
minInterval = 0.5
|
||||
minInterval = 1
|
||||
end
|
||||
if MTH_PS_ShouldHandleEvent(evt, minInterval) then
|
||||
MTH_PSP_RequestScan(evt, 1)
|
||||
MTH_PSP_RequestScan(evt, minInterval)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -278,7 +331,7 @@ function MTH_PS_InitService()
|
||||
return
|
||||
end
|
||||
|
||||
MTH_PS_Frame = CreateFrame("Frame", "MTHPetSpellScanFrame")
|
||||
MTH_PS_Frame = CreateFrame("Frame", "MTH_PetSpellbookEvent")
|
||||
MTH_PS_Frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
MTH_PS_Frame:RegisterEvent("UNIT_PET")
|
||||
MTH_PS_Frame:RegisterEvent("PET_BAR_UPDATE")
|
||||
@@ -295,6 +348,7 @@ function MTH_PS_ShutdownService(_reason)
|
||||
MTH_PS_Frame:SetScript("OnEvent", nil)
|
||||
MTH_PS_Frame = nil
|
||||
MTH_PS_LastScanAt = 0
|
||||
MTH_PS_LastNoPetScanAt = 0
|
||||
MTH_PS_ClearForceWindow()
|
||||
end
|
||||
|
||||
|
||||
+1415
-177
File diff suppressed because it is too large
Load Diff
+147
-12
@@ -12,7 +12,7 @@ local function MTH_PT_GetGlobal(name)
|
||||
return nil
|
||||
end
|
||||
|
||||
local MTH_ItemLinkCacheTooltip = nil
|
||||
local MTH_ItemLinkCache = nil
|
||||
|
||||
local function MTH_GetQualityHexColor(quality)
|
||||
local q = tonumber(quality)
|
||||
@@ -34,14 +34,14 @@ function MTH_PrimeItemCache(itemId)
|
||||
if not id or id <= 0 then return false end
|
||||
if type(GetItemInfo) == "function" and GetItemInfo(id) then return true end
|
||||
|
||||
if not MTH_ItemLinkCacheTooltip then
|
||||
MTH_ItemLinkCacheTooltip = CreateFrame("GameTooltip", "MTH_ItemLinkCacheTooltip", UIParent, "GameTooltipTemplate")
|
||||
if not MTH_ItemLinkCacheTooltip then return false end
|
||||
MTH_ItemLinkCacheTooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
||||
if not MTH_ItemLinkCache then
|
||||
MTH_ItemLinkCache = CreateFrame("GameTooltip", "MTH_ItemLinkCache", UIParent, "GameTooltipTemplate")
|
||||
if not MTH_ItemLinkCache then return false end
|
||||
MTH_ItemLinkCache:SetOwner(UIParent, "ANCHOR_NONE")
|
||||
end
|
||||
|
||||
MTH_ItemLinkCacheTooltip:ClearLines()
|
||||
MTH_ItemLinkCacheTooltip:SetHyperlink("item:" .. tostring(id) .. ":0:0:0")
|
||||
MTH_ItemLinkCache:ClearLines()
|
||||
MTH_ItemLinkCache:SetHyperlink("item:" .. tostring(id) .. ":0:0:0")
|
||||
return type(GetItemInfo) == "function" and (GetItemInfo(id) ~= nil) or false
|
||||
end
|
||||
|
||||
@@ -240,6 +240,34 @@ local function MTH_CommandPetSpellScanFallback()
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_CommandFoodData(limitText)
|
||||
if type(FOM_PrintCollectedFoodData) ~= "function" then
|
||||
MTH:Print("Food data command is not available yet")
|
||||
return
|
||||
end
|
||||
local trimmed = string.gsub(tostring(limitText or ""), "^%s+", "")
|
||||
trimmed = string.gsub(trimmed, "%s+$", "")
|
||||
if string.lower(trimmed) == "purge" then
|
||||
if type(FOM_PruneCollectedFoodData) ~= "function" then
|
||||
MTH:Print("Food data purge is not available yet")
|
||||
return
|
||||
end
|
||||
local removed = tonumber(FOM_PruneCollectedFoodData()) or 0
|
||||
MTH:Print("Food data purge removed rows: " .. tostring(removed))
|
||||
return
|
||||
end
|
||||
if trimmed == "" then
|
||||
FOM_PrintCollectedFoodData(nil)
|
||||
return
|
||||
end
|
||||
local limit = tonumber(trimmed)
|
||||
if not limit then
|
||||
MTH:Print("Usage: /mth food [limit|purge]")
|
||||
return
|
||||
end
|
||||
FOM_PrintCollectedFoodData(limit)
|
||||
end
|
||||
|
||||
if type(MTH_PS_ScanNow) ~= "function" then
|
||||
function MTH_PS_ScanNow(trigger)
|
||||
local ok, count = MTH_CommandPetSpellScanFallback()
|
||||
@@ -282,23 +310,130 @@ function SlashCmdList.MTH(msg, editbox)
|
||||
msg = string.gsub(tostring(msg), "^%s+", "")
|
||||
msg = string.gsub(msg, "%s+$", "")
|
||||
local lowerMsg = string.lower(msg)
|
||||
local _, _, lowerCmd, lowerArg = string.find(lowerMsg, "^(%S+)%s*(.-)%s*$")
|
||||
if msg == "" then
|
||||
MTH:Print("Available: /mth options, /mth book")
|
||||
elseif lowerMsg == "err" or lowerMsg == "errors" or lowerMsg == "debug" then
|
||||
if MTH_DebugFrame and MTH_DebugFrame.Toggle then
|
||||
MTH_DebugFrame:Toggle()
|
||||
else
|
||||
MTH:Print("Debug frame is not available.")
|
||||
end
|
||||
elseif lowerMsg == "options" then
|
||||
MTH_CommandOptions()
|
||||
elseif lowerMsg == "book" or lowerMsg == "hunterbook" then
|
||||
MTH_CommandBook()
|
||||
elseif lowerMsg == "peers" or lowerMsg == "who" then
|
||||
MTH_CommandPeers()
|
||||
elseif lowerMsg == "err" then
|
||||
if MTH_DebugFrame and type(MTH_DebugFrame.Toggle) == "function" then
|
||||
MTH_DebugFrame:Toggle()
|
||||
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("Debug frame is not available yet")
|
||||
MTH:Print("Beast Lore Scan: |cffffff00/mth bls reset|r — wipe all recorded beast data")
|
||||
end
|
||||
else
|
||||
MTH:Print("Unknown command: " .. tostring(msg))
|
||||
MTH:Print("Available: /mth options, /mth book")
|
||||
MTH:Print("Available: /mth options, /mth book, /mth npcid, /mth bls reset")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+7
-10
@@ -29,7 +29,7 @@ function MTH_DebugFrame:Initialize()
|
||||
self.initialized = true
|
||||
|
||||
-- Create main frame
|
||||
self.frame = CreateFrame("Frame", "MTH_DebugFrameWindow", UIParent)
|
||||
self.frame = CreateFrame("Frame", "MTH_DebugWindow", UIParent)
|
||||
self.frame:SetWidth(800)
|
||||
self.frame:SetHeight(400)
|
||||
self.frame:SetPoint("CENTER", UIParent, "CENTER")
|
||||
@@ -51,13 +51,13 @@ function MTH_DebugFrame:Initialize()
|
||||
if UISpecialFrames then
|
||||
local already = false
|
||||
for i = 1, table.getn(UISpecialFrames) do
|
||||
if UISpecialFrames[i] == "MTH_DebugFrameWindow" then
|
||||
if UISpecialFrames[i] == "MTH_DebugWindow" then
|
||||
already = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not already then
|
||||
table.insert(UISpecialFrames, "MTH_DebugFrameWindow")
|
||||
table.insert(UISpecialFrames, "MTH_DebugWindow")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -91,7 +91,7 @@ function MTH_DebugFrame:Initialize()
|
||||
copyButton:SetScript("OnClick", function() MTH_DebugFrame:SelectAllText() end)
|
||||
|
||||
-- Scroll frame + text content with proper vertical scrollbar
|
||||
self.scrollFrame = CreateFrame("ScrollFrame", "MTH_DebugScrollFrame", self.frame, "UIPanelScrollFrameTemplate")
|
||||
self.scrollFrame = CreateFrame("ScrollFrame", "MTH_DebugScroll", self.frame, "UIPanelScrollFrameTemplate")
|
||||
self.scrollFrame:SetPoint("TOPLEFT", self.frame, "TOPLEFT", 15, -50)
|
||||
self.scrollFrame:SetPoint("BOTTOMRIGHT", self.frame, "BOTTOMRIGHT", -35, 45)
|
||||
|
||||
@@ -366,16 +366,13 @@ MTH_DebugFrame.UninstallHooks = MTH_DF_UninstallHooks
|
||||
-- Event listener for addon load
|
||||
local eventFrame = CreateFrame("Frame")
|
||||
eventFrame:RegisterEvent("ADDON_LOADED")
|
||||
eventFrame:SetScript("OnEvent", function(self, event, addonName)
|
||||
if event == "ADDON_LOADED" and addonName == "MetaHunt" then
|
||||
eventFrame:SetScript("OnEvent", function()
|
||||
if event == "ADDON_LOADED" and arg1 == "MetaHunt" then
|
||||
if MTH and MTH.GetConfig then
|
||||
MTH_DF_SetGlobalCaptureEnabled(MTH:GetConfig("debug", "globalErrorCapture", false))
|
||||
end
|
||||
MTH_DF_InstallHooks()
|
||||
MTH_DebugFrame:Initialize()
|
||||
if MTH and MTH.Print then
|
||||
local mode = MTH_DF_IsGlobalCaptureEnabled() and "legacy-global" or "safe-local"
|
||||
MTH:Print("=== MetaHunt Debug Frame Initialized (" .. mode .. ") ===", "debug")
|
||||
end
|
||||
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -0,0 +1,404 @@
|
||||
-- hunterbook-model-viewer.lua
|
||||
-- Embeds a small 3D creature skin preview at the bottom of the Beast Lore /
|
||||
-- Abilities inspector. Clicking it opens a larger draggable popup with
|
||||
-- < / > navigation through all skin variants of the selected family.
|
||||
--
|
||||
-- Uses MTH_DS_BeastSkins[familyName] generated by .tools/generators/gen_beast_skins.py
|
||||
-- Skin rendering: PlayerModel:SetUnit(CreatureDisplayInfo.ID)
|
||||
|
||||
local MTH_MV = {
|
||||
inited = false,
|
||||
family = nil,
|
||||
skins = {},
|
||||
index = 1,
|
||||
facing = 0.6,
|
||||
rotating = false,
|
||||
rotateLastX = 0,
|
||||
keepPopup = false,
|
||||
skinBeastRows = {},
|
||||
skinListEmpty = nil,
|
||||
-- small preview (parented to book frame, anchored below MTH_BOOK_DetailBackdrop)
|
||||
previewFrame = nil,
|
||||
previewModel = nil,
|
||||
-- popup
|
||||
popup = nil,
|
||||
popupModel = nil,
|
||||
popupTitle = nil,
|
||||
popupSkinLabel = nil,
|
||||
}
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Internal
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
local function MTH_MV_ApplyModel(model, skinId)
|
||||
if not model or not skinId then
|
||||
return
|
||||
end
|
||||
model:SetUnit(skinId)
|
||||
model:SetPosition(0, 0, 0)
|
||||
model:SetModelScale(1)
|
||||
local useFacing = (MTH_MV.popupModel ~= nil and model == MTH_MV.popupModel)
|
||||
model:SetFacing(useFacing and MTH_MV.facing or 0.6)
|
||||
end
|
||||
|
||||
local MTH_MV_BuildSkinBeastList -- forward declaration
|
||||
|
||||
local function MTH_MV_DisplayCurrent()
|
||||
local skin = MTH_MV.skins[MTH_MV.index]
|
||||
if not skin then return end
|
||||
local n = table.getn(MTH_MV.skins)
|
||||
|
||||
MTH_MV_ApplyModel(MTH_MV.previewModel, skin.id)
|
||||
MTH_MV_ApplyModel(MTH_MV.popupModel, skin.id)
|
||||
|
||||
local indexStr = tostring(MTH_MV.index) .. " / " .. tostring(n)
|
||||
if MTH_MV.popupSkinLabel then
|
||||
MTH_MV.popupSkinLabel:SetText(indexStr .. " · " .. tostring(skin.tex or ""))
|
||||
end
|
||||
MTH_MV_BuildSkinBeastList(skin.id)
|
||||
end
|
||||
|
||||
MTH_MV_BuildSkinBeastList = function(skinId)
|
||||
for i = 1, table.getn(MTH_MV.skinBeastRows) do
|
||||
MTH_MV.skinBeastRows[i]:Hide()
|
||||
end
|
||||
if MTH_MV.skinListEmpty then MTH_MV.skinListEmpty:Hide() end
|
||||
if not skinId or not MTH_DS_Beasts then return end
|
||||
|
||||
local matches = {}
|
||||
for npcId, beast in pairs(MTH_DS_Beasts) do
|
||||
if type(beast) == "table" and beast.skinId == skinId then
|
||||
local nm = (MTH and MTH.GetLocalizedBeastName and MTH:GetLocalizedBeastName(npcId, beast.name)) or beast.name
|
||||
table.insert(matches, { id = npcId, name = nm or "?", lvl = tostring(beast.lvl or "?") })
|
||||
end
|
||||
end
|
||||
table.sort(matches, function(a, b) return (a.name or "") < (b.name or "") end)
|
||||
|
||||
local maxRows = table.getn(MTH_MV.skinBeastRows)
|
||||
local shown = 0
|
||||
for i = 1, table.getn(matches) do
|
||||
if shown >= maxRows then break end
|
||||
shown = shown + 1
|
||||
local row = MTH_MV.skinBeastRows[shown]
|
||||
row._npcId = matches[i].id
|
||||
row.nameText:SetText(matches[i].name)
|
||||
row.lvlText:SetText(matches[i].lvl)
|
||||
row:Show()
|
||||
end
|
||||
if shown == 0 and MTH_MV.skinListEmpty then
|
||||
MTH_MV.skinListEmpty:Show()
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_MV_Init()
|
||||
if MTH_MV.inited then return end
|
||||
local backdrop = getglobal("MTH_BOOK_DetailBackdrop")
|
||||
if not backdrop then
|
||||
return
|
||||
end
|
||||
MTH_MV.inited = true
|
||||
|
||||
-- ----------------------------------------------------------------
|
||||
-- Model preview container (sibling of inspector, full column width)
|
||||
-- Hardcoded offset from book frame TOPLEFT: x=608 (right column),
|
||||
-- y = -(166 inspector_top + 178 inspector_h + 6 gap) = -350
|
||||
-- ----------------------------------------------------------------
|
||||
local bookFrame = backdrop:GetParent()
|
||||
MTH_MV.previewFrame = CreateFrame("Frame", "MTH_BOOK_SkinPreview", bookFrame)
|
||||
MTH_MV.previewFrame:SetWidth(136)
|
||||
MTH_MV.previewFrame:SetHeight(136)
|
||||
MTH_MV.previewFrame:SetPoint("TOPLEFT", bookFrame, "TOPLEFT", 608, -384)
|
||||
MTH_MV.previewFrame:SetBackdrop({
|
||||
bgFile = "Interface\\Buttons\\WHITE8X8",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 12,
|
||||
insets = {left = 3, right = 3, top = 3, bottom = 3},
|
||||
})
|
||||
MTH_MV.previewFrame:SetBackdropColor(0, 0, 0, 0.7)
|
||||
MTH_MV.previewFrame:SetBackdropBorderColor(0.35, 0.35, 0.35, 0.8)
|
||||
MTH_MV.previewFrame:Hide()
|
||||
|
||||
-- PlayerModel fills the inner area
|
||||
MTH_MV.previewModel = CreateFrame("PlayerModel", nil, MTH_MV.previewFrame)
|
||||
MTH_MV.previewModel:SetPoint("TOPLEFT", MTH_MV.previewFrame, "TOPLEFT", 3, -3)
|
||||
MTH_MV.previewModel:SetPoint("BOTTOMRIGHT", MTH_MV.previewFrame, "BOTTOMRIGHT", -3, 3)
|
||||
|
||||
-- Invisible click overlay → opens popup
|
||||
local previewBtn = CreateFrame("Button", nil, MTH_MV.previewFrame)
|
||||
previewBtn:SetAllPoints(MTH_MV.previewFrame)
|
||||
previewBtn:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
|
||||
previewBtn:SetScript("OnClick", function()
|
||||
MTH_BOOK_ModelViewer_OpenPopup()
|
||||
end)
|
||||
previewBtn:SetScript("OnEnter", function()
|
||||
GameTooltip:SetOwner(MTH_MV.previewFrame, "ANCHOR_LEFT")
|
||||
GameTooltip:AddLine("Click to open skin viewer", 1, 1, 1)
|
||||
GameTooltip:Show()
|
||||
end)
|
||||
previewBtn:SetScript("OnLeave", function()
|
||||
GameTooltip:Hide()
|
||||
end)
|
||||
|
||||
-- ----------------------------------------------------------------
|
||||
-- Popup frame (wider: left side = model viewer, right = beast list)
|
||||
-- ----------------------------------------------------------------
|
||||
local popup = CreateFrame("Frame", "MTH_BOOK_ModelPopup", UIParent)
|
||||
popup:SetWidth(490)
|
||||
popup:SetHeight(320)
|
||||
popup:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
|
||||
popup:SetFrameStrata("TOOLTIP")
|
||||
popup:SetToplevel(true)
|
||||
popup:SetMovable(true)
|
||||
popup:EnableMouse(true)
|
||||
popup:RegisterForDrag("LeftButton")
|
||||
popup:SetScript("OnDragStart", function() this:StartMoving() end)
|
||||
popup:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
|
||||
popup:SetScript("OnHide", function() MTH_MV.rotating = false end)
|
||||
popup:Hide()
|
||||
popup:SetBackdrop({
|
||||
bgFile = "Interface\\Buttons\\WHITE8X8",
|
||||
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
|
||||
tile = true, tileSize = 32, edgeSize = 32,
|
||||
insets = {left = 11, right = 12, top = 12, bottom = 11},
|
||||
})
|
||||
popup:SetBackdropColor(0.05, 0.05, 0.08, 0.95)
|
||||
|
||||
-- Large model background (left side, x=20)
|
||||
local modelBg = CreateFrame("Frame", nil, popup)
|
||||
modelBg:SetWidth(224)
|
||||
modelBg:SetHeight(226)
|
||||
modelBg:SetPoint("TOPLEFT", popup, "TOPLEFT", 20, -42)
|
||||
modelBg:SetBackdrop({
|
||||
bgFile = "Interface\\Buttons\\WHITE8X8",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 12,
|
||||
insets = {left = 3, right = 3, top = 3, bottom = 3},
|
||||
})
|
||||
modelBg:SetBackdropColor(0, 0, 0, 0.85)
|
||||
modelBg:SetBackdropBorderColor(0.35, 0.35, 0.35, 0.9)
|
||||
|
||||
MTH_MV.popupModel = CreateFrame("PlayerModel", "MTH_BOOK_ModelPopupModel", modelBg)
|
||||
MTH_MV.popupModel:SetPoint("TOPLEFT", modelBg, "TOPLEFT", 3, -3)
|
||||
MTH_MV.popupModel:SetPoint("BOTTOMRIGHT", modelBg, "BOTTOMRIGHT", -3, 3)
|
||||
|
||||
-- Mouse rotation: drag on the black model area rotates; outside drags the popup
|
||||
MTH_MV.popupModel:EnableMouse(true)
|
||||
MTH_MV.popupModel:SetScript("OnMouseDown", function()
|
||||
MTH_MV.rotating = true
|
||||
MTH_MV.rotateLastX = GetCursorPosition()
|
||||
end)
|
||||
MTH_MV.popupModel:SetScript("OnMouseUp", function()
|
||||
MTH_MV.rotating = false
|
||||
end)
|
||||
MTH_MV.popupModel:SetScript("OnUpdate", function()
|
||||
if not MTH_MV.rotating then return end
|
||||
local cx = GetCursorPosition()
|
||||
local dx = cx - MTH_MV.rotateLastX
|
||||
MTH_MV.rotateLastX = cx
|
||||
if dx ~= 0 then
|
||||
MTH_MV.facing = MTH_MV.facing - dx * 0.03
|
||||
MTH_MV.popupModel:SetFacing(MTH_MV.facing)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Title (family name) anchored above the model
|
||||
MTH_MV.popupTitle = popup:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
MTH_MV.popupTitle:SetPoint("TOP", modelBg, "TOP", 0, 18)
|
||||
MTH_MV.popupTitle:SetTextColor(1, 0.82, 0)
|
||||
MTH_MV.popupTitle:SetText("Skin Viewer")
|
||||
|
||||
-- Close [X] button
|
||||
local closeBtn = CreateFrame("Button", nil, popup)
|
||||
closeBtn:SetWidth(22)
|
||||
closeBtn:SetHeight(22)
|
||||
closeBtn:SetPoint("TOPRIGHT", popup, "TOPRIGHT", -10, -10)
|
||||
closeBtn:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
|
||||
local closeLbl = closeBtn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
closeLbl:SetAllPoints(closeBtn)
|
||||
closeLbl:SetText("X")
|
||||
closeLbl:SetTextColor(0.9, 0.9, 0.9)
|
||||
closeBtn:SetScript("OnClick", function() this:GetParent():Hide() end)
|
||||
|
||||
-- "Unique Appearance" badge removed (inline texture syntax unsupported in this client)
|
||||
|
||||
-- Nav: ◀ label ▶ (kept within the left 264px area)
|
||||
local prevBtn = CreateFrame("Button", nil, popup, "UIPanelButtonTemplate")
|
||||
prevBtn:SetWidth(28)
|
||||
prevBtn:SetHeight(20)
|
||||
prevBtn:SetPoint("BOTTOMLEFT", popup, "BOTTOMLEFT", 14, 14)
|
||||
prevBtn:SetText("<")
|
||||
prevBtn:SetScript("OnClick", function()
|
||||
local n = table.getn(MTH_MV.skins)
|
||||
if n < 1 then return end
|
||||
MTH_MV.index = MTH_MV.index - 1
|
||||
if MTH_MV.index < 1 then MTH_MV.index = n end
|
||||
MTH_MV_DisplayCurrent()
|
||||
end)
|
||||
|
||||
local nextBtn = CreateFrame("Button", nil, popup, "UIPanelButtonTemplate")
|
||||
nextBtn:SetWidth(28)
|
||||
nextBtn:SetHeight(20)
|
||||
nextBtn:SetPoint("BOTTOMLEFT", popup, "BOTTOMLEFT", 222, 14)
|
||||
nextBtn:SetText(">")
|
||||
nextBtn:SetScript("OnClick", function()
|
||||
local n = table.getn(MTH_MV.skins)
|
||||
if n < 1 then return end
|
||||
MTH_MV.index = MTH_MV.index + 1
|
||||
if MTH_MV.index > n then MTH_MV.index = 1 end
|
||||
MTH_MV_DisplayCurrent()
|
||||
end)
|
||||
|
||||
MTH_MV.popupSkinLabel = popup:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
|
||||
MTH_MV.popupSkinLabel:SetPoint("BOTTOMLEFT", prevBtn, "BOTTOMRIGHT", 4, 0)
|
||||
MTH_MV.popupSkinLabel:SetPoint("BOTTOMRIGHT", nextBtn, "BOTTOMLEFT", -4, 0)
|
||||
MTH_MV.popupSkinLabel:SetJustifyH("CENTER")
|
||||
MTH_MV.popupSkinLabel:SetTextColor(0.9, 0.9, 0.9)
|
||||
|
||||
-- ---------------------------------------------------------------
|
||||
-- Right panel: vertical divider + beast list
|
||||
-- ---------------------------------------------------------------
|
||||
local divider = popup:CreateTexture(nil, "ARTWORK")
|
||||
divider:SetTexture("Interface\\Buttons\\WHITE8X8")
|
||||
divider:SetVertexColor(0.35, 0.35, 0.35, 0.8)
|
||||
divider:SetPoint("TOPLEFT", popup, "TOPLEFT", 270, -36)
|
||||
divider:SetPoint("BOTTOMLEFT", popup, "BOTTOMLEFT", 270, 12)
|
||||
divider:SetWidth(1)
|
||||
|
||||
local listHeader = popup:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
|
||||
listHeader:SetPoint("TOPLEFT", popup, "TOPLEFT", 278, -18)
|
||||
listHeader:SetTextColor(1, 0.82, 0)
|
||||
listHeader:SetText("Beasts with this skin")
|
||||
|
||||
local listSep = popup:CreateTexture(nil, "ARTWORK")
|
||||
listSep:SetTexture("Interface\\Buttons\\WHITE8X8")
|
||||
listSep:SetVertexColor(0.35, 0.35, 0.35, 0.6)
|
||||
listSep:SetPoint("TOPLEFT", popup, "TOPLEFT", 278, -30)
|
||||
listSep:SetPoint("TOPRIGHT", popup, "TOPRIGHT", -10, -30)
|
||||
listSep:SetHeight(1)
|
||||
|
||||
MTH_MV.skinListEmpty = popup:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
|
||||
MTH_MV.skinListEmpty:SetPoint("TOPLEFT", popup, "TOPLEFT", 278, -38)
|
||||
MTH_MV.skinListEmpty:SetTextColor(0.5, 0.5, 0.5)
|
||||
MTH_MV.skinListEmpty:SetText("\226\128\148")
|
||||
MTH_MV.skinListEmpty:Hide()
|
||||
|
||||
-- Beast rows (14 max)
|
||||
local ROW_X = 278
|
||||
local ROW_START = -36
|
||||
local ROW_H = 17
|
||||
local MAX_ROWS = 14
|
||||
for i = 1, MAX_ROWS do
|
||||
local row = CreateFrame("Button", nil, popup)
|
||||
row:SetPoint("TOPLEFT", popup, "TOPLEFT", ROW_X, ROW_START - (i - 1) * ROW_H)
|
||||
row:SetWidth(200)
|
||||
row:SetHeight(ROW_H - 1)
|
||||
row._npcId = nil
|
||||
|
||||
local hl = row:CreateTexture(nil, "HIGHLIGHT")
|
||||
hl:SetAllPoints(row)
|
||||
hl:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
|
||||
hl:SetBlendMode("ADD")
|
||||
hl:SetAlpha(0.35)
|
||||
|
||||
row.nameText = row:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
||||
row.nameText:SetPoint("LEFT", row, "LEFT", 0, 0)
|
||||
row.nameText:SetWidth(158)
|
||||
row.nameText:SetJustifyH("LEFT")
|
||||
|
||||
row.lvlText = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
|
||||
row.lvlText:SetPoint("LEFT", row, "LEFT", 160, 0)
|
||||
row.lvlText:SetWidth(38)
|
||||
row.lvlText:SetJustifyH("LEFT")
|
||||
row.lvlText:SetTextColor(0.7, 0.7, 0.7)
|
||||
|
||||
row:SetScript("OnClick", function()
|
||||
if this._npcId and type(MTH_BOOK_JumpToBeastById) == "function" then
|
||||
MTH_MV.keepPopup = true
|
||||
MTH_BOOK_JumpToBeastById(this._npcId)
|
||||
MTH_MV.keepPopup = false
|
||||
end
|
||||
end)
|
||||
row:Hide()
|
||||
MTH_MV.skinBeastRows[i] = row
|
||||
end
|
||||
|
||||
MTH_MV.popup = popup
|
||||
end
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Public API
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
function MTH_BOOK_ModelViewer_SetFamily(family, skinId)
|
||||
MTH_MV_Init()
|
||||
if not MTH_MV.inited then return end
|
||||
local skins = MTH_DS_BeastSkins and type(MTH_DS_BeastSkins) == "table" and MTH_DS_BeastSkins[family]
|
||||
if not skins or table.getn(skins) == 0 then
|
||||
MTH_BOOK_ModelViewer_Clear()
|
||||
return
|
||||
end
|
||||
|
||||
-- Filter to only skins used by at least one tameable beast
|
||||
local usedSkinIds = {}
|
||||
if MTH_DS_Beasts then
|
||||
for _, beast in pairs(MTH_DS_Beasts) do
|
||||
if type(beast) == "table" and beast.skinId then
|
||||
usedSkinIds[beast.skinId] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
local filteredSkins = {}
|
||||
for i = 1, table.getn(skins) do
|
||||
if usedSkinIds[skins[i].id] then
|
||||
table.insert(filteredSkins, skins[i])
|
||||
end
|
||||
end
|
||||
if table.getn(filteredSkins) == 0 then
|
||||
MTH_BOOK_ModelViewer_Clear()
|
||||
return
|
||||
end
|
||||
|
||||
MTH_MV.family = family
|
||||
MTH_MV.skins = filteredSkins
|
||||
MTH_MV.facing = 0.6
|
||||
|
||||
-- If we have a specific skinId, jump to the matching skin entry.
|
||||
MTH_MV.index = 1
|
||||
if skinId then
|
||||
for i = 1, table.getn(filteredSkins) do
|
||||
if filteredSkins[i].id == skinId then
|
||||
MTH_MV.index = i
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if MTH_MV.popupTitle then
|
||||
MTH_MV.popupTitle:SetText(tostring(family) .. " — Skins")
|
||||
end
|
||||
|
||||
MTH_MV_DisplayCurrent()
|
||||
|
||||
if MTH_MV.previewFrame then MTH_MV.previewFrame:Show() end
|
||||
MTH_MV_DisplayCurrent()
|
||||
end
|
||||
|
||||
function MTH_BOOK_ModelViewer_Clear()
|
||||
if MTH_MV.previewFrame then MTH_MV.previewFrame:Hide() end
|
||||
if not MTH_MV.keepPopup then
|
||||
if MTH_MV.popup and MTH_MV.popup:IsShown() then MTH_MV.popup:Hide() end
|
||||
end
|
||||
MTH_MV.family = nil
|
||||
MTH_MV.skins = {}
|
||||
MTH_MV.index = 1
|
||||
end
|
||||
|
||||
function MTH_BOOK_ModelViewer_OpenPopup()
|
||||
MTH_MV_Init()
|
||||
if not MTH_MV.popup then return end
|
||||
if table.getn(MTH_MV.skins) == 0 then return end
|
||||
MTH_MV.popup:Show()
|
||||
MTH_MV.popup:Raise()
|
||||
MTH_MV_DisplayCurrent()
|
||||
end
|
||||
@@ -2,17 +2,18 @@ if type(MTH_HUNTERBOOK_TABS) ~= "table" then MTH_HUNTERBOOK_TABS = {} end
|
||||
|
||||
MTH_HUNTERBOOK_TABS.pets = {
|
||||
headerLabel = "Beasts",
|
||||
columnLabels = { "ID", "Lvl", "Family", "Name", "Abilities", "Zone", "R", "E", "U" },
|
||||
columnLabels = { "ID", "Lvl", "Fam", "Name", "Abilities", "Zone", "R", "E", "U", "AS" },
|
||||
columnLayout = {
|
||||
{ x = 8, width = 28, align = "LEFT" },
|
||||
{ x = 38, width = 30, align = "LEFT" },
|
||||
{ x = 68, width = 74, align = "LEFT" },
|
||||
{ x = 142, width = 130, align = "LEFT" },
|
||||
{ x = 272, width = 180, align = "LEFT" },
|
||||
{ x = 452, width = 68, align = "LEFT" },
|
||||
{ x = 520, width = 10, align = "CENTER" },
|
||||
{ x = 532, width = 10, align = "CENTER" },
|
||||
{ x = 544, width = 10, align = "CENTER" },
|
||||
{ x = 68, width = 18, align = "LEFT" },
|
||||
{ x = 88, width = 130, align = "LEFT" },
|
||||
{ x = 220, width = 148, align = "LEFT" },
|
||||
{ x = 370, width = 80, align = "LEFT" },
|
||||
{ x = 452, width = 14, align = "CENTER" },
|
||||
{ x = 468, width = 14, align = "CENTER" },
|
||||
{ x = 484, width = 14, align = "CENTER" },
|
||||
{ x = 500, width = 54, align = "LEFT" },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -28,13 +29,31 @@ function MTH_BOOK_GetBeastZoneSummary(beast)
|
||||
return "-"
|
||||
end
|
||||
|
||||
local seen = {}
|
||||
local zoneNames = {}
|
||||
-- Count coords per WMA zone ID to find the dominant zone.
|
||||
local coordCount = {}
|
||||
for i = 1, table.getn(beast.coords) do
|
||||
local c = beast.coords[i]
|
||||
if c and c[3] and not seen[c[3]] then
|
||||
seen[c[3]] = true
|
||||
table.insert(zoneNames, MTH_BOOK_GetZoneName(c[3]))
|
||||
if c and c[3] then
|
||||
local zid = c[3]
|
||||
coordCount[zid] = (coordCount[zid] or 0) + 1
|
||||
end
|
||||
end
|
||||
local zids = {}
|
||||
for zid, _ in pairs(coordCount) do
|
||||
table.insert(zids, zid)
|
||||
end
|
||||
-- Sort by frequency descending so the zone with most spawns is listed first.
|
||||
table.sort(zids, function(a, b)
|
||||
return (coordCount[a] or 0) > (coordCount[b] or 0)
|
||||
end)
|
||||
-- Resolve to zone names, deduplicating by name (multiple WMA IDs can resolve to the same zone).
|
||||
local seenNames = {}
|
||||
local zoneNames = {}
|
||||
for i = 1, table.getn(zids) do
|
||||
local name = MTH_BOOK_GetZoneName(zids[i])
|
||||
if name and not seenNames[name] then
|
||||
seenNames[name] = true
|
||||
table.insert(zoneNames, name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -67,6 +86,69 @@ function MTH_BOOK_SplitAbilities(text)
|
||||
return out
|
||||
end
|
||||
|
||||
local _subzoneChildCache = nil
|
||||
|
||||
local function MTH_BOOK_EnsureSubzoneCache()
|
||||
if _subzoneChildCache then return end
|
||||
_subzoneChildCache = {}
|
||||
if not MTH_DS_Zones then return end
|
||||
for zid, row in pairs(MTH_DS_Zones) do
|
||||
local parent = row.parent
|
||||
local x1 = row.x1
|
||||
local y1 = row.y1
|
||||
local w = row.width
|
||||
local h = row.height
|
||||
if parent and x1 and y1 and w and h then
|
||||
local names = row.names
|
||||
local name = names and (names.enUS or names[GetLocale and GetLocale() or "enUS"] or names.deDE)
|
||||
if name then
|
||||
if not _subzoneChildCache[parent] then
|
||||
_subzoneChildCache[parent] = {}
|
||||
end
|
||||
table.insert(_subzoneChildCache[parent], { x1, y1, x1 + w, y1 + h, name })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_BOOK_GetBeastSubZoneSummary(beast)
|
||||
if not beast or not beast.coords or table.getn(beast.coords) == 0 then return nil end
|
||||
MTH_BOOK_EnsureSubzoneCache()
|
||||
if not _subzoneChildCache then return nil end
|
||||
|
||||
local counts = {}
|
||||
for i = 1, table.getn(beast.coords) do
|
||||
local c = beast.coords[i]
|
||||
if c then
|
||||
local cx, cy, wmaId = c[1], c[2], c[3]
|
||||
if cx and cy and wmaId then
|
||||
local pfqId = wmaId
|
||||
if type(MTH_MAP_WMA_TO_PFQ) == "table" then
|
||||
pfqId = MTH_MAP_WMA_TO_PFQ[wmaId] or wmaId
|
||||
end
|
||||
local children = _subzoneChildCache[pfqId]
|
||||
if children then
|
||||
for _, sub in ipairs(children) do
|
||||
if cx >= sub[1] and cx <= sub[3] and cy >= sub[2] and cy <= sub[4] then
|
||||
counts[sub[5]] = (counts[sub[5]] or 0) + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local bestName, bestCount = nil, 0
|
||||
for name, count in pairs(counts) do
|
||||
if count > bestCount then
|
||||
bestName = name
|
||||
bestCount = count
|
||||
end
|
||||
end
|
||||
return bestName
|
||||
end
|
||||
|
||||
function MTH_BOOK_HasUsableAbilities(beast)
|
||||
if not beast then return false end
|
||||
local abilities = MTH_BOOK_SplitAbilities(beast.abilities)
|
||||
@@ -231,8 +313,11 @@ function MTH_BOOK_BeastMatches(beastId, beast)
|
||||
end
|
||||
|
||||
if MTH_BOOK_STATE.petInZoneOnly then
|
||||
local currentZoneId = MTH_BOOK_GetCurrentZoneId()
|
||||
if currentZoneId and not MTH_BOOK_BeastHasZoneId(beast, currentZoneId) then
|
||||
-- Use the zone ID cached once per BuildResults call (avoids N calls to
|
||||
-- GetCurrentZoneId which is expensive). If zone ID is nil (new/unknown
|
||||
-- zone like Moonwhisper Coast), no DB entry can match — exclude all.
|
||||
local currentZoneId = MTH_BOOK_STATE._cachedZoneId
|
||||
if not currentZoneId or not MTH_BOOK_BeastHasZoneId(beast, currentZoneId) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
@@ -250,6 +335,12 @@ function MTH_BOOK_BeastMatches(beastId, beast)
|
||||
end
|
||||
end
|
||||
|
||||
if MTH_BOOK_STATE.petZoneFilter and MTH_BOOK_STATE.petZoneFilter ~= "all" then
|
||||
if not MTH_BOOK_BeastHasZoneId(beast, MTH_BOOK_STATE.petZoneFilter) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -257,7 +348,7 @@ function MTH_BOOK_BeastSort(a, b)
|
||||
local beasts = MTH_DS_Beasts
|
||||
local ba = beasts and beasts[a]
|
||||
local bb = beasts and beasts[b]
|
||||
if not ba or not bb then return a < b end
|
||||
if not ba or not bb then return tostring(a) < tostring(b) end
|
||||
local la = MTH_BOOK_ParseLevel(ba.lvl) or 0
|
||||
local lb = MTH_BOOK_ParseLevel(bb.lvl) or 0
|
||||
if la ~= lb then return la < lb end
|
||||
|
||||
@@ -7,13 +7,12 @@ MTH_HUNTERBOOK_TABS.families = {
|
||||
{ x = 10, width = 106, align = "LEFT" },
|
||||
{ x = 122, width = 52, align = "LEFT" },
|
||||
{ x = 176, width = 52, align = "LEFT" },
|
||||
{ x = 232, width = 292, align = "LEFT" },
|
||||
{ x = 460, width = 184, align = "LEFT" },
|
||||
{ x = 232, width = 364, align = "LEFT" },
|
||||
{ x = 532, width = 112, align = "LEFT" },
|
||||
},
|
||||
}
|
||||
|
||||
local function MTH_BOOKTAB_FamiliesTrace(message)
|
||||
return
|
||||
end
|
||||
|
||||
local function MTH_BOOKTAB_FamiliesSafeLower(value)
|
||||
@@ -27,6 +26,11 @@ local function MTH_BOOKTAB_FamiliesTrim(value)
|
||||
return text
|
||||
end
|
||||
|
||||
local function MTH_BOOKTAB_ShouldDisplayAllDiet(familyName)
|
||||
local token = MTH_BOOKTAB_FamiliesSafeLower(MTH_BOOKTAB_FamiliesTrim(familyName))
|
||||
return token == "bears" or token == "boars"
|
||||
end
|
||||
|
||||
local function MTH_BOOKTAB_FindAbilityBundle(abilityName)
|
||||
if not (MTH_DS_PetSpells and type(MTH_DS_PetSpells.byAbility) == "table") then
|
||||
return nil
|
||||
@@ -78,6 +82,7 @@ function MTH_BOOKTAB_BuildFamiliesRows()
|
||||
|
||||
for familyName, familyRow in pairs(families) do
|
||||
if type(familyRow) == "table" then
|
||||
MTH_BOOKTAB_FamiliesTrace("BUILD " .. tostring(familyName) .. " icon=" .. tostring(familyRow.icon))
|
||||
local abilities = {}
|
||||
local seen = {}
|
||||
|
||||
@@ -95,25 +100,49 @@ function MTH_BOOKTAB_BuildFamiliesRows()
|
||||
if token ~= "" and not seen[token] then
|
||||
seen[token] = true
|
||||
local spellRows = (type(bundle) == "table" and type(bundle.spells) == "table") and bundle.spells or {}
|
||||
local firstAnySpell = nil
|
||||
local firstBeastSpell = nil
|
||||
local rankMin = nil
|
||||
local rankMax = nil
|
||||
local rankMap = {}
|
||||
local beastRankMin = nil
|
||||
local beastRankMax = nil
|
||||
local beastRankMap = {}
|
||||
local anyRankMin = nil
|
||||
local anyRankMax = nil
|
||||
local anyRankMap = {}
|
||||
for s = 1, table.getn(spellRows) do
|
||||
local spell = spellRows[s]
|
||||
if type(spell) == "table" and MTH_BOOKTAB_FamiliesSafeLower(spell.learnMethod or "beast") ~= "trainer" then
|
||||
if not firstBeastSpell then
|
||||
firstBeastSpell = spell
|
||||
if type(spell) == "table" then
|
||||
if not firstAnySpell then
|
||||
firstAnySpell = spell
|
||||
end
|
||||
local rank = tonumber(spell.rankNumber)
|
||||
if rank and rank > 0 then
|
||||
rankMap[rank] = true
|
||||
if not rankMin or rank < rankMin then rankMin = rank end
|
||||
if not rankMax or rank > rankMax then rankMax = rank end
|
||||
anyRankMap[rank] = true
|
||||
if not anyRankMin or rank < anyRankMin then anyRankMin = rank end
|
||||
if not anyRankMax or rank > anyRankMax then anyRankMax = rank end
|
||||
end
|
||||
if MTH_BOOKTAB_FamiliesSafeLower(spell.learnMethod or "beast") ~= "trainer" then
|
||||
if not firstBeastSpell then
|
||||
firstBeastSpell = spell
|
||||
end
|
||||
if rank and rank > 0 then
|
||||
beastRankMap[rank] = true
|
||||
if not beastRankMin or rank < beastRankMin then beastRankMin = rank end
|
||||
if not beastRankMax or rank > beastRankMax then beastRankMax = rank end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local displaySpell = firstBeastSpell or firstAnySpell
|
||||
local rankMap = beastRankMap
|
||||
local rankMin = beastRankMin
|
||||
local rankMax = beastRankMax
|
||||
if not firstBeastSpell then
|
||||
rankMap = anyRankMap
|
||||
rankMin = anyRankMin
|
||||
rankMax = anyRankMax
|
||||
end
|
||||
|
||||
local rankCount = 0
|
||||
for _ in pairs(rankMap) do
|
||||
rankCount = rankCount + 1
|
||||
@@ -123,8 +152,8 @@ function MTH_BOOKTAB_BuildFamiliesRows()
|
||||
name = canonicalMap[token] or canonical,
|
||||
token = token,
|
||||
isUnique = (abilityCounts[token] or 0) == 1,
|
||||
icon = firstBeastSpell and firstBeastSpell.icon or nil,
|
||||
description = firstBeastSpell and firstBeastSpell.description or "",
|
||||
icon = displaySpell and displaySpell.icon or nil,
|
||||
description = displaySpell and displaySpell.description or "",
|
||||
rankMin = rankMin,
|
||||
rankMax = rankMax,
|
||||
rankCount = rankCount,
|
||||
@@ -141,25 +170,32 @@ function MTH_BOOKTAB_BuildFamiliesRows()
|
||||
return MTH_BOOKTAB_FamiliesSafeLower(a.name) < MTH_BOOKTAB_FamiliesSafeLower(b.name)
|
||||
end)
|
||||
|
||||
local dietItems = {}
|
||||
if type(familyRow.food) == "table" then
|
||||
for i = 1, table.getn(familyRow.food) do
|
||||
local food = MTH_BOOKTAB_FamiliesTrim(familyRow.food[i])
|
||||
if food ~= "" then
|
||||
table.insert(dietItems, string.upper(string.sub(food, 1, 1)) .. string.sub(food, 2))
|
||||
local dietText = ""
|
||||
if MTH_BOOKTAB_ShouldDisplayAllDiet(familyName) then
|
||||
dietText = "ALL"
|
||||
else
|
||||
local dietItems = {}
|
||||
if type(familyRow.food) == "table" then
|
||||
for i = 1, table.getn(familyRow.food) do
|
||||
local food = MTH_BOOKTAB_FamiliesTrim(familyRow.food[i])
|
||||
if food ~= "" then
|
||||
table.insert(dietItems, string.upper(string.sub(food, 1, 1)) .. string.sub(food, 2))
|
||||
end
|
||||
end
|
||||
table.sort(dietItems, function(a, b)
|
||||
return MTH_BOOKTAB_FamiliesSafeLower(a) < MTH_BOOKTAB_FamiliesSafeLower(b)
|
||||
end)
|
||||
end
|
||||
table.sort(dietItems, function(a, b)
|
||||
return MTH_BOOKTAB_FamiliesSafeLower(a) < MTH_BOOKTAB_FamiliesSafeLower(b)
|
||||
end)
|
||||
dietText = table.concat(dietItems, ", ")
|
||||
end
|
||||
|
||||
table.insert(results, {
|
||||
family = tostring(familyName),
|
||||
icon = familyRow.icon or nil,
|
||||
named = tonumber(familyRow.named) or 0,
|
||||
coords = tonumber(familyRow.coords) or 0,
|
||||
abilities = abilities,
|
||||
dietText = table.concat(dietItems, ", "),
|
||||
dietText = dietText,
|
||||
})
|
||||
end
|
||||
end
|
||||
@@ -238,7 +274,7 @@ function MTH_BOOKTAB_EnsureFamiliesUI()
|
||||
ui.headerAbilities:SetText("Abilities")
|
||||
|
||||
ui.headerDiet = ui.frame:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
|
||||
ui.headerDiet:SetPoint("TOPLEFT", ui.frame, "TOPLEFT", 460, -2)
|
||||
ui.headerDiet:SetPoint("TOPLEFT", ui.frame, "TOPLEFT", 532, -2)
|
||||
ui.headerDiet:SetTextColor(1.00, 0.82, 0.00)
|
||||
ui.headerDiet:SetText("Diet")
|
||||
|
||||
@@ -254,9 +290,15 @@ function MTH_BOOKTAB_EnsureFamiliesUI()
|
||||
row:SetPoint("TOPRIGHT", ui.rows[i - 1], "BOTTOMRIGHT", 0, -1)
|
||||
end
|
||||
|
||||
row.familyIcon = row:CreateTexture(nil, "ARTWORK")
|
||||
row.familyIcon:SetPoint("LEFT", row, "LEFT", 4, 0)
|
||||
row.familyIcon:SetWidth(16)
|
||||
row.familyIcon:SetHeight(16)
|
||||
row.familyIcon:Hide()
|
||||
|
||||
row.family = row:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
||||
row.family:SetPoint("LEFT", row, "LEFT", 4, 0)
|
||||
row.family:SetWidth(106)
|
||||
row.family:SetPoint("LEFT", row, "LEFT", 24, 0)
|
||||
row.family:SetWidth(88)
|
||||
row.family:SetJustifyH("LEFT")
|
||||
|
||||
row.named = row:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
||||
@@ -270,8 +312,8 @@ function MTH_BOOKTAB_EnsureFamiliesUI()
|
||||
row.coords:SetJustifyH("LEFT")
|
||||
|
||||
row.diet = row:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
||||
row.diet:SetPoint("LEFT", row, "LEFT", 460, 0)
|
||||
row.diet:SetWidth(184)
|
||||
row.diet:SetPoint("LEFT", row, "LEFT", 532, 0)
|
||||
row.diet:SetWidth(112)
|
||||
row.diet:SetJustifyH("LEFT")
|
||||
|
||||
row.abilityButtons = {}
|
||||
@@ -358,11 +400,20 @@ function MTH_BOOKTAB_RenderFamiliesList()
|
||||
if row then
|
||||
rowFrame:Show()
|
||||
rowFrame.family:SetText(tostring(row.family or "-"))
|
||||
local familyIconPath = row.icon and MTH_BOOK_ResolveIconPath and MTH_BOOK_ResolveIconPath(row.icon) or nil
|
||||
MTH_BOOKTAB_FamiliesTrace("RENDER " .. tostring(row.family) .. " icon=" .. tostring(row.icon) .. " path=" .. tostring(familyIconPath))
|
||||
if familyIconPath then
|
||||
rowFrame.familyIcon:SetTexture(familyIconPath)
|
||||
rowFrame.familyIcon:Show()
|
||||
else
|
||||
rowFrame.familyIcon:Hide()
|
||||
end
|
||||
rowFrame.named:SetText(tostring(row.named or 0))
|
||||
rowFrame.coords:SetText(tostring(row.coords or 0))
|
||||
rowFrame.diet:SetText(tostring(row.dietText or "-"))
|
||||
|
||||
local offsetX = 232
|
||||
local abilityMaxRight = 526
|
||||
for b = 1, table.getn(rowFrame.abilityButtons) do
|
||||
local button = rowFrame.abilityButtons[b]
|
||||
local ability = row.abilities and row.abilities[b] or nil
|
||||
@@ -375,17 +426,23 @@ function MTH_BOOKTAB_RenderFamiliesList()
|
||||
button.text:SetText(nameText)
|
||||
local textW = button.text:GetStringWidth() or 40
|
||||
if textW < 24 then textW = 24 end
|
||||
button:SetWidth(14 + textW)
|
||||
button:ClearAllPoints()
|
||||
button:SetPoint("LEFT", rowFrame, "LEFT", offsetX, 0)
|
||||
local iconPath = ability.icon and MTH_BOOK_ResolveIconPath and MTH_BOOK_ResolveIconPath(ability.icon) or nil
|
||||
if iconPath then
|
||||
button.icon:SetTexture(iconPath)
|
||||
local buttonWidth = 14 + textW
|
||||
if (offsetX + buttonWidth) > abilityMaxRight then
|
||||
button.entry = nil
|
||||
button:Hide()
|
||||
else
|
||||
button.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
|
||||
button:SetWidth(buttonWidth)
|
||||
button:ClearAllPoints()
|
||||
button:SetPoint("LEFT", rowFrame, "LEFT", offsetX, 0)
|
||||
local iconPath = ability.icon and MTH_BOOK_ResolveIconPath and MTH_BOOK_ResolveIconPath(ability.icon) or nil
|
||||
if iconPath then
|
||||
button.icon:SetTexture(iconPath)
|
||||
else
|
||||
button.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
|
||||
end
|
||||
button:Show()
|
||||
offsetX = offsetX + button:GetWidth() + 6
|
||||
end
|
||||
button:Show()
|
||||
offsetX = offsetX + button:GetWidth() + 6
|
||||
else
|
||||
button.entry = nil
|
||||
button:Hide()
|
||||
|
||||
@@ -140,7 +140,7 @@ function MTH_BOOK_GetResistanceShortName(nameText)
|
||||
if string.find(lowerName, "arcane", 1, true) then return "AR" end
|
||||
if string.find(lowerName, "nature", 1, true) then return "NR" end
|
||||
if string.find(lowerName, "fire", 1, true) then return "FR" end
|
||||
if string.find(lowerName, "frost", 1, true) then return "FR" end
|
||||
if string.find(lowerName, "frost", 1, true) then return "FrR" end
|
||||
if string.find(lowerName, "shadow", 1, true) then return "SR" end
|
||||
return tostring(nameText or "-")
|
||||
end
|
||||
|
||||
+507
-133
@@ -55,7 +55,7 @@ local function MTH_BOOK_FamiliesTrace(message)
|
||||
end
|
||||
|
||||
local MTH_BOOK_STATE = {
|
||||
mode = "stable",
|
||||
mode = "pets",
|
||||
search = "",
|
||||
quick = "all",
|
||||
minLevel = nil,
|
||||
@@ -69,6 +69,8 @@ local MTH_BOOK_STATE = {
|
||||
petOnlyMyLevel = true,
|
||||
itemOnlyMyLevel = false,
|
||||
petInZoneOnly = false,
|
||||
petContinent = "all",
|
||||
petZoneFilter = "all",
|
||||
itemSubtype = "all",
|
||||
npcFunction = "all",
|
||||
npcZone = "all",
|
||||
@@ -150,7 +152,7 @@ local function MTH_HB_RequireOpenDeps()
|
||||
return true
|
||||
end
|
||||
|
||||
local MTH_BOOK_MAX_COLS = 9
|
||||
local MTH_BOOK_MAX_COLS = 10
|
||||
local MTH_BOOK_MAX_ROWS = 20
|
||||
|
||||
local MTH_BOOK_PetFamilyOptions = {
|
||||
@@ -222,7 +224,8 @@ local MTH_BOOK_CONTENT_LAYOUT_DEFAULT = {
|
||||
detailX = 608,
|
||||
detailY = -166,
|
||||
detailW = 136,
|
||||
detailH = 324,
|
||||
detailH = 208,
|
||||
detailTextH = 192, -- inspector text only; model viewer sits below in its own frame
|
||||
}
|
||||
|
||||
local MTH_BOOK_CONTENT_LAYOUT_ITEMS = {
|
||||
@@ -273,7 +276,7 @@ local MTH_BOOK_CONTENT_LAYOUT_FAMILIES = {
|
||||
listX = 16,
|
||||
listY = -74,
|
||||
listW = 728,
|
||||
listH = 376,
|
||||
listH = 456,
|
||||
detailX = 748,
|
||||
detailY = -74,
|
||||
detailW = 1,
|
||||
@@ -328,7 +331,7 @@ local function MTH_BOOK_ApplyContentLayoutForMode()
|
||||
detailText:ClearAllPoints()
|
||||
detailText:SetPoint("TOPLEFT", detailParent, "TOPLEFT", 6, -6)
|
||||
detailText:SetWidth(layout.detailW - 12)
|
||||
detailText:SetHeight(layout.detailH - 12)
|
||||
detailText:SetHeight(layout.detailTextH or (layout.detailH - 12))
|
||||
end
|
||||
|
||||
local sliderHeight = layout.listH - 32
|
||||
@@ -363,7 +366,7 @@ local function MTH_BOOK_UpdateCheckboxLayoutByMode()
|
||||
getglobal("MTH_BOOK_HideNoAbilities"),
|
||||
getglobal("MTH_BOOK_HideUnknown"),
|
||||
}
|
||||
local xOffsets = { 18, 86, 154, 232, 372 }
|
||||
local xOffsets = { 18, 86, 154, 232, 345 }
|
||||
local yOffset = -140
|
||||
if MTH_BOOK_STATE.mode == "npcs" then
|
||||
yOffset = -116
|
||||
@@ -753,12 +756,15 @@ local function MTH_BOOK_ShowAllFilteredBeastsOnMap()
|
||||
end
|
||||
|
||||
local nodes = {}
|
||||
local firstZoneId = nil
|
||||
for i = 1, table.getn(MTH_BOOK_STATE.results or {}) do
|
||||
local beastId = tonumber(MTH_BOOK_STATE.results[i])
|
||||
local beast = beastId and MTH_DS_Beasts and MTH_DS_Beasts[beastId]
|
||||
if beast and beast.coords then
|
||||
local beastDisplayName = (MTH and MTH.GetLocalizedBeastName and MTH:GetLocalizedBeastName(beastId, beast.name)) or beast.name or "Unknown"
|
||||
local cr, cg, cb = 0.95, 0.82, 0.10
|
||||
if MTH_Map and MTH_Map.GetFamilyColor then
|
||||
cr, cg, cb = MTH_Map:GetFamilyColor(beast.family)
|
||||
end
|
||||
for j = 1, table.getn(beast.coords) do
|
||||
local c = beast.coords[j]
|
||||
if c and c[1] and c[2] and c[3] then
|
||||
@@ -766,9 +772,6 @@ local function MTH_BOOK_ShowAllFilteredBeastsOnMap()
|
||||
local y = tonumber(c[2])
|
||||
local zoneId = tonumber(c[3])
|
||||
if x and y and zoneId then
|
||||
if not firstZoneId then
|
||||
firstZoneId = zoneId
|
||||
end
|
||||
local details = string.format("Family: %s\nLevel: %s\nAbilities: %s", beast.family or "?", beast.lvl or "?", beast.abilities or "None")
|
||||
table.insert(nodes, {
|
||||
zoneId = zoneId,
|
||||
@@ -777,7 +780,7 @@ local function MTH_BOOK_ShowAllFilteredBeastsOnMap()
|
||||
title = string.format("%s (%d)", beastDisplayName, beastId),
|
||||
detail = details,
|
||||
beastId = beastId,
|
||||
color = { 0.95, 0.82, 0.10 },
|
||||
color = { cr, cg, cb },
|
||||
})
|
||||
end
|
||||
end
|
||||
@@ -793,8 +796,11 @@ local function MTH_BOOK_ShowAllFilteredBeastsOnMap()
|
||||
if not MTH_Map:SetSource("focus") then
|
||||
return
|
||||
end
|
||||
if firstZoneId and MTH_Map.OpenWorldMapForZone then
|
||||
MTH_Map:OpenWorldMapForZone(firstZoneId)
|
||||
-- Navigate to the player's current (filter) zone, not the first coord's zone ID
|
||||
-- which may point to a different zone due to multi-zone beast spawn data.
|
||||
local navZoneId = MTH_BOOK_STATE._cachedZoneId
|
||||
if navZoneId and MTH_Map.OpenWorldMapForZone then
|
||||
MTH_Map:OpenWorldMapForZone(navZoneId)
|
||||
end
|
||||
MTH_Map:UpdateWorldMap()
|
||||
MTH_Map:UpdateMinimap()
|
||||
@@ -1002,9 +1008,9 @@ end
|
||||
local function MTH_BOOK_ParseProjectileDPSFromText(text)
|
||||
if type(text) ~= "string" or text == "" then return nil end
|
||||
local lowered = string.lower(text)
|
||||
local raw = string.match(lowered, "adds%s+([%d]+[%.,]?[%d]*)%s+damage%s+per%s+seconds?")
|
||||
local _, _, raw = string.find(lowered, "adds%s+([%d]+[%.,]?[%d]*)%s+damage%s+per%s+seconds?")
|
||||
if not raw then
|
||||
raw = string.match(lowered, "([%d]+[%.,]?[%d]*)%s+damage%s+per%s+seconds?")
|
||||
_, _, raw = string.find(lowered, "([%d]+[%.,]?[%d]*)%s+damage%s+per%s+seconds?")
|
||||
end
|
||||
if not raw then return nil end
|
||||
local normalized = string.gsub(raw, ",", ".")
|
||||
@@ -1075,11 +1081,17 @@ end
|
||||
MTH_BOOK_GetZoneName = function(zoneId)
|
||||
local normalizedId = tonumber(zoneId) or zoneId
|
||||
if not normalizedId then return "Zone " .. tostring(zoneId or "?") end
|
||||
if MTH_DS_ZoneNamesFallback and MTH_DS_ZoneNamesFallback[normalizedId] then
|
||||
return MTH_DS_ZoneNamesFallback[normalizedId]
|
||||
-- Beast coords use WMA IDs. Always translate WMA→pfQ first so that e.g.
|
||||
-- WMA 4 → pfQ 14 (Durotar) instead of hitting pfQ 4 (Blasted Lands) by accident.
|
||||
local pfqId = normalizedId
|
||||
if type(MTH_MAP_WMA_TO_PFQ) == "table" then
|
||||
pfqId = MTH_MAP_WMA_TO_PFQ[normalizedId] or normalizedId
|
||||
end
|
||||
if not MTH_DS_Zones then return "Zone " .. tostring(zoneId or "?") end
|
||||
local row = MTH_DS_Zones[normalizedId] or MTH_DS_Zones[tostring(normalizedId)]
|
||||
if MTH_DS_ZoneNamesFallback and MTH_DS_ZoneNamesFallback[pfqId] then
|
||||
return MTH_DS_ZoneNamesFallback[pfqId]
|
||||
end
|
||||
if not MTH_DS_Zones then return "Zone " .. tostring(normalizedId) end
|
||||
local row = MTH_DS_Zones[pfqId] or MTH_DS_Zones[tostring(pfqId)]
|
||||
if not row then return "Zone " .. tostring(normalizedId) end
|
||||
local names = row.names
|
||||
if not names then return "Zone " .. tostring(normalizedId) end
|
||||
@@ -1108,7 +1120,12 @@ function MTH_BOOK_GetCurrentZoneId()
|
||||
if MTH_Map and type(MTH_Map.GetMapIDByName) == "function" then
|
||||
local mapId = MTH_Map:GetMapIDByName(zoneName)
|
||||
if mapId then
|
||||
return tonumber(mapId) or mapId
|
||||
-- Translate pfQ → WMA so zone IDs match coord tuples in MTH_DS_Beasts.
|
||||
local pfqId = tonumber(mapId)
|
||||
if pfqId and type(MTH_MAP_PFQ_TO_WMA) == "table" then
|
||||
return MTH_MAP_PFQ_TO_WMA[pfqId] or pfqId
|
||||
end
|
||||
return pfqId or mapId
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1122,7 +1139,11 @@ function MTH_BOOK_GetCurrentZoneId()
|
||||
if row and row.names then
|
||||
for _, value in pairs(row.names) do
|
||||
if MTH_BOOK_NormalizeZoneLookupName(value) == normalized then
|
||||
return tonumber(zoneId) or zoneId
|
||||
local pfqId = tonumber(zoneId) or zoneId
|
||||
if type(pfqId) == "number" and type(MTH_MAP_PFQ_TO_WMA) == "table" then
|
||||
return MTH_MAP_PFQ_TO_WMA[pfqId] or pfqId
|
||||
end
|
||||
return pfqId
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1281,6 +1302,7 @@ local function MTH_BOOK_GetSortKey(entry, col)
|
||||
if col == 7 then return traits.rare and 1 or 0 end
|
||||
if col == 8 then return traits.elite and 1 or 0 end
|
||||
if col == 9 then return traits.unique and 1 or 0 end
|
||||
if col == 10 then return tonumber(beast.attackSpeed) or 0 end
|
||||
end
|
||||
|
||||
if MTH_BOOK_STATE.mode == "abilities" then
|
||||
@@ -1430,12 +1452,25 @@ local function MTH_BOOK_BuildResults()
|
||||
local results = {}
|
||||
|
||||
if MTH_BOOK_STATE.mode == "pets" then
|
||||
if not MTH_DS_Beasts then return results end
|
||||
for beastId, beast in pairs(MTH_DS_Beasts) do
|
||||
if MTH_BOOK_BeastMatches(beastId, beast) then
|
||||
table.insert(results, beastId)
|
||||
-- Cache zone info once for this build pass (avoids calling GetCurrentZoneId
|
||||
-- once per beast, which is expensive and causes freezes on large datasets).
|
||||
if MTH_BOOK_STATE.petInZoneOnly then
|
||||
MTH_BOOK_STATE._cachedZoneId = MTH_BOOK_GetCurrentZoneId()
|
||||
MTH_BOOK_STATE._cachedZoneName = (type(GetRealZoneText) == "function" and GetRealZoneText())
|
||||
or (type(GetZoneText) == "function" and GetZoneText()) or nil
|
||||
else
|
||||
MTH_BOOK_STATE._cachedZoneId = nil
|
||||
MTH_BOOK_STATE._cachedZoneName = nil
|
||||
end
|
||||
|
||||
if MTH_DS_Beasts then
|
||||
for beastId, beast in pairs(MTH_DS_Beasts) do
|
||||
if MTH_BOOK_BeastMatches(beastId, beast) then
|
||||
table.insert(results, beastId)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(results, MTH_BOOK_BeastSort)
|
||||
MTH_BOOK_ApplyActiveSort(results)
|
||||
return results
|
||||
@@ -1537,13 +1572,75 @@ local function MTH_BOOK_BuildResults()
|
||||
if MTH_BOOK_STATE.mode == "pethistory" then
|
||||
local store = MTH_BOOK_GetPetDatastore()
|
||||
if type(store) ~= "table" or type(store.historyById) ~= "table" then return results end
|
||||
|
||||
local cached = {}
|
||||
for petId, row in pairs(store.historyById) do
|
||||
if type(row) == "table" then
|
||||
table.insert(results, petId)
|
||||
local idText = tostring(petId)
|
||||
table.insert(cached, {
|
||||
id = petId,
|
||||
idText = idText,
|
||||
name = MTH_BOOK_SafeLower(row.name),
|
||||
family = MTH_BOOK_SafeLower(row.family),
|
||||
level = tonumber(row.level) or 0,
|
||||
abandonedAt = tonumber(row.abandonedAt) or 0,
|
||||
reason = MTH_BOOK_SafeLower(tostring(row.abandonReason or "")),
|
||||
})
|
||||
end
|
||||
end
|
||||
table.sort(results, MTH_BOOK_PetHistorySort)
|
||||
MTH_BOOK_ApplyActiveSort(results)
|
||||
|
||||
local function defaultHistoryCompare(a, b)
|
||||
if a.abandonedAt ~= b.abandonedAt then
|
||||
return a.abandonedAt > b.abandonedAt
|
||||
end
|
||||
if a.name ~= b.name then
|
||||
return a.name < b.name
|
||||
end
|
||||
return a.idText < b.idText
|
||||
end
|
||||
|
||||
local state = MTH_BOOK_GetSortState()
|
||||
if state and state.col then
|
||||
table.sort(cached, function(a, b)
|
||||
local ka = nil
|
||||
local kb = nil
|
||||
if state.col == 1 then
|
||||
ka = a.idText
|
||||
kb = b.idText
|
||||
elseif state.col == 2 then
|
||||
ka = a.name
|
||||
kb = b.name
|
||||
elseif state.col == 3 then
|
||||
ka = a.family
|
||||
kb = b.family
|
||||
elseif state.col == 4 then
|
||||
ka = a.level
|
||||
kb = b.level
|
||||
elseif state.col == 5 then
|
||||
ka = a.abandonedAt
|
||||
kb = b.abandonedAt
|
||||
elseif state.col == 6 then
|
||||
ka = a.reason
|
||||
kb = b.reason
|
||||
end
|
||||
|
||||
if ka ~= kb then
|
||||
if ka == nil then return not state.asc end
|
||||
if kb == nil then return state.asc end
|
||||
if state.asc then
|
||||
return ka < kb
|
||||
end
|
||||
return ka > kb
|
||||
end
|
||||
return defaultHistoryCompare(a, b)
|
||||
end)
|
||||
else
|
||||
table.sort(cached, defaultHistoryCompare)
|
||||
end
|
||||
|
||||
for i = 1, table.getn(cached) do
|
||||
table.insert(results, cached[i].id)
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
@@ -1990,6 +2087,77 @@ local function MTH_BOOK_UpdatePetLearnSourceDropdownText()
|
||||
MTH_BOOK_DropdownSetText(sourceDropdown, MTH_BOOK_GetPetLearnSourceLabel(MTH_BOOK_STATE.petLearnSource))
|
||||
end
|
||||
|
||||
local MTH_BOOK_BeastContinentOptions = {
|
||||
{ value = "all", label = "" },
|
||||
{ value = 1, label = "Kalimdor" },
|
||||
{ value = 0, label = "E. Kingdoms" },
|
||||
}
|
||||
|
||||
local MTH_BOOK_BeastZoneOptions = {
|
||||
{ value = "all", label = "All Zones" },
|
||||
}
|
||||
|
||||
local function MTH_BOOK_BuildBeastZoneOptions(continentMapId)
|
||||
local seen = {}
|
||||
local rows = {}
|
||||
if MTH_DS_Beasts and MTH_DS_WMAZones then
|
||||
for _, beast in pairs(MTH_DS_Beasts) do
|
||||
if beast and beast.coords then
|
||||
for i = 1, table.getn(beast.coords) do
|
||||
local c = beast.coords[i]
|
||||
if c and c[3] and not seen[c[3]] then
|
||||
local wmaEntry = MTH_DS_WMAZones[c[3]]
|
||||
if wmaEntry and wmaEntry.mapId == continentMapId then
|
||||
seen[c[3]] = true
|
||||
local zoneName = MTH_BOOK_GetZoneName and MTH_BOOK_GetZoneName(c[3])
|
||||
if zoneName and string.sub(zoneName, 1, 5) ~= "Zone " then
|
||||
table.insert(rows, { value = c[3], label = zoneName })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
table.sort(rows, function(a, b)
|
||||
return MTH_BOOK_SafeLower(a.label) < MTH_BOOK_SafeLower(b.label)
|
||||
end)
|
||||
MTH_BOOK_BeastZoneOptions = { { value = "all", label = "All Zones" } }
|
||||
for i = 1, table.getn(rows) do
|
||||
table.insert(MTH_BOOK_BeastZoneOptions, rows[i])
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_BOOK_GetBeastContinentLabel(value)
|
||||
for i = 1, table.getn(MTH_BOOK_BeastContinentOptions) do
|
||||
if MTH_BOOK_BeastContinentOptions[i].value == value then
|
||||
return MTH_BOOK_BeastContinentOptions[i].label
|
||||
end
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
local function MTH_BOOK_GetBeastZoneLabel(value)
|
||||
for i = 1, table.getn(MTH_BOOK_BeastZoneOptions) do
|
||||
if MTH_BOOK_BeastZoneOptions[i].value == value then
|
||||
return MTH_BOOK_BeastZoneOptions[i].label
|
||||
end
|
||||
end
|
||||
return "All Zones"
|
||||
end
|
||||
|
||||
local function MTH_BOOK_UpdateBeastContinentDropdownText()
|
||||
local dd = getglobal("MTH_BOOK_BeastContinentDropdown")
|
||||
if not dd then return end
|
||||
MTH_BOOK_DropdownSetText(dd, MTH_BOOK_GetBeastContinentLabel(MTH_BOOK_STATE.petContinent))
|
||||
end
|
||||
|
||||
local function MTH_BOOK_UpdateBeastZoneDropdownText()
|
||||
local dd = getglobal("MTH_BOOK_BeastZoneDropdown")
|
||||
if not dd then return end
|
||||
MTH_BOOK_DropdownSetText(dd, MTH_BOOK_GetBeastZoneLabel(MTH_BOOK_STATE.petZoneFilter))
|
||||
end
|
||||
|
||||
local function MTH_BOOK_GetItemSubtypeLabelByValue(value)
|
||||
local options = MTH_BOOK_GetItemSubtypeOptions()
|
||||
for i = 1, table.getn(options) do
|
||||
@@ -2025,7 +2193,7 @@ local function MTH_BOOK_UpdateQuickFilterControls()
|
||||
if MTH_BOOK_IsItemMode() then
|
||||
MTH_BOOK_STATE.pageSize = 18
|
||||
elseif MTH_BOOK_STATE.mode == "families" then
|
||||
MTH_BOOK_STATE.pageSize = 16
|
||||
MTH_BOOK_STATE.pageSize = MTH_BOOK_MAX_ROWS
|
||||
elseif MTH_BOOK_STATE.mode == "stable" then
|
||||
MTH_BOOK_STATE.pageSize = 5
|
||||
elseif MTH_BOOK_STATE.mode == "pethistory" then
|
||||
@@ -2038,6 +2206,9 @@ local function MTH_BOOK_UpdateQuickFilterControls()
|
||||
local abilityDropdown = getglobal("MTH_BOOK_AbilityDropdown")
|
||||
local rankDropdown = getglobal("MTH_BOOK_RankDropdown")
|
||||
local petLearnSourceDropdown = getglobal("MTH_BOOK_PetLearnSourceDropdown")
|
||||
local beastContinentDropdown = getglobal("MTH_BOOK_BeastContinentDropdown")
|
||||
local beastZoneDropdown = getglobal("MTH_BOOK_BeastZoneDropdown")
|
||||
local beastZoneLabel = getglobal("MTH_BOOK_BeastZoneLabel")
|
||||
local itemSubtypeDropdown = getglobal("MTH_BOOK_ItemSubtypeDropdown")
|
||||
local npcFunctionDropdown = getglobal("MTH_BOOK_NPCFunctionDropdown")
|
||||
local npcZoneDropdown = getglobal("MTH_BOOK_NPCZoneDropdown")
|
||||
@@ -2158,6 +2329,19 @@ local function MTH_BOOK_UpdateQuickFilterControls()
|
||||
end
|
||||
end
|
||||
if petLearnSourceDropdown then petLearnSourceDropdown:Hide() end
|
||||
if beastZoneLabel then beastZoneLabel:Show() end
|
||||
if beastContinentDropdown then
|
||||
beastContinentDropdown:Show()
|
||||
MTH_BOOK_UpdateBeastContinentDropdownText()
|
||||
end
|
||||
if beastZoneDropdown then
|
||||
if MTH_BOOK_STATE.petContinent ~= "all" then
|
||||
beastZoneDropdown:Show()
|
||||
MTH_BOOK_UpdateBeastZoneDropdownText()
|
||||
else
|
||||
beastZoneDropdown:Hide()
|
||||
end
|
||||
end
|
||||
if itemSubtypeDropdown then itemSubtypeDropdown:Hide() end
|
||||
if npcFunctionDropdown then npcFunctionDropdown:Hide() end
|
||||
if npcZoneDropdown then npcZoneDropdown:Hide() end
|
||||
@@ -2193,6 +2377,9 @@ local function MTH_BOOK_UpdateQuickFilterControls()
|
||||
petLearnSourceDropdown:Show()
|
||||
MTH_BOOK_UpdatePetLearnSourceDropdownText()
|
||||
end
|
||||
if beastZoneLabel then beastZoneLabel:Hide() end
|
||||
if beastContinentDropdown then beastContinentDropdown:Hide() end
|
||||
if beastZoneDropdown then beastZoneDropdown:Hide() end
|
||||
if itemSubtypeDropdown then itemSubtypeDropdown:Hide() end
|
||||
if petOnlyMyLevel then
|
||||
petOnlyMyLevel:ClearAllPoints()
|
||||
@@ -2249,6 +2436,9 @@ local function MTH_BOOK_UpdateQuickFilterControls()
|
||||
if abilityDropdown then abilityDropdown:Hide() end
|
||||
if rankDropdown then rankDropdown:Hide() end
|
||||
if petLearnSourceDropdown then petLearnSourceDropdown:Hide() end
|
||||
if beastZoneLabel then beastZoneLabel:Hide() end
|
||||
if beastContinentDropdown then beastContinentDropdown:Hide() end
|
||||
if beastZoneDropdown then beastZoneDropdown:Hide() end
|
||||
if itemSubtypeDropdown then itemSubtypeDropdown:Hide() end
|
||||
if npcFunctionDropdown then npcFunctionDropdown:Show() end
|
||||
if npcZoneDropdown then npcZoneDropdown:Hide() end
|
||||
@@ -2303,6 +2493,9 @@ local function MTH_BOOK_UpdateQuickFilterControls()
|
||||
if abilityDropdown then abilityDropdown:Hide() end
|
||||
if rankDropdown then rankDropdown:Hide() end
|
||||
if petLearnSourceDropdown then petLearnSourceDropdown:Hide() end
|
||||
if beastZoneLabel then beastZoneLabel:Hide() end
|
||||
if beastContinentDropdown then beastContinentDropdown:Hide() end
|
||||
if beastZoneDropdown then beastZoneDropdown:Hide() end
|
||||
if itemSubtypeDropdown then
|
||||
itemSubtypeDropdown:ClearAllPoints()
|
||||
itemSubtypeDropdown:SetPoint("TOPLEFT", itemSubtypeDropdown:GetParent(), "TOPLEFT", 238, -80)
|
||||
@@ -2440,6 +2633,15 @@ local function MTH_BOOK_UpdateQuickFilterControls()
|
||||
if MTH_BOOK_STATE.mode ~= "pets" and petInZoneOnly then
|
||||
petInZoneOnly:Hide()
|
||||
end
|
||||
if MTH_BOOK_STATE.mode ~= "pets" and beastContinentDropdown then
|
||||
beastContinentDropdown:Hide()
|
||||
end
|
||||
if MTH_BOOK_STATE.mode ~= "pets" and beastZoneDropdown then
|
||||
beastZoneDropdown:Hide()
|
||||
end
|
||||
if MTH_BOOK_STATE.mode ~= "pets" and beastZoneLabel then
|
||||
beastZoneLabel:Hide()
|
||||
end
|
||||
if MTH_BOOK_STATE.mode ~= "npcs" and npcInZoneOnly then
|
||||
npcInZoneOnly:Hide()
|
||||
end
|
||||
@@ -2545,6 +2747,7 @@ local function MTH_BOOK_InitRankDropdown()
|
||||
MTH_BOOK_UpdateRankDropdownText()
|
||||
end
|
||||
|
||||
|
||||
local function MTH_BOOK_InitPetLearnSourceDropdown()
|
||||
local sourceDropdown = getglobal("MTH_BOOK_PetLearnSourceDropdown")
|
||||
if not sourceDropdown then return end
|
||||
@@ -2639,6 +2842,56 @@ local function MTH_BOOK_AddStableStyleKV(lines, label, value)
|
||||
table.insert(lines, "|cff9a9a9a" .. tostring(label or "") .. ":|r |cffffffff" .. tostring(value or "-") .. "|r")
|
||||
end
|
||||
|
||||
local function MTH_BOOK_GetOrCreateDetailTitleLabel()
|
||||
local lbl = getglobal("MTH_BOOK_DetailTitleLabel")
|
||||
if lbl then return lbl end
|
||||
local parent = getglobal("MTH_BOOK_DetailBackdrop")
|
||||
if not parent then return nil end
|
||||
lbl = parent:CreateFontString("MTH_BOOK_DetailTitleLabel", "OVERLAY")
|
||||
lbl:SetFontObject(GameFontNormal)
|
||||
lbl:SetJustifyH("LEFT")
|
||||
lbl:SetJustifyV("TOP")
|
||||
lbl:SetPoint("TOPLEFT", parent, "TOPLEFT", 8, -8)
|
||||
lbl:SetWidth(120)
|
||||
lbl:Hide()
|
||||
return lbl
|
||||
end
|
||||
|
||||
local function MTH_BOOK_ShowDetailTitle(text)
|
||||
local lbl = MTH_BOOK_GetOrCreateDetailTitleLabel()
|
||||
if lbl then
|
||||
lbl:SetText(tostring(text or ""))
|
||||
lbl:Show()
|
||||
end
|
||||
local editBox = getglobal("MTH_BOOK_DetailBackdropDetailText")
|
||||
local parent = getglobal("MTH_BOOK_DetailBackdrop")
|
||||
if editBox and parent then
|
||||
editBox:ClearAllPoints()
|
||||
editBox:SetPoint("TOPLEFT", parent, "TOPLEFT", 6, -28)
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_BOOK_HideDetailTitle()
|
||||
local lbl = getglobal("MTH_BOOK_DetailTitleLabel")
|
||||
if lbl then lbl:Hide() end
|
||||
local editBox = getglobal("MTH_BOOK_DetailBackdropDetailText")
|
||||
local parent = getglobal("MTH_BOOK_DetailBackdrop")
|
||||
if editBox and parent then
|
||||
editBox:ClearAllPoints()
|
||||
editBox:SetPoint("TOPLEFT", parent, "TOPLEFT", 6, -6)
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_BOOK_FormatBeastReact(reactA, reactH)
|
||||
local function reactColor(r)
|
||||
local rl = r and string.lower(r) or ""
|
||||
if rl == "friendly" then return "|cFF44DD44" end
|
||||
if rl == "neutral" then return "|cFFFFCC00" end
|
||||
return "|cFFDD4444"
|
||||
end
|
||||
return reactColor(reactA) .. "A|r " .. reactColor(reactH) .. "H|r"
|
||||
end
|
||||
|
||||
local function MTH_BOOK_FormatDateTimeValue(value)
|
||||
local ts = tonumber(value)
|
||||
if not ts or ts <= 0 then
|
||||
@@ -2879,7 +3132,7 @@ end
|
||||
function MTH_BOOK_SetDetailText(detail, text)
|
||||
if not detail then return end
|
||||
local wrapped = tostring(text or "")
|
||||
if MTH_BOOK_STATE.mode ~= "pethistory" then
|
||||
if MTH_BOOK_STATE.mode ~= "pethistory" and MTH_BOOK_STATE.mode ~= "pets" and MTH_BOOK_STATE.mode ~= "abilities" then
|
||||
wrapped = MTH_BOOK_WrapDetailText(wrapped)
|
||||
end
|
||||
detail._mthLocking = true
|
||||
@@ -2932,9 +3185,15 @@ end
|
||||
function MTH_BOOK_UpdateDetail()
|
||||
local detail = getglobal("MTH_BOOK_DetailBackdropDetailText")
|
||||
if not detail then return end
|
||||
MTH_BOOK_HideDetailTitle()
|
||||
-- Hide model skin preview when not in a beast-list mode
|
||||
if MTH_BOOK_STATE.mode ~= "pets" and MTH_BOOK_STATE.mode ~= "abilities" then
|
||||
if MTH_BOOK_ModelViewer_Clear then MTH_BOOK_ModelViewer_Clear() end
|
||||
end
|
||||
local petTop = MTH_BOOK_STATE.petUI and MTH_BOOK_STATE.petUI.detailTop
|
||||
local petBottom = MTH_BOOK_STATE.petUI and MTH_BOOK_STATE.petUI.detailBottom
|
||||
if not MTH_BOOK_STATE.selectedEntry then
|
||||
if MTH_BOOK_ModelViewer_Clear then MTH_BOOK_ModelViewer_Clear() end
|
||||
if MTH_BOOK_STATE.mode == "petabilities" then
|
||||
if petTop and petBottom then
|
||||
MTH_BOOK_SetDetailText(petTop, "|cFFFFD100Baseline|r\n\nSelect a spell baseline from the left list.")
|
||||
@@ -3005,49 +3264,52 @@ function MTH_BOOK_UpdateDetail()
|
||||
return
|
||||
end
|
||||
local beastId = selected.beastId
|
||||
|
||||
local beast = MTH_DS_Beasts and MTH_DS_Beasts[beastId]
|
||||
if not beast then
|
||||
MTH_BOOK_SetDetailText(detail, "|cFFFFD100Inspector|r\n\nSelect an entry from the list to view identity, stats, sources and locations.")
|
||||
MTH_BOOK_UpdateOpenMapButton()
|
||||
return
|
||||
end
|
||||
local lines = {}
|
||||
local beastDisplayName = (MTH and MTH.GetLocalizedBeastName and MTH:GetLocalizedBeastName(beastId, beast.name)) or beast.name
|
||||
table.insert(lines, "|cFFFFFF00" .. (beastDisplayName or "Unknown") .. "|r")
|
||||
MTH_BOOK_AddDetailSection(lines, "Identity")
|
||||
MTH_BOOK_AddDetailKV(lines, "ID", beastId)
|
||||
MTH_BOOK_AddDetailKV(lines, "Family", beast.family or "?")
|
||||
MTH_BOOK_ShowDetailTitle("|cFFFFFF00" .. (beastDisplayName or "Unknown") .. "|r")
|
||||
|
||||
MTH_BOOK_AddDetailSection(lines, "Stats")
|
||||
MTH_BOOK_AddDetailKV(lines, "Level", beast.lvl or "?")
|
||||
MTH_BOOK_AddDetailKV(lines, "Attack Speed", beast.attackSpeed or "?")
|
||||
local lines = {}
|
||||
-- Identity block
|
||||
MTH_BOOK_AddStableStyleKV(lines, "ID", beastId)
|
||||
MTH_BOOK_AddStableStyleKV(lines, "Family", beast.family or "?")
|
||||
local rankLabel = beast.rank
|
||||
if rankLabel == "normal" or rankLabel == nil or rankLabel == "" then rankLabel = nil end
|
||||
if rankLabel then MTH_BOOK_AddStableStyleKV(lines, "Rank", rankLabel) end
|
||||
local spawnCount = (beast.coords and table.getn(beast.coords)) or 0
|
||||
MTH_BOOK_AddStableStyleKV(lines, "Spawns", spawnCount > 0 and tostring(spawnCount) or "?")
|
||||
if beast.reactA or beast.reactH then
|
||||
table.insert(lines, "|cff9a9a9aReaction:|r " .. MTH_BOOK_FormatBeastReact(beast.reactA, beast.reactH))
|
||||
end
|
||||
|
||||
-- Stats block
|
||||
MTH_BOOK_AddStableStyleKV(lines, "Level", beast.lvl or "?")
|
||||
MTH_BOOK_AddStableStyleKV(lines, "Atk Speed", beast.attackSpeed or "?")
|
||||
local respawnWindow = MTH_BOOK_FormatRespawnWindow(beast)
|
||||
if respawnWindow then
|
||||
MTH_BOOK_AddDetailKV(lines, "Respawn", respawnWindow)
|
||||
if respawnWindow then MTH_BOOK_AddStableStyleKV(lines, "Respawn", respawnWindow) end
|
||||
if beast.health then MTH_BOOK_AddStableStyleKV(lines, "Health", beast.health) end
|
||||
if beast.armor then MTH_BOOK_AddStableStyleKV(lines, "Armor", beast.armor) end
|
||||
if beast.dmgMin and beast.dmgMax then
|
||||
MTH_BOOK_AddStableStyleKV(lines, "Damage", string.format("%.1f - %.1f", tonumber(beast.dmgMin) or 0, tonumber(beast.dmgMax) or 0))
|
||||
end
|
||||
MTH_BOOK_AddDetailKV(lines, "Rare", beast.rare and "Yes" or "No")
|
||||
MTH_BOOK_AddDetailKV(lines, "Abilities", beast.abilities or "None")
|
||||
|
||||
local fam = MTH_DS_Families and beast.family and MTH_DS_Families[beast.family]
|
||||
if fam and fam.abilities and table.getn(fam.abilities) > 0 then
|
||||
MTH_BOOK_AddDetailSection(lines, "Family Pool")
|
||||
table.insert(lines, " " .. table.concat(fam.abilities, ", "))
|
||||
end
|
||||
|
||||
if beast.coords and table.getn(beast.coords) > 0 then
|
||||
MTH_BOOK_AddDetailSection(lines, "Locations")
|
||||
for i = 1, table.getn(beast.coords) do
|
||||
local c = beast.coords[i]
|
||||
if c then
|
||||
local x = tonumber(c[1] or 0) or 0
|
||||
local y = tonumber(c[2] or 0) or 0
|
||||
local zoneId = c[3]
|
||||
table.insert(lines, string.format(" - %s (%.1f, %.1f)", MTH_BOOK_GetZoneName(zoneId), x, y))
|
||||
end
|
||||
if i >= 8 then break end
|
||||
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
|
||||
|
||||
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_UpdateOpenMapButton()
|
||||
return
|
||||
@@ -3066,37 +3328,38 @@ function MTH_BOOK_UpdateDetail()
|
||||
MTH_BOOK_UpdateOpenMapButton()
|
||||
return
|
||||
end
|
||||
MTH_BOOK_ShowDetailTitle("|cFFFFFF00" .. tostring(entry.abilityToken) .. "|r")
|
||||
|
||||
local lines = {}
|
||||
table.insert(lines, "|cFFFFFF00" .. tostring(entry.abilityToken) .. "|r")
|
||||
local beastDisplayName = (MTH and MTH.GetLocalizedBeastName and MTH:GetLocalizedBeastName(entry.beastId, beast.name)) or beast.name
|
||||
MTH_BOOK_AddStableStyleKV(lines, "Beast", tostring(beastDisplayName or "Unknown") .. " (#" .. tostring(entry.beastId) .. ")")
|
||||
MTH_BOOK_AddStableStyleKV(lines, "Family", beast.family or "?")
|
||||
local rankLabel = beast.rank
|
||||
if rankLabel == "normal" or rankLabel == nil or rankLabel == "" then rankLabel = nil end
|
||||
if rankLabel then MTH_BOOK_AddStableStyleKV(lines, "Rank", rankLabel) end
|
||||
|
||||
MTH_BOOK_AddDetailSection(lines, "Identity")
|
||||
MTH_BOOK_AddDetailKV(lines, "Beast", tostring(beastDisplayName or "Unknown") .. " (ID " .. tostring(entry.beastId) .. ")")
|
||||
MTH_BOOK_AddDetailKV(lines, "Family", beast.family or "?")
|
||||
|
||||
MTH_BOOK_AddDetailSection(lines, "Stats")
|
||||
MTH_BOOK_AddDetailKV(lines, "Level", beast.lvl or "?")
|
||||
MTH_BOOK_AddDetailKV(lines, "Attack Speed", beast.attackSpeed or "?")
|
||||
MTH_BOOK_AddStableStyleKV(lines, "Level", beast.lvl or "?")
|
||||
MTH_BOOK_AddStableStyleKV(lines, "Atk Speed", beast.attackSpeed or "?")
|
||||
local respawnWindow = MTH_BOOK_FormatRespawnWindow(beast)
|
||||
if respawnWindow then
|
||||
MTH_BOOK_AddDetailKV(lines, "Respawn", respawnWindow)
|
||||
if respawnWindow then MTH_BOOK_AddStableStyleKV(lines, "Respawn", respawnWindow) end
|
||||
if beast.health then MTH_BOOK_AddStableStyleKV(lines, "Health", beast.health) end
|
||||
if beast.armor then MTH_BOOK_AddStableStyleKV(lines, "Armor", beast.armor) end
|
||||
if beast.dmgMin and beast.dmgMax then
|
||||
MTH_BOOK_AddStableStyleKV(lines, "Damage", string.format("%.1f - %.1f", tonumber(beast.dmgMin) or 0, tonumber(beast.dmgMax) or 0))
|
||||
end
|
||||
MTH_BOOK_AddDetailKV(lines, "Rare", beast.rare and "Yes" or "No")
|
||||
|
||||
if beast.coords and table.getn(beast.coords) > 0 then
|
||||
MTH_BOOK_AddDetailSection(lines, "Locations")
|
||||
for i = 1, table.getn(beast.coords) do
|
||||
local c = beast.coords[i]
|
||||
if c then
|
||||
local x = tonumber(c[1] or 0) or 0
|
||||
local y = tonumber(c[2] or 0) or 0
|
||||
local zoneId = c[3]
|
||||
table.insert(lines, string.format(" - %s (%.1f, %.1f)", MTH_BOOK_GetZoneName(zoneId), x, y))
|
||||
end
|
||||
if i >= 8 then break end
|
||||
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
|
||||
|
||||
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_UpdateOpenMapButton()
|
||||
return
|
||||
@@ -3405,7 +3668,7 @@ local function MTH_BOOK_GetColumnLabels()
|
||||
return tabDef.columnLabels
|
||||
end
|
||||
if MTH_BOOK_STATE.mode == "pets" then
|
||||
return { "ID", "Lvl", "Family", "Name", "Abilities", "Zone", "R", "E", "U" }
|
||||
return { "ID", "Lvl", "Fam", "Name", "Abilities", "Zone", "R", "E", "U", "AS" }
|
||||
elseif MTH_BOOK_STATE.mode == "petabilities" then
|
||||
return { "Ability Name", "Ranks", "Families" }
|
||||
elseif MTH_BOOK_STATE.mode == "stable" then
|
||||
@@ -3431,13 +3694,14 @@ local function MTH_BOOK_GetColumnLayout()
|
||||
return {
|
||||
{ x = 8, width = 28, align = "LEFT" },
|
||||
{ x = 38, width = 30, align = "LEFT" },
|
||||
{ x = 68, width = 74, align = "LEFT" },
|
||||
{ x = 142, width = 130, align = "LEFT" },
|
||||
{ x = 272, width = 180, align = "LEFT" },
|
||||
{ x = 452, width = 68, align = "LEFT" },
|
||||
{ x = 520, width = 10, align = "CENTER" },
|
||||
{ x = 532, width = 10, align = "CENTER" },
|
||||
{ x = 544, width = 10, align = "CENTER" },
|
||||
{ x = 68, width = 18, align = "LEFT" },
|
||||
{ x = 88, width = 130, align = "LEFT" },
|
||||
{ x = 220, width = 148, align = "LEFT" },
|
||||
{ x = 370, width = 80, align = "LEFT" },
|
||||
{ x = 452, width = 14, align = "CENTER" },
|
||||
{ x = 468, width = 14, align = "CENTER" },
|
||||
{ x = 484, width = 14, align = "CENTER" },
|
||||
{ x = 500, width = 54, align = "LEFT" },
|
||||
}
|
||||
elseif MTH_BOOK_STATE.mode == "petabilities" then
|
||||
return {
|
||||
@@ -3598,6 +3862,19 @@ local function MTH_BOOK_ApplyColumnLayout(parent)
|
||||
btn.cols[itemNameColumn]:SetPoint("LEFT", btn, "LEFT", itemNameLayout.x + 12, 0)
|
||||
btn.cols[itemNameColumn]:SetWidth(itemNameLayout.width - 16)
|
||||
end
|
||||
elseif MTH_BOOK_STATE.mode == "families" and layout[1] then
|
||||
local familyCol = layout[1]
|
||||
btn.itemIcon:ClearAllPoints()
|
||||
btn.itemIcon:SetPoint("LEFT", btn, "LEFT", familyCol.x, 0)
|
||||
if btn.cols and btn.cols[1] then
|
||||
btn.cols[1]:ClearAllPoints()
|
||||
btn.cols[1]:SetPoint("LEFT", btn, "LEFT", familyCol.x + 18, 0)
|
||||
btn.cols[1]:SetWidth(familyCol.width - 18)
|
||||
end
|
||||
elseif MTH_BOOK_STATE.mode == "pets" and layout[3] then
|
||||
local famCol = layout[3]
|
||||
btn.itemIcon:ClearAllPoints()
|
||||
btn.itemIcon:SetPoint("LEFT", btn, "LEFT", famCol.x, 0)
|
||||
else
|
||||
btn.itemIcon:Hide()
|
||||
end
|
||||
@@ -3608,8 +3885,9 @@ end
|
||||
|
||||
local function MTH_BOOK_GetRowValues(entry)
|
||||
if MTH_BOOK_STATE.mode == "pets" then
|
||||
-- MetaHunt DB entry
|
||||
local beast = MTH_DS_Beasts and MTH_DS_Beasts[entry]
|
||||
if not beast then return { "", "", "", "", "", "", "", "", "" } end
|
||||
if not beast then return { "", "", "", "", "", "", "", "", "", "" } end
|
||||
local beastDisplayName = (MTH and MTH.GetLocalizedBeastName and MTH:GetLocalizedBeastName(entry, beast.name)) or beast.name
|
||||
local traits = MTH_BOOK_ParseBeastTraits(beast)
|
||||
local abilities = MTH_BOOK_GetBeastAbilitiesSummary(beast)
|
||||
@@ -3617,13 +3895,14 @@ local function MTH_BOOK_GetRowValues(entry)
|
||||
return {
|
||||
"|cFF33CCFF" .. tostring(entry) .. "|r",
|
||||
tostring(beast.lvl or "?"),
|
||||
tostring(beast.family or "?"),
|
||||
"", -- family icon rendered separately
|
||||
tostring(beastDisplayName or "Unknown"),
|
||||
abilities,
|
||||
zone,
|
||||
(traits.rare and "R" or ""),
|
||||
(traits.elite and "E" or ""),
|
||||
(traits.unique and "U" or ""),
|
||||
tostring(beast.attackSpeed or ""),
|
||||
}
|
||||
end
|
||||
|
||||
@@ -4028,6 +4307,31 @@ MTH_BOOK_UpdateResults = function()
|
||||
btn.itemIcon:SetTexture(nil)
|
||||
btn.itemIcon:Hide()
|
||||
end
|
||||
elseif MTH_BOOK_STATE.mode == "families" and type(entry) == "table" and entry.icon then
|
||||
local iconPath = MTH_BOOK_ResolveIconPath(entry.icon)
|
||||
if iconPath then
|
||||
btn.itemIcon:SetTexture(iconPath)
|
||||
btn.itemIcon:Show()
|
||||
else
|
||||
btn.itemIcon:SetTexture(nil)
|
||||
btn.itemIcon:Hide()
|
||||
end
|
||||
elseif MTH_BOOK_STATE.mode == "pets" then
|
||||
local beast = MTH_DS_Beasts and MTH_DS_Beasts[entry]
|
||||
local famData = beast and beast.family and MTH_DS_Families and MTH_DS_Families[beast.family]
|
||||
if famData and famData.icon and famData.icon ~= "" then
|
||||
local iconPath = MTH_BOOK_ResolveIconPath(famData.icon)
|
||||
if iconPath then
|
||||
btn.itemIcon:SetTexture(iconPath)
|
||||
btn.itemIcon:Show()
|
||||
else
|
||||
btn.itemIcon:SetTexture(nil)
|
||||
btn.itemIcon:Hide()
|
||||
end
|
||||
else
|
||||
btn.itemIcon:SetTexture(nil)
|
||||
btn.itemIcon:Hide()
|
||||
end
|
||||
else
|
||||
btn.itemIcon:SetTexture(nil)
|
||||
btn.itemIcon:Hide()
|
||||
@@ -4379,23 +4683,14 @@ local function MTH_BOOK_LayoutSectionTabs()
|
||||
local sectionPetHistory = getglobal("MTH_BOOK_SectionPetHistory")
|
||||
if not (tabBar and sectionPets and sectionFamilies and sectionPetAbilities and sectionItems and sectionNPCs and sectionProjectiles and sectionAmmoBags) then return end
|
||||
|
||||
if sectionStable then
|
||||
sectionStable:ClearAllPoints()
|
||||
sectionStable:SetPoint("TOPLEFT", tabBar, "TOPLEFT", 0, 0)
|
||||
end
|
||||
sectionPets:ClearAllPoints()
|
||||
sectionPets:SetPoint("TOPLEFT", tabBar, "TOPLEFT", 0, 0)
|
||||
|
||||
sectionPetAbilities:ClearAllPoints()
|
||||
if sectionStable then
|
||||
sectionPetAbilities:SetPoint("LEFT", sectionStable, "RIGHT", 2, 0)
|
||||
else
|
||||
sectionPetAbilities:SetPoint("TOPLEFT", tabBar, "TOPLEFT", 0, 0)
|
||||
end
|
||||
|
||||
sectionPets:ClearAllPoints()
|
||||
sectionPets:SetPoint("LEFT", sectionPetAbilities, "RIGHT", 2, 0)
|
||||
sectionPetAbilities:SetPoint("LEFT", sectionPets, "RIGHT", 2, 0)
|
||||
|
||||
sectionFamilies:ClearAllPoints()
|
||||
sectionFamilies:SetPoint("LEFT", sectionPets, "RIGHT", 2, 0)
|
||||
sectionFamilies:SetPoint("LEFT", sectionPetAbilities, "RIGHT", 2, 0)
|
||||
|
||||
sectionNPCs:ClearAllPoints()
|
||||
sectionNPCs:SetPoint("LEFT", sectionFamilies, "RIGHT", 2, 0)
|
||||
@@ -4409,9 +4704,18 @@ local function MTH_BOOK_LayoutSectionTabs()
|
||||
sectionAmmoBags:ClearAllPoints()
|
||||
sectionAmmoBags:SetPoint("LEFT", sectionProjectiles, "RIGHT", 2, 0)
|
||||
|
||||
if sectionStable then
|
||||
sectionStable:ClearAllPoints()
|
||||
sectionStable:SetPoint("LEFT", sectionAmmoBags, "RIGHT", 2, 0)
|
||||
end
|
||||
|
||||
if sectionPetHistory then
|
||||
sectionPetHistory:ClearAllPoints()
|
||||
sectionPetHistory:SetPoint("LEFT", sectionAmmoBags, "RIGHT", 2, 0)
|
||||
if sectionStable then
|
||||
sectionPetHistory:SetPoint("LEFT", sectionStable, "RIGHT", 2, 0)
|
||||
else
|
||||
sectionPetHistory:SetPoint("LEFT", sectionAmmoBags, "RIGHT", 2, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4430,6 +4734,8 @@ local function MTH_BOOK_GetFilterWidgets()
|
||||
npcFunctionDropdown = getglobal("MTH_BOOK_NPCFunctionDropdown"),
|
||||
npcZoneDropdown = getglobal("MTH_BOOK_NPCZoneDropdown"),
|
||||
petLearnSourceDropdown = getglobal("MTH_BOOK_PetLearnSourceDropdown"),
|
||||
beastContinentDropdown = getglobal("MTH_BOOK_BeastContinentDropdown"),
|
||||
beastZoneDropdown = getglobal("MTH_BOOK_BeastZoneDropdown"),
|
||||
itemSubtypeDropdown = getglobal("MTH_BOOK_ItemSubtypeDropdown"),
|
||||
petOnlyMyLevel = getglobal("MTH_BOOK_PetOnlyMyLevel"),
|
||||
petInZoneOnly = getglobal("MTH_BOOK_PetInZoneOnly"),
|
||||
@@ -4451,6 +4757,8 @@ local function MTH_BOOK_ResetStateForMode(mode)
|
||||
MTH_BOOK_STATE.petOnlyMyLevel = false
|
||||
MTH_BOOK_STATE.itemOnlyMyLevel = false
|
||||
MTH_BOOK_STATE.petInZoneOnly = false
|
||||
MTH_BOOK_STATE.petContinent = "all"
|
||||
MTH_BOOK_STATE.petZoneFilter = "all"
|
||||
MTH_BOOK_STATE.itemSubtype = "all"
|
||||
MTH_BOOK_STATE.npcFunction = "all"
|
||||
MTH_BOOK_STATE.npcZone = "all"
|
||||
@@ -4514,6 +4822,8 @@ local function MTH_BOOK_ApplyStateToWidgets(widgets)
|
||||
if widgets.petInZoneOnly then
|
||||
widgets.petInZoneOnly:SetChecked(MTH_BOOK_STATE.mode == "pets" and MTH_BOOK_STATE.petInZoneOnly and 1 or nil)
|
||||
end
|
||||
if widgets.beastContinentDropdown then MTH_BOOK_UpdateBeastContinentDropdownText() end
|
||||
if widgets.beastZoneDropdown then MTH_BOOK_UpdateBeastZoneDropdownText() end
|
||||
if widgets.npcInZoneOnly then
|
||||
widgets.npcInZoneOnly:SetChecked(MTH_BOOK_STATE.mode == "npcs" and MTH_BOOK_STATE.npcInZoneOnly and 1 or nil)
|
||||
end
|
||||
@@ -4552,6 +4862,8 @@ function MTH_BOOK_JumpToBeastById(beastId)
|
||||
MTH_BOOK_STATE.mode = "pets"
|
||||
local widgets = MTH_BOOK_GetFilterWidgets()
|
||||
MTH_BOOK_ResetStateForMode("pets")
|
||||
MTH_BOOK_STATE.petHideNoAbilities = false
|
||||
MTH_BOOK_STATE.petHideUnknown = false
|
||||
MTH_BOOK_STATE.search = tostring(id)
|
||||
MTH_BOOK_STATE.forcedBeastId = id
|
||||
MTH_BOOK_ApplyStateToWidgets(widgets)
|
||||
@@ -4761,6 +5073,8 @@ local function MTH_BOOK_ResetAllFiltersAndRefresh()
|
||||
if widgets.abilityDropdown then MTH_BOOK_UpdateAbilityDropdownText() end
|
||||
if widgets.rankDropdown then MTH_BOOK_UpdateRankDropdownText() end
|
||||
if widgets.petLearnSourceDropdown then MTH_BOOK_UpdatePetLearnSourceDropdownText() end
|
||||
if widgets.beastContinentDropdown then MTH_BOOK_UpdateBeastContinentDropdownText() end
|
||||
if widgets.beastZoneDropdown then MTH_BOOK_UpdateBeastZoneDropdownText() end
|
||||
if widgets.itemSubtypeDropdown then MTH_BOOK_UpdateItemSubtypeDropdownText() end
|
||||
if widgets.npcFunctionDropdown or widgets.npcZoneDropdown then MTH_BOOK_UpdateNPCDropdownTexts() end
|
||||
|
||||
@@ -4768,6 +5082,71 @@ local function MTH_BOOK_ResetAllFiltersAndRefresh()
|
||||
MTH_BOOK_RefreshFilter()
|
||||
end
|
||||
|
||||
local function MTH_BOOK_WireBeastDropdowns()
|
||||
local continentDD = getglobal("MTH_BOOK_BeastContinentDropdown")
|
||||
if continentDD then
|
||||
UIDropDownMenu_Initialize(continentDD, function()
|
||||
for i = 1, table.getn(MTH_BOOK_BeastContinentOptions) do
|
||||
local option = MTH_BOOK_BeastContinentOptions[i]
|
||||
local info = MTH_BOOK_DropdownCreateInfo()
|
||||
info.text = (option.label ~= "") and option.label or "(any)"
|
||||
info.func = function()
|
||||
MTH_BOOK_STATE.petContinent = option.value
|
||||
MTH_BOOK_STATE.petZoneFilter = "all"
|
||||
MTH_BOOK_STATE.page = 1
|
||||
MTH_BOOK_STATE.selectedEntry = nil
|
||||
MTH_BOOK_DropdownSetText(continentDD, info.text)
|
||||
if option.value ~= "all" then
|
||||
MTH_BOOK_BuildBeastZoneOptions(option.value)
|
||||
local zoneDD = getglobal("MTH_BOOK_BeastZoneDropdown")
|
||||
if zoneDD then
|
||||
UIDropDownMenu_Initialize(zoneDD, MTH_BOOK_STATE._beastZoneInitFunc)
|
||||
zoneDD:Show()
|
||||
MTH_BOOK_UpdateBeastZoneDropdownText()
|
||||
end
|
||||
else
|
||||
local zoneDD = getglobal("MTH_BOOK_BeastZoneDropdown")
|
||||
if zoneDD then zoneDD:Hide() end
|
||||
end
|
||||
MTH_BOOK_RefreshFilter()
|
||||
end
|
||||
info.checked = (MTH_BOOK_STATE.petContinent == option.value)
|
||||
UIDropDownMenu_AddButton(info)
|
||||
end
|
||||
end)
|
||||
UIDropDownMenu_SetWidth(80, continentDD)
|
||||
UIDropDownMenu_JustifyText("LEFT", continentDD)
|
||||
MTH_BOOK_UpdateBeastContinentDropdownText()
|
||||
end
|
||||
|
||||
local zoneInitFunc = function()
|
||||
local zoneDD = getglobal("MTH_BOOK_BeastZoneDropdown")
|
||||
for i = 1, table.getn(MTH_BOOK_BeastZoneOptions) do
|
||||
local option = MTH_BOOK_BeastZoneOptions[i]
|
||||
local info = MTH_BOOK_DropdownCreateInfo()
|
||||
info.text = option.label
|
||||
info.func = function()
|
||||
MTH_BOOK_STATE.petZoneFilter = option.value
|
||||
MTH_BOOK_STATE.page = 1
|
||||
MTH_BOOK_STATE.selectedEntry = nil
|
||||
if zoneDD then MTH_BOOK_DropdownSetText(zoneDD, option.label) end
|
||||
MTH_BOOK_RefreshFilter()
|
||||
end
|
||||
info.checked = (MTH_BOOK_STATE.petZoneFilter == option.value)
|
||||
UIDropDownMenu_AddButton(info)
|
||||
end
|
||||
end
|
||||
MTH_BOOK_STATE._beastZoneInitFunc = zoneInitFunc
|
||||
|
||||
local zoneDD = getglobal("MTH_BOOK_BeastZoneDropdown")
|
||||
if zoneDD then
|
||||
UIDropDownMenu_Initialize(zoneDD, zoneInitFunc)
|
||||
UIDropDownMenu_SetWidth(120, zoneDD)
|
||||
UIDropDownMenu_JustifyText("LEFT", zoneDD)
|
||||
MTH_BOOK_UpdateBeastZoneDropdownText()
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_BOOK_WireUI(frame)
|
||||
if frame and frame.SetBackdropColor then
|
||||
frame:SetBackdropColor(0.05, 0.05, 0.05, 1.00)
|
||||
@@ -4789,12 +5168,6 @@ local function MTH_BOOK_WireUI(frame)
|
||||
local requireVendor = getglobal("MTH_BOOK_RequireVendor")
|
||||
local requireDrop = getglobal("MTH_BOOK_RequireDrop")
|
||||
local requireObject = getglobal("MTH_BOOK_RequireObject")
|
||||
local abilityDropdown = getglobal("MTH_BOOK_AbilityDropdown")
|
||||
local rankDropdown = getglobal("MTH_BOOK_RankDropdown")
|
||||
local petLearnSourceDropdown = getglobal("MTH_BOOK_PetLearnSourceDropdown")
|
||||
local itemSubtypeDropdown = getglobal("MTH_BOOK_ItemSubtypeDropdown")
|
||||
local npcFunctionDropdown = getglobal("MTH_BOOK_NPCFunctionDropdown")
|
||||
local npcZoneDropdown = getglobal("MTH_BOOK_NPCZoneDropdown")
|
||||
local petBookScanButton = getglobal("MTH_BOOK_PetBookScanButton")
|
||||
local hideNoAbilities = getglobal("MTH_BOOK_HideNoAbilities")
|
||||
local hideUnknown = getglobal("MTH_BOOK_HideUnknown")
|
||||
@@ -4855,6 +5228,7 @@ local function MTH_BOOK_WireUI(frame)
|
||||
MTH_BOOK_InitFamilyDropdown()
|
||||
MTH_BOOK_InitAbilityDropdown()
|
||||
MTH_BOOK_InitRankDropdown()
|
||||
MTH_BOOK_WireBeastDropdowns()
|
||||
MTH_BOOK_InitPetLearnSourceDropdown()
|
||||
MTH_BOOK_InitItemSubtypeDropdown()
|
||||
MTH_BOOK_InitNPCFunctionDropdown()
|
||||
@@ -5004,19 +5378,19 @@ local function MTH_BOOK_WireUI(frame)
|
||||
listSlider:SetScript("OnMouseDown", function()
|
||||
MTH_BOOK_STATE.sliderDragging = true
|
||||
MTH_BOOK_SetSliderFromCursor(this)
|
||||
this:SetScript("OnUpdate", function()
|
||||
if IsMouseButtonDown and not IsMouseButtonDown("LeftButton") then
|
||||
MTH_BOOK_STATE.sliderDragging = false
|
||||
this:SetScript("OnUpdate", nil)
|
||||
else
|
||||
MTH_BOOK_SetSliderFromCursor(this)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
listSlider:SetScript("OnMouseUp", function()
|
||||
MTH_BOOK_SetSliderFromCursor(this)
|
||||
MTH_BOOK_STATE.sliderDragging = false
|
||||
end)
|
||||
listSlider:SetScript("OnUpdate", function()
|
||||
if MTH_BOOK_STATE.sliderDragging then
|
||||
if IsMouseButtonDown and not IsMouseButtonDown("LeftButton") then
|
||||
MTH_BOOK_STATE.sliderDragging = false
|
||||
else
|
||||
MTH_BOOK_SetSliderFromCursor(this)
|
||||
end
|
||||
end
|
||||
this:SetScript("OnUpdate", nil)
|
||||
end)
|
||||
listSlider:SetScript("OnValueChanged", function()
|
||||
local value = this:GetValue()
|
||||
@@ -5119,19 +5493,19 @@ local function MTH_BOOK_WireUI(frame)
|
||||
sliderBackdrop:SetScript("OnMouseDown", function()
|
||||
MTH_BOOK_STATE.sliderDragging = true
|
||||
MTH_BOOK_SetSliderFromCursor(listSlider)
|
||||
listSlider:SetScript("OnUpdate", function()
|
||||
if IsMouseButtonDown and not IsMouseButtonDown("LeftButton") then
|
||||
MTH_BOOK_STATE.sliderDragging = false
|
||||
this:SetScript("OnUpdate", nil)
|
||||
else
|
||||
MTH_BOOK_SetSliderFromCursor(listSlider)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
sliderBackdrop:SetScript("OnMouseUp", function()
|
||||
MTH_BOOK_SetSliderFromCursor(listSlider)
|
||||
MTH_BOOK_STATE.sliderDragging = false
|
||||
end)
|
||||
sliderBackdrop:SetScript("OnUpdate", function()
|
||||
if MTH_BOOK_STATE.sliderDragging then
|
||||
if IsMouseButtonDown and not IsMouseButtonDown("LeftButton") then
|
||||
MTH_BOOK_STATE.sliderDragging = false
|
||||
else
|
||||
MTH_BOOK_SetSliderFromCursor(listSlider)
|
||||
end
|
||||
end
|
||||
listSlider:SetScript("OnUpdate", nil)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
+24
-5
@@ -57,6 +57,14 @@
|
||||
</Anchors>
|
||||
</FontString>
|
||||
|
||||
<FontString name="$parentBeastZoneLabel" inherits="GameFontNormalSmall" text="Zone:" hidden="true">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT">
|
||||
<Offset><AbsDimension x="464" y="-142"/></Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
|
||||
</Layer>
|
||||
</Layers>
|
||||
|
||||
@@ -74,7 +82,7 @@
|
||||
</Frame>
|
||||
|
||||
<Frame name="$parentDetailBackdrop">
|
||||
<Size><AbsDimension x="136" y="324"/></Size>
|
||||
<Size><AbsDimension x="136" y="155"/></Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT"><Offset><AbsDimension x="608" y="-166"/></Offset></Anchor>
|
||||
</Anchors>
|
||||
@@ -85,7 +93,7 @@
|
||||
</Backdrop>
|
||||
<Frames>
|
||||
<EditBox name="$parentDetailText" autoFocus="false" multiLine="true" text="Select an entry to view details.">
|
||||
<Size><AbsDimension x="120" y="306"/></Size>
|
||||
<Size><AbsDimension x="120" y="139"/></Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT"><Offset><AbsDimension x="8" y="-8"/></Offset></Anchor>
|
||||
</Anchors>
|
||||
@@ -96,7 +104,7 @@
|
||||
<Button name="$parentOpenMapButton" inherits="UIPanelButtonTemplate" text="Open Map" hidden="true">
|
||||
<Size><AbsDimension x="136" y="22"/></Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT"><Offset><AbsDimension x="608" y="-496"/></Offset></Anchor>
|
||||
<Anchor point="TOPLEFT"><Offset><AbsDimension x="608" y="-524"/></Offset></Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
|
||||
@@ -265,7 +273,7 @@
|
||||
</Frame>
|
||||
<CheckButton name="$parentPetInZoneOnly" inherits="UICheckButtonTemplate" hidden="true">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT"><Offset><AbsDimension x="488" y="-112"/></Offset></Anchor>
|
||||
<Anchor point="TOPLEFT"><Offset><AbsDimension x="526" y="-106"/></Offset></Anchor>
|
||||
</Anchors>
|
||||
</CheckButton>
|
||||
<Button name="$parentShowAllOnMapButton" inherits="UIPanelButtonTemplate" text="Show all on map" hidden="true">
|
||||
@@ -298,8 +306,19 @@
|
||||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="232" y="-140"/></Offset></Anchor></Anchors>
|
||||
</CheckButton>
|
||||
<CheckButton name="$parentHideUnknown" inherits="UICheckButtonTemplate">
|
||||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="372" y="-140"/></Offset></Anchor></Anchors>
|
||||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="290" y="-140"/></Offset></Anchor></Anchors>
|
||||
</CheckButton>
|
||||
<Frame name="$parentBeastContinentDropdown" inherits="UIDropDownMenuTemplate" hidden="true">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT"><Offset><AbsDimension x="482" y="-136"/></Offset></Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
|
||||
<Frame name="$parentBeastZoneDropdown" inherits="UIDropDownMenuTemplate" hidden="true">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT"><Offset><AbsDimension x="592" y="-136"/></Offset></Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
|
||||
<Frame name="$parentListSliderBackdrop">
|
||||
<Size><AbsDimension x="22" y="322"/></Size>
|
||||
|
||||
@@ -9,7 +9,6 @@ local MTH_LOCALE_ALIASES = {
|
||||
enGB = "enUS",
|
||||
esMX = "esES",
|
||||
zhTW = "zhCN",
|
||||
frFR = "enUS",
|
||||
}
|
||||
|
||||
local MTH_SUPPORTED_LOCALES = {
|
||||
@@ -198,6 +197,9 @@ local MTH_SPELL_ID_BY_TOKEN = {
|
||||
["Counterattack"] = 19306,
|
||||
["Clever Traps"] = 19239,
|
||||
["Deterrence"] = 19263,
|
||||
["Entrapment"] = 19184,
|
||||
["Entrapment (Rank 2)"] = 19387,
|
||||
["Entrapment (Rank 3)"] = 19388,
|
||||
["Explosive Trap"] = 13813,
|
||||
["Explosive Trap Effect"] = 13812,
|
||||
["Feed Pet"] = 6991,
|
||||
|
||||
+47
-23
@@ -12,6 +12,7 @@ MTH_Map = {
|
||||
mapZoneCache = {},
|
||||
focusNodes = {},
|
||||
pendingZoneOpenId = nil,
|
||||
pendingZoneOpenPfqId = nil,
|
||||
pendingZoneOpenSourceId = nil,
|
||||
pendingZoneOpenAttempts = 0,
|
||||
pendingZoneOpenNextAttemptAt = 0,
|
||||
@@ -60,11 +61,6 @@ local function MTH_Map_Mod(a, b)
|
||||
return 0
|
||||
end
|
||||
|
||||
local function MTH_Map_Log(msg)
|
||||
if MTH and MTH.debug and MTH.Print then
|
||||
MTH:Print("[MAP] " .. tostring(msg), "debug")
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_Map_NormalizeName(name)
|
||||
if not name then return "" end
|
||||
@@ -130,12 +126,18 @@ local function MTH_Map_GetZoneNameById(zoneId)
|
||||
local normalizedId = tonumber(zoneId) or zoneId
|
||||
if not normalizedId then return nil end
|
||||
|
||||
if MTH_DS_ZoneNamesFallback and MTH_DS_ZoneNamesFallback[normalizedId] then
|
||||
return MTH_DS_ZoneNamesFallback[normalizedId]
|
||||
-- Translate WMA→pfQ first so WMA IDs don't accidentally hit wrong pfQ entries.
|
||||
local pfqId = normalizedId
|
||||
if type(MTH_MAP_WMA_TO_PFQ) == "table" then
|
||||
pfqId = MTH_MAP_WMA_TO_PFQ[normalizedId] or normalizedId
|
||||
end
|
||||
|
||||
if MTH_DS_ZoneNamesFallback and MTH_DS_ZoneNamesFallback[pfqId] then
|
||||
return MTH_DS_ZoneNamesFallback[pfqId]
|
||||
end
|
||||
|
||||
if not MTH_DS_Zones then return nil end
|
||||
local row = MTH_DS_Zones[normalizedId] or MTH_DS_Zones[tostring(normalizedId)]
|
||||
local row = MTH_DS_Zones[pfqId] or MTH_DS_Zones[tostring(pfqId)]
|
||||
if not row or not row.names then return nil end
|
||||
return row.names.enUS or row.names[GetLocale()] or row.names.deDE or row.names.frFR
|
||||
end
|
||||
@@ -327,7 +329,6 @@ function MTH_Map:BuildZoneLookup()
|
||||
for _ in pairs(self.zoneNameNormToId) do
|
||||
count = count + 1
|
||||
end
|
||||
MTH_Map_Log("Zone lookup rebuilt: " .. tostring(count) .. " entries")
|
||||
end
|
||||
|
||||
function MTH_Map:GetMapIDByName(name)
|
||||
@@ -418,6 +419,15 @@ function MTH_Map:ResolveZoneHierarchy(zoneId)
|
||||
return resolved
|
||||
end
|
||||
|
||||
-- Translate a pfQ AreaTable ID to a WMA ID (for zone matching against coord tuples).
|
||||
-- Falls back to the pfQ ID itself if no mapping exists (sub-zones, custom zones).
|
||||
local function MTH_Map_PfqToWma(pfqId)
|
||||
if type(MTH_MAP_PFQ_TO_WMA) == "table" then
|
||||
return MTH_MAP_PFQ_TO_WMA[pfqId] or pfqId
|
||||
end
|
||||
return pfqId
|
||||
end
|
||||
|
||||
function MTH_Map:GetCurrentMapID()
|
||||
local continent = GetCurrentMapContinent and GetCurrentMapContinent() or nil
|
||||
local zone = GetCurrentMapZone and GetCurrentMapZone() or nil
|
||||
@@ -434,6 +444,7 @@ function MTH_Map:GetCurrentMapID()
|
||||
if mapId then
|
||||
local resolved = self:ResolveZoneHierarchy(mapId)
|
||||
local normalized = resolved.zoneId or mapId
|
||||
normalized = MTH_Map_PfqToWma(normalized)
|
||||
self.lastMapContext = string.format("continent=%s zone=%s mapZone='%s' real=nil mapId=%s normalized=%s", tostring(continent), tostring(zone), tostring(zoneName), tostring(mapId), tostring(normalized))
|
||||
return normalized
|
||||
end
|
||||
@@ -449,6 +460,7 @@ function MTH_Map:GetCurrentMapID()
|
||||
mapId = self:GetMapIDByName(real)
|
||||
local resolved = self:ResolveZoneHierarchy(mapId)
|
||||
local normalized = resolved.zoneId or mapId
|
||||
normalized = MTH_Map_PfqToWma(normalized)
|
||||
self.lastMapContext = string.format("continent=%s zone=%s mapZone='%s' real='%s' mapId=%s normalized=%s", tostring(continent), tostring(zone), tostring(zoneName), tostring(real), tostring(mapId), tostring(normalized))
|
||||
return normalized
|
||||
end
|
||||
@@ -467,6 +479,7 @@ end
|
||||
|
||||
local function MTH_Map_ClearPendingZoneOpen()
|
||||
MTH_Map.pendingZoneOpenId = nil
|
||||
MTH_Map.pendingZoneOpenPfqId = nil
|
||||
MTH_Map.pendingZoneOpenSourceId = nil
|
||||
MTH_Map.pendingZoneOpenAttempts = 0
|
||||
MTH_Map.pendingZoneOpenNextAttemptAt = 0
|
||||
@@ -532,8 +545,12 @@ end
|
||||
function MTH_Map:OpenWorldMapForZone(zoneId)
|
||||
local zid = tonumber(zoneId)
|
||||
if not zid then return false end
|
||||
local resolved = self:ResolveZoneHierarchy(zid)
|
||||
local targetZoneId = tonumber(resolved.zoneId or zid) or zid
|
||||
-- Translate WMA ID → pfQ so game map APIs (pfMap, SetMapZoom) work correctly.
|
||||
local pfqZid = (type(MTH_MAP_WMA_TO_PFQ) == "table" and MTH_MAP_WMA_TO_PFQ[zid]) or zid
|
||||
local resolved = self:ResolveZoneHierarchy(pfqZid)
|
||||
local targetZoneId = tonumber(resolved.zoneId or pfqZid) or pfqZid
|
||||
-- WMA ID of this zone, for comparing against GetCurrentMapID() which returns WMA IDs.
|
||||
local targetWmaId = (type(MTH_MAP_PFQ_TO_WMA) == "table" and MTH_MAP_PFQ_TO_WMA[targetZoneId]) or zid
|
||||
|
||||
if ToggleWorldMap then
|
||||
if not WorldMapFrame or not WorldMapFrame:IsShown() then
|
||||
@@ -546,34 +563,39 @@ function MTH_Map:OpenWorldMapForZone(zoneId)
|
||||
if pfMap and pfMap.SetMapByID then
|
||||
pfMap:SetMapByID(targetZoneId)
|
||||
local currentAfterPF = self:GetCurrentMapID()
|
||||
if tonumber(currentAfterPF) == tonumber(targetZoneId) then
|
||||
if tonumber(currentAfterPF) == tonumber(targetWmaId) then
|
||||
MTH_Map_ClearPendingZoneOpen()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local zoomApplied = MTH_Map_ApplyWorldMapZone(targetZoneId, zid)
|
||||
local zoomApplied = MTH_Map_ApplyWorldMapZone(zid, zid)
|
||||
if zoomApplied then
|
||||
local currentAfterZoom = self:GetCurrentMapID()
|
||||
if tonumber(currentAfterZoom) == tonumber(targetZoneId) then
|
||||
if tonumber(currentAfterZoom) == tonumber(targetWmaId) then
|
||||
MTH_Map_ClearPendingZoneOpen()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local nowMapId = self:GetCurrentMapID()
|
||||
if tonumber(nowMapId) == tonumber(targetZoneId) then
|
||||
if tonumber(nowMapId) == tonumber(targetWmaId) then
|
||||
MTH_Map_ClearPendingZoneOpen()
|
||||
return true
|
||||
end
|
||||
|
||||
self.pendingZoneOpenId = targetZoneId
|
||||
self.pendingZoneOpenSourceId = zid
|
||||
self.pendingZoneOpenId = targetWmaId
|
||||
self.pendingZoneOpenPfqId = targetZoneId
|
||||
self.pendingZoneOpenSourceId = pfqZid
|
||||
self.pendingZoneOpenAttempts = 8
|
||||
self.pendingZoneOpenNextAttemptAt = (GetTime and GetTime() or 0) + 0.25
|
||||
return true
|
||||
end
|
||||
|
||||
function MTH_Map:GetFamilyColor(family)
|
||||
return MTH_Map_GetFamilyColor(family)
|
||||
end
|
||||
|
||||
function MTH_Map:FocusBeast(beastId, beast)
|
||||
local id = tonumber(beastId)
|
||||
if not id then return false end
|
||||
@@ -890,7 +912,6 @@ function MTH_Map:RebuildNodes()
|
||||
end
|
||||
end
|
||||
|
||||
MTH_Map_Log("Rebuilt nodes for source '" .. tostring(self.activeSource) .. "'")
|
||||
end
|
||||
|
||||
function MTH_Map:UpdateWorldMap()
|
||||
@@ -1019,6 +1040,11 @@ function MTH_Map:UpdateMinimap()
|
||||
|
||||
local minimapSizes = MTH_DS_MinimapSizes or (pfDB and pfDB["minimap"])
|
||||
local mapSize = minimapSizes and minimapSizes[mapId]
|
||||
if not mapSize and type(MTH_MAP_WMA_TO_PFQ) == "table" then
|
||||
-- Fallback: try the pfQ key (for sub-zones not yet mapped to WMA)
|
||||
local pfqId = MTH_MAP_WMA_TO_PFQ[mapId]
|
||||
mapSize = pfqId and minimapSizes and minimapSizes[pfqId]
|
||||
end
|
||||
if not mapSize then
|
||||
self.lastMiniReason = self.verboseMiniReasons and "missing-minimap-size" or "missing-size"
|
||||
self._lastMiniState = nil
|
||||
@@ -1227,7 +1253,6 @@ function MTH_Map:RegisterDefaultProviders()
|
||||
end
|
||||
|
||||
if unresolvedCount > 0 then
|
||||
MTH_Map_Log("drops source: " .. tostring(unresolvedCount) .. " drop-creature links have no loaded coordinates (sample IDs: " .. table.concat(unresolvedSamples, ", ") .. ")")
|
||||
end
|
||||
|
||||
return nodes
|
||||
@@ -1244,7 +1269,7 @@ function MTH_Map:Init()
|
||||
self.nodesByZone = self.nodesByZone or {}
|
||||
|
||||
if not self.controller then
|
||||
self.controller = CreateFrame("Frame", "MTHMapController", UIParent)
|
||||
self.controller = CreateFrame("Frame", "MTH_MapController", UIParent)
|
||||
self.controller:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
self.controller:RegisterEvent("ZONE_CHANGED")
|
||||
self.controller:RegisterEvent("ZONE_CHANGED_NEW_AREA")
|
||||
@@ -1274,9 +1299,9 @@ function MTH_Map:Init()
|
||||
|
||||
if WorldMapFrame and WorldMapFrame:IsShown() then
|
||||
if pfMap and pfMap.SetMapByID then
|
||||
pfMap:SetMapByID(MTH_Map.pendingZoneOpenId)
|
||||
pfMap:SetMapByID(MTH_Map.pendingZoneOpenPfqId or MTH_Map.pendingZoneOpenId)
|
||||
end
|
||||
MTH_Map_ApplyWorldMapZone(MTH_Map.pendingZoneOpenId, MTH_Map.pendingZoneOpenSourceId)
|
||||
MTH_Map_ApplyWorldMapZone(MTH_Map.pendingZoneOpenId or MTH_Map.pendingZoneOpenPfqId, MTH_Map.pendingZoneOpenId or MTH_Map.pendingZoneOpenPfqId)
|
||||
local nowMapId = MTH_Map:GetCurrentMapID()
|
||||
if tonumber(nowMapId) == tonumber(MTH_Map.pendingZoneOpenId) then
|
||||
MTH_Map_ClearPendingZoneOpen()
|
||||
@@ -1318,5 +1343,4 @@ function MTH_Map:Init()
|
||||
end)
|
||||
end
|
||||
|
||||
MTH_Map_Log("Map system initialized")
|
||||
end
|
||||
|
||||
+29
-26
@@ -1,5 +1,13 @@
|
||||
------------------------------------------------------
|
||||
-- MetaHunt Minimap Button
|
||||
--
|
||||
-- NOTE: The namespace table is MTH_MinimapButton (a plain Lua table).
|
||||
-- The actual UI frame is named "MTH_MinimapBtn" to avoid a global
|
||||
-- collision — CreateFrame("...", "MTH_MinimapButton", ...) would
|
||||
-- OVERWRITE the namespace table with the frame object, orphaning
|
||||
-- all methods and .frame/.icon references. pfUI iterates Minimap
|
||||
-- children by name and calls _G[name]:GetHeight(); if the global is
|
||||
-- a plain {} table instead of a frame, that call crashes.
|
||||
------------------------------------------------------
|
||||
|
||||
if not MTH_MinimapButton then
|
||||
@@ -84,7 +92,9 @@ function MTH_MinimapButton:Initialize()
|
||||
return
|
||||
end
|
||||
|
||||
local button = CreateFrame("Button", "MTH_MinimapButtonFrame", Minimap)
|
||||
-- Frame name is MTH_MinimapBtn (NOT "MTH_MinimapButton") to avoid
|
||||
-- overwriting the namespace table in _G.
|
||||
local button = CreateFrame("Button", "MTH_MinimapBtn", Minimap)
|
||||
if not button then
|
||||
return
|
||||
end
|
||||
@@ -114,10 +124,9 @@ function MTH_MinimapButton:Initialize()
|
||||
highlight:SetHeight(31)
|
||||
highlight:SetPoint("CENTER", button, "CENTER", 0, 0)
|
||||
|
||||
button:SetScript("OnEnter", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
GameTooltip:SetOwner(self, "ANCHOR_LEFT")
|
||||
button:SetScript("OnEnter", function()
|
||||
if not this then return end
|
||||
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
|
||||
GameTooltip:SetText(MTH_MB_L("MINIMAP_TITLE", "MetaHunt"), 1, 0.82, 0)
|
||||
GameTooltip:AddLine(MTH_MB_L("MINIMAP_HINT_LEFT_CLICK", "Left-Click: Open Hunter Book"), 1, 1, 1)
|
||||
GameTooltip:AddLine(MTH_MB_L("MINIMAP_HINT_RIGHT_CLICK", "Right-Click: Open MetaHunt Options"), 1, 1, 1)
|
||||
@@ -129,25 +138,23 @@ function MTH_MinimapButton:Initialize()
|
||||
GameTooltip:Hide()
|
||||
end)
|
||||
|
||||
button:SetScript("OnDragStart", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
self.dragging = 1
|
||||
self:SetScript("OnUpdate", function()
|
||||
button:SetScript("OnDragStart", function()
|
||||
if not this then return end
|
||||
this.dragging = 1
|
||||
this:SetScript("OnUpdate", function()
|
||||
MTH_MB_UpdateDragPosition()
|
||||
end)
|
||||
end)
|
||||
|
||||
button:SetScript("OnDragStop", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
self.dragging = nil
|
||||
self:SetScript("OnUpdate", nil)
|
||||
button:SetScript("OnDragStop", function()
|
||||
if not this then return end
|
||||
this.dragging = nil
|
||||
this:SetScript("OnUpdate", nil)
|
||||
MTH_MB_UpdateDragPosition()
|
||||
end)
|
||||
|
||||
button:SetScript("OnClick", function(_, mouseButton)
|
||||
mouseButton = mouseButton or arg1
|
||||
button:SetScript("OnClick", function()
|
||||
local mouseButton = arg1
|
||||
if mouseButton == "RightButton" then
|
||||
if type(MTH_OpenOptions) == "function" then
|
||||
MTH_OpenOptions("General")
|
||||
@@ -167,16 +174,12 @@ function MTH_MinimapButton:Initialize()
|
||||
MTH_MB_UpdatePosition()
|
||||
end
|
||||
|
||||
local loader = CreateFrame("Frame", "MTH_MinimapButtonLoader")
|
||||
local loader = CreateFrame("Frame", "MTH_MinimapLoader")
|
||||
loader:RegisterEvent("ADDON_LOADED")
|
||||
loader:SetScript("OnEvent", function(self, eventName, addonName)
|
||||
eventName = eventName or event
|
||||
addonName = addonName or arg1
|
||||
if eventName == "ADDON_LOADED" and addonName == "MetaHunt" then
|
||||
loader:SetScript("OnEvent", function()
|
||||
if event == "ADDON_LOADED" and arg1 == "MetaHunt" then
|
||||
MTH_MinimapButton:Initialize()
|
||||
if self and self.UnregisterAllEvents then
|
||||
self:UnregisterAllEvents()
|
||||
self:SetScript("OnEvent", nil)
|
||||
end
|
||||
this:UnregisterAllEvents()
|
||||
this:SetScript("OnEvent", nil)
|
||||
end
|
||||
end)
|
||||
|
||||
+42
-43
@@ -53,6 +53,14 @@ local function MTH_AB_SetCheckedNoClick(check, checked)
|
||||
MTH_AB_STATE.syncing = false
|
||||
end
|
||||
|
||||
local function MTH_AB_IsChecked(control)
|
||||
if not control or type(control.GetChecked) ~= "function" then
|
||||
return false
|
||||
end
|
||||
local checked = control:GetChecked()
|
||||
return checked == 1 or checked == true
|
||||
end
|
||||
|
||||
local function MTH_AB_GetEngine()
|
||||
return MTH_AutoBuyEngine
|
||||
end
|
||||
@@ -92,10 +100,10 @@ end
|
||||
|
||||
local function MTH_AB_EnsureConfig()
|
||||
local store = MTH_AB_GetStore()
|
||||
if store.enabled == nil then store.enabled = true end
|
||||
if store.enabled == nil then store.enabled = false end
|
||||
if type(store.projectiles) ~= "table" then store.projectiles = {} end
|
||||
if type(store.petFood) ~= "table" then store.petFood = {} end
|
||||
if store.projectiles.enabled == nil then store.projectiles.enabled = true end
|
||||
if store.projectiles.enabled == nil then store.projectiles.enabled = false end
|
||||
if store.petFood.enabled == nil then store.petFood.enabled = false end
|
||||
if store.petFood.stacks == nil then store.petFood.stacks = 1 end
|
||||
if store.petFood.scope == nil then store.petFood.scope = "current" end
|
||||
@@ -510,7 +518,7 @@ local function MTH_AB_RefreshOptionsUI()
|
||||
local store = MTH_AB_EnsureConfig()
|
||||
local moduleEnabled = true
|
||||
if MTH and MTH.IsModuleEnabled then
|
||||
moduleEnabled = MTH:IsModuleEnabled("autobuy", true) and true or false
|
||||
moduleEnabled = MTH:IsModuleEnabled("autobuy", false) and true or false
|
||||
end
|
||||
|
||||
MTH_AB_SetCheckedNoClick(MTH_AB_STATE.controls.moduleEnabled, moduleEnabled)
|
||||
@@ -649,28 +657,25 @@ local function MTH_AB_CreateRow(container, subtype, index, xBase, yOffset)
|
||||
row.suffix:SetText("Stacks")
|
||||
|
||||
if row.check then
|
||||
row.check:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self or MTH_AB_STATE.syncing then return end
|
||||
row.check:SetScript("OnClick", function()
|
||||
if not this or MTH_AB_STATE.syncing then return end
|
||||
local store = MTH_AB_EnsureConfig()
|
||||
MTH_AB_SetRuleEnabled(store, subtype, index, self:GetChecked() and true or false)
|
||||
MTH_AB_SetRuleEnabled(store, subtype, index, MTH_AB_IsChecked(this))
|
||||
MTH_AB_RefreshOptionsUI()
|
||||
end)
|
||||
end
|
||||
|
||||
row.qty:SetScript("OnEnterPressed", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
row.qty:SetScript("OnEnterPressed", function()
|
||||
if not this then return end
|
||||
local store = MTH_AB_EnsureConfig()
|
||||
MTH_AB_SetRuleStacks(store, subtype, index, self:GetText())
|
||||
MTH_AB_SetRuleStacks(store, subtype, index, this:GetText())
|
||||
MTH_AB_RefreshOptionsUI()
|
||||
self:ClearFocus()
|
||||
this:ClearFocus()
|
||||
end)
|
||||
row.qty:SetScript("OnEditFocusLost", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
row.qty:SetScript("OnEditFocusLost", function()
|
||||
if not this then return end
|
||||
local store = MTH_AB_EnsureConfig()
|
||||
MTH_AB_SetRuleStacks(store, subtype, index, self:GetText())
|
||||
MTH_AB_SetRuleStacks(store, subtype, index, this:GetText())
|
||||
MTH_AB_RefreshOptionsUI()
|
||||
end)
|
||||
|
||||
@@ -707,11 +712,10 @@ local function MTH_AB_BuildUI(container)
|
||||
|
||||
controls.moduleEnabled = MTH_CreateCheckbox(container, "MetaHuntOptionsAutoBuyModuleEnabled", "Enable Auto Buy module", -30)
|
||||
if controls.moduleEnabled then
|
||||
controls.moduleEnabled:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self or MTH_AB_STATE.syncing then return end
|
||||
controls.moduleEnabled:SetScript("OnClick", function()
|
||||
if not this or MTH_AB_STATE.syncing then return end
|
||||
if MTH and MTH.SetModuleEnabled then
|
||||
local ok, err = MTH:SetModuleEnabled("autobuy", self:GetChecked() and true or false)
|
||||
local ok, err = MTH:SetModuleEnabled("autobuy", MTH_AB_IsChecked(this))
|
||||
if not ok and MTH and MTH.Print then
|
||||
MTH:Print("Failed to change Auto Buy state: " .. tostring(err), "error")
|
||||
end
|
||||
@@ -722,11 +726,10 @@ local function MTH_AB_BuildUI(container)
|
||||
|
||||
controls.projectilesEnabled = MTH_CreateCheckbox(container, "MetaHuntOptionsAutoBuyProjectilesEnabled", "Enable for Projectiles", -74)
|
||||
if controls.projectilesEnabled then
|
||||
controls.projectilesEnabled:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self or MTH_AB_STATE.syncing then return end
|
||||
controls.projectilesEnabled:SetScript("OnClick", function()
|
||||
if not this or MTH_AB_STATE.syncing then return end
|
||||
local store = MTH_AB_EnsureConfig()
|
||||
store.projectiles.enabled = self:GetChecked() and true or false
|
||||
store.projectiles.enabled = MTH_AB_IsChecked(this)
|
||||
MTH_AB_RefreshOptionsUI()
|
||||
end)
|
||||
end
|
||||
@@ -761,11 +764,10 @@ local function MTH_AB_BuildUI(container)
|
||||
|
||||
controls.petFoodEnabled = MTH_CreateCheckbox(container, "MetaHuntOptionsAutoBuyPetFoodEnabled", "Enable for Pet Food", -322, MTH_AB_LAYOUT.LEFT_SECTION_X)
|
||||
if controls.petFoodEnabled then
|
||||
controls.petFoodEnabled:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self or MTH_AB_STATE.syncing then return end
|
||||
controls.petFoodEnabled:SetScript("OnClick", function()
|
||||
if not this or MTH_AB_STATE.syncing then return end
|
||||
local store = MTH_AB_EnsureConfig()
|
||||
store.petFood.enabled = self:GetChecked() and true or false
|
||||
store.petFood.enabled = MTH_AB_IsChecked(this)
|
||||
MTH_AB_RefreshOptionsUI()
|
||||
end)
|
||||
end
|
||||
@@ -783,19 +785,17 @@ local function MTH_AB_BuildUI(container)
|
||||
controls.petFoodQty:SetHeight(20)
|
||||
controls.petFoodQty:SetNumeric(true)
|
||||
controls.petFoodQty:SetAutoFocus(false)
|
||||
controls.petFoodQty:SetScript("OnEnterPressed", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
controls.petFoodQty:SetScript("OnEnterPressed", function()
|
||||
if not this then return end
|
||||
local store = MTH_AB_EnsureConfig()
|
||||
MTH_AB_SetPetFoodStacks(store, self:GetText())
|
||||
MTH_AB_SetPetFoodStacks(store, this:GetText())
|
||||
MTH_AB_RefreshOptionsUI()
|
||||
self:ClearFocus()
|
||||
this:ClearFocus()
|
||||
end)
|
||||
controls.petFoodQty:SetScript("OnEditFocusLost", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
controls.petFoodQty:SetScript("OnEditFocusLost", function()
|
||||
if not this then return end
|
||||
local store = MTH_AB_EnsureConfig()
|
||||
MTH_AB_SetPetFoodStacks(store, self:GetText())
|
||||
MTH_AB_SetPetFoodStacks(store, this:GetText())
|
||||
MTH_AB_RefreshOptionsUI()
|
||||
end)
|
||||
end
|
||||
@@ -808,9 +808,8 @@ local function MTH_AB_BuildUI(container)
|
||||
|
||||
controls.petFoodScopeCurrent = MTH_CreateCheckbox(container, "MetaHuntOptionsAutoBuyPetFoodScopeCurrent", "Buy only for my current pet", -376, MTH_AB_LAYOUT.LEFT_SECTION_X + 28)
|
||||
if controls.petFoodScopeCurrent then
|
||||
controls.petFoodScopeCurrent:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self or MTH_AB_STATE.syncing then return end
|
||||
controls.petFoodScopeCurrent:SetScript("OnClick", function()
|
||||
if not this or MTH_AB_STATE.syncing then return end
|
||||
local store = MTH_AB_EnsureConfig()
|
||||
store.petFood.scope = "current"
|
||||
MTH_AB_RefreshOptionsUI()
|
||||
@@ -819,9 +818,8 @@ local function MTH_AB_BuildUI(container)
|
||||
|
||||
controls.petFoodScopeAll = MTH_CreateCheckbox(container, "MetaHuntOptionsAutoBuyPetFoodScopeAll", "Buy for all my pets", -402, MTH_AB_LAYOUT.LEFT_SECTION_X + 28)
|
||||
if controls.petFoodScopeAll then
|
||||
controls.petFoodScopeAll:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self or MTH_AB_STATE.syncing then return end
|
||||
controls.petFoodScopeAll:SetScript("OnClick", function()
|
||||
if not this or MTH_AB_STATE.syncing then return end
|
||||
local store = MTH_AB_EnsureConfig()
|
||||
store.petFood.scope = "all"
|
||||
MTH_AB_RefreshOptionsUI()
|
||||
@@ -843,6 +841,7 @@ local function MTH_AB_BuildUI(container)
|
||||
text:SetText("")
|
||||
controls.petFoodPetLines[i] = { icon = icon, text = text }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function MTH_SetupAutoBuyOptions()
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
local MTH_AQ_READY = MTH_OptionsRequire and MTH_OptionsRequire("options-autoquest", {
|
||||
"MTH_GetFrame",
|
||||
"MTH_ClearContainer",
|
||||
"MTH_CreateCheckbox",
|
||||
})
|
||||
|
||||
local function MTH_AQ_IsChecked(control)
|
||||
if not control or type(control.GetChecked) ~= "function" then
|
||||
return false
|
||||
end
|
||||
local checked = control:GetChecked()
|
||||
return checked == 1 or checked == true
|
||||
end
|
||||
|
||||
local function MTH_AQ_EnsureStore()
|
||||
if type(MTH_CharSavedVariables) ~= "table" then
|
||||
MTH_CharSavedVariables = {}
|
||||
end
|
||||
if type(MTH_CharSavedVariables.autoquest) ~= "table" then
|
||||
MTH_CharSavedVariables.autoquest = {}
|
||||
end
|
||||
local store = MTH_CharSavedVariables.autoquest
|
||||
if type(MTH_CharSavedVariables.questautomation) == "table" then
|
||||
local legacy = MTH_CharSavedVariables.questautomation
|
||||
if store.scorpokDrazial == nil and legacy.scorpokDrazial ~= nil then
|
||||
store.scorpokDrazial = legacy.scorpokDrazial and true or false
|
||||
end
|
||||
if store.scorpokTooltip == nil and legacy.scorpokTooltip ~= nil then
|
||||
store.scorpokTooltip = legacy.scorpokTooltip and true or false
|
||||
end
|
||||
end
|
||||
if store.scorpokDrazial == nil then
|
||||
store.scorpokDrazial = false
|
||||
end
|
||||
if store.arrowsForSissies == nil then
|
||||
store.arrowsForSissies = false
|
||||
end
|
||||
return store
|
||||
end
|
||||
|
||||
function MTH_SetupAutoQuestOptions()
|
||||
if not MTH_AQ_READY then return end
|
||||
|
||||
local container = MTH_GetFrame("MetaHuntOptionsAutoQuest")
|
||||
if not container then return end
|
||||
|
||||
MTH_ClearContainer(container)
|
||||
|
||||
local title = container:CreateFontString("MetaHuntOptionsAutoQuestTitle", "ARTWORK", "GameFontHighlight")
|
||||
title:SetPoint("TOPLEFT", container, "TOPLEFT", 20, -10)
|
||||
title:SetText("Auto Quest")
|
||||
|
||||
local body = container:CreateFontString("MetaHuntOptionsAutoQuestBody", "ARTWORK", "GameFontNormalSmall")
|
||||
body:SetPoint("TOPLEFT", container, "TOPLEFT", 20, -30)
|
||||
body:SetWidth(560)
|
||||
body:SetJustifyH("LEFT")
|
||||
body:SetJustifyV("TOP")
|
||||
body:SetTextColor(0.45, 0.75, 1)
|
||||
body:SetText("Automation for specific quest interactions.")
|
||||
|
||||
local moduleEnabled = true
|
||||
if MTH and MTH.GetModule then
|
||||
local module = MTH:GetModule("autoquest")
|
||||
if type(module) == "table" and module.enabled ~= nil then
|
||||
moduleEnabled = module.enabled and true or false
|
||||
elseif MTH and MTH.IsModuleEnabled then
|
||||
moduleEnabled = MTH:IsModuleEnabled("autoquest", false) and true or false
|
||||
end
|
||||
elseif MTH and MTH.IsModuleEnabled then
|
||||
moduleEnabled = MTH:IsModuleEnabled("autoquest", false) and true or false
|
||||
end
|
||||
local moduleToggle = MTH_CreateCheckbox(container, "MetaHuntOptionsAutoQuestModuleToggle", "Enable Auto Quest module", -70, 20)
|
||||
if moduleToggle then
|
||||
moduleToggle:SetChecked(moduleEnabled and true or false)
|
||||
moduleToggle:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local enabled = MTH_AQ_IsChecked(this)
|
||||
if MTH and MTH.SetModuleEnabled then
|
||||
local ok, err = MTH:SetModuleEnabled("autoquest", enabled)
|
||||
if not ok and MTH and MTH.Print then
|
||||
MTH:Print("Failed to change Auto Quest module state: " .. tostring(err), "error")
|
||||
end
|
||||
end
|
||||
local module = MTH and MTH.GetModule and MTH:GetModule("autoquest") or nil
|
||||
local actual = (type(module) == "table" and module.enabled ~= nil) and (module.enabled and true or false) or enabled
|
||||
this:SetChecked(actual and true or false)
|
||||
end)
|
||||
end
|
||||
|
||||
local store = MTH_AQ_EnsureStore()
|
||||
if store.scorpokTooltip == nil then
|
||||
store.scorpokTooltip = false
|
||||
end
|
||||
|
||||
local sectionWidth = (container:GetWidth() or 600) - 40
|
||||
if sectionWidth < 360 then
|
||||
sectionWidth = 360
|
||||
end
|
||||
|
||||
local function ensureSection(name, sectionTitle, yOffset, height)
|
||||
local section = getglobal(name)
|
||||
if not section then
|
||||
section = CreateFrame("Frame", name, container, "OptionFrameBoxTemplate")
|
||||
end
|
||||
if not section then
|
||||
return nil
|
||||
end
|
||||
section:SetParent(container)
|
||||
section:ClearAllPoints()
|
||||
section:SetPoint("TOPLEFT", container, "TOPLEFT", 20, yOffset)
|
||||
section:SetWidth(sectionWidth)
|
||||
section:SetHeight(height)
|
||||
section:Show()
|
||||
|
||||
local titleFrame = getglobal(name .. "Title")
|
||||
if titleFrame then
|
||||
titleFrame:SetText(sectionTitle)
|
||||
end
|
||||
return section
|
||||
end
|
||||
|
||||
local function ensureCheckbox(section, name, label, yOffset, checked)
|
||||
local check = getglobal(name)
|
||||
if not check then
|
||||
check = CreateFrame("CheckButton", name, section, "OptionsCheckButtonTemplate")
|
||||
end
|
||||
if not check then
|
||||
return nil
|
||||
end
|
||||
check:SetParent(section)
|
||||
check:ClearAllPoints()
|
||||
check:SetPoint("TOPLEFT", section, "TOPLEFT", 12, yOffset)
|
||||
check:SetChecked(checked and true or false)
|
||||
check:Show()
|
||||
|
||||
local text = getglobal(name .. "Text")
|
||||
if text then
|
||||
text:SetText(label)
|
||||
end
|
||||
return check
|
||||
end
|
||||
|
||||
local scorpokSection = ensureSection("MetaHuntAutoQuestScorpokBox", "Salt of the Scorpok", -130, 112)
|
||||
if scorpokSection then
|
||||
local scorpokToggle = ensureCheckbox(
|
||||
scorpokSection,
|
||||
"MetaHuntOptionsAutoQuestScorpokToggle",
|
||||
"Enable SHIFT-rightclick for Bloodmage Drazial",
|
||||
-10,
|
||||
store.scorpokDrazial and true or false
|
||||
)
|
||||
if scorpokToggle then
|
||||
scorpokToggle:SetScript("OnClick", function()
|
||||
local enabled = MTH_AQ_IsChecked(this)
|
||||
store.scorpokDrazial = enabled and true or false
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
|
||||
if type(moduleStore) == "table" then
|
||||
moduleStore.scorpokDrazial = store.scorpokDrazial and true or false
|
||||
end
|
||||
end
|
||||
local module = MTH and MTH.GetModule and MTH:GetModule("autoquest")
|
||||
if module and module.SetScorpokDrazialEnabled then
|
||||
module:SetScorpokDrazialEnabled(enabled)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local tooltipToggle = ensureCheckbox(
|
||||
scorpokSection,
|
||||
"MetaHuntOptionsAutoQuestScorpokTooltipToggle",
|
||||
"Enhance Tooltip on Drazial and related beasts (requires Tooltips module enabled)",
|
||||
-42,
|
||||
store.scorpokTooltip and true or false
|
||||
)
|
||||
if tooltipToggle then
|
||||
tooltipToggle:SetScript("OnClick", function()
|
||||
local enabled = MTH_AQ_IsChecked(this)
|
||||
store.scorpokTooltip = enabled and true or false
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
|
||||
if type(moduleStore) == "table" then
|
||||
moduleStore.scorpokTooltip = store.scorpokTooltip and true or false
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
local sissiesSection = ensureSection("MetaHuntAutoQuestSissiesBox", "Arrows Are For Sissies", -255, 108)
|
||||
if sissiesSection then
|
||||
local sissiesNote = getglobal("MetaHuntOptionsAutoQuestSissiesNote")
|
||||
if not sissiesNote then
|
||||
sissiesNote = sissiesSection:CreateFontString("MetaHuntOptionsAutoQuestSissiesNote", "ARTWORK", "GameFontNormalSmall")
|
||||
end
|
||||
sissiesNote:ClearAllPoints()
|
||||
sissiesNote:SetPoint("TOPLEFT", sissiesSection, "TOPLEFT", 14, -10)
|
||||
sissiesNote:SetWidth(sectionWidth - 28)
|
||||
sissiesNote:SetJustifyH("LEFT")
|
||||
sissiesNote:SetTextColor(0.45, 0.75, 1)
|
||||
sissiesNote:SetText("Note that you should not activate this if you are using LazyPig")
|
||||
sissiesNote:Show()
|
||||
|
||||
local sissiesToggle = ensureCheckbox(
|
||||
sissiesSection,
|
||||
"MetaHuntOptionsAutoQuestSissiesToggle",
|
||||
"Enable SHIFT-rightclick for Artilleryman Sheldonore",
|
||||
-40,
|
||||
store.arrowsForSissies and true or false
|
||||
)
|
||||
if sissiesToggle then
|
||||
sissiesToggle:SetScript("OnClick", function()
|
||||
local enabled = MTH_AQ_IsChecked(this)
|
||||
store.arrowsForSissies = enabled and true or false
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
|
||||
if type(moduleStore) == "table" then
|
||||
moduleStore.arrowsForSissies = store.arrowsForSissies and true or false
|
||||
end
|
||||
end
|
||||
local module = MTH and MTH.GetModule and MTH:GetModule("autoquest")
|
||||
if module and module.SetArrowsForSissiesEnabled then
|
||||
module:SetArrowsForSissiesEnabled(enabled)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
+41
-37
@@ -307,6 +307,14 @@ local function MTH_CHRON_MakeSmall(parent, name, text, x, y)
|
||||
return label
|
||||
end
|
||||
|
||||
local function MTH_CHRON_IsChecked(control)
|
||||
if not control or type(control.GetChecked) ~= "function" then
|
||||
return false
|
||||
end
|
||||
local checked = control:GetChecked()
|
||||
return checked == 1 or checked == true
|
||||
end
|
||||
|
||||
|
||||
local function MTH_CHRON_MakeInput(parent, name, x, y, width, height, value, onAccept)
|
||||
local edit = CreateFrame("EditBox", name, parent, "InputBoxTemplate")
|
||||
@@ -318,13 +326,12 @@ local function MTH_CHRON_MakeInput(parent, name, x, y, width, height, value, onA
|
||||
edit:SetHeight(height or 20)
|
||||
edit:SetAutoFocus(false)
|
||||
edit:SetText(tostring(value or ""))
|
||||
edit:SetScript("OnEnterPressed", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
edit:SetScript("OnEnterPressed", function()
|
||||
if not this then return end
|
||||
if type(onAccept) == "function" then
|
||||
onAccept(self:GetText() or "")
|
||||
onAccept(this:GetText() or "")
|
||||
end
|
||||
self:ClearFocus()
|
||||
this:ClearFocus()
|
||||
end)
|
||||
return edit
|
||||
end
|
||||
@@ -377,14 +384,18 @@ local function MTH_CHRON_RenderTimerSection(container, profile, title, items, bu
|
||||
local check = MTH_CreateCheckbox(container, controlName, label, timerY, timerX)
|
||||
if check then
|
||||
check:SetChecked(profile.disabledSpells[bucket][timerName] == nil and true or false)
|
||||
check:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
if self:GetChecked() then
|
||||
check:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local currentlyDisabled = profile.disabledSpells[bucket][timerName] ~= nil
|
||||
if currentlyDisabled then
|
||||
profile.disabledSpells[bucket][timerName] = nil
|
||||
this:SetChecked(true)
|
||||
else
|
||||
profile.disabledSpells[bucket][timerName] = {}
|
||||
this:SetChecked(nil)
|
||||
end
|
||||
|
||||
MTH_CHRON_ApplyLiveProfile(profile)
|
||||
end)
|
||||
end
|
||||
timerY = timerY - 20
|
||||
@@ -457,10 +468,9 @@ function MTH_SetupChronometerOptions(tabKey)
|
||||
if moduleCheck then
|
||||
local module = MTH and MTH:GetModule("chronometer")
|
||||
moduleCheck:SetChecked(module and module.enabled and true or false)
|
||||
moduleCheck:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
local enabled = self:GetChecked() and true or false
|
||||
moduleCheck:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local enabled = MTH_CHRON_IsChecked(this)
|
||||
if MTH and MTH.SetModuleEnabled then
|
||||
MTH:SetModuleEnabled("chronometer", enabled)
|
||||
end
|
||||
@@ -482,40 +492,36 @@ function MTH_SetupChronometerOptions(tabKey)
|
||||
local killCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerFadeOnKill", "Fade on kill", -154)
|
||||
if killCheck then
|
||||
killCheck:SetChecked(profile.fadeonkill and true or false)
|
||||
killCheck:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
profile.fadeonkill = self:GetChecked() and true or false
|
||||
killCheck:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
profile.fadeonkill = MTH_CHRON_IsChecked(this)
|
||||
end)
|
||||
end
|
||||
|
||||
local fadeCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerFadeOnFade", "Fade on aura fade", -179)
|
||||
if fadeCheck then
|
||||
fadeCheck:SetChecked(profile.fadeonfade and true or false)
|
||||
fadeCheck:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
profile.fadeonfade = self:GetChecked() and true or false
|
||||
fadeCheck:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
profile.fadeonfade = MTH_CHRON_IsChecked(this)
|
||||
end)
|
||||
end
|
||||
|
||||
local selfCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerSelfBars", "Show self bars", -204)
|
||||
if selfCheck then
|
||||
selfCheck:SetChecked(profile.selfbars and true or false)
|
||||
selfCheck:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
profile.selfbars = self:GetChecked() and true or false
|
||||
selfCheck:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
profile.selfbars = MTH_CHRON_IsChecked(this)
|
||||
end)
|
||||
end
|
||||
|
||||
local onlySelfCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerOnlySelf", "Only self target", -229)
|
||||
if onlySelfCheck then
|
||||
onlySelfCheck:SetChecked(profile.onlyself and true or false)
|
||||
onlySelfCheck:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
profile.onlyself = self:GetChecked() and true or false
|
||||
onlySelfCheck:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
profile.onlyself = MTH_CHRON_IsChecked(this)
|
||||
end)
|
||||
end
|
||||
elseif section == "bar" then
|
||||
@@ -597,10 +603,9 @@ function MTH_SetupChronometerOptions(tabKey)
|
||||
local growCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerGrowUp", "Grow bars upward", -438)
|
||||
if growCheck then
|
||||
growCheck:SetChecked(profile.growup and true or false)
|
||||
growCheck:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
profile.growup = self:GetChecked() and true or false
|
||||
growCheck:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
profile.growup = MTH_CHRON_IsChecked(this)
|
||||
MTH_CHRON_ApplyLiveProfile(profile)
|
||||
end)
|
||||
end
|
||||
@@ -608,10 +613,9 @@ function MTH_SetupChronometerOptions(tabKey)
|
||||
local reverseCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsChronometerReverse", "Reverse bars", -463)
|
||||
if reverseCheck then
|
||||
reverseCheck:SetChecked(profile.reverse and true or false)
|
||||
reverseCheck:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
profile.reverse = self:GetChecked() and true or false
|
||||
reverseCheck:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
profile.reverse = MTH_CHRON_IsChecked(this)
|
||||
MTH_CHRON_ApplyLiveProfile(profile)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -159,6 +159,16 @@ function MTH_SetupCreditsOptions()
|
||||
cursor,
|
||||
-4)
|
||||
|
||||
|
||||
cursor = MTH_CreditsCreateText(content, cursor,
|
||||
MTH_CR_L("CREDITS_ABOUT_ICU", "- ICU was an old vanilla addon. I used the following last revision and added many more features of config options to it."),
|
||||
"GameFontNormalSmall", -10)
|
||||
cursor = MTH_CreditsCreateLink(content,
|
||||
"https://github.com/wigan91/ICU-TWoW",
|
||||
"https://github.com/wigan91/ICU-TWoW",
|
||||
cursor,
|
||||
-4)
|
||||
|
||||
cursor = MTH_CreditsCreateText(content, cursor,
|
||||
MTH_CR_L("CREDITS_ABOUT_MAP", "- The Map/Marker system is the one of pfQuest from Master Shagu. Unfortunately he is no more reachable for some months and I could not have some talk with him about this. I mostly let it untouched, I just made slight modifications so it can integrate better within Metahunt, and doesn't conflict with pfQuest."),
|
||||
"GameFontNormalSmall", -10)
|
||||
|
||||
@@ -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
|
||||
+18
-20
@@ -226,10 +226,9 @@ function MTH_SetupFeedOMaticOptions()
|
||||
|
||||
local moduleCheck = MTH_CreateCheckbox(container, "MetaHuntOptionsFeedOMaticEnabled", MTH_FOM_L("FOM_ENABLE_MODULE", "Enable FeedOMatic module"), -32 + yAdjust)
|
||||
if moduleCheck then
|
||||
moduleCheck:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
local enabled = self:GetChecked() == 1
|
||||
moduleCheck:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local enabled = this:GetChecked() == 1
|
||||
if MTH and MTH.SetModuleEnabled then
|
||||
local ok, err = MTH:SetModuleEnabled("feedomatic", enabled)
|
||||
if not ok and MTH and MTH.Print then
|
||||
@@ -263,11 +262,11 @@ function MTH_SetupFeedOMaticOptions()
|
||||
MTH_FOM_StartBindingCapture()
|
||||
end
|
||||
end)
|
||||
bindButton:SetScript("OnKeyDown", function(_, key)
|
||||
bindButton:SetScript("OnKeyDown", function()
|
||||
if not MTH_FOM_STATE.bindingCapture then
|
||||
return
|
||||
end
|
||||
key = key or arg1
|
||||
local key = arg1
|
||||
if not key or key == "" then
|
||||
return
|
||||
end
|
||||
@@ -305,10 +304,10 @@ function MTH_SetupFeedOMaticOptions()
|
||||
MTH_FOM_STATE.ctrl.PreferHigherQuality = MTH_CreateCheckbox(container, "MetaHuntOptionsFOMPreferQuality", FOM_OptionsButtonText and FOM_OptionsButtonText["PreferHigherQuality"] or MTH_FOM_L("FOM_LABEL_PREFER_HIGHER_QUALITY_FOOD", "Prefer higher quality food"), -220 + yAdjust)
|
||||
MTH_FOM_STATE.ctrl.Fallback = MTH_CreateCheckbox(container, "MetaHuntOptionsFOMFallback", FOM_OptionsButtonText and FOM_OptionsButtonText["Fallback"] or MTH_FOM_L("FOM_LABEL_FALLBACK_TO_AVOIDED_FOODS", "Fallback to avoided foods"), -245 + yAdjust)
|
||||
|
||||
if MTH_FOM_STATE.ctrl.AvoidQuestFood then MTH_FOM_STATE.ctrl.AvoidQuestFood:SetScript("OnClick", function(self) self = self or this if not self then return end FOM_Config.AvoidQuestFood = self:GetChecked() == 1 end) end
|
||||
if MTH_FOM_STATE.ctrl.AvoidBonusFood then MTH_FOM_STATE.ctrl.AvoidBonusFood:SetScript("OnClick", function(self) self = self or this if not self then return end FOM_Config.AvoidBonusFood = self:GetChecked() == 1 end) end
|
||||
if MTH_FOM_STATE.ctrl.PreferHigherQuality then MTH_FOM_STATE.ctrl.PreferHigherQuality:SetScript("OnClick", function(self) self = self or this if not self then return end FOM_Config.PreferHigherQuality = self:GetChecked() == 1 end) end
|
||||
if MTH_FOM_STATE.ctrl.Fallback then MTH_FOM_STATE.ctrl.Fallback:SetScript("OnClick", function(self) self = self or this if not self then return end FOM_Config.Fallback = self:GetChecked() == 1 end) end
|
||||
if MTH_FOM_STATE.ctrl.AvoidQuestFood then MTH_FOM_STATE.ctrl.AvoidQuestFood:SetScript("OnClick", function() if not this then return end FOM_Config.AvoidQuestFood = this:GetChecked() == 1 end) end
|
||||
if MTH_FOM_STATE.ctrl.AvoidBonusFood then MTH_FOM_STATE.ctrl.AvoidBonusFood:SetScript("OnClick", function() if not this then return end FOM_Config.AvoidBonusFood = this:GetChecked() == 1 end) end
|
||||
if MTH_FOM_STATE.ctrl.PreferHigherQuality then MTH_FOM_STATE.ctrl.PreferHigherQuality:SetScript("OnClick", function() if not this then return end FOM_Config.PreferHigherQuality = this:GetChecked() == 1 end) end
|
||||
if MTH_FOM_STATE.ctrl.Fallback then MTH_FOM_STATE.ctrl.Fallback:SetScript("OnClick", function() if not this then return end FOM_Config.Fallback = this:GetChecked() == 1 end) end
|
||||
|
||||
local keepOpenLabel = container:CreateFontString("MetaHuntOptionsFOMKeepOpenLabel", "ARTWORK", "GameFontNormalSmall")
|
||||
keepOpenLabel:SetPoint("TOPLEFT", container, "TOPLEFT", 20, -302 + yAdjust)
|
||||
@@ -320,14 +319,13 @@ function MTH_SetupFeedOMaticOptions()
|
||||
keepOpen:SetHeight(20)
|
||||
keepOpen:SetNumeric(true)
|
||||
keepOpen:SetAutoFocus(false)
|
||||
keepOpen:SetScript("OnTextChanged", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
local value = tonumber(self:GetText()) or 0
|
||||
keepOpen:SetScript("OnTextChanged", function()
|
||||
if not this then return end
|
||||
local value = tonumber(this:GetText()) or 0
|
||||
FOM_Config.KeepOpenSlots = value
|
||||
end)
|
||||
keepOpen:SetScript("OnEnterPressed", function(self) self = self or this if self then self:ClearFocus() end end)
|
||||
keepOpen:SetScript("OnEscapePressed", function(self) self = self or this if self then self:ClearFocus() end end)
|
||||
keepOpen:SetScript("OnEnterPressed", function() if this then this:ClearFocus() end end)
|
||||
keepOpen:SetScript("OnEscapePressed", function() if this then this:ClearFocus() end end)
|
||||
MTH_FOM_STATE.keepOpenEdit = keepOpen
|
||||
|
||||
local notifyHeader = container:CreateFontString("MetaHuntOptionsFOMNotifyHeader", "ARTWORK", "GameFontHighlight")
|
||||
@@ -356,10 +354,10 @@ function MTH_SetupFeedOMaticOptions()
|
||||
MTH_FOM_STATE.ctrl.AudioWarningBell = MTH_CreateCheckbox(container, "MetaHuntOptionsFOMAudioWarningBell", FOM_OptionsButtonText and FOM_OptionsButtonText["AudioWarningBell"] or MTH_FOM_L("FOM_LABEL_USE_BELL_SOUND", "Use bell sound"), -403 + yAdjust, rightColumnX)
|
||||
MTH_FOM_STATE.ctrl.TextWarning = MTH_CreateCheckbox(container, "MetaHuntOptionsFOMTextWarning", FOM_OptionsButtonText and FOM_OptionsButtonText["TextWarning"] or MTH_FOM_L("FOM_LABEL_SHOW_TEXT", "Show text"), -428 + yAdjust, rightColumnX)
|
||||
MTH_FOM_STATE.ctrl.IconWarning = MTH_CreateCheckbox(container, "MetaHuntOptionsFOMIconWarning", FOM_OptionsButtonText and FOM_OptionsButtonText["IconWarning"] or MTH_FOM_L("FOM_LABEL_FLASH_ICON", "Flash icon"), -453 + yAdjust, rightColumnX)
|
||||
if MTH_FOM_STATE.ctrl.AudioWarning then MTH_FOM_STATE.ctrl.AudioWarning:SetScript("OnClick", function(self) self = self or this if not self then return end if self:GetChecked() == 1 then if FOM_Config.AudioWarning ~= "bell" then FOM_Config.AudioWarning = true end else FOM_Config.AudioWarning = nil end MTH_RefreshFeedOMaticOptions() end) end
|
||||
if MTH_FOM_STATE.ctrl.AudioWarningBell then MTH_FOM_STATE.ctrl.AudioWarningBell:SetScript("OnClick", function(self) self = self or this if not self then return end if self:GetChecked() == 1 then FOM_Config.AudioWarning = "bell" else FOM_Config.AudioWarning = true end MTH_RefreshFeedOMaticOptions() end) end
|
||||
if MTH_FOM_STATE.ctrl.TextWarning then MTH_FOM_STATE.ctrl.TextWarning:SetScript("OnClick", function(self) self = self or this if not self then return end FOM_Config.TextWarning = self:GetChecked() == 1 end) end
|
||||
if MTH_FOM_STATE.ctrl.IconWarning then MTH_FOM_STATE.ctrl.IconWarning:SetScript("OnClick", function(self) self = self or this if not self then return end FOM_Config.IconWarning = self:GetChecked() == 1 end) end
|
||||
if MTH_FOM_STATE.ctrl.AudioWarning then MTH_FOM_STATE.ctrl.AudioWarning:SetScript("OnClick", function() if not this then return end if this:GetChecked() == 1 then if FOM_Config.AudioWarning ~= "bell" then FOM_Config.AudioWarning = true end else FOM_Config.AudioWarning = nil end MTH_RefreshFeedOMaticOptions() end) end
|
||||
if MTH_FOM_STATE.ctrl.AudioWarningBell then MTH_FOM_STATE.ctrl.AudioWarningBell:SetScript("OnClick", function() if not this then return end if this:GetChecked() == 1 then FOM_Config.AudioWarning = "bell" else FOM_Config.AudioWarning = true end MTH_RefreshFeedOMaticOptions() end) end
|
||||
if MTH_FOM_STATE.ctrl.TextWarning then MTH_FOM_STATE.ctrl.TextWarning:SetScript("OnClick", function() if not this then return end FOM_Config.TextWarning = this:GetChecked() == 1 end) end
|
||||
if MTH_FOM_STATE.ctrl.IconWarning then MTH_FOM_STATE.ctrl.IconWarning:SetScript("OnClick", function() if not this then return end FOM_Config.IconWarning = this:GetChecked() == 1 end) end
|
||||
|
||||
local cookHeader = container:CreateFontString("MetaHuntOptionsFOMCookingHeader", "ARTWORK", "GameFontHighlight")
|
||||
cookHeader:SetPoint("TOPLEFT", container, "TOPLEFT", rightColumnX, -62 + yAdjust)
|
||||
|
||||
@@ -0,0 +1,590 @@
|
||||
local MTH_ICU_OPT_READY = true
|
||||
local MTH_ICU_OPT_MISSING = {}
|
||||
|
||||
if type(MTH_GetFrame) ~= "function" then table.insert(MTH_ICU_OPT_MISSING, "MTH_GetFrame") end
|
||||
if type(MTH_ClearContainer) ~= "function" then table.insert(MTH_ICU_OPT_MISSING, "MTH_ClearContainer") end
|
||||
if type(MTH_CreateCheckbox) ~= "function" then table.insert(MTH_ICU_OPT_MISSING, "MTH_CreateCheckbox") end
|
||||
|
||||
if table.getn(MTH_ICU_OPT_MISSING) > 0 then
|
||||
MTH_ICU_OPT_READY = false
|
||||
if MTH and MTH.Print then
|
||||
MTH:Print("[MTH ICU OPTIONS] missing dependencies: " .. table.concat(MTH_ICU_OPT_MISSING, ", "), "error")
|
||||
end
|
||||
end
|
||||
|
||||
local MTH_ICU_OPT_STATE = {
|
||||
container = nil,
|
||||
built = false,
|
||||
controls = {},
|
||||
}
|
||||
|
||||
local MTH_ICU_LAYOUT = {
|
||||
LEFT_X = 20,
|
||||
LEFT_DROPDOWN_X = 94,
|
||||
RIGHT_X = 280,
|
||||
RIGHT_DROPDOWN_X = 366,
|
||||
DROPDOWN_WIDTH = 108,
|
||||
COLOR_BUTTON_X = 378,
|
||||
COLOR_BUTTON_WIDTH = 78,
|
||||
COLOR_ROW_STEP = 24,
|
||||
}
|
||||
|
||||
local MTH_ICU_OPTIONS_FALLBACK = {
|
||||
ALERT = { "AUTO", "PARTY", "RAID", "SELF", "MTH Message", "OFF" },
|
||||
ANNOUNCE = { "AUTO", "SAY", "YELL", "PARTY", "RAID", "SELF", "MTH Message", "OFF" },
|
||||
ANCHOR = { "TOP", "TOPLEFT", "TOPRIGHT", "BOTTOM", "BOTTOMLEFT", "BOTTOMRIGHT", "LEFT", "RIGHT", "CUSTOM" },
|
||||
POPUP_HIDE_DELAY = { "INSTANT", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
|
||||
HEALTH_TEXT_MODE = { "NONE", "PERCENT", "HP", "BOTH" },
|
||||
PLAYER_COLOR_MODE = { "CLASS", "REACTION", "FACTION", "CUSTOM" },
|
||||
}
|
||||
|
||||
local MTH_ICU_DEFAULT_BG_COLORS = {
|
||||
PLAYER_HOSTILE = { 1.00, 0.20, 0.20 },
|
||||
PLAYER_NEUTRAL = { 1.00, 0.85, 0.10 },
|
||||
PLAYER_FRIENDLY = { 0.20, 0.75, 1.00 },
|
||||
NPC_HOSTILE = { 1.00, 0.20, 0.20 },
|
||||
NPC_NEUTRAL = { 1.00, 0.85, 0.10 },
|
||||
NPC_FRIENDLY = { 0.10, 0.90, 0.10 },
|
||||
UNKNOWN = { 0.70, 0.70, 0.70 },
|
||||
}
|
||||
|
||||
local MTH_ICU_COLOR_ROWS = {
|
||||
{ key = "PLAYER_HOSTILE", label = "Player hostile" },
|
||||
{ key = "PLAYER_NEUTRAL", label = "Player neutral" },
|
||||
{ key = "PLAYER_FRIENDLY", label = "Player friendly" },
|
||||
{ key = "NPC_HOSTILE", label = "NPC hostile" },
|
||||
{ key = "NPC_NEUTRAL", label = "NPC neutral" },
|
||||
{ key = "NPC_FRIENDLY", label = "NPC friendly" },
|
||||
{ key = "UNKNOWN", label = "Unknown fallback" },
|
||||
}
|
||||
|
||||
local function MTH_ICU_GetStore()
|
||||
local store = nil
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
store = MTH:GetModuleCharSavedVariables("icu")
|
||||
end
|
||||
if type(store) ~= "table" then
|
||||
ICUvars = ICUvars or {}
|
||||
store = ICUvars
|
||||
end
|
||||
|
||||
if store.ALERT == nil then store.ALERT = "MTH Message" end
|
||||
if store.ALERT == "SAY" or store.ALERT == "YELL" then store.ALERT = "SELF" end
|
||||
if store.ANNOUNCE == nil then store.ANNOUNCE = "MTH Message" end
|
||||
if store.ANCHOR == nil then store.ANCHOR = "BOTTOMRIGHT" end
|
||||
if store.POPUP_HIDE_DELAY == nil then
|
||||
store.POPUP_HIDE_DELAY = "INSTANT"
|
||||
else
|
||||
local rawDelay = tostring(store.POPUP_HIDE_DELAY)
|
||||
if rawDelay ~= "INSTANT" then
|
||||
local n = tonumber(rawDelay)
|
||||
if not n then
|
||||
store.POPUP_HIDE_DELAY = "INSTANT"
|
||||
else
|
||||
n = math.floor(n)
|
||||
if n < 1 then
|
||||
store.POPUP_HIDE_DELAY = "INSTANT"
|
||||
elseif n > 10 then
|
||||
store.POPUP_HIDE_DELAY = "10"
|
||||
else
|
||||
store.POPUP_HIDE_DELAY = tostring(n)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if store.mouseOver == nil then store.mouseOver = false end
|
||||
if store.HEALTH_TEXT_MODE == nil then store.HEALTH_TEXT_MODE = "BOTH" end
|
||||
if store.HEALTH_TEXT_MODE == "AUTO" then store.HEALTH_TEXT_MODE = "BOTH" end
|
||||
if store.PLAYER_COLOR_MODE == nil then store.PLAYER_COLOR_MODE = "CLASS" end
|
||||
if store.REACTION_ONLY_PVP_PLAYERS == nil then store.REACTION_ONLY_PVP_PLAYERS = true end
|
||||
if store.SHOW_GUILD_NAME == nil then store.SHOW_GUILD_NAME = false end
|
||||
if store.SHOW_PLAYER_CLASS == nil then store.SHOW_PLAYER_CLASS = true end
|
||||
if store.SHOW_PLAYER_RACE == nil then store.SHOW_PLAYER_RACE = true end
|
||||
if store.SHOW_CUSTOM_TITLES == nil then store.SHOW_CUSTOM_TITLES = false end
|
||||
if store.EXPAND_UP == nil then store.EXPAND_UP = false end
|
||||
|
||||
if type(store.COLORS) ~= "table" then
|
||||
store.COLORS = {}
|
||||
end
|
||||
for key, def in pairs(MTH_ICU_DEFAULT_BG_COLORS) do
|
||||
if type(store.COLORS[key]) ~= "table" then
|
||||
store.COLORS[key] = { def[1], def[2], def[3] }
|
||||
end
|
||||
end
|
||||
|
||||
ICUvars = store
|
||||
return store
|
||||
end
|
||||
|
||||
local function MTH_ICU_GetOptionValues(key)
|
||||
if type(ICU_OPTIONS) == "table" and type(ICU_OPTIONS[key]) == "table" then
|
||||
return ICU_OPTIONS[key]
|
||||
end
|
||||
return MTH_ICU_OPTIONS_FALLBACK[key] or {}
|
||||
end
|
||||
|
||||
local function MTH_ICU_SetValue(key, value)
|
||||
local store = MTH_ICU_GetStore()
|
||||
store[key] = tostring(value or "")
|
||||
if key == "ANCHOR" and type(ICU_SetPoints) == "function" then
|
||||
ICU_SetPoints()
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_ICU_DropdownSetText(frame, text)
|
||||
if UIDropDownMenu_SetText then
|
||||
UIDropDownMenu_SetText(tostring(text or ""), frame)
|
||||
return
|
||||
end
|
||||
if not frame or not frame.GetName then return end
|
||||
local textRegion = getglobal(frame:GetName() .. "Text")
|
||||
if textRegion and textRegion.SetText then
|
||||
textRegion:SetText(tostring(text or ""))
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_ICU_GetColor(key)
|
||||
local store = MTH_ICU_GetStore()
|
||||
local row = store.COLORS and store.COLORS[key]
|
||||
if type(row) == "table" then
|
||||
return tonumber(row[1]) or 0, tonumber(row[2]) or 0, tonumber(row[3]) or 0
|
||||
end
|
||||
local def = MTH_ICU_DEFAULT_BG_COLORS[key] or MTH_ICU_DEFAULT_BG_COLORS.UNKNOWN
|
||||
return def[1], def[2], def[3]
|
||||
end
|
||||
|
||||
local function MTH_ICU_SetColor(key, r, g, b)
|
||||
local store = MTH_ICU_GetStore()
|
||||
if type(store.COLORS) ~= "table" then
|
||||
store.COLORS = {}
|
||||
end
|
||||
store.COLORS[key] = {
|
||||
math.max(0, math.min(1, tonumber(r) or 0)),
|
||||
math.max(0, math.min(1, tonumber(g) or 0)),
|
||||
math.max(0, math.min(1, tonumber(b) or 0)),
|
||||
}
|
||||
end
|
||||
|
||||
local function MTH_ICU_OpenColorPicker(colorKey)
|
||||
if not ColorPickerFrame then
|
||||
if MTH and MTH.Print then
|
||||
MTH:Print("ColorPickerFrame is not available in this client", "error")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local currentR, currentG, currentB = MTH_ICU_GetColor(colorKey)
|
||||
local function applyColor()
|
||||
local r, g, b = ColorPickerFrame:GetColorRGB()
|
||||
MTH_ICU_SetColor(colorKey, r, g, b)
|
||||
MTH_RefreshICUOptions()
|
||||
end
|
||||
|
||||
ColorPickerFrame.func = applyColor
|
||||
ColorPickerFrame.cancelFunc = function(prev)
|
||||
if type(prev) == "table" then
|
||||
local r = prev.r or prev[1] or currentR
|
||||
local g = prev.g or prev[2] or currentG
|
||||
local b = prev.b or prev[3] or currentB
|
||||
MTH_ICU_SetColor(colorKey, r, g, b)
|
||||
MTH_RefreshICUOptions()
|
||||
end
|
||||
end
|
||||
ColorPickerFrame:SetColorRGB(currentR, currentG, currentB)
|
||||
ColorPickerFrame.hasOpacity = false
|
||||
ColorPickerFrame.opacity = 1
|
||||
ColorPickerFrame.previousValues = { currentR, currentG, currentB }
|
||||
ColorPickerFrame:Show()
|
||||
end
|
||||
|
||||
local function MTH_ICU_CreateOptionRow(container, rowName, label, key, y, labelX, dropdownX)
|
||||
labelX = labelX or MTH_ICU_LAYOUT.LEFT_X
|
||||
dropdownX = dropdownX or MTH_ICU_LAYOUT.LEFT_DROPDOWN_X
|
||||
|
||||
local labelFs = container:CreateFontString(rowName .. "Label", "ARTWORK", "GameFontNormalSmall")
|
||||
labelFs:SetPoint("TOPLEFT", container, "TOPLEFT", labelX, y)
|
||||
labelFs:SetText(label)
|
||||
|
||||
local dropdown = CreateFrame("Frame", rowName .. "Drop", container, "UIDropDownMenuTemplate")
|
||||
dropdown:ClearAllPoints()
|
||||
dropdown:SetPoint("TOPLEFT", container, "TOPLEFT", dropdownX, y + 12)
|
||||
if UIDropDownMenu_SetWidth then
|
||||
UIDropDownMenu_SetWidth(MTH_ICU_LAYOUT.DROPDOWN_WIDTH, dropdown)
|
||||
end
|
||||
if UIDropDownMenu_JustifyText then
|
||||
UIDropDownMenu_JustifyText("LEFT", dropdown)
|
||||
end
|
||||
|
||||
if UIDropDownMenu_Initialize then
|
||||
UIDropDownMenu_Initialize(dropdown, function()
|
||||
local values = MTH_ICU_GetOptionValues(key)
|
||||
local store = MTH_ICU_GetStore()
|
||||
local current = tostring(store[key] or "")
|
||||
local infoFactory = UIDropDownMenu_CreateInfo
|
||||
|
||||
for i = 1, table.getn(values) do
|
||||
local optionValue = tostring(values[i])
|
||||
local info = type(infoFactory) == "function" and infoFactory() or {}
|
||||
info.text = optionValue
|
||||
info.checked = optionValue == current and 1 or nil
|
||||
info.func = function()
|
||||
MTH_ICU_SetValue(key, optionValue)
|
||||
MTH_RefreshICUOptions()
|
||||
end
|
||||
if UIDropDownMenu_AddButton then UIDropDownMenu_AddButton(info) end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
MTH_ICU_OPT_STATE.controls[key] = {
|
||||
label = labelFs,
|
||||
dropdown = dropdown,
|
||||
}
|
||||
end
|
||||
|
||||
local function MTH_ICU_CreateColorRow(container, rowName, label, colorKey, y, labelX, buttonX)
|
||||
labelX = labelX or MTH_ICU_LAYOUT.RIGHT_X
|
||||
buttonX = buttonX or MTH_ICU_LAYOUT.COLOR_BUTTON_X
|
||||
|
||||
local labelFs = container:CreateFontString(rowName .. "Label", "ARTWORK", "GameFontNormalSmall")
|
||||
labelFs:SetPoint("TOPLEFT", container, "TOPLEFT", labelX, y)
|
||||
labelFs:SetText(label)
|
||||
|
||||
local button = CreateFrame("Button", rowName .. "Button", container, "UIPanelButtonTemplate")
|
||||
button:SetPoint("TOPLEFT", container, "TOPLEFT", buttonX, y + 8)
|
||||
button:SetWidth(MTH_ICU_LAYOUT.COLOR_BUTTON_WIDTH)
|
||||
button:SetHeight(22)
|
||||
button:SetText("Pick")
|
||||
button:SetScript("OnClick", function()
|
||||
MTH_ICU_OpenColorPicker(colorKey)
|
||||
end)
|
||||
|
||||
local swatch = button:CreateTexture(rowName .. "Swatch", "ARTWORK")
|
||||
swatch:SetTexture("Interface\\Buttons\\WHITE8X8")
|
||||
swatch:SetPoint("LEFT", button, "LEFT", 6, 0)
|
||||
swatch:SetWidth(14)
|
||||
swatch:SetHeight(14)
|
||||
|
||||
MTH_ICU_OPT_STATE.controls[colorKey] = {
|
||||
label = labelFs,
|
||||
button = button,
|
||||
swatch = swatch,
|
||||
isColor = true,
|
||||
}
|
||||
end
|
||||
|
||||
local function MTH_ICU_BuildUI(container)
|
||||
if MTH_ICU_OPT_STATE.built and MTH_ICU_OPT_STATE.container == container then
|
||||
return
|
||||
end
|
||||
|
||||
MTH_ClearContainer(container)
|
||||
MTH_ICU_OPT_STATE.controls = {}
|
||||
MTH_ICU_OPT_STATE.container = container
|
||||
MTH_ICU_OPT_STATE.built = true
|
||||
|
||||
local title = container:CreateFontString("MetaHuntOptionsICUTitle", "ARTWORK", "GameFontHighlight")
|
||||
title:SetPoint("TOPLEFT", container, "TOPLEFT", 20, -10)
|
||||
title:SetText("MTH ICU")
|
||||
|
||||
local note = container:CreateFontString("MetaHuntOptionsICUNote", "ARTWORK", "GameFontNormalSmall")
|
||||
note:SetPoint("TOPLEFT", container, "TOPLEFT", 20, -32)
|
||||
note:SetWidth(560)
|
||||
note:SetJustifyH("LEFT")
|
||||
note:SetJustifyV("TOP")
|
||||
note:SetTextColor(0.35, 0.65, 1)
|
||||
note:SetText("ICU is a minimap targeting utility module for your Trackings.\nIt provides enhanced target information and click actions for players and NPCs on the minimap.")
|
||||
|
||||
local moduleEnabled = MTH_CreateCheckbox(container, "MetaHuntOptionsICUModuleEnabled", "Enable ICU module", -72, MTH_ICU_LAYOUT.LEFT_X)
|
||||
if moduleEnabled then
|
||||
moduleEnabled:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
if MTH and MTH.SetModuleEnabled then
|
||||
local ok, err = MTH:SetModuleEnabled("icu", this:GetChecked() == 1)
|
||||
if not ok and MTH and MTH.Print then
|
||||
MTH:Print("Failed to change ICU module state: " .. tostring(err), "error")
|
||||
end
|
||||
end
|
||||
MTH_RefreshICUOptions()
|
||||
end)
|
||||
MTH_ICU_OPT_STATE.controls.moduleEnabled = moduleEnabled
|
||||
end
|
||||
|
||||
local mouseOver = MTH_CreateCheckbox(container, "MetaHuntOptionsICUMouseOver", "Enable CTRL mouseover scan", -98, MTH_ICU_LAYOUT.LEFT_X)
|
||||
if mouseOver then
|
||||
mouseOver:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local store = MTH_ICU_GetStore()
|
||||
store.mouseOver = this:GetChecked() == 1 and true or false
|
||||
end)
|
||||
MTH_ICU_OPT_STATE.controls.mouseOver = mouseOver
|
||||
end
|
||||
|
||||
local sectionHeader = container:CreateFontString("MetaHuntOptionsICUSectionHeader", "ARTWORK", "GameFontHighlight")
|
||||
sectionHeader:SetPoint("TOPLEFT", container, "TOPLEFT", MTH_ICU_LAYOUT.LEFT_X, -146)
|
||||
sectionHeader:SetText("General Settings")
|
||||
|
||||
MTH_ICU_CreateOptionRow(container, "MetaHuntOptionsICUAlert", "ALERT PVP", "ALERT", -172, MTH_ICU_LAYOUT.LEFT_X, MTH_ICU_LAYOUT.LEFT_DROPDOWN_X)
|
||||
MTH_ICU_CreateOptionRow(container, "MetaHuntOptionsICUAnnounce", "ANNOUNCE on click", "ANNOUNCE", -198, MTH_ICU_LAYOUT.LEFT_X, MTH_ICU_LAYOUT.LEFT_DROPDOWN_X)
|
||||
MTH_ICU_CreateOptionRow(container, "MetaHuntOptionsICUHealthMode", "Health text", "HEALTH_TEXT_MODE", -224, MTH_ICU_LAYOUT.LEFT_X, MTH_ICU_LAYOUT.LEFT_DROPDOWN_X)
|
||||
MTH_ICU_CreateOptionRow(container, "MetaHuntOptionsICUHideDelay", "List hide delay", "POPUP_HIDE_DELAY", -250, MTH_ICU_LAYOUT.LEFT_X, MTH_ICU_LAYOUT.LEFT_DROPDOWN_X)
|
||||
MTH_ICU_CreateOptionRow(container, "MetaHuntOptionsICUAnchor", "ANCHOR", "ANCHOR", -276, MTH_ICU_LAYOUT.LEFT_X, MTH_ICU_LAYOUT.LEFT_DROPDOWN_X)
|
||||
|
||||
local toggleAnchorButton = CreateFrame("Button", "MetaHuntOptionsICUToggleAnchorButton", container, "UIPanelButtonTemplate")
|
||||
toggleAnchorButton:SetPoint("TOPLEFT", container, "TOPLEFT", MTH_ICU_LAYOUT.LEFT_X, -302)
|
||||
toggleAnchorButton:SetWidth(116)
|
||||
toggleAnchorButton:SetHeight(22)
|
||||
toggleAnchorButton:SetText("Toggle Anchor")
|
||||
toggleAnchorButton:SetScript("OnClick", function()
|
||||
if type(ICU_ToggleAnchor) == "function" then
|
||||
ICU_ToggleAnchor()
|
||||
end
|
||||
end)
|
||||
MTH_ICU_OPT_STATE.controls.customAnchorButton = toggleAnchorButton
|
||||
|
||||
local expandUp = MTH_CreateCheckbox(container, "MetaHuntOptionsICUExpandUp", "Expand Up", -301, MTH_ICU_LAYOUT.LEFT_X + 132)
|
||||
if expandUp then
|
||||
expandUp:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local store = MTH_ICU_GetStore()
|
||||
store.EXPAND_UP = this:GetChecked() == 1 and true or false
|
||||
if type(ICU_SetPoints) == "function" then
|
||||
ICU_SetPoints()
|
||||
end
|
||||
end)
|
||||
MTH_ICU_OPT_STATE.controls.expandUp = expandUp
|
||||
end
|
||||
|
||||
local showGuild = MTH_CreateCheckbox(container, "MetaHuntOptionsICUShowGuild", "Show player guild names", -344, MTH_ICU_LAYOUT.LEFT_X)
|
||||
if showGuild then
|
||||
showGuild:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local store = MTH_ICU_GetStore()
|
||||
store.SHOW_GUILD_NAME = this:GetChecked() == 1 and true or false
|
||||
end)
|
||||
MTH_ICU_OPT_STATE.controls.showGuildName = showGuild
|
||||
end
|
||||
|
||||
local showClass = MTH_CreateCheckbox(container, "MetaHuntOptionsICUShowClass", "Show player class", -368, MTH_ICU_LAYOUT.LEFT_X)
|
||||
if showClass then
|
||||
showClass:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local store = MTH_ICU_GetStore()
|
||||
store.SHOW_PLAYER_CLASS = this:GetChecked() == 1 and true or false
|
||||
end)
|
||||
MTH_ICU_OPT_STATE.controls.showPlayerClass = showClass
|
||||
end
|
||||
|
||||
local showRace = MTH_CreateCheckbox(container, "MetaHuntOptionsICUShowRace", "Show player race", -392, MTH_ICU_LAYOUT.LEFT_X)
|
||||
if showRace then
|
||||
showRace:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local store = MTH_ICU_GetStore()
|
||||
store.SHOW_PLAYER_RACE = this:GetChecked() == 1 and true or false
|
||||
end)
|
||||
MTH_ICU_OPT_STATE.controls.showPlayerRace = showRace
|
||||
end
|
||||
|
||||
local showTitles = MTH_CreateCheckbox(container, "MetaHuntOptionsICUShowTitles", "Show custom titles in alerts", -416, MTH_ICU_LAYOUT.LEFT_X)
|
||||
if showTitles then
|
||||
showTitles:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local store = MTH_ICU_GetStore()
|
||||
store.SHOW_CUSTOM_TITLES = this:GetChecked() == 1 and true or false
|
||||
end)
|
||||
MTH_ICU_OPT_STATE.controls.showCustomTitles = showTitles
|
||||
end
|
||||
|
||||
local rightHeader = container:CreateFontString("MetaHuntOptionsICURightHeader", "ARTWORK", "GameFontHighlight")
|
||||
rightHeader:SetPoint("TOPLEFT", container, "TOPLEFT", MTH_ICU_LAYOUT.RIGHT_X, -146)
|
||||
rightHeader:SetText("Background Colors")
|
||||
|
||||
MTH_ICU_CreateOptionRow(container, "MetaHuntOptionsICUPlayerColorMode", "Player colors", "PLAYER_COLOR_MODE", -172, MTH_ICU_LAYOUT.RIGHT_X, MTH_ICU_LAYOUT.RIGHT_DROPDOWN_X)
|
||||
|
||||
local reactionOnlyPvp = MTH_CreateCheckbox(container, "MetaHuntOptionsICUReactionOnlyPvp", "Reaction only when PvP-flagged", -200, MTH_ICU_LAYOUT.RIGHT_X)
|
||||
if reactionOnlyPvp then
|
||||
reactionOnlyPvp:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local store = MTH_ICU_GetStore()
|
||||
store.REACTION_ONLY_PVP_PLAYERS = this:GetChecked() == 1 and true or false
|
||||
end)
|
||||
MTH_ICU_OPT_STATE.controls.reactionOnlyPvp = reactionOnlyPvp
|
||||
end
|
||||
|
||||
local colorHeader = container:CreateFontString("MetaHuntOptionsICUColorsHeader", "ARTWORK", "GameFontHighlight")
|
||||
colorHeader:SetPoint("TOPLEFT", container, "TOPLEFT", MTH_ICU_LAYOUT.RIGHT_X, -224)
|
||||
|
||||
local colorScope = container:CreateFontString("MetaHuntOptionsICUColorsScope", "ARTWORK", "GameFontNormalSmall")
|
||||
colorScope:SetPoint("TOPLEFT", container, "TOPLEFT", MTH_ICU_LAYOUT.RIGHT_X, -242)
|
||||
colorScope:SetWidth(250)
|
||||
colorScope:SetJustifyH("LEFT")
|
||||
colorScope:SetJustifyV("TOP")
|
||||
colorScope:SetTextColor(0.35, 0.65, 1)
|
||||
colorScope:SetText("Player pickers: REACTION / FACTION / CUSTOM\nNPC pickers: always")
|
||||
|
||||
local colorY = -284
|
||||
for i = 1, table.getn(MTH_ICU_COLOR_ROWS) do
|
||||
local row = MTH_ICU_COLOR_ROWS[i]
|
||||
MTH_ICU_CreateColorRow(container, "MetaHuntOptionsICUColor" .. tostring(i), row.label, row.key, colorY, MTH_ICU_LAYOUT.RIGHT_X, MTH_ICU_LAYOUT.COLOR_BUTTON_X)
|
||||
colorY = colorY - MTH_ICU_LAYOUT.COLOR_ROW_STEP
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
function MTH_RefreshICUOptions()
|
||||
if not MTH_ICU_OPT_READY then return end
|
||||
|
||||
local controls = MTH_ICU_OPT_STATE.controls
|
||||
if type(controls) ~= "table" then
|
||||
return
|
||||
end
|
||||
|
||||
local store = MTH_ICU_GetStore()
|
||||
local moduleEnabled = MTH and MTH.IsModuleEnabled and MTH:IsModuleEnabled("icu", false) or false
|
||||
|
||||
if controls.moduleEnabled then
|
||||
controls.moduleEnabled:SetChecked(moduleEnabled and 1 or nil)
|
||||
end
|
||||
|
||||
if controls.mouseOver then
|
||||
controls.mouseOver:SetChecked(store.mouseOver and 1 or nil)
|
||||
if controls.mouseOver.Enable then
|
||||
if moduleEnabled then controls.mouseOver:Enable() else controls.mouseOver:Disable() end
|
||||
end
|
||||
end
|
||||
|
||||
if controls.showGuildName then
|
||||
controls.showGuildName:SetChecked(store.SHOW_GUILD_NAME and 1 or nil)
|
||||
if controls.showGuildName.Enable then
|
||||
if moduleEnabled then controls.showGuildName:Enable() else controls.showGuildName:Disable() end
|
||||
end
|
||||
end
|
||||
|
||||
if controls.showPlayerClass then
|
||||
controls.showPlayerClass:SetChecked(store.SHOW_PLAYER_CLASS and 1 or nil)
|
||||
if controls.showPlayerClass.Enable then
|
||||
if moduleEnabled then controls.showPlayerClass:Enable() else controls.showPlayerClass:Disable() end
|
||||
end
|
||||
end
|
||||
|
||||
if controls.showPlayerRace then
|
||||
controls.showPlayerRace:SetChecked(store.SHOW_PLAYER_RACE and 1 or nil)
|
||||
if controls.showPlayerRace.Enable then
|
||||
if moduleEnabled then controls.showPlayerRace:Enable() else controls.showPlayerRace:Disable() end
|
||||
end
|
||||
end
|
||||
|
||||
if controls.showCustomTitles then
|
||||
controls.showCustomTitles:SetChecked(store.SHOW_CUSTOM_TITLES and 1 or nil)
|
||||
if controls.showCustomTitles.Enable then
|
||||
if moduleEnabled then controls.showCustomTitles:Enable() else controls.showCustomTitles:Disable() end
|
||||
end
|
||||
end
|
||||
|
||||
local isCustomAnchor = tostring(store.ANCHOR or "") == "CUSTOM"
|
||||
|
||||
if controls.customAnchorButton then
|
||||
if moduleEnabled and isCustomAnchor then
|
||||
controls.customAnchorButton:Show()
|
||||
if controls.customAnchorButton.Enable then controls.customAnchorButton:Enable() end
|
||||
else
|
||||
controls.customAnchorButton:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
if controls.expandUp then
|
||||
controls.expandUp:SetChecked(store.EXPAND_UP and 1 or nil)
|
||||
if moduleEnabled and isCustomAnchor then
|
||||
controls.expandUp:Show()
|
||||
if controls.expandUp.Enable then controls.expandUp:Enable() end
|
||||
else
|
||||
controls.expandUp:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local optionKeys = { "ALERT", "ANNOUNCE", "ANCHOR", "HEALTH_TEXT_MODE", "POPUP_HIDE_DELAY", "PLAYER_COLOR_MODE" }
|
||||
for i = 1, table.getn(optionKeys) do
|
||||
local key = optionKeys[i]
|
||||
local row = controls[key]
|
||||
if row and row.dropdown then
|
||||
MTH_ICU_DropdownSetText(row.dropdown, tostring(store[key] or ""))
|
||||
if UIDropDownMenu_EnableDropDown and UIDropDownMenu_DisableDropDown then
|
||||
if moduleEnabled then
|
||||
UIDropDownMenu_EnableDropDown(row.dropdown)
|
||||
else
|
||||
UIDropDownMenu_DisableDropDown(row.dropdown)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if controls.reactionOnlyPvp then
|
||||
controls.reactionOnlyPvp:SetChecked(store.REACTION_ONLY_PVP_PLAYERS and 1 or nil)
|
||||
if controls.reactionOnlyPvp.Enable then
|
||||
if moduleEnabled and tostring(store.PLAYER_COLOR_MODE or "") == "REACTION" then
|
||||
controls.reactionOnlyPvp:Enable()
|
||||
else
|
||||
controls.reactionOnlyPvp:Disable()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, table.getn(MTH_ICU_COLOR_ROWS) do
|
||||
local row = MTH_ICU_COLOR_ROWS[i]
|
||||
local ctrl = controls[row.key]
|
||||
if ctrl and ctrl.swatch then
|
||||
local r, g, b = MTH_ICU_GetColor(row.key)
|
||||
ctrl.swatch:SetVertexColor(r, g, b)
|
||||
if ctrl.button and ctrl.button.Enable then
|
||||
if moduleEnabled then ctrl.button:Enable() else ctrl.button:Disable() end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_SetupICUOptions()
|
||||
local container = MTH_GetFrame("MetaHuntOptionsICU")
|
||||
if not container then return end
|
||||
|
||||
if not MTH_ICU_OPT_READY then
|
||||
if type(MTH_ClearContainer) == "function" then
|
||||
MTH_ClearContainer(container)
|
||||
end
|
||||
local title = container:CreateFontString("MetaHuntOptionsICUErrorTitle", "ARTWORK", "GameFontHighlight")
|
||||
title:SetPoint("TOPLEFT", container, "TOPLEFT", 20, -10)
|
||||
title:SetText("MTH ICU")
|
||||
|
||||
local body = container:CreateFontString("MetaHuntOptionsICUErrorBody", "ARTWORK", "GameFontNormalSmall")
|
||||
body:SetPoint("TOPLEFT", container, "TOPLEFT", 20, -34)
|
||||
body:SetWidth(620)
|
||||
body:SetJustifyH("LEFT")
|
||||
body:SetJustifyV("TOP")
|
||||
body:SetTextColor(1, 0.3, 0.3)
|
||||
body:SetText("ICU options cannot initialize. Missing dependencies: " .. table.concat(MTH_ICU_OPT_MISSING, ", "))
|
||||
return
|
||||
end
|
||||
|
||||
local ok, err = pcall(function()
|
||||
MTH_ICU_BuildUI(container)
|
||||
MTH_RefreshICUOptions()
|
||||
end)
|
||||
if not ok then
|
||||
if MTH and MTH.Print then
|
||||
MTH:Print("[MTH ICU OPTIONS] setup failed: " .. tostring(err), "error")
|
||||
end
|
||||
if type(MTH_ClearContainer) == "function" then
|
||||
MTH_ClearContainer(container)
|
||||
end
|
||||
local title = container:CreateFontString("MetaHuntOptionsICUCrashTitle", "ARTWORK", "GameFontHighlight")
|
||||
title:SetPoint("TOPLEFT", container, "TOPLEFT", 20, -10)
|
||||
title:SetText("MTH ICU")
|
||||
local body = container:CreateFontString("MetaHuntOptionsICUCrashBody", "ARTWORK", "GameFontNormalSmall")
|
||||
body:SetPoint("TOPLEFT", container, "TOPLEFT", 20, -34)
|
||||
body:SetWidth(620)
|
||||
body:SetJustifyH("LEFT")
|
||||
body:SetJustifyV("TOP")
|
||||
body:SetTextColor(1, 0.3, 0.3)
|
||||
body:SetText("ICU options failed to render. Check chat/debug for details.")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,403 @@
|
||||
------------------------------------------------------
|
||||
-- MetaHunt Profile Management Options Panel
|
||||
------------------------------------------------------
|
||||
|
||||
local MAX_PROFILE_ROWS = 15
|
||||
local MAX_CHAR_ROWS = 10
|
||||
local ROW_H = 26
|
||||
|
||||
-- Row pools — anonymous frames created once against scroll content, reused each refresh
|
||||
local gProfileRows = {} -- [i] = { frame, nameText, infoText, loadBtn, delBtn }
|
||||
local gCharRows = {} -- [i] = { frame, nameText, infoText, copyBtn }
|
||||
|
||||
-- Static element refs created once
|
||||
local gActiveLabel = nil
|
||||
local gSetupDone = false
|
||||
|
||||
-- Pending confirmations — globals so StaticPopup OnAccept can read them
|
||||
MTH_PROFILE_PENDING_LOAD = nil
|
||||
MTH_PROFILE_PENDING_DELETE = nil
|
||||
MTH_PROFILE_PENDING_SAVE = nil
|
||||
|
||||
-- ── Static popup dialogs ───────────────────────────────────────────────────
|
||||
|
||||
StaticPopupDialogs["MTH_PROFILE_LOAD_CONFIRM"] = {
|
||||
text = "Load profile \"%s\"?\n\nCurrent settings will be replaced.\nThe UI will reload to apply all changes.",
|
||||
button1 = "Load & Reload",
|
||||
button2 = "Cancel",
|
||||
OnAccept = function()
|
||||
if MTH_PROFILE_PENDING_LOAD then
|
||||
local ok, err = MTH_Profile_Load(MTH_PROFILE_PENDING_LOAD)
|
||||
MTH_PROFILE_PENDING_LOAD = nil
|
||||
if ok then
|
||||
ReloadUI()
|
||||
elseif MTH and MTH.Print then
|
||||
MTH:Print("Profile load failed: " .. tostring(err), "error")
|
||||
end
|
||||
end
|
||||
end,
|
||||
timeout = 0, whileDead = 0, hideOnEscape = 1,
|
||||
}
|
||||
|
||||
StaticPopupDialogs["MTH_PROFILE_DELETE_CONFIRM"] = {
|
||||
text = "Delete profile \"%s\"?\n\nThis cannot be undone.",
|
||||
button1 = "Delete",
|
||||
button2 = "Cancel",
|
||||
OnAccept = function()
|
||||
if MTH_PROFILE_PENDING_DELETE then
|
||||
MTH_Profile_Delete(MTH_PROFILE_PENDING_DELETE)
|
||||
MTH_PROFILE_PENDING_DELETE = nil
|
||||
MTH_SetupProfilesOptions()
|
||||
end
|
||||
end,
|
||||
timeout = 0, whileDead = 0, hideOnEscape = 1,
|
||||
}
|
||||
|
||||
StaticPopupDialogs["MTH_PROFILE_SAVE_CONFIRM"] = {
|
||||
text = "Profile \"%s\" already exists.\nOverwrite with current settings?",
|
||||
button1 = "Overwrite",
|
||||
button2 = "Cancel",
|
||||
OnAccept = function()
|
||||
if MTH_PROFILE_PENDING_SAVE then
|
||||
MTH_Profile_Save(MTH_PROFILE_PENDING_SAVE)
|
||||
MTH_PROFILE_PENDING_SAVE = nil
|
||||
MTH_SetupProfilesOptions()
|
||||
end
|
||||
end,
|
||||
timeout = 0, whileDead = 0, hideOnEscape = 1,
|
||||
}
|
||||
|
||||
-- ── internal helpers ───────────────────────────────────────────────────────
|
||||
|
||||
local function PROF_TrimString(s)
|
||||
if type(s) ~= "string" then return "" end
|
||||
return string.gsub(s, "^%s*(.-)%s*$", "%1")
|
||||
end
|
||||
|
||||
local function PROF_DoSave(rawName)
|
||||
local name = PROF_TrimString(rawName)
|
||||
if string.len(name) == 0 then
|
||||
if MTH and MTH.Print then MTH:Print("Enter a profile name first.", "error") end
|
||||
return
|
||||
end
|
||||
if string.len(name) > 50 then
|
||||
if MTH and MTH.Print then MTH:Print("Profile name too long (50 chars max).", "error") end
|
||||
return
|
||||
end
|
||||
local existing = type(MTH_SavedVariables) == "table"
|
||||
and type(MTH_SavedVariables.profiles) == "table"
|
||||
and MTH_SavedVariables.profiles[name] ~= nil
|
||||
if existing then
|
||||
MTH_PROFILE_PENDING_SAVE = name
|
||||
StaticPopup_Show("MTH_PROFILE_SAVE_CONFIRM", name)
|
||||
else
|
||||
MTH_Profile_Save(name)
|
||||
if MTH and MTH.Print then MTH:Print("Profile saved: " .. name) end
|
||||
MTH_SetupProfilesOptions()
|
||||
end
|
||||
end
|
||||
|
||||
-- ── scroll frames + row pool creation (idempotent) ────────────────────────
|
||||
|
||||
local function PROF_EnsureScrollFrames(container)
|
||||
if not MTH_GetFrame("MetaHuntOptionsProfilesScroll") then
|
||||
local sf = CreateFrame("ScrollFrame", "MetaHuntOptionsProfilesScroll", container, "UIPanelScrollFrameTemplate")
|
||||
local sc = CreateFrame("Frame", "MetaHuntOptionsProfilesContent", sf)
|
||||
sc:SetWidth(510)
|
||||
sc:SetHeight(MAX_PROFILE_ROWS * ROW_H + 4)
|
||||
sf:SetScrollChild(sc)
|
||||
end
|
||||
if not MTH_GetFrame("MetaHuntOptionsCharScroll") then
|
||||
local csf = CreateFrame("ScrollFrame", "MetaHuntOptionsCharScroll", container, "UIPanelScrollFrameTemplate")
|
||||
local csc = CreateFrame("Frame", "MetaHuntOptionsCharContent", csf)
|
||||
csc:SetWidth(510)
|
||||
csc:SetHeight(MAX_CHAR_ROWS * ROW_H + 4)
|
||||
csf:SetScrollChild(csc)
|
||||
end
|
||||
end
|
||||
|
||||
local function PROF_EnsureProfileRows()
|
||||
local sc = MTH_GetFrame("MetaHuntOptionsProfilesContent")
|
||||
if not sc then return end
|
||||
for i = 1, MAX_PROFILE_ROWS do
|
||||
if not gProfileRows[i] then
|
||||
local row = CreateFrame("Frame", nil, sc)
|
||||
row:SetHeight(ROW_H)
|
||||
row:SetWidth(510)
|
||||
row:SetPoint("TOPLEFT", sc, "TOPLEFT", 0, -(i - 1) * ROW_H)
|
||||
|
||||
local nameText = row:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
||||
nameText:SetPoint("LEFT", row, "LEFT", 4, 2)
|
||||
nameText:SetWidth(210)
|
||||
nameText:SetJustifyH("LEFT")
|
||||
|
||||
local infoText = row:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
|
||||
infoText:SetPoint("LEFT", row, "LEFT", 218, 2)
|
||||
infoText:SetWidth(155)
|
||||
infoText:SetJustifyH("LEFT")
|
||||
infoText:SetTextColor(0.55, 0.55, 0.55)
|
||||
|
||||
local loadBtn = CreateFrame("Button", nil, row, "UIPanelButtonTemplate")
|
||||
loadBtn:SetWidth(58)
|
||||
loadBtn:SetHeight(20)
|
||||
loadBtn:SetPoint("RIGHT", row, "RIGHT", -62, 0)
|
||||
loadBtn:SetText("Load")
|
||||
|
||||
local delBtn = CreateFrame("Button", nil, row, "UIPanelButtonTemplate")
|
||||
delBtn:SetWidth(58)
|
||||
delBtn:SetHeight(20)
|
||||
delBtn:SetPoint("RIGHT", row, "RIGHT", 0, 0)
|
||||
delBtn:SetText("Delete")
|
||||
|
||||
gProfileRows[i] = { frame = row, nameText = nameText, infoText = infoText, loadBtn = loadBtn, delBtn = delBtn }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function PROF_EnsureCharRows()
|
||||
local csc = MTH_GetFrame("MetaHuntOptionsCharContent")
|
||||
if not csc then return end
|
||||
for i = 1, MAX_CHAR_ROWS do
|
||||
if not gCharRows[i] then
|
||||
local row = CreateFrame("Frame", nil, csc)
|
||||
row:SetHeight(ROW_H)
|
||||
row:SetWidth(510)
|
||||
row:SetPoint("TOPLEFT", csc, "TOPLEFT", 0, -(i - 1) * ROW_H)
|
||||
|
||||
local nameText = row:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
||||
nameText:SetPoint("LEFT", row, "LEFT", 4, 2)
|
||||
nameText:SetWidth(250)
|
||||
nameText:SetJustifyH("LEFT")
|
||||
nameText:SetTextColor(0.70, 0.85, 1.00)
|
||||
|
||||
local infoText = row:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
|
||||
infoText:SetPoint("LEFT", row, "LEFT", 258, 2)
|
||||
infoText:SetWidth(120)
|
||||
infoText:SetJustifyH("LEFT")
|
||||
infoText:SetTextColor(0.55, 0.55, 0.55)
|
||||
|
||||
local copyBtn = CreateFrame("Button", nil, row, "UIPanelButtonTemplate")
|
||||
copyBtn:SetWidth(80)
|
||||
copyBtn:SetHeight(20)
|
||||
copyBtn:SetPoint("RIGHT", row, "RIGHT", 0, 0)
|
||||
copyBtn:SetText("Import")
|
||||
|
||||
gCharRows[i] = { frame = row, nameText = nameText, infoText = infoText, copyBtn = copyBtn }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- ── dynamic refresh functions ──────────────────────────────────────────────
|
||||
|
||||
local function PROF_RefreshActive()
|
||||
if not gActiveLabel then return end
|
||||
local active = type(MTH_Profile_GetActive) == "function" and MTH_Profile_GetActive()
|
||||
if active then
|
||||
gActiveLabel:SetText("Active: |cffffd200" .. active .. "|r")
|
||||
gActiveLabel:SetTextColor(0.90, 0.90, 0.90)
|
||||
else
|
||||
gActiveLabel:SetText("Active: |cff888888Custom (unsaved)|r")
|
||||
gActiveLabel:SetTextColor(0.90, 0.90, 0.90)
|
||||
end
|
||||
gActiveLabel:Show()
|
||||
end
|
||||
|
||||
local function PROF_RefreshProfileList()
|
||||
PROF_EnsureProfileRows()
|
||||
local profiles = type(MTH_Profile_GetList) == "function" and MTH_Profile_GetList() or {}
|
||||
local active = type(MTH_Profile_GetActive) == "function" and MTH_Profile_GetActive()
|
||||
local n = table.getn(profiles)
|
||||
|
||||
local sc = MTH_GetFrame("MetaHuntOptionsProfilesContent")
|
||||
if sc then
|
||||
sc:SetHeight(math.max(n * ROW_H + 4, ROW_H))
|
||||
end
|
||||
|
||||
for i = 1, MAX_PROFILE_ROWS do
|
||||
local row = gProfileRows[i]
|
||||
if not row then break end
|
||||
local name = profiles[i]
|
||||
if name then
|
||||
-- Name (with active indicator)
|
||||
if name == active then
|
||||
row.nameText:SetText(name .. " |cff00cc44[active]|r")
|
||||
else
|
||||
row.nameText:SetText(name)
|
||||
end
|
||||
-- Info: date saved by who
|
||||
local p = type(MTH_SavedVariables) == "table"
|
||||
and type(MTH_SavedVariables.profiles) == "table"
|
||||
and MTH_SavedVariables.profiles[name]
|
||||
local info = ""
|
||||
if type(p) == "table" then
|
||||
if p.savedAt and p.savedAt ~= "" then
|
||||
info = p.savedAt
|
||||
end
|
||||
end
|
||||
row.infoText:SetText(info)
|
||||
-- Wire buttons (SetScript replaces previous handler each refresh)
|
||||
local rowName = name
|
||||
row.loadBtn:SetScript("OnClick", function()
|
||||
MTH_PROFILE_PENDING_LOAD = rowName
|
||||
StaticPopup_Show("MTH_PROFILE_LOAD_CONFIRM", rowName)
|
||||
end)
|
||||
row.delBtn:SetScript("OnClick", function()
|
||||
MTH_PROFILE_PENDING_DELETE = rowName
|
||||
StaticPopup_Show("MTH_PROFILE_DELETE_CONFIRM", rowName)
|
||||
end)
|
||||
row.frame:Show()
|
||||
row.loadBtn:Show()
|
||||
row.delBtn:Show()
|
||||
else
|
||||
row.frame:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function PROF_RefreshCharList()
|
||||
PROF_EnsureCharRows()
|
||||
local chars = type(MTH_Profile_GetCharList) == "function" and MTH_Profile_GetCharList() or {}
|
||||
local n = table.getn(chars)
|
||||
|
||||
local csc = MTH_GetFrame("MetaHuntOptionsCharContent")
|
||||
if csc then
|
||||
csc:SetHeight(math.max(n * ROW_H + 4, ROW_H))
|
||||
end
|
||||
|
||||
for i = 1, MAX_CHAR_ROWS do
|
||||
local row = gCharRows[i]
|
||||
if not row then break end
|
||||
local charKey = chars[i]
|
||||
if charKey then
|
||||
local snap = type(MTH_SavedVariables) == "table"
|
||||
and type(MTH_SavedVariables.charSnapshots) == "table"
|
||||
and MTH_SavedVariables.charSnapshots[charKey]
|
||||
local info = (type(snap) == "table" and snap.savedAt) and snap.savedAt or ""
|
||||
row.nameText:SetText(charKey)
|
||||
row.infoText:SetText(info)
|
||||
local ck = charKey
|
||||
row.copyBtn:SetScript("OnClick", function()
|
||||
local ok, pName = MTH_Profile_CopyFromChar(ck)
|
||||
if ok then
|
||||
MTH_SetupProfilesOptions()
|
||||
if MTH and MTH.Print then
|
||||
MTH:Print('Imported "' .. ck .. '" as profile "' .. tostring(pName) .. '".')
|
||||
end
|
||||
end
|
||||
end)
|
||||
row.frame:Show()
|
||||
row.copyBtn:Show()
|
||||
else
|
||||
row.frame:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- ── main setup (static elements created once, dynamic lists refreshed every call) ──
|
||||
|
||||
function MTH_SetupProfilesOptions()
|
||||
local container = MTH_GetFrame("MetaHuntOptionsProfiles")
|
||||
if not container then return end
|
||||
|
||||
if not gSetupDone then
|
||||
-- Title
|
||||
local title = container:CreateFontString(nil, "ARTWORK", "GameFontNormal")
|
||||
title:SetPoint("TOPLEFT", container, "TOPLEFT", 6, -6)
|
||||
title:SetText("Profiles")
|
||||
title:SetTextColor(1.00, 0.82, 0.00)
|
||||
|
||||
-- Active profile indicator
|
||||
gActiveLabel = container:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
|
||||
gActiveLabel:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -4)
|
||||
gActiveLabel:SetWidth(540)
|
||||
gActiveLabel:SetJustifyH("LEFT")
|
||||
|
||||
-- ── Save As section ───────────────────────────────────────────────
|
||||
local saveHdr = container:CreateFontString(nil, "ARTWORK", "GameFontNormal")
|
||||
saveHdr:SetPoint("TOPLEFT", gActiveLabel, "BOTTOMLEFT", 0, -10)
|
||||
saveHdr:SetText("Save current settings as:")
|
||||
saveHdr:SetTextColor(0.90, 0.90, 0.90)
|
||||
|
||||
local eb = CreateFrame("EditBox", "MTH_ProfileNameInput", container, "InputBoxTemplate")
|
||||
eb:SetWidth(240)
|
||||
eb:SetHeight(20)
|
||||
eb:SetMaxLetters(50)
|
||||
eb:SetAutoFocus(false)
|
||||
eb:SetPoint("TOPLEFT", saveHdr, "BOTTOMLEFT", 2, -6)
|
||||
eb:SetScript("OnEnterPressed", function()
|
||||
PROF_DoSave(this:GetText())
|
||||
this:SetText("")
|
||||
this:ClearFocus()
|
||||
end)
|
||||
eb:SetScript("OnEscapePressed", function()
|
||||
this:SetText("")
|
||||
this:ClearFocus()
|
||||
end)
|
||||
|
||||
local saveBtn = CreateFrame("Button", "MTH_ProfileSaveBtn", container, "UIPanelButtonTemplate")
|
||||
saveBtn:SetWidth(70)
|
||||
saveBtn:SetHeight(20)
|
||||
saveBtn:SetPoint("LEFT", eb, "RIGHT", 6, 0)
|
||||
saveBtn:SetText("Save")
|
||||
saveBtn:SetScript("OnClick", function()
|
||||
local box = MTH_GetFrame("MTH_ProfileNameInput")
|
||||
if box then
|
||||
PROF_DoSave(box:GetText())
|
||||
box:SetText("")
|
||||
box:ClearFocus()
|
||||
end
|
||||
end)
|
||||
|
||||
-- ── Saved Profiles section ────────────────────────────────────────
|
||||
local profHdr = container:CreateFontString(nil, "ARTWORK", "GameFontNormal")
|
||||
profHdr:SetPoint("TOPLEFT", eb, "BOTTOMLEFT", -2, -12)
|
||||
profHdr:SetText("Saved Profiles")
|
||||
profHdr:SetTextColor(1.00, 0.82, 0.00)
|
||||
|
||||
local rule1 = container:CreateTexture(nil, "ARTWORK")
|
||||
rule1:SetPoint("TOPLEFT", profHdr, "BOTTOMLEFT", 0, -3)
|
||||
rule1:SetWidth(540)
|
||||
rule1:SetHeight(1)
|
||||
rule1:SetTexture(0.30, 0.30, 0.30, 0.80)
|
||||
|
||||
PROF_EnsureScrollFrames(container)
|
||||
|
||||
local sf = MTH_GetFrame("MetaHuntOptionsProfilesScroll")
|
||||
sf:SetPoint("TOPLEFT", rule1, "BOTTOMLEFT", 0, -4)
|
||||
sf:SetWidth(530)
|
||||
sf:SetHeight(170)
|
||||
sf:Show()
|
||||
|
||||
-- ── Copy from Character section ───────────────────────────────────
|
||||
local charHdr = container:CreateFontString(nil, "ARTWORK", "GameFontNormal")
|
||||
charHdr:SetPoint("TOPLEFT", sf, "BOTTOMLEFT", 0, -10)
|
||||
charHdr:SetText("Copy from Character")
|
||||
charHdr:SetTextColor(1.00, 0.82, 0.00)
|
||||
|
||||
local charNote = container:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
|
||||
charNote:SetPoint("TOPLEFT", charHdr, "BOTTOMLEFT", 0, -2)
|
||||
charNote:SetWidth(540)
|
||||
charNote:SetJustifyH("LEFT")
|
||||
charNote:SetText("Snapshots are saved automatically on logout. Click Import to create a profile from one.")
|
||||
charNote:SetTextColor(0.60, 0.60, 0.60)
|
||||
|
||||
local rule2 = container:CreateTexture(nil, "ARTWORK")
|
||||
rule2:SetPoint("TOPLEFT", charNote, "BOTTOMLEFT", 0, -3)
|
||||
rule2:SetWidth(540)
|
||||
rule2:SetHeight(1)
|
||||
rule2:SetTexture(0.30, 0.30, 0.30, 0.80)
|
||||
|
||||
local csf = MTH_GetFrame("MetaHuntOptionsCharScroll")
|
||||
csf:SetPoint("TOPLEFT", rule2, "BOTTOMLEFT", 0, -4)
|
||||
csf:SetWidth(530)
|
||||
csf:SetHeight(140)
|
||||
csf:Show()
|
||||
|
||||
gSetupDone = true
|
||||
end
|
||||
|
||||
-- Refresh dynamic content every time the panel is opened
|
||||
PROF_RefreshActive()
|
||||
PROF_RefreshProfileList()
|
||||
PROF_RefreshCharList()
|
||||
end
|
||||
+29
-2
@@ -3,8 +3,8 @@ local MTH_OPTIONS_SETUP = {} -- Track which frames have been set up
|
||||
MTH_OPTIONS_CONST = MTH_OPTIONS_CONST or {}
|
||||
MTH_OPTIONS_CONST.NAV_DEFAULT_WIDTH = MTH_OPTIONS_CONST.NAV_DEFAULT_WIDTH or 120
|
||||
MTH_OPTIONS_CONST.WINDOW_PADDING = MTH_OPTIONS_CONST.WINDOW_PADDING or 12
|
||||
MTH_OPTIONS_CONST.CONTENT_TOP_OFFSET = MTH_OPTIONS_CONST.CONTENT_TOP_OFFSET or -72
|
||||
MTH_OPTIONS_CONST.CONTENT_HEIGHT = MTH_OPTIONS_CONST.CONTENT_HEIGHT or 540
|
||||
MTH_OPTIONS_CONST.CONTENT_TOP_OFFSET = MTH_OPTIONS_CONST.CONTENT_TOP_OFFSET or -58
|
||||
MTH_OPTIONS_CONST.CONTENT_HEIGHT = MTH_OPTIONS_CONST.CONTENT_HEIGHT or 566
|
||||
MTH_OPTIONS_CONST.CLOSE_BTN_SIZE = MTH_OPTIONS_CONST.CLOSE_BTN_SIZE or 22
|
||||
MTH_OPTIONS_CONST.CLOSE_BTN_OFFSET_X = MTH_OPTIONS_CONST.CLOSE_BTN_OFFSET_X or -8
|
||||
MTH_OPTIONS_CONST.CLOSE_BTN_OFFSET_Y = MTH_OPTIONS_CONST.CLOSE_BTN_OFFSET_Y or -8
|
||||
@@ -117,6 +117,11 @@ function MTH_SelectOptionsTab(tabKey)
|
||||
MTH_SetupGeneralOptions()
|
||||
MTH_OPTIONS_SETUP["General"] = true
|
||||
end
|
||||
elseif tabKey == "Profiles" then
|
||||
if type(MTH_SetupProfilesOptions) == "function" then
|
||||
MTH_SetupProfilesOptions()
|
||||
MTH_OPTIONS_SETUP["Profiles"] = true
|
||||
end
|
||||
elseif tabKey == "Messages" then
|
||||
if not MTH_OPTIONS_SETUP["Messages"] then
|
||||
if type(MTH_SetupMessagesOptions) == "function" then
|
||||
@@ -195,6 +200,28 @@ function MTH_SelectOptionsTab(tabKey)
|
||||
else
|
||||
MTH_SetupAutoBuyOptions()
|
||||
end
|
||||
elseif tabKey == "AutoQuest" then
|
||||
if type(MTH_SetupAutoQuestOptions) == "function" then
|
||||
MTH_SetupAutoQuestOptions()
|
||||
MTH_OPTIONS_SETUP["AutoQuest"] = true
|
||||
end
|
||||
elseif tabKey == "ExpAmmo" then
|
||||
if not MTH_OPTIONS_SETUP["ExpAmmo"] then
|
||||
if type(MTH_SetupExpAmmoOptions) == "function" then
|
||||
MTH_SetupExpAmmoOptions()
|
||||
MTH_OPTIONS_SETUP["ExpAmmo"] = true
|
||||
end
|
||||
end
|
||||
elseif tabKey == "ICU" then
|
||||
if type(MTH_SetupICUOptions) == "function" then
|
||||
MTH_SetupICUOptions()
|
||||
MTH_OPTIONS_SETUP["ICU"] = true
|
||||
if type(MTH_RefreshICUOptions) == "function" then
|
||||
MTH_RefreshICUOptions()
|
||||
end
|
||||
elseif MTH and MTH.Print then
|
||||
MTH:Print("ICU options setup function is not loaded", "error")
|
||||
end
|
||||
elseif tabKey == "Credits" then
|
||||
local setupCredits = _G and _G["MTH_SetupCreditsOptions"]
|
||||
if type(setupCredits) == "function" then
|
||||
|
||||
+10
-2
@@ -27,7 +27,8 @@ MTH_OPTIONS_CONST = MTH_OPTIONS_CONST or {
|
||||
}
|
||||
|
||||
MTH_OPTIONS_TABS = MTH_OPTIONS_TABS or {
|
||||
{ key = "General", label = "General", frame = "MetaHuntOptionsGeneral" },
|
||||
{ key = "General", label = "General", frame = "MetaHuntOptionsGeneral" },
|
||||
{ key = "Profiles", label = "Profiles", frame = "MetaHuntOptionsProfiles" },
|
||||
{ key = "Messages", label = "Messages", frame = "MetaHuntOptionsMessages" },
|
||||
{ key = "Pet", label = "ZPet", frame = "MetaHuntOptionsPet" },
|
||||
{ key = "Track", label = "ZTrack", frame = "MetaHuntOptionsTrack" },
|
||||
@@ -41,6 +42,9 @@ MTH_OPTIONS_TABS = MTH_OPTIONS_TABS or {
|
||||
{ key = "SmartAmmo", label = "Smart Ammo", frame = "MetaHuntOptionsSmartAmmo" },
|
||||
{ key = "FeedOMatic", label = "FeedOMatic", frame = "MetaHuntOptionsFeedOMatic" },
|
||||
{ key = "AutoBuy", label = "Auto Buy", frame = "MetaHuntOptionsAutoBuy" },
|
||||
{ key = "AutoQuest", label = "Auto Quest", frame = "MetaHuntOptionsAutoQuest" },
|
||||
{ key = "ICU", label = "ICU", frame = "MetaHuntOptionsICU" },
|
||||
{ key = "ExpAmmo", label = "MM Widget", frame = "MetaHuntOptionsExpAmmo" },
|
||||
{ key = "ChronometerGeneral", label = "General", frame = "MetaHuntOptionsChronometer" },
|
||||
{ key = "ChronometerBar", label = "Bar", frame = "MetaHuntOptionsChronometer" },
|
||||
{ key = "ChronometerClassSpells", label = "Hunter Spells", frame = "MetaHuntOptionsChronometer" },
|
||||
@@ -50,10 +54,14 @@ MTH_OPTIONS_TABS = MTH_OPTIONS_TABS or {
|
||||
}
|
||||
|
||||
MTH_OPTIONS_TREE = MTH_OPTIONS_TREE or {
|
||||
{ label = "General", key = "General" },
|
||||
{ label = "General", key = "General" },
|
||||
{ label = "Profiles", key = "Profiles" },
|
||||
{ label = "Messages", key = "Messages" },
|
||||
{ label = "Auto Buy", key = "AutoBuy" },
|
||||
{ label = "Auto Quest", key = "AutoQuest" },
|
||||
{ label = "Feed-O-Matic", key = "FeedOMatic" },
|
||||
{ label = "ICU", key = "ICU" },
|
||||
{ label = "MM Widget", key = "ExpAmmo" },
|
||||
{
|
||||
label = "zButtons",
|
||||
node = "zButtons",
|
||||
|
||||
+168
-122
@@ -21,6 +21,14 @@ local function MTH_ZB_RefreshTab(tabName)
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_ZB_IsChecked(control)
|
||||
if not control or type(control.GetChecked) ~= "function" then
|
||||
return false
|
||||
end
|
||||
local checked = control:GetChecked()
|
||||
return checked == 1 or checked == true
|
||||
end
|
||||
|
||||
local function MTH_RebuildSpellOrder(buttonName, buttonObj, itemList, maxButtons)
|
||||
if not (buttonName and buttonObj and itemList and maxButtons) then return end
|
||||
local info = {}
|
||||
@@ -187,15 +195,15 @@ local function MTH_EnsureAmmoOptionsWatcher()
|
||||
if MTH_AmmoOptionsWatcher then
|
||||
return
|
||||
end
|
||||
MTH_AmmoOptionsWatcher = CreateFrame("Frame", "MTHAmmoOptionsWatcherFrame")
|
||||
MTH_AmmoOptionsWatcher = CreateFrame("Frame", "MTH_AmmoOptionsWatcher")
|
||||
if not MTH_AmmoOptionsWatcher then
|
||||
return
|
||||
end
|
||||
MTH_AmmoOptionsWatcher:RegisterEvent("UNIT_INVENTORY_CHANGED")
|
||||
MTH_AmmoOptionsWatcher:RegisterEvent("BAG_UPDATE")
|
||||
MTH_AmmoOptionsWatcher:SetScript("OnEvent", function(_, eventName, unit)
|
||||
eventName = eventName or event
|
||||
unit = unit or arg1
|
||||
MTH_AmmoOptionsWatcher:SetScript("OnEvent", function()
|
||||
local eventName = event
|
||||
local unit = arg1
|
||||
if eventName == "UNIT_INVENTORY_CHANGED" and unit and unit ~= "player" then
|
||||
return
|
||||
end
|
||||
@@ -239,6 +247,16 @@ local function MTH_ZB_EnsureButtonOptionDefaults(buttonName)
|
||||
end
|
||||
saved["children"]["hideonclick"] = saved["children"]["hideonclick"] and true or false
|
||||
|
||||
if saved["children"]["expandonhover"] == nil then
|
||||
saved["children"]["expandonhover"] = false
|
||||
end
|
||||
saved["children"]["expandonhover"] = saved["children"]["expandonhover"] and true or false
|
||||
|
||||
if saved["children"]["fadetimer"] == nil then
|
||||
saved["children"]["fadetimer"] = 0
|
||||
end
|
||||
saved["children"]["fadetimer"] = tonumber(saved["children"]["fadetimer"]) or 0
|
||||
|
||||
if type(saved["parent"]) ~= "table" then
|
||||
saved["parent"] = {}
|
||||
end
|
||||
@@ -325,16 +343,15 @@ local function MTH_SetupButtonOptions(containerName, buttonName, displayName, ma
|
||||
enableButton:SetChecked(enabledValue and true or false)
|
||||
enableButton.buttonName = buttonName
|
||||
enableButton.buttonObj = buttonObj
|
||||
enableButton:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
local checked = self:GetChecked() and true or false
|
||||
MTH_SetButtonEnabledState(self.buttonName, self.buttonObj, checked)
|
||||
enableButton:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local checked = MTH_ZB_IsChecked(this)
|
||||
MTH_SetButtonEnabledState(this.buttonName, this.buttonObj, checked)
|
||||
end)
|
||||
end
|
||||
|
||||
local parentSection = MTH_ZB_EnsureSection(containerName.."ParentSection", MTH_ZB_L("ZB_SECTION_PARENT_BUTTON", "Parent Button"), -52, 116)
|
||||
local childrenSection = MTH_ZB_EnsureSection(containerName.."ChildrenSection", MTH_ZB_L("ZB_SECTION_CHILDREN_BUTTONS", "Children Buttons"), -184, 235)
|
||||
local childrenSection = MTH_ZB_EnsureSection(containerName.."ChildrenSection", MTH_ZB_L("ZB_SECTION_CHILDREN_BUTTONS", "Children Buttons"), -184, 310)
|
||||
|
||||
local parentYOffset = -18
|
||||
local childrenYOffset = -18
|
||||
@@ -384,16 +401,15 @@ local function MTH_SetupButtonOptions(containerName, buttonName, displayName, ma
|
||||
expandLeft:SetChecked(saved["firstbutton"] == "LEFT")
|
||||
expandLeft.buttonName = buttonName
|
||||
expandLeft.buttonObj = buttonObj
|
||||
expandLeft:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
local checked = self:GetChecked() and true or false
|
||||
local btnName = self.buttonName
|
||||
expandLeft:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local checked = MTH_ZB_IsChecked(this)
|
||||
local btnName = this.buttonName
|
||||
if not btnName or not (ZHunterMod_Saved and ZHunterMod_Saved[btnName]) then return end
|
||||
ZHunterMod_Saved[btnName]["firstbutton"] = checked and "LEFT" or "RIGHT"
|
||||
ZHunterMod_Saved[btnName]["horizontal"] = checked and 1 or nil
|
||||
ZHunterMod_Saved[btnName]["vertical"] = checked and 1 or nil
|
||||
MTH_RefreshButtonGeometry(btnName, self.buttonObj)
|
||||
MTH_RefreshButtonGeometry(btnName, this.buttonObj)
|
||||
end)
|
||||
end
|
||||
childrenYOffset = childrenYOffset - 30
|
||||
@@ -406,17 +422,64 @@ local function MTH_SetupButtonOptions(containerName, buttonName, displayName, ma
|
||||
if hideClick.buttonObj then
|
||||
hideClick.buttonObj.hideonclick = saved["children"]["hideonclick"] and true or false
|
||||
end
|
||||
hideClick:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
local checked = self:GetChecked() and true or false
|
||||
ZHunterMod_Saved[self.buttonName]["children"]["hideonclick"] = checked
|
||||
local btnObj = self.buttonObj or getglobal(self.buttonName)
|
||||
hideClick:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local checked = MTH_ZB_IsChecked(this)
|
||||
ZHunterMod_Saved[this.buttonName]["children"]["hideonclick"] = checked
|
||||
local btnObj = this.buttonObj or getglobal(this.buttonName)
|
||||
if btnObj then btnObj.hideonclick = checked end
|
||||
end)
|
||||
end
|
||||
childrenYOffset = childrenYOffset - 25
|
||||
|
||||
local expandOnHover = MTH_CreateCheckbox(childrenSection or container, containerName.."ExpandOnHover", MTH_ZB_L("ZB_LABEL_EXPAND_ON_HOVER", "Expand on Hover"), childrenYOffset)
|
||||
if expandOnHover then
|
||||
expandOnHover:SetChecked(saved["children"]["expandonhover"])
|
||||
expandOnHover.buttonName = buttonName
|
||||
expandOnHover.buttonObj = buttonObj
|
||||
expandOnHover:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local checked = MTH_ZB_IsChecked(this)
|
||||
local btnName = this.buttonName
|
||||
if not btnName or not (ZHunterMod_Saved and ZHunterMod_Saved[btnName]) then return end
|
||||
if not ZHunterMod_Saved[btnName]["children"] then
|
||||
ZHunterMod_Saved[btnName]["children"] = {}
|
||||
end
|
||||
ZHunterMod_Saved[btnName]["children"]["expandonhover"] = checked
|
||||
local btnObj = this.buttonObj or getglobal(btnName)
|
||||
if btnObj then btnObj.expandonhover = checked end
|
||||
end)
|
||||
end
|
||||
childrenYOffset = childrenYOffset - 40
|
||||
|
||||
local fadeTimer = MTH_CreateSlider(childrenSection or container, containerName.."FadeTimer", MTH_ZB_L("ZB_LABEL_AUTO_HIDE_TIMER", "Auto-Hide Timer (seconds)"), 0, 10, 1, childrenYOffset)
|
||||
if fadeTimer then
|
||||
fadeTimer:SetWidth(leftWidth - 40)
|
||||
fadeTimer:SetValue(saved["children"]["fadetimer"] or 0)
|
||||
fadeTimer.buttonName = buttonName
|
||||
fadeTimer.buttonObj = buttonObj
|
||||
fadeTimer.onChange = function(val, slider)
|
||||
local frame = slider or fadeTimer
|
||||
local btnName = frame and frame.buttonName
|
||||
if not btnName or not (ZHunterMod_Saved and ZHunterMod_Saved[btnName]) then return end
|
||||
if not ZHunterMod_Saved[btnName]["children"] then
|
||||
ZHunterMod_Saved[btnName]["children"] = {}
|
||||
end
|
||||
local secs = math.floor((val or 0) + 0.5)
|
||||
ZHunterMod_Saved[btnName]["children"]["fadetimer"] = secs
|
||||
local btnObj = frame.buttonObj or getglobal(btnName)
|
||||
if btnObj then
|
||||
btnObj.fadetimer = secs
|
||||
if secs <= 0 then
|
||||
ZSpellButton_StopFadeTimer(btnObj)
|
||||
elseif btnObj.children and btnObj.children:IsVisible() then
|
||||
ZSpellButton_StartFadeTimer(btnObj)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
childrenYOffset = childrenYOffset - 50
|
||||
|
||||
local showTooltip = MTH_CreateCheckbox(childrenSection or container, containerName.."ShowTooltip", MTH_ZB_L("ZB_LABEL_SHOW_TOOLTIP", "Show Tooltip"), childrenYOffset)
|
||||
if showTooltip then
|
||||
showTooltip:SetChecked(saved["tooltip"])
|
||||
@@ -425,12 +488,11 @@ local function MTH_SetupButtonOptions(containerName, buttonName, displayName, ma
|
||||
if showTooltip.buttonObj then
|
||||
showTooltip.buttonObj.tooltip = saved["tooltip"] and true or false
|
||||
end
|
||||
showTooltip:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
local checked = self:GetChecked() and true or false
|
||||
ZHunterMod_Saved[self.buttonName]["tooltip"] = checked
|
||||
local btnObj = self.buttonObj or getglobal(self.buttonName)
|
||||
showTooltip:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local checked = MTH_ZB_IsChecked(this)
|
||||
ZHunterMod_Saved[this.buttonName]["tooltip"] = checked
|
||||
local btnObj = this.buttonObj or getglobal(this.buttonName)
|
||||
if btnObj then btnObj.tooltip = checked end
|
||||
end)
|
||||
end
|
||||
@@ -443,13 +505,12 @@ local function MTH_SetupButtonOptions(containerName, buttonName, displayName, ma
|
||||
showAmmoName.buttonName = buttonName
|
||||
showAmmoName.buttonObj = buttonObj
|
||||
showAmmoName.maxButtons = maxButtons
|
||||
showAmmoName:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
local checked = self:GetChecked() and true or false
|
||||
local btnName = self.buttonName
|
||||
showAmmoName:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local checked = MTH_ZB_IsChecked(this)
|
||||
local btnName = this.buttonName
|
||||
ZHunterMod_Saved[btnName]["showammoname"] = checked
|
||||
local btnObj = self.buttonObj or getglobal(btnName)
|
||||
local btnObj = this.buttonObj or getglobal(btnName)
|
||||
if btnObj then
|
||||
for i = 1, (btnObj.count or 0) do
|
||||
local child = getglobal(btnName..i)
|
||||
@@ -498,13 +559,12 @@ local function MTH_SetupButtonOptions(containerName, buttonName, displayName, ma
|
||||
hideButton:SetChecked(saved["parent"]["hide"])
|
||||
hideButton.buttonName = buttonName
|
||||
hideButton.buttonObj = buttonObj
|
||||
hideButton:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
local checked = self:GetChecked() == 1
|
||||
ZHunterMod_Saved[self.buttonName]["parent"]["hide"] = checked
|
||||
if self.buttonObj then
|
||||
if checked then self.buttonObj:Hide() else self.buttonObj:Show() end
|
||||
hideButton:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local checked = this:GetChecked() == 1
|
||||
ZHunterMod_Saved[this.buttonName]["parent"]["hide"] = checked
|
||||
if this.buttonObj then
|
||||
if checked then this.buttonObj:Hide() else this.buttonObj:Show() end
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -515,13 +575,12 @@ local function MTH_SetupButtonOptions(containerName, buttonName, displayName, ma
|
||||
useCircle:SetChecked(saved["parent"]["circle"])
|
||||
useCircle.buttonName = buttonName
|
||||
useCircle.buttonObj = buttonObj
|
||||
useCircle:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
local checked = self:GetChecked() == 1
|
||||
ZHunterMod_Saved[self.buttonName]["parent"]["circle"] = checked
|
||||
if self.buttonObj and self.buttonObj.circle then
|
||||
if checked then self.buttonObj.circle:Show() else self.buttonObj.circle:Hide() end
|
||||
useCircle:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local checked = this:GetChecked() == 1
|
||||
ZHunterMod_Saved[this.buttonName]["parent"]["circle"] = checked
|
||||
if this.buttonObj and this.buttonObj.circle then
|
||||
if checked then this.buttonObj.circle:Show() else this.buttonObj.circle:Hide() end
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -579,17 +638,16 @@ local function MTH_SetupButtonOptions(containerName, buttonName, displayName, ma
|
||||
showText:SetText("")
|
||||
end
|
||||
showToggle:SetChecked(ZHunterMod_Saved[buttonName]["visible"][showToggle.spellIndex] ~= false)
|
||||
showToggle:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
local checked = self:GetChecked() == 1
|
||||
local btnName = self.buttonName
|
||||
local visibleIndex = self.spellIndex
|
||||
showToggle:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local checked = this:GetChecked() == 1
|
||||
local btnName = this.buttonName
|
||||
local visibleIndex = this.spellIndex
|
||||
if not ZHunterMod_Saved[btnName]["visible"] then
|
||||
ZHunterMod_Saved[btnName]["visible"] = {}
|
||||
end
|
||||
ZHunterMod_Saved[btnName]["visible"][visibleIndex] = checked
|
||||
MTH_RefreshButtonLayout(btnName, self.buttonObj, self.itemList, self.maxButtons)
|
||||
MTH_RefreshButtonLayout(btnName, this.buttonObj, this.itemList, this.maxButtons)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -604,18 +662,17 @@ local function MTH_SetupButtonOptions(containerName, buttonName, displayName, ma
|
||||
downBtn.buttonObj = buttonObj
|
||||
downBtn.itemList = itemList
|
||||
downBtn.maxButtons = maxButtons
|
||||
downBtn:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
local idx = self.spellIndex
|
||||
local btnName = self.buttonName
|
||||
local contName = self.containerName
|
||||
local maxBtns = self.maxButtons
|
||||
downBtn:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local idx = this.spellIndex
|
||||
local btnName = this.buttonName
|
||||
local contName = this.containerName
|
||||
local maxBtns = this.maxButtons
|
||||
if idx < maxBtns then
|
||||
local temp = ZHunterMod_Saved[btnName]["spells"][idx+1]
|
||||
ZHunterMod_Saved[btnName]["spells"][idx+1] = ZHunterMod_Saved[btnName]["spells"][idx]
|
||||
ZHunterMod_Saved[btnName]["spells"][idx] = temp
|
||||
MTH_RebuildSpellOrder(btnName, self.buttonObj, self.itemList, self.maxButtons)
|
||||
MTH_RebuildSpellOrder(btnName, this.buttonObj, this.itemList, this.maxButtons)
|
||||
local tabName = gsub(contName, "MetaHuntOptions", "")
|
||||
MTH_ZB_RefreshTab(tabName)
|
||||
end
|
||||
@@ -632,17 +689,16 @@ local function MTH_SetupButtonOptions(containerName, buttonName, displayName, ma
|
||||
upBtn.buttonObj = buttonObj
|
||||
upBtn.itemList = itemList
|
||||
upBtn.maxButtons = maxButtons
|
||||
upBtn:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
local idx = self.spellIndex
|
||||
local btnName = self.buttonName
|
||||
local contName = self.containerName
|
||||
upBtn:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
local idx = this.spellIndex
|
||||
local btnName = this.buttonName
|
||||
local contName = this.containerName
|
||||
if idx > 1 then
|
||||
local temp = ZHunterMod_Saved[btnName]["spells"][idx-1]
|
||||
ZHunterMod_Saved[btnName]["spells"][idx-1] = ZHunterMod_Saved[btnName]["spells"][idx]
|
||||
ZHunterMod_Saved[btnName]["spells"][idx] = temp
|
||||
MTH_RebuildSpellOrder(btnName, self.buttonObj, self.itemList, self.maxButtons)
|
||||
MTH_RebuildSpellOrder(btnName, this.buttonObj, this.itemList, this.maxButtons)
|
||||
local tabName = gsub(contName, "MetaHuntOptions", "")
|
||||
MTH_ZB_RefreshTab(tabName)
|
||||
end
|
||||
@@ -741,11 +797,10 @@ function MTH_SetupSmartAmmoOptions()
|
||||
end
|
||||
if moduleToggle then
|
||||
moduleToggle:SetChecked(moduleEnabled)
|
||||
moduleToggle:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
moduleToggle:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
if MTH and MTH.SetModuleEnabled then
|
||||
MTH:SetModuleEnabled("smartammo", self:GetChecked() and true or false)
|
||||
MTH:SetModuleEnabled("smartammo", MTH_ZB_IsChecked(this))
|
||||
end
|
||||
MTH_SetupSmartAmmoOptions()
|
||||
end)
|
||||
@@ -758,11 +813,10 @@ function MTH_SetupSmartAmmoOptions()
|
||||
if not moduleEnabled then
|
||||
smartToggle:Disable()
|
||||
end
|
||||
smartToggle:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
smartToggle:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
if type(MTHSmartAmmo_SetSmartEnabled) == "function" then
|
||||
MTHSmartAmmo_SetSmartEnabled(self:GetChecked() and 1 or nil)
|
||||
MTHSmartAmmo_SetSmartEnabled(MTH_ZB_IsChecked(this) and 1 or nil)
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -777,11 +831,10 @@ function MTH_SetupSmartAmmoOptions()
|
||||
if not moduleEnabled then
|
||||
reloadToggle:Disable()
|
||||
end
|
||||
reloadToggle:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
reloadToggle:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
if type(MTHSmartAmmo_SetReloadEnabled) == "function" then
|
||||
MTHSmartAmmo_SetReloadEnabled(self:GetChecked() and 1 or nil)
|
||||
MTHSmartAmmo_SetReloadEnabled(MTH_ZB_IsChecked(this) and 1 or nil)
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -817,11 +870,10 @@ function MTH_SetupMessagesOptions()
|
||||
local initModulesToggle = MTH_CreateCheckbox(section, "MetaHuntMessagesInitModules", "Init : modules loaded", -36)
|
||||
if initModulesToggle then
|
||||
initModulesToggle:SetChecked(msgSettings.initModulesLoaded and true or false)
|
||||
initModulesToggle:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
initModulesToggle:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
if MTH and MTH.SetMessageEnabled then
|
||||
MTH:SetMessageEnabled("initModulesLoaded", self:GetChecked() and true or false)
|
||||
MTH:SetMessageEnabled("initModulesLoaded", MTH_ZB_IsChecked(this))
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -829,11 +881,10 @@ function MTH_SetupMessagesOptions()
|
||||
local initWelcomeToggle = MTH_CreateCheckbox(section, "MetaHuntMessagesInitWelcome", "Init : Sarcastic welcome message", -64)
|
||||
if initWelcomeToggle then
|
||||
initWelcomeToggle:SetChecked(msgSettings.initSarcasticWelcome ~= false)
|
||||
initWelcomeToggle:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
initWelcomeToggle:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
if MTH and MTH.SetMessageEnabled then
|
||||
MTH:SetMessageEnabled("initSarcasticWelcome", self:GetChecked() and true or false)
|
||||
MTH:SetMessageEnabled("initSarcasticWelcome", MTH_ZB_IsChecked(this))
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -841,11 +892,10 @@ function MTH_SetupMessagesOptions()
|
||||
local petHungryToggle = MTH_CreateCheckbox(section, "MetaHuntMessagesPetHungry", "Pet is hungry (spam)", -92)
|
||||
if petHungryToggle then
|
||||
petHungryToggle:SetChecked(msgSettings.petHungry and true or false)
|
||||
petHungryToggle:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
petHungryToggle:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
if MTH and MTH.SetMessageEnabled then
|
||||
MTH:SetMessageEnabled("petHungry", self:GetChecked() and true or false)
|
||||
MTH:SetMessageEnabled("petHungry", MTH_ZB_IsChecked(this))
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -853,11 +903,10 @@ function MTH_SetupMessagesOptions()
|
||||
local beastTrainingScanToggle = MTH_CreateCheckbox(section, "MetaHuntMessagesBeastTrainingScan", "Beasttraining scan", -120)
|
||||
if beastTrainingScanToggle then
|
||||
beastTrainingScanToggle:SetChecked(msgSettings.beastTrainingScan ~= false)
|
||||
beastTrainingScanToggle:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
beastTrainingScanToggle:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
if MTH and MTH.SetMessageEnabled then
|
||||
MTH:SetMessageEnabled("beastTrainingScan", self:GetChecked() and true or false)
|
||||
MTH:SetMessageEnabled("beastTrainingScan", MTH_ZB_IsChecked(this))
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -865,11 +914,10 @@ function MTH_SetupMessagesOptions()
|
||||
local spellbookScanToggle = MTH_CreateCheckbox(section, "MetaHuntMessagesSpellbookScan", "Spellbook scan", -148)
|
||||
if spellbookScanToggle then
|
||||
spellbookScanToggle:SetChecked(msgSettings.spellbookScan and true or false)
|
||||
spellbookScanToggle:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
spellbookScanToggle:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
if MTH and MTH.SetMessageEnabled then
|
||||
MTH:SetMessageEnabled("spellbookScan", self:GetChecked() and true or false)
|
||||
MTH:SetMessageEnabled("spellbookScan", MTH_ZB_IsChecked(this))
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -877,11 +925,10 @@ function MTH_SetupMessagesOptions()
|
||||
local petRanAwayToggle = MTH_CreateCheckbox(section, "MetaHuntMessagesPetRanAway", "Pet ran away", -176)
|
||||
if petRanAwayToggle then
|
||||
petRanAwayToggle:SetChecked(msgSettings.petRanAway ~= false)
|
||||
petRanAwayToggle:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
petRanAwayToggle:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
if MTH and MTH.SetMessageEnabled then
|
||||
MTH:SetMessageEnabled("petRanAway", self:GetChecked() and true or false)
|
||||
MTH:SetMessageEnabled("petRanAway", MTH_ZB_IsChecked(this))
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -889,11 +936,10 @@ function MTH_SetupMessagesOptions()
|
||||
local mapMarkersToggle = MTH_CreateCheckbox(section, "MetaHuntMessagesMapMarkers", "Map markers", -204)
|
||||
if mapMarkersToggle then
|
||||
mapMarkersToggle:SetChecked(msgSettings.mapMarkers ~= false)
|
||||
mapMarkersToggle:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
mapMarkersToggle:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
if MTH and MTH.SetMessageEnabled then
|
||||
MTH:SetMessageEnabled("mapMarkers", self:GetChecked() and true or false)
|
||||
MTH:SetMessageEnabled("mapMarkers", MTH_ZB_IsChecked(this))
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -1002,7 +1048,7 @@ function MTH_SetupGeneralOptions()
|
||||
local smartModuleToggle = ensureCheckbox(smartAmmoSection, "MetaHuntGeneralSmartAmmoModuleToggle", "Enable module", -10, smartModuleEnabled)
|
||||
if smartModuleToggle then
|
||||
smartModuleToggle:SetScript("OnClick", function()
|
||||
local enabled = this:GetChecked() and true or false
|
||||
local enabled = MTH_ZB_IsChecked(this)
|
||||
if MTH and MTH.SetModuleEnabled then
|
||||
local ok = MTH:SetModuleEnabled("smartammo", enabled)
|
||||
if not ok then
|
||||
@@ -1031,7 +1077,7 @@ function MTH_SetupGeneralOptions()
|
||||
end
|
||||
smartToggle:SetScript("OnClick", function()
|
||||
if type(MTHSmartAmmo_SetSmartEnabled) == "function" then
|
||||
MTHSmartAmmo_SetSmartEnabled(this:GetChecked() and 1 or nil)
|
||||
MTHSmartAmmo_SetSmartEnabled(MTH_ZB_IsChecked(this) and 1 or nil)
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -1045,7 +1091,7 @@ function MTH_SetupGeneralOptions()
|
||||
end
|
||||
reloadToggle:SetScript("OnClick", function()
|
||||
if type(MTHSmartAmmo_SetReloadEnabled) == "function" then
|
||||
MTHSmartAmmo_SetReloadEnabled(this:GetChecked() and 1 or nil)
|
||||
MTHSmartAmmo_SetReloadEnabled(MTH_ZB_IsChecked(this) and 1 or nil)
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -1059,7 +1105,7 @@ function MTH_SetupGeneralOptions()
|
||||
end
|
||||
weaponSwapToggle:SetScript("OnClick", function()
|
||||
if type(MTHSmartAmmo_SetWeaponSwapEnabled) == "function" then
|
||||
MTHSmartAmmo_SetWeaponSwapEnabled(this:GetChecked() and 1 or nil)
|
||||
MTHSmartAmmo_SetWeaponSwapEnabled(MTH_ZB_IsChecked(this) and 1 or nil)
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -1072,7 +1118,7 @@ function MTH_SetupGeneralOptions()
|
||||
if autoStripToggle then
|
||||
autoStripToggle:SetScript("OnClick", function()
|
||||
if type(AutoStrip_SetAutoStripToggle) == "function" then
|
||||
AutoStrip_SetAutoStripToggle(this:GetChecked())
|
||||
AutoStrip_SetAutoStripToggle(MTH_ZB_IsChecked(this))
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -1081,7 +1127,7 @@ function MTH_SetupGeneralOptions()
|
||||
if displayToggle then
|
||||
displayToggle:SetScript("OnClick", function()
|
||||
if type(AutoStrip_SetDisplayToggle) == "function" then
|
||||
AutoStrip_SetDisplayToggle(this:GetChecked())
|
||||
AutoStrip_SetDisplayToggle(MTH_ZB_IsChecked(this))
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -1095,7 +1141,7 @@ function MTH_SetupGeneralOptions()
|
||||
local antiToggle = ensureCheckbox(antiSection, "MetaHuntGeneralAntiDazeToggle", "Enable Anti-Daze", -10, antiDazeEnabled)
|
||||
if antiToggle then
|
||||
antiToggle:SetScript("OnClick", function()
|
||||
local enabled = this:GetChecked() and true or false
|
||||
local enabled = MTH_ZB_IsChecked(this)
|
||||
if type(AntiDaze_SetEnabled) == "function" then
|
||||
AntiDaze_SetEnabled(enabled, 1)
|
||||
end
|
||||
@@ -1158,7 +1204,7 @@ function MTH_SetupGeneralOptions()
|
||||
local moduleToggle = ensureCheckbox(tooltipsSection, "MetaHuntGeneralTooltipsModuleToggle", "Enable module", -10, moduleEnabled)
|
||||
if moduleToggle then
|
||||
moduleToggle:SetScript("OnClick", function()
|
||||
local enabled = this:GetChecked() and true or false
|
||||
local enabled = MTH_ZB_IsChecked(this)
|
||||
if MTH and MTH.SetModuleEnabled then
|
||||
local ok = MTH:SetModuleEnabled("tooltips", enabled)
|
||||
if not ok then
|
||||
@@ -1175,7 +1221,7 @@ function MTH_SetupGeneralOptions()
|
||||
local beastToggle = ensureCheckbox(tooltipsSection, "MetaHuntGeneralTooltipsBeastToggle", "Activate on Beasts", -86, tooltipsStore.beastTooltips and true or false)
|
||||
if beastToggle then
|
||||
beastToggle:SetScript("OnClick", function()
|
||||
local enabled = this:GetChecked() and true or false
|
||||
local enabled = MTH_ZB_IsChecked(this)
|
||||
tooltipsStore.beastTooltips = enabled
|
||||
local tooltipsModule = MTH and MTH.GetModule and MTH:GetModule("tooltips")
|
||||
if tooltipsModule and tooltipsModule.SetBeastTooltipsEnabled then
|
||||
@@ -1191,7 +1237,7 @@ function MTH_SetupGeneralOptions()
|
||||
local ownPetToggle = ensureCheckbox(tooltipsSection, "MetaHuntGeneralTooltipsOwnPetToggle", ownPetLabel, -158, tooltipsStore.ownPetTooltips and true or false)
|
||||
if ownPetToggle then
|
||||
ownPetToggle:SetScript("OnClick", function()
|
||||
local enabled = this:GetChecked() and true or false
|
||||
local enabled = MTH_ZB_IsChecked(this)
|
||||
tooltipsStore.ownPetTooltips = enabled
|
||||
local tooltipsModule = MTH and MTH.GetModule and MTH:GetModule("tooltips")
|
||||
if tooltipsModule and tooltipsModule.SetOwnPetTooltipsEnabled then
|
||||
@@ -1205,7 +1251,7 @@ function MTH_SetupGeneralOptions()
|
||||
local ammoToggle = ensureCheckbox(tooltipsSection, "MetaHuntGeneralTooltipsAmmoVendorToggle", "Activate on Vendors", -222, tooltipsStore.ammoVendorTooltips and true or false)
|
||||
if ammoToggle then
|
||||
ammoToggle:SetScript("OnClick", function()
|
||||
local enabled = this:GetChecked() and true or false
|
||||
local enabled = MTH_ZB_IsChecked(this)
|
||||
tooltipsStore.ammoVendorTooltips = enabled
|
||||
local tooltipsModule = MTH and MTH.GetModule and MTH:GetModule("tooltips")
|
||||
if tooltipsModule and tooltipsModule.SetAmmoVendorTooltipsEnabled then
|
||||
@@ -1219,7 +1265,7 @@ function MTH_SetupGeneralOptions()
|
||||
local foodToggle = ensureCheckbox(tooltipsSection, "MetaHuntGeneralTooltipsFoodToggle", foodLabel, -274, tooltipsStore.foodItemTooltips and true or false)
|
||||
if foodToggle then
|
||||
foodToggle:SetScript("OnClick", function()
|
||||
local enabled = this:GetChecked() and true or false
|
||||
local enabled = MTH_ZB_IsChecked(this)
|
||||
tooltipsStore.foodItemTooltips = enabled
|
||||
local tooltipsModule = MTH and MTH.GetModule and MTH:GetModule("tooltips")
|
||||
if tooltipsModule and tooltipsModule.SetFoodItemTooltipsEnabled then
|
||||
|
||||
+3
-3
@@ -68,9 +68,9 @@ function MTH_CreateSlider(parent, name, label, minVal, maxVal, step, yOffset)
|
||||
if lowLabel then lowLabel:Hide() end
|
||||
if highLabel then highLabel:Hide() end
|
||||
|
||||
slider:SetScript("OnValueChanged", function(self, newValue)
|
||||
local activeSlider = self or this or slider
|
||||
local current = tonumber(newValue)
|
||||
slider:SetScript("OnValueChanged", function()
|
||||
local activeSlider = this or this or slider
|
||||
local current = tonumber(arg1)
|
||||
if not current and activeSlider and activeSlider.GetValue then
|
||||
current = tonumber(activeSlider:GetValue())
|
||||
end
|
||||
|
||||
+6
-2
@@ -46,12 +46,12 @@
|
||||
<Frames>
|
||||
<Frame name="$parentNav" enableMouse="true">
|
||||
<Size>
|
||||
<AbsDimension x="120" y="540"/>
|
||||
<AbsDimension x="120" y="566"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="12" y="-72"/>
|
||||
<AbsDimension x="12" y="-58"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
@@ -66,6 +66,7 @@
|
||||
|
||||
<!-- Content Areas -->
|
||||
<Frame name="$parentGeneral" hidden="true" enableMouse="true"/>
|
||||
<Frame name="$parentProfiles" hidden="true" enableMouse="true"/>
|
||||
<Frame name="$parentMessages" hidden="true" enableMouse="true"/>
|
||||
<Frame name="$parentPet" hidden="true" enableMouse="true"/>
|
||||
<Frame name="$parentTrack" hidden="true" enableMouse="true"/>
|
||||
@@ -79,6 +80,9 @@
|
||||
<Frame name="$parentSmartAmmo" hidden="true" enableMouse="true"/>
|
||||
<Frame name="$parentFeedOMatic" hidden="true" enableMouse="true"/>
|
||||
<Frame name="$parentAutoBuy" hidden="true" enableMouse="true"/>
|
||||
<Frame name="$parentAutoQuest" hidden="true" enableMouse="true"/>
|
||||
<Frame name="$parentICU" hidden="true" enableMouse="true"/>
|
||||
<Frame name="$parentExpAmmo" hidden="true" enableMouse="true"/>
|
||||
<Frame name="$parentChronometer" hidden="true" enableMouse="true"/>
|
||||
<Frame name="$parentCredits" hidden="true" enableMouse="true"/>
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
if not MTH_ST_LifecycleService then
|
||||
MTH_ST_LifecycleService = {}
|
||||
end
|
||||
|
||||
function MTH_ST_LifecycleService:HandleEvent(evt, eventArg1, eventArg2)
|
||||
if type(MTH_ST_HandlePlayerEnteringWorld) == "function" and MTH_ST_HandlePlayerEnteringWorld(evt) then
|
||||
return true, "lifecycle-enter-world"
|
||||
end
|
||||
if type(MTH_ST_HandleSpellcastEvent) == "function" and MTH_ST_HandleSpellcastEvent(evt, eventArg1, eventArg2) then
|
||||
return true, "lifecycle-spellcast"
|
||||
end
|
||||
if type(MTH_ST_HandleUnitPetEvent) == "function" and MTH_ST_HandleUnitPetEvent(evt, eventArg1) then
|
||||
if evt == "UNIT_PET" then
|
||||
if eventArg1 == "player" then
|
||||
return true, "lifecycle-unit-pet-player"
|
||||
end
|
||||
return true, "lifecycle-unit-pet-other"
|
||||
end
|
||||
return true, "lifecycle-unit-pet"
|
||||
end
|
||||
return false
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
if not MTH_ST_RunawayService then
|
||||
MTH_ST_RunawayService = {}
|
||||
end
|
||||
|
||||
function MTH_ST_RunawayService:HandleEvent(evt, eventArg1, _eventArg2)
|
||||
if type(MTH_ST_HandleRunawayEvent) ~= "function" then
|
||||
return false
|
||||
end
|
||||
return MTH_ST_HandleRunawayEvent(evt, eventArg1) and true or false
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
if not MTH_ST_StableScanService then
|
||||
MTH_ST_StableScanService = {}
|
||||
end
|
||||
|
||||
function MTH_ST_StableScanService:HandleEvent(evt, _eventArg1, _eventArg2)
|
||||
if type(MTH_ST_HandleStableUiEvent) ~= "function" then
|
||||
return false
|
||||
end
|
||||
return MTH_ST_HandleStableUiEvent(evt) and true or false
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
if not MTH_ST_VitalsService then
|
||||
MTH_ST_VitalsService = {}
|
||||
end
|
||||
|
||||
function MTH_ST_VitalsService:HandleEvent(evt, eventArg1, _eventArg2)
|
||||
if type(MTH_ST_HandleVitalsEvent) ~= "function" then
|
||||
return false
|
||||
end
|
||||
return MTH_ST_HandleVitalsEvent(evt, eventArg1) and true or false
|
||||
end
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
------------------------------------------------------
|
||||
-- MetaHunt Profile System
|
||||
-- Captures:
|
||||
-- MTH_SavedVariables.modules (account-wide option values, e.g. feedomatic)
|
||||
-- MTH_CharSavedVariables.modules (per-char option values: ICU, Chronometer,
|
||||
-- AutoBuy, AutoQuest, SmartAmmo, tooltips...)
|
||||
-- MTH_CharSavedVariables.moduleStates (enabled/disabled per char)
|
||||
-- ZHunterMod_Saved / MTH_CharSavedVariables.modules.zhunter (zButtons layout)
|
||||
-- Auto-snapshots current character on PLAYER_LOGOUT into
|
||||
-- MTH_SavedVariables.charSnapshots["CharName-RealmName"]
|
||||
------------------------------------------------------
|
||||
|
||||
local function MTH_Profile_DeepCopy(orig)
|
||||
if type(orig) ~= "table" then return orig end
|
||||
local copy = {}
|
||||
for k, v in orig do
|
||||
copy[MTH_Profile_DeepCopy(k)] = MTH_Profile_DeepCopy(v)
|
||||
end
|
||||
return copy
|
||||
end
|
||||
|
||||
local function MTH_Profile_EnsureStore()
|
||||
if type(MTH_SavedVariables) ~= "table" then
|
||||
MTH_SavedVariables = {}
|
||||
end
|
||||
if type(MTH_SavedVariables.profiles) ~= "table" then
|
||||
MTH_SavedVariables.profiles = {}
|
||||
end
|
||||
if type(MTH_SavedVariables.charSnapshots) ~= "table" then
|
||||
MTH_SavedVariables.charSnapshots = {}
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_Profile_GetCharKey()
|
||||
local name = (type(UnitName) == "function") and UnitName("player") or "Unknown"
|
||||
local realm = (type(GetRealmName) == "function") and GetRealmName() or "Unknown"
|
||||
name = (name and name ~= "") and name or "Unknown"
|
||||
realm = (realm and realm ~= "") and realm or "Unknown"
|
||||
return name .. "-" .. realm
|
||||
end
|
||||
|
||||
local function MTH_Profile_BuildSnapshot()
|
||||
local snap = {}
|
||||
snap.savedBy = MTH_Profile_GetCharKey()
|
||||
snap.savedAt = (type(date) == "function") and date("%Y-%m-%d %H:%M") or ""
|
||||
|
||||
-- Account-wide module option values (e.g. feedomatic)
|
||||
snap.config = (type(MTH_SavedVariables) == "table"
|
||||
and type(MTH_SavedVariables.modules) == "table")
|
||||
and MTH_Profile_DeepCopy(MTH_SavedVariables.modules)
|
||||
or {}
|
||||
|
||||
-- Per-character module option values (ICU, Chronometer, AutoBuy, SmartAmmo, etc.)
|
||||
snap.charConfig = (type(MTH_CharSavedVariables) == "table"
|
||||
and type(MTH_CharSavedVariables.modules) == "table")
|
||||
and MTH_Profile_DeepCopy(MTH_CharSavedVariables.modules)
|
||||
or {}
|
||||
|
||||
-- Per-character module enabled/disabled states
|
||||
snap.moduleStates = (type(MTH_CharSavedVariables) == "table"
|
||||
and type(MTH_CharSavedVariables.moduleStates) == "table")
|
||||
and MTH_Profile_DeepCopy(MTH_CharSavedVariables.moduleStates)
|
||||
or {}
|
||||
|
||||
-- zButtons config — kept as dedicated key for clarity
|
||||
-- (also lives in charConfig.zhunter but we keep it explicit)
|
||||
local zh = nil
|
||||
if type(MTH_CharSavedVariables) == "table"
|
||||
and type(MTH_CharSavedVariables.modules) == "table"
|
||||
and type(MTH_CharSavedVariables.modules.zhunter) == "table"
|
||||
then
|
||||
zh = MTH_CharSavedVariables.modules.zhunter
|
||||
elseif type(ZHunterMod_Saved) == "table" then
|
||||
zh = ZHunterMod_Saved
|
||||
end
|
||||
snap.zhunter = zh and MTH_Profile_DeepCopy(zh) or {}
|
||||
|
||||
return snap
|
||||
end
|
||||
|
||||
-- Save current settings as a named profile
|
||||
function MTH_Profile_Save(name)
|
||||
if type(name) ~= "string" or string.len(name) == 0 then
|
||||
return false, "invalid name"
|
||||
end
|
||||
MTH_Profile_EnsureStore()
|
||||
MTH_SavedVariables.profiles[name] = MTH_Profile_BuildSnapshot()
|
||||
return true
|
||||
end
|
||||
|
||||
-- Delete a named profile
|
||||
function MTH_Profile_Delete(name)
|
||||
MTH_Profile_EnsureStore()
|
||||
if MTH_SavedVariables.profiles[name] == nil then return false end
|
||||
MTH_SavedVariables.profiles[name] = nil
|
||||
if type(MTH_CharSavedVariables) == "table"
|
||||
and MTH_CharSavedVariables.activeProfile == name
|
||||
then
|
||||
MTH_CharSavedVariables.activeProfile = nil
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- Apply a profile to SavedVariables; a /reload is required for changes to take full effect
|
||||
function MTH_Profile_Load(name)
|
||||
MTH_Profile_EnsureStore()
|
||||
local p = MTH_SavedVariables.profiles[name]
|
||||
if type(p) ~= "table" then return false, "profile not found" end
|
||||
|
||||
if type(MTH_CharSavedVariables) ~= "table" then MTH_CharSavedVariables = {} end
|
||||
if type(MTH_CharSavedVariables.modules) ~= "table" then MTH_CharSavedVariables.modules = {} end
|
||||
|
||||
-- Apply account-wide module option values (e.g. feedomatic)
|
||||
if type(p.config) == "table" then
|
||||
if type(MTH_SavedVariables.modules) ~= "table" then
|
||||
MTH_SavedVariables.modules = {}
|
||||
end
|
||||
for modName, modData in p.config do
|
||||
MTH_SavedVariables.modules[modName] = MTH_Profile_DeepCopy(modData)
|
||||
end
|
||||
end
|
||||
|
||||
-- Apply per-character module option values (ICU, Chronometer, AutoBuy, SmartAmmo, etc.)
|
||||
if type(p.charConfig) == "table" then
|
||||
for modName, modData in p.charConfig do
|
||||
MTH_CharSavedVariables.modules[modName] = MTH_Profile_DeepCopy(modData)
|
||||
end
|
||||
end
|
||||
|
||||
-- Apply module enabled/disabled
|
||||
if type(p.moduleStates) == "table" then
|
||||
if type(MTH_CharSavedVariables.moduleStates) ~= "table" then
|
||||
MTH_CharSavedVariables.moduleStates = {}
|
||||
end
|
||||
for k, v in p.moduleStates do
|
||||
MTH_CharSavedVariables.moduleStates[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
-- Apply zButtons (also written into charConfig.zhunter above, but keep explicit)
|
||||
if type(p.zhunter) == "table" then
|
||||
ZHunterMod_Saved = MTH_Profile_DeepCopy(p.zhunter)
|
||||
MTH_CharSavedVariables.modules.zhunter = ZHunterMod_Saved
|
||||
end
|
||||
|
||||
MTH_CharSavedVariables.activeProfile = name
|
||||
return true
|
||||
end
|
||||
|
||||
-- Create a named profile from another character's auto-snapshot
|
||||
-- profileName defaults to charKey if not provided
|
||||
function MTH_Profile_CopyFromChar(charKey, profileName)
|
||||
MTH_Profile_EnsureStore()
|
||||
local snap = MTH_SavedVariables.charSnapshots[charKey]
|
||||
if type(snap) ~= "table" then
|
||||
return false, "no snapshot for " .. tostring(charKey)
|
||||
end
|
||||
local name = (type(profileName) == "string" and string.len(profileName) > 0)
|
||||
and profileName or charKey
|
||||
MTH_SavedVariables.profiles[name] = MTH_Profile_DeepCopy(snap)
|
||||
return true, name
|
||||
end
|
||||
|
||||
-- Return sorted list of profile names
|
||||
function MTH_Profile_GetList()
|
||||
MTH_Profile_EnsureStore()
|
||||
local list = {}
|
||||
for name, _ in MTH_SavedVariables.profiles do
|
||||
table.insert(list, name)
|
||||
end
|
||||
table.sort(list)
|
||||
return list
|
||||
end
|
||||
|
||||
-- Return sorted list of character snapshot keys
|
||||
function MTH_Profile_GetCharList()
|
||||
MTH_Profile_EnsureStore()
|
||||
local list = {}
|
||||
for charKey, _ in MTH_SavedVariables.charSnapshots do
|
||||
table.insert(list, charKey)
|
||||
end
|
||||
table.sort(list)
|
||||
return list
|
||||
end
|
||||
|
||||
-- Return the active profile name for the current character, or nil
|
||||
function MTH_Profile_GetActive()
|
||||
if type(MTH_CharSavedVariables) == "table" then
|
||||
return MTH_CharSavedVariables.activeProfile
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Auto-snapshot on logout so other characters can import this config
|
||||
local MTH_ProfileEventFrame = CreateFrame("Frame", "MTH_ProfileEventFrame")
|
||||
MTH_ProfileEventFrame:RegisterEvent("PLAYER_LOGOUT")
|
||||
MTH_ProfileEventFrame:SetScript("OnEvent", function()
|
||||
if event == "PLAYER_LOGOUT" then
|
||||
MTH_Profile_EnsureStore()
|
||||
MTH_SavedVariables.charSnapshots[MTH_Profile_GetCharKey()] = MTH_Profile_BuildSnapshot()
|
||||
end
|
||||
end)
|
||||
+7
-8
@@ -65,11 +65,10 @@ local function MTH_UIR_CreateControl(frame, key, option, context, x, y, width)
|
||||
checkButton:SetPoint("TOPLEFT", frame, "TOPLEFT", x, y + 2)
|
||||
checkButton:SetChecked(MTH_UI.ResolveValue(option.get, context) and 1 or nil)
|
||||
MTH_UIR_SetCheckboxLabel(checkButton, optionName or "")
|
||||
checkButton:SetScript("OnClick", function(self)
|
||||
self = self or this
|
||||
if not self then return end
|
||||
checkButton:SetScript("OnClick", function()
|
||||
if not this then return end
|
||||
if option.set then
|
||||
option.set(context, self:GetChecked() == 1)
|
||||
option.set(context, this:GetChecked() == 1)
|
||||
end
|
||||
end)
|
||||
if MTH_UI.ResolveValue(option.disabled, context) then
|
||||
@@ -100,8 +99,8 @@ local function MTH_UIR_CreateControl(frame, key, option, context, x, y, width)
|
||||
text:SetText(optionName or "Run")
|
||||
text:SetTextColor(1.00, 0.82, 0.00)
|
||||
|
||||
button:SetScript("OnEnter", function(self) self = self or this if self then self:SetBackdropBorderColor(0.6, 0.6, 0.6) end end)
|
||||
button:SetScript("OnLeave", function(self) self = self or this if self then self:SetBackdropBorderColor(0.4, 0.4, 0.4) end end)
|
||||
button:SetScript("OnEnter", function() if this then this:SetBackdropBorderColor(0.6, 0.6, 0.6) end end)
|
||||
button:SetScript("OnLeave", function() if this then this:SetBackdropBorderColor(0.4, 0.4, 0.4) end end)
|
||||
button:SetScript("OnClick", function()
|
||||
if option.func then
|
||||
option.func(context)
|
||||
@@ -139,8 +138,8 @@ local function MTH_UIR_CreateControl(frame, key, option, context, x, y, width)
|
||||
text:SetText(tostring(currentValue or "Choose"))
|
||||
text:SetTextColor(0.90, 0.90, 0.90)
|
||||
|
||||
button:SetScript("OnEnter", function(self) self = self or this if self then self:SetBackdropBorderColor(0.6, 0.6, 0.6) end end)
|
||||
button:SetScript("OnLeave", function(self) self = self or this if self then self:SetBackdropBorderColor(0.4, 0.4, 0.4) end end)
|
||||
button:SetScript("OnEnter", function() if this then this:SetBackdropBorderColor(0.6, 0.6, 0.6) end end)
|
||||
button:SetScript("OnLeave", function() if this then this:SetBackdropBorderColor(0.4, 0.4, 0.4) end end)
|
||||
button:SetScript("OnClick", function()
|
||||
if option.onClick then
|
||||
option.onClick(context, option)
|
||||
|
||||
+15
-3
@@ -4,7 +4,9 @@ MTH.VersionCheck = MTH.VersionCheck or {}
|
||||
local VC = MTH.VersionCheck
|
||||
VC.abbrev = "MTH"
|
||||
VC.channelName = "LFT"
|
||||
VC.updateUrl = "https://github.com/DuvelCorp/MetaHunt"
|
||||
VC.nextPublishAt = nil
|
||||
VC.lastPublishedAt = nil
|
||||
VC.joinAt = nil
|
||||
VC.notified = false
|
||||
VC._invalidVersionWarned = false
|
||||
@@ -218,7 +220,11 @@ function VC:GetTrackedPeers()
|
||||
end
|
||||
|
||||
function VC:ResetPublishDelay()
|
||||
self.nextPublishAt = VC_GetTimeNow() + math.random(10, 20)
|
||||
local now = VC_GetTimeNow()
|
||||
if self.lastPublishedAt and (now - self.lastPublishedAt) < 600 then
|
||||
return -- 10-minute cooldown between publishes
|
||||
end
|
||||
self.nextPublishAt = now + math.random(10, 20)
|
||||
end
|
||||
|
||||
function VC:ShouldPublish()
|
||||
@@ -246,6 +252,7 @@ function VC:TryPublish()
|
||||
end
|
||||
local payload = self.abbrev .. ":" .. tostring(localVersionNumber) .. ":v"
|
||||
SendChatMessage(payload, "CHANNEL", nil, tostring(channelId))
|
||||
self.lastPublishedAt = VC_GetTimeNow()
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -290,7 +297,12 @@ function VC:HandleRemoteMessage(message, author, channelLabel)
|
||||
self.notified = true
|
||||
self.nextPublishAt = nil
|
||||
if MTH and type(MTH.Print) == "function" then
|
||||
MTH:Print("A new version is available !")
|
||||
local localVersionText = tostring(self:GetLocalVersionString() or "?")
|
||||
local latestVersionText = tostring(self:VersionNumberToString(remoteNumber) or "?")
|
||||
MTH:Print("A new version is available!")
|
||||
MTH:Print("YOU SHOULD UPGRADE ! Your version : " .. localVersionText
|
||||
.. " - Latest version " .. latestVersionText
|
||||
.. " --> " .. tostring(self.updateUrl or ""))
|
||||
end
|
||||
|
||||
if VC.frame then
|
||||
@@ -299,7 +311,7 @@ function VC:HandleRemoteMessage(message, author, channelLabel)
|
||||
end
|
||||
|
||||
if not VC.frame then
|
||||
local frame = CreateFrame("Frame", "MTHVersionCheckFrame", UIParent)
|
||||
local frame = CreateFrame("Frame", "MTH_VersionCheck", UIParent)
|
||||
if frame then
|
||||
VC.frame = frame
|
||||
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,329 @@
|
||||
-- MetaHunt: Beast family DBC enrichment (scales, food validation)
|
||||
-- AUTO-GENERATED by .tools — do not edit by hand.
|
||||
-- Source DBC(s): CreatureFamily.dbc, ItemPetFood.dbc
|
||||
-- Generated: 2026-03-20 13:57 UTC
|
||||
|
||||
if not MTH_DS_Families then return end
|
||||
|
||||
-- DBC ID=1 PetFoodMask=208 scale=[0.70-1.00]
|
||||
if MTH_DS_Families["Wolves"] then
|
||||
MTH_DS_Families["Wolves"]["dbcId"] = 1
|
||||
MTH_DS_Families["Wolves"]["minScale"] = 0.7
|
||||
MTH_DS_Families["Wolves"]["maxScale"] = 1.0
|
||||
MTH_DS_Families["Wolves"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Wolves"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Wolves"]["foodMask"] = 208
|
||||
MTH_DS_Families["Wolves"]["foodDbc"] = {
|
||||
"fungus",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=2 PetFoodMask=209 scale=[0.70-1.10]
|
||||
if MTH_DS_Families["Cats"] then
|
||||
MTH_DS_Families["Cats"]["dbcId"] = 2
|
||||
MTH_DS_Families["Cats"]["minScale"] = 0.7
|
||||
MTH_DS_Families["Cats"]["maxScale"] = 1.1
|
||||
MTH_DS_Families["Cats"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Cats"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Cats"]["foodMask"] = 209
|
||||
MTH_DS_Families["Cats"]["foodDbc"] = {
|
||||
"meat",
|
||||
"fungus",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=3 PetFoodMask=203 scale=[0.40-0.60]
|
||||
if MTH_DS_Families["Spiders"] then
|
||||
MTH_DS_Families["Spiders"]["dbcId"] = 3
|
||||
MTH_DS_Families["Spiders"]["minScale"] = 0.4
|
||||
MTH_DS_Families["Spiders"]["maxScale"] = 0.6
|
||||
MTH_DS_Families["Spiders"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Spiders"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Spiders"]["foodMask"] = 203
|
||||
MTH_DS_Families["Spiders"]["foodDbc"] = {
|
||||
"meat",
|
||||
"fish",
|
||||
"bread",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=4 PetFoodMask=210 scale=[0.60-1.00]
|
||||
if MTH_DS_Families["Bears"] then
|
||||
MTH_DS_Families["Bears"]["dbcId"] = 4
|
||||
MTH_DS_Families["Bears"]["minScale"] = 0.6
|
||||
MTH_DS_Families["Bears"]["maxScale"] = 1.0
|
||||
MTH_DS_Families["Bears"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Bears"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Bears"]["foodMask"] = 210
|
||||
MTH_DS_Families["Bears"]["foodDbc"] = {
|
||||
"bread",
|
||||
"cheese",
|
||||
"fish",
|
||||
"fruit",
|
||||
"fungus",
|
||||
"meat",
|
||||
"raw fish",
|
||||
"raw meat",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=5 PetFoodMask=211 scale=[0.60-1.00]
|
||||
if MTH_DS_Families["Boars"] then
|
||||
MTH_DS_Families["Boars"]["dbcId"] = 5
|
||||
MTH_DS_Families["Boars"]["minScale"] = 0.6
|
||||
MTH_DS_Families["Boars"]["maxScale"] = 1.0
|
||||
MTH_DS_Families["Boars"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Boars"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Boars"]["foodMask"] = 211
|
||||
MTH_DS_Families["Boars"]["foodDbc"] = {
|
||||
"bread",
|
||||
"cheese",
|
||||
"fish",
|
||||
"fruit",
|
||||
"fungus",
|
||||
"meat",
|
||||
"raw fish",
|
||||
"raw meat",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=6 PetFoodMask=212 scale=[0.40-0.60]
|
||||
if MTH_DS_Families["Crocolisks"] then
|
||||
MTH_DS_Families["Crocolisks"]["dbcId"] = 6
|
||||
MTH_DS_Families["Crocolisks"]["minScale"] = 0.4
|
||||
MTH_DS_Families["Crocolisks"]["maxScale"] = 0.6
|
||||
MTH_DS_Families["Crocolisks"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Crocolisks"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Crocolisks"]["foodMask"] = 212
|
||||
MTH_DS_Families["Crocolisks"]["foodDbc"] = {
|
||||
"cheese",
|
||||
"fungus",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=7 PetFoodMask=213 scale=[0.50-0.90]
|
||||
if MTH_DS_Families["Carrion Birds"] then
|
||||
MTH_DS_Families["Carrion Birds"]["dbcId"] = 7
|
||||
MTH_DS_Families["Carrion Birds"]["minScale"] = 0.5
|
||||
MTH_DS_Families["Carrion Birds"]["maxScale"] = 0.9
|
||||
MTH_DS_Families["Carrion Birds"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Carrion Birds"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Carrion Birds"]["foodMask"] = 213
|
||||
MTH_DS_Families["Carrion Birds"]["foodDbc"] = {
|
||||
"meat",
|
||||
"cheese",
|
||||
"fungus",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=8 PetFoodMask=214 scale=[0.70-1.40]
|
||||
if MTH_DS_Families["Crabs"] then
|
||||
MTH_DS_Families["Crabs"]["dbcId"] = 8
|
||||
MTH_DS_Families["Crabs"]["minScale"] = 0.7
|
||||
MTH_DS_Families["Crabs"]["maxScale"] = 1.4
|
||||
MTH_DS_Families["Crabs"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Crabs"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Crabs"]["foodMask"] = 214
|
||||
MTH_DS_Families["Crabs"]["foodDbc"] = {
|
||||
"fish",
|
||||
"cheese",
|
||||
"fungus",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=9 PetFoodMask=215 scale=[0.70-1.00]
|
||||
if MTH_DS_Families["Gorillas"] then
|
||||
MTH_DS_Families["Gorillas"]["dbcId"] = 9
|
||||
MTH_DS_Families["Gorillas"]["minScale"] = 0.7
|
||||
MTH_DS_Families["Gorillas"]["maxScale"] = 1.0
|
||||
MTH_DS_Families["Gorillas"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Gorillas"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Gorillas"]["foodMask"] = 215
|
||||
MTH_DS_Families["Gorillas"]["foodDbc"] = {
|
||||
"meat",
|
||||
"fish",
|
||||
"cheese",
|
||||
"fungus",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=11 PetFoodMask=217 scale=[0.50-0.80]
|
||||
if MTH_DS_Families["Raptors"] then
|
||||
MTH_DS_Families["Raptors"]["dbcId"] = 11
|
||||
MTH_DS_Families["Raptors"]["minScale"] = 0.5
|
||||
MTH_DS_Families["Raptors"]["maxScale"] = 0.8
|
||||
MTH_DS_Families["Raptors"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Raptors"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Raptors"]["foodMask"] = 217
|
||||
MTH_DS_Families["Raptors"]["foodDbc"] = {
|
||||
"meat",
|
||||
"bread",
|
||||
"fungus",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=12 PetFoodMask=218 scale=[0.50-0.80]
|
||||
if MTH_DS_Families["Tallstriders"] then
|
||||
MTH_DS_Families["Tallstriders"]["dbcId"] = 12
|
||||
MTH_DS_Families["Tallstriders"]["minScale"] = 0.5
|
||||
MTH_DS_Families["Tallstriders"]["maxScale"] = 0.8
|
||||
MTH_DS_Families["Tallstriders"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Tallstriders"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Tallstriders"]["foodMask"] = 218
|
||||
MTH_DS_Families["Tallstriders"]["foodDbc"] = {
|
||||
"fish",
|
||||
"bread",
|
||||
"fungus",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=20 PetFoodMask=236 scale=[0.70-1.00]
|
||||
if MTH_DS_Families["Scorpids"] then
|
||||
MTH_DS_Families["Scorpids"]["dbcId"] = 20
|
||||
MTH_DS_Families["Scorpids"]["minScale"] = 0.7
|
||||
MTH_DS_Families["Scorpids"]["maxScale"] = 1.0
|
||||
MTH_DS_Families["Scorpids"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Scorpids"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Scorpids"]["foodMask"] = 236
|
||||
MTH_DS_Families["Scorpids"]["foodDbc"] = {
|
||||
"cheese",
|
||||
"bread",
|
||||
"fruit",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=21 PetFoodMask=251 scale=[0.50-0.80]
|
||||
if MTH_DS_Families["Turtles"] then
|
||||
MTH_DS_Families["Turtles"]["dbcId"] = 21
|
||||
MTH_DS_Families["Turtles"]["minScale"] = 0.5
|
||||
MTH_DS_Families["Turtles"]["maxScale"] = 0.8
|
||||
MTH_DS_Families["Turtles"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Turtles"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Turtles"]["foodMask"] = 251
|
||||
MTH_DS_Families["Turtles"]["foodDbc"] = {
|
||||
"meat",
|
||||
"fish",
|
||||
"bread",
|
||||
"fungus",
|
||||
"fruit",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=24 PetFoodMask=653 scale=[0.40-0.70]
|
||||
if MTH_DS_Families["Bats"] then
|
||||
MTH_DS_Families["Bats"]["dbcId"] = 24
|
||||
MTH_DS_Families["Bats"]["minScale"] = 0.4
|
||||
MTH_DS_Families["Bats"]["maxScale"] = 0.7
|
||||
MTH_DS_Families["Bats"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Bats"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Bats"]["foodMask"] = 653
|
||||
MTH_DS_Families["Bats"]["foodDbc"] = {
|
||||
"meat",
|
||||
"cheese",
|
||||
"bread",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=25 PetFoodMask=654 scale=[0.70-0.90]
|
||||
if MTH_DS_Families["Hyenas"] then
|
||||
MTH_DS_Families["Hyenas"]["dbcId"] = 25
|
||||
MTH_DS_Families["Hyenas"]["minScale"] = 0.7
|
||||
MTH_DS_Families["Hyenas"]["maxScale"] = 0.9
|
||||
MTH_DS_Families["Hyenas"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Hyenas"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Hyenas"]["foodMask"] = 654
|
||||
MTH_DS_Families["Hyenas"]["foodDbc"] = {
|
||||
"fish",
|
||||
"cheese",
|
||||
"bread",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=26 PetFoodMask=655 scale=[0.50-0.80]
|
||||
if MTH_DS_Families["Owls"] then
|
||||
MTH_DS_Families["Owls"]["dbcId"] = 26
|
||||
MTH_DS_Families["Owls"]["minScale"] = 0.5
|
||||
MTH_DS_Families["Owls"]["maxScale"] = 0.8
|
||||
MTH_DS_Families["Owls"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Owls"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Owls"]["foodMask"] = 655
|
||||
MTH_DS_Families["Owls"]["foodDbc"] = {
|
||||
"meat",
|
||||
"fish",
|
||||
"cheese",
|
||||
"bread",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=27 PetFoodMask=656 scale=[0.50-0.70]
|
||||
if MTH_DS_Families["Wind Serpents"] then
|
||||
MTH_DS_Families["Wind Serpents"]["dbcId"] = 27
|
||||
MTH_DS_Families["Wind Serpents"]["minScale"] = 0.5
|
||||
MTH_DS_Families["Wind Serpents"]["maxScale"] = 0.7
|
||||
MTH_DS_Families["Wind Serpents"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Wind Serpents"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Wind Serpents"]["foodMask"] = 656
|
||||
MTH_DS_Families["Wind Serpents"]["foodDbc"] = {
|
||||
"fungus",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=35 PetFoodMask=1009 scale=[0.60-0.80]
|
||||
if MTH_DS_Families["Serpents"] then
|
||||
MTH_DS_Families["Serpents"]["dbcId"] = 35
|
||||
MTH_DS_Families["Serpents"]["minScale"] = 0.6
|
||||
MTH_DS_Families["Serpents"]["maxScale"] = 0.8
|
||||
MTH_DS_Families["Serpents"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Serpents"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Serpents"]["foodMask"] = 1009
|
||||
MTH_DS_Families["Serpents"]["foodDbc"] = {
|
||||
"meat",
|
||||
"fungus",
|
||||
"fruit",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
|
||||
-- DBC ID=36 PetFoodMask=1010 scale=[0.70-0.90]
|
||||
if MTH_DS_Families["Foxes"] then
|
||||
MTH_DS_Families["Foxes"]["dbcId"] = 36
|
||||
MTH_DS_Families["Foxes"]["minScale"] = 0.7
|
||||
MTH_DS_Families["Foxes"]["maxScale"] = 0.9
|
||||
MTH_DS_Families["Foxes"]["minScaleLevel"] = 1
|
||||
MTH_DS_Families["Foxes"]["maxScaleLevel"] = 60
|
||||
MTH_DS_Families["Foxes"]["foodMask"] = 1010
|
||||
MTH_DS_Families["Foxes"]["foodDbc"] = {
|
||||
"fish",
|
||||
"fungus",
|
||||
"fruit",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
}
|
||||
end
|
||||
+112
-9
@@ -6,6 +6,7 @@ if not MTH_DS then MTH_DS = {} end
|
||||
|
||||
MTH_DS_Families = {
|
||||
["Bats"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Bat",
|
||||
["named"] = 20,
|
||||
["coords"] = 18,
|
||||
["food"] = {
|
||||
@@ -13,69 +14,95 @@ MTH_DS_Families = {
|
||||
"fungus",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Cower",
|
||||
"Dive",
|
||||
"Growl",
|
||||
"Screech",
|
||||
},
|
||||
},
|
||||
["Bears"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Bear",
|
||||
["named"] = 45,
|
||||
["coords"] = 45,
|
||||
["food"] = {
|
||||
"meat",
|
||||
"fruit",
|
||||
"fish",
|
||||
"fungus",
|
||||
"cheese",
|
||||
"bread",
|
||||
"cheese",
|
||||
"fruit",
|
||||
"fungus",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Claw",
|
||||
"Cower",
|
||||
"Growl",
|
||||
"Roar of Fortitude",
|
||||
},
|
||||
},
|
||||
["Boars"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Boar",
|
||||
["named"] = 45,
|
||||
["coords"] = 87,
|
||||
["food"] = {
|
||||
"meat",
|
||||
"fruit",
|
||||
"fish",
|
||||
"fungus",
|
||||
"cheese",
|
||||
"bread",
|
||||
"cheese",
|
||||
"fruit",
|
||||
"fungus",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Charge",
|
||||
"Cower",
|
||||
"Dash",
|
||||
"Growl",
|
||||
},
|
||||
},
|
||||
["Carrion Birds"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Vulture",
|
||||
["named"] = 36,
|
||||
["coords"] = 101,
|
||||
["food"] = {
|
||||
"meat",
|
||||
"raw meat",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Claw",
|
||||
"Cower",
|
||||
"Dive",
|
||||
"Growl",
|
||||
"Screech",
|
||||
},
|
||||
},
|
||||
["Cats"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Cat",
|
||||
["named"] = 85,
|
||||
["coords"] = 88,
|
||||
["food"] = {
|
||||
"meat",
|
||||
"fish",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Claw",
|
||||
"Cower",
|
||||
"Dash",
|
||||
"Growl",
|
||||
"Prowl",
|
||||
},
|
||||
},
|
||||
["Crabs"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Crab",
|
||||
["named"] = 32,
|
||||
["coords"] = 74,
|
||||
["food"] = {
|
||||
@@ -83,39 +110,51 @@ MTH_DS_Families = {
|
||||
"fish",
|
||||
"fungus",
|
||||
"bread",
|
||||
"raw fish",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bubble Barrier",
|
||||
"Claw",
|
||||
"Cower",
|
||||
"Growl",
|
||||
},
|
||||
},
|
||||
["Crocolisks"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Crocolisk",
|
||||
["named"] = 27,
|
||||
["coords"] = 71,
|
||||
["food"] = {
|
||||
"meat",
|
||||
"fish",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
},
|
||||
["abilities"] = {
|
||||
"BIte",
|
||||
"Bite",
|
||||
"Claw",
|
||||
"Cower",
|
||||
"Death Roll",
|
||||
"Growl",
|
||||
},
|
||||
},
|
||||
["Foxes"] = {
|
||||
["icon"] = "ability_hunter_aspectofthefox",
|
||||
["named"] = 9,
|
||||
["coords"] = 51,
|
||||
["food"] = {
|
||||
"meat",
|
||||
"fruit",
|
||||
"raw meat",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Cower",
|
||||
"Dash",
|
||||
"Grace",
|
||||
"Growl",
|
||||
},
|
||||
},
|
||||
["Gorillas"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Gorilla",
|
||||
["named"] = 24,
|
||||
["coords"] = 117,
|
||||
["food"] = {
|
||||
@@ -123,79 +162,111 @@ MTH_DS_Families = {
|
||||
"fungus",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Cower",
|
||||
"Growl",
|
||||
"Thunderstomp",
|
||||
},
|
||||
},
|
||||
["Hyenas"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Hyena",
|
||||
["named"] = 26,
|
||||
["coords"] = 36,
|
||||
["food"] = {
|
||||
"meat",
|
||||
"fruit",
|
||||
"raw meat",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Cower",
|
||||
"Dash",
|
||||
"Growl",
|
||||
"Packleader",
|
||||
},
|
||||
},
|
||||
["Owls"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Owl",
|
||||
["named"] = 16,
|
||||
["coords"] = 59,
|
||||
["food"] = {
|
||||
"meat",
|
||||
"raw meat",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Claw",
|
||||
"Cower",
|
||||
"Dive",
|
||||
"Growl",
|
||||
"Screech",
|
||||
},
|
||||
},
|
||||
["Raptors"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Raptor",
|
||||
["named"] = 51,
|
||||
["coords"] = 115,
|
||||
["food"] = {
|
||||
"meat",
|
||||
"raw meat",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Claw",
|
||||
"Cower",
|
||||
"Dash",
|
||||
"Growl",
|
||||
"Savage Rend",
|
||||
},
|
||||
},
|
||||
["Scorpids"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Scorpid",
|
||||
["named"] = 38,
|
||||
["coords"] = 36,
|
||||
["food"] = {
|
||||
"meat",
|
||||
"raw meat",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Claw",
|
||||
"Cower",
|
||||
"Growl",
|
||||
"Scorpid Poison",
|
||||
},
|
||||
},
|
||||
["Serpents (Cobra)"] = {
|
||||
["Serpents"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Serpent1",
|
||||
["named"] = 10,
|
||||
["coords"] = 13,
|
||||
["food"] = {
|
||||
"meat",
|
||||
"fish",
|
||||
"raw meat",
|
||||
"raw fish",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Cower",
|
||||
"Growl",
|
||||
"Poison Spit",
|
||||
},
|
||||
},
|
||||
["Spiders"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Spider",
|
||||
["named"] = 91,
|
||||
["coords"] = 213,
|
||||
["food"] = {
|
||||
"meat",
|
||||
"raw meat",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Cower",
|
||||
"Growl",
|
||||
"Web",
|
||||
},
|
||||
},
|
||||
["Tallstriders"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_TallStrider",
|
||||
["named"] = 15,
|
||||
["coords"] = 112,
|
||||
["food"] = {
|
||||
@@ -206,45 +277,77 @@ MTH_DS_Families = {
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Cower",
|
||||
"Dash",
|
||||
"Growl",
|
||||
"Strider Presence",
|
||||
},
|
||||
},
|
||||
["Turtles"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Turtle",
|
||||
["named"] = 25,
|
||||
["coords"] = 42,
|
||||
["food"] = {
|
||||
"fruit",
|
||||
"fish",
|
||||
"fungus",
|
||||
"raw fish",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Cower",
|
||||
"Growl",
|
||||
"Shell Shield",
|
||||
},
|
||||
},
|
||||
["Wind Serpents"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_WindSerpent",
|
||||
["named"] = 27,
|
||||
["coords"] = 42,
|
||||
["food"] = {
|
||||
"fish",
|
||||
"cheese",
|
||||
"bread",
|
||||
"raw fish",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Cower",
|
||||
"Dive",
|
||||
"Growl",
|
||||
"Lightning Breath",
|
||||
},
|
||||
},
|
||||
["Wolves"] = {
|
||||
["icon"] = "Ability_Hunter_Pet_Wolf",
|
||||
["named"] = 81,
|
||||
["coords"] = 99,
|
||||
["food"] = {
|
||||
"meat",
|
||||
"raw meat",
|
||||
},
|
||||
["abilities"] = {
|
||||
"Bite",
|
||||
"Cower",
|
||||
"Dash",
|
||||
"Furious Howl",
|
||||
"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
@@ -0,0 +1,890 @@
|
||||
-- MetaHunt: Beast appearance skin variants per family
|
||||
-- AUTO-GENERATED by .tools — do not edit by hand.
|
||||
-- Source DBC(s): CreatureDisplayInfo.dbc, CreatureModelData.dbc
|
||||
-- Generated: 2026-03-23 15:09 UTC
|
||||
-- Total skins: 258 across 20 families
|
||||
|
||||
if not MTH_DS then MTH_DS = {} end
|
||||
|
||||
MTH_DS_BeastSkins = {
|
||||
["Bats"] = {
|
||||
{id=1954, tex="BatSkin01", unique=false, modelPath="Creature\\FelBat\\FelBat.mdx"},
|
||||
{id=3956, tex="BatSkinBrown01", unique=false, modelPath="Creature\\FelBat\\FelBat.mdx"},
|
||||
{id=4185, tex="BatSkinViolet01", unique=false, modelPath="Creature\\FelBat\\FelBat.mdx"},
|
||||
{id=4735, tex="BatSkinWhite01", unique=false, modelPath="Creature\\FelBat\\FelBat.mdx"},
|
||||
{id=15191, tex="MobatSkinBlue01", unique=true, modelPath="Creature\\mobat\\Mobat.mdx"},
|
||||
},
|
||||
["Bears"] = {
|
||||
{id=706, tex="BearSkinBlack", unique=false, modelPath="Creature\\bear\\Bear.mdx"},
|
||||
{id=806, tex="BearSkinBlue", unique=false, modelPath="Creature\\bear\\Bear.mdx"},
|
||||
{id=820, tex="BearSkinDrkBrown", unique=false, modelPath="Creature\\bear\\Bear.mdx"},
|
||||
{id=822, tex="BearSkinBrown", unique=false, modelPath="Creature\\bear\\Bear.mdx"},
|
||||
{id=865, tex="BearSkinWhite", unique=false, modelPath="Creature\\bear\\Bear.mdx"},
|
||||
{id=1082, tex="BearSkinBlackDiseased", unique=true, modelPath="Creature\\bear\\Bear.mdx"},
|
||||
{id=1083, tex="BearSkinDrkBrownDiseased", unique=false, modelPath="Creature\\bear\\Bear.mdx"},
|
||||
{id=9492, tex="BearSkinrex2", unique=false, modelPath="Creature\\bear\\Bear.mdx"},
|
||||
{id=18352, tex="PolarBearCubSkin", unique=true, modelPath="Creature\\bear\\Bear.mdx"},
|
||||
{id=19113, tex="FatherBear", 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=20637, tex="BearSkinWhiteDiseased", unique=true, modelPath="Creature\\bear\\Bear.mdx"},
|
||||
{id=21549, tex="bearskinblue2", unique=true, modelPath="Creature\\bear\\Bear.mdx"},
|
||||
{id=21550, tex="bearskinblue3", unique=true, modelPath="Creature\\bear\\Bear.mdx"},
|
||||
},
|
||||
["Boars"] = {
|
||||
{id=193, tex="BoarSkinIvory", unique=false, modelPath="Creature\\Boar\\Boar.mdx"},
|
||||
{id=377, tex="BoarSkinBrown", unique=false, modelPath="Creature\\Boar\\Boar.mdx"},
|
||||
{id=381, tex="BoarSkinBlue", unique=false, modelPath="Creature\\Boar\\Boar.mdx"},
|
||||
{id=2450, tex="BoarSkinIvoryArmored", unique=false, modelPath="Creature\\Boar\\Boar.mdx"},
|
||||
{id=3026, tex="BoarSkinCrimson", unique=false, modelPath="Creature\\Boar\\Boar.mdx"},
|
||||
{id=4713, tex="BoarSkinBrownArmored", unique=false, modelPath="Creature\\Boar\\Boar.mdx"},
|
||||
{id=4714, tex="BoarSkinBlueArmored", unique=true, modelPath="Creature\\Boar\\Boar.mdx"},
|
||||
{id=6121, tex="BoarSkinUndead", unique=false, modelPath="Creature\\Boar\\Boar.mdx"},
|
||||
{id=8869, tex="BoarSkinYellow", unique=false, modelPath="Creature\\Boar\\Boar.mdx"},
|
||||
{id=18729, tex="QuillBeastBlue", unique=true, modelPath="Creature\\Boar\\Boar.mdx"},
|
||||
{id=20504, tex="BoarSkinQuel", unique=true, modelPath="Creature\\Boar\\Boar.mdx"},
|
||||
},
|
||||
["Carrion Birds"] = {
|
||||
{id=388, tex="CarrionBirdSkin", unique=false, modelPath="Creature\\CarrionBird\\CarrionBird.mdx"},
|
||||
{id=410, tex="CarrionBirdSkinBrown", unique=false, modelPath="Creature\\CarrionBird\\CarrionBird.mdx"},
|
||||
{id=490, tex="CarrionBirdSkinRed", unique=false, modelPath="Creature\\CarrionBird\\CarrionBird.mdx"},
|
||||
{id=507, tex="CarrionBirdSkinBlue", unique=false, modelPath="Creature\\CarrionBird\\CarrionBird.mdx"},
|
||||
{id=18390, tex="CarrionBirdSkinWhite", unique=true, modelPath="Creature\\CarrionBird\\CarrionBird.mdx"},
|
||||
},
|
||||
["Cats"] = {
|
||||
{id=320, tex="TigerSkinRed", unique=false, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=321, tex="TigerSkinBlackStriped", unique=false, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=599, tex="TigerSkinBlack", unique=false, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=616, tex="TigerSkinWhite", unique=false, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=632, tex="TigerSkinYellow", unique=false, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=748, tex="TigerSkinSnow", unique=false, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=892, tex="DruidCatSkinBlack", unique=true, modelPath="Creature\\DruidCat\\DruidCat.mdx"},
|
||||
{id=1056, tex="TigerSkinBrown", unique=false, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=1057, tex="LionSkinGold", unique=false, modelPath="Creature\\Lion\\Lion.mdx"},
|
||||
{id=1933, tex="LionessSkinGold", unique=false, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=1934, tex="LionSkinWhite", unique=false, modelPath="Creature\\Lion\\Lion.mdx"},
|
||||
{id=3029, tex="TigerSkinDark", unique=false, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=4424, tex="LionSkinBlack", unique=true, modelPath="Creature\\Lion\\Lion.mdx"},
|
||||
{id=5448, tex="MaineCoon", unique=true, modelPath="Creature\\Cat\\Cat.mdx"},
|
||||
{id=5554, tex="OrangeTabby", unique=true, modelPath="Creature\\Cat\\Cat.mdx"},
|
||||
{id=5555, tex="SilverTabby", unique=true, modelPath="Creature\\Cat\\Cat.mdx"},
|
||||
{id=5556, tex="Bombay", unique=true, modelPath="Creature\\Cat\\Cat.mdx"},
|
||||
{id=5585, tex="Birman", unique=false, modelPath="Creature\\Cat\\Cat.mdx"},
|
||||
{id=5586, tex="CornishRex", unique=true, modelPath="Creature\\Cat\\Cat.mdx"},
|
||||
{id=9209, tex="Cringer", unique=true, modelPath="Creature\\Cat\\Cat.mdx"},
|
||||
{id=9230, tex="TigerSkinGreen", unique=false, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=9949, tex="TigerSkinIce", unique=false, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=9954, tex="RidingTigerSkinLavender", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=9956, tex="RidingTigerSkinWhitenosaddle", unique=false, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=9958, tex="TigerSkinNostripeWhite", unique=false, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=9989, tex="White", unique=false, modelPath="Creature\\Cat\\Cat.mdx"},
|
||||
{id=10054, tex="RidingTigerSkinAqua", unique=false, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=11448, tex="TigerSkinBlackSpotted", unique=false, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=11709, tex="Salome", unique=true, modelPath="Creature\\Cat\\Cat.mdx"},
|
||||
{id=18027, tex="LynxSkinRed", unique=true, modelPath="Creature\\DruidCat\\DruidCat.mdx"},
|
||||
{id=18028, tex="LynxSkinYellow", unique=true, modelPath="Creature\\DruidCat\\DruidCat.mdx"},
|
||||
{id=18389, tex="Boots", unique=true, modelPath="Creature\\Cat\\Cat.mdx"},
|
||||
{id=18426, tex="RidingTigerSkinYellownosaddle", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=18427, tex="RidingTigerSkinIcenosaddle", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=18428, tex="RidingTigerSkinRednosaddle", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=18429, tex="RidingTigerSkinSnownosaddle", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=18430, tex="RidingTigerSkinGoldnosaddle", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=18431, tex="RidingTigerSkinBrownnosaddle", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=18432, tex="RidingTigerSkinBlacknosaddle", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=18433, tex="RidingTigerSkinDarknosaddle", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=18434, tex="RidingTigerSkinNostripeWhitenosaddle", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=20388, tex="TIGERSKINBLACKGEM", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=20389, tex="TigerSkinDiamond", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=20390, tex="TigerSkinJade", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=20391, tex="TigerSkinRuby", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=20392, tex="TigerSkinSaphire", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=20393, tex="TigerSkinTurquoise", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
{id=20410, tex="LionessSkinEmerald", unique=true, modelPath="Creature\\Tiger\\Tiger.mdx"},
|
||||
{id=20437, tex="RidingTigerSkinDarknosaddle.blp", unique=true, modelPath="Creature\\FrostSabre\\FrostSabre.mdx"},
|
||||
},
|
||||
["Crabs"] = {
|
||||
{id=342, tex="CrabSkinBronze", unique=false, modelPath="Creature\\Crab\\Crab.mdx"},
|
||||
{id=979, tex="CrabSkinSaphire", unique=false, modelPath="Creature\\Crab\\Crab.mdx"},
|
||||
{id=981, tex="CrabSkinIvory", unique=false, modelPath="Creature\\Crab\\Crab.mdx"},
|
||||
{id=1307, tex="CrabSkinVermillian", unique=false, modelPath="Creature\\Crab\\Crab.mdx"},
|
||||
{id=18757, tex="CrabSkinDarkDiamond", unique=true, modelPath="Creature\\Crab\\Crab.mdx"},
|
||||
{id=18758, tex="CrabSkinTrueSilver", unique=true, modelPath="Creature\\Crab\\Crab.mdx"},
|
||||
},
|
||||
["Crocolisks"] = {
|
||||
{id=807, tex="CrocodileSkinSwamp", unique=false, modelPath="Creature\\Crocodile\\Crocodile.mdx"},
|
||||
{id=833, tex="CrocodileSkinRiver", unique=false, modelPath="Creature\\Crocodile\\Crocodile.mdx"},
|
||||
{id=925, tex="CrocodileSkinMarsh", unique=false, modelPath="Creature\\Crocodile\\Crocodile.mdx"},
|
||||
{id=1609, tex="CrocodileSkinAlbino", unique=false, modelPath="Creature\\Crocodile\\Crocodile.mdx"},
|
||||
},
|
||||
["Foxes"] = {
|
||||
{id=18004, tex="MistFoxSkin", unique=true, modelPath="Creature\\Mistfox\\Mistfox.mdx"},
|
||||
{id=18005, tex="MistFoxSkinArctic", unique=true, modelPath="Creature\\Mistfox\\Mistfox.mdx"},
|
||||
{id=18006, tex="MistFoxSkinBlack", unique=false, modelPath="Creature\\Mistfox\\Mistfox.mdx"},
|
||||
{id=18007, tex="MistFoxSkinBrown", unique=true, modelPath="Creature\\Mistfox\\Mistfox.mdx"},
|
||||
{id=18008, tex="MistFoxSkinRed", unique=false, modelPath="Creature\\Mistfox\\Mistfox.mdx"},
|
||||
{id=18244, tex="MistFoxSkinSpirit", unique=true, modelPath="Creature\\Mistfox\\Mistfox.mdx"},
|
||||
{id=18773, tex="MistFoxSkinPink", unique=true, modelPath="Creature\\Mistfox\\Mistfox.mdx"},
|
||||
{id=19105, tex="MistFoxSkinEvil", unique=true, modelPath="Creature\\Mistfox\\Mistfox.mdx"},
|
||||
{id=19106, tex="MistFoxSkinGolden", unique=true, modelPath="Creature\\Mistfox\\Mistfox.mdx"},
|
||||
{id=21282, tex="fox2_black", unique=true, modelPath="Creature\\fox2\\fox2.mdx"},
|
||||
{id=21283, tex="fox2_blue", unique=true, modelPath="Creature\\fox2\\fox2.mdx"},
|
||||
{id=21284, tex="fox2_darkred", unique=true, modelPath="Creature\\fox2\\fox2.mdx"},
|
||||
{id=21285, tex="fox2_green", unique=true, modelPath="Creature\\fox2\\fox2.mdx"},
|
||||
{id=21286, tex="fox2_orange", unique=true, modelPath="Creature\\fox2\\fox2.mdx"},
|
||||
{id=21287, tex="fox2_purple", unique=true, modelPath="Creature\\fox2\\fox2.mdx"},
|
||||
{id=21288, tex="fox2_red", unique=true, modelPath="Creature\\fox2\\fox2.mdx"},
|
||||
{id=21289, tex="fox2_teal", unique=true, modelPath="Creature\\fox2\\fox2.mdx"},
|
||||
{id=21290, tex="fox2_white", unique=true, modelPath="Creature\\fox2\\fox2.mdx"},
|
||||
},
|
||||
["Gorillas"] = {
|
||||
{id=792, tex="GorillaSkinSilver", unique=false, modelPath="Creature\\Gorilla\\Gorilla.mdx"},
|
||||
{id=809, tex="GorillaSkinBlack", unique=false, modelPath="Creature\\Gorilla\\Gorilla.mdx"},
|
||||
{id=838, tex="GorillaSkinGrey", unique=false, modelPath="Creature\\Gorilla\\Gorilla.mdx"},
|
||||
{id=840, tex="GorillaSkinWhite", unique=false, modelPath="Creature\\Gorilla\\Gorilla.mdx"},
|
||||
{id=3186, tex="GorillaSkinRed", unique=false, modelPath="Creature\\Gorilla\\Gorilla.mdx"},
|
||||
{id=8841, tex="GorillaSkinAmy", unique=true, modelPath="Creature\\Gorilla\\Gorilla.mdx"},
|
||||
},
|
||||
["Hyenas"] = {
|
||||
{id=1534, tex="HyenaSkinOarnge", unique=false, modelPath="Creature\\Hyena\\Hyena.mdx"},
|
||||
{id=1536, tex="HyenaSkin", unique=false, modelPath="Creature\\Hyena\\Hyena.mdx"},
|
||||
{id=2709, tex="HyenaSkinRed", unique=false, modelPath="Creature\\Hyena\\Hyena.mdx"},
|
||||
{id=2710, tex="HyenaSkinYellow", unique=false, modelPath="Creature\\Hyena\\Hyena.mdx"},
|
||||
{id=2713, tex="HyenaSkinBlue", 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"},
|
||||
},
|
||||
["Moths"] = {
|
||||
{id=21298, tex="mothardenwealdmount_blue", unique=true, modelPath="Creature\\mothardenwealdmount\\mothardenwealdmount.mdx"},
|
||||
{id=21299, tex="mothardenwealdmount_dark", unique=true, modelPath="Creature\\mothardenwealdmount\\mothardenwealdmount.mdx"},
|
||||
{id=21300, tex="mothardenwealdmount_mint", unique=true, modelPath="Creature\\mothardenwealdmount\\mothardenwealdmount.mdx"},
|
||||
{id=21301, tex="mothardenwealdmount_red", unique=true, modelPath="Creature\\mothardenwealdmount\\mothardenwealdmount.mdx"},
|
||||
{id=21431, tex="MothSkinBeige", unique=true, modelPath="Creature\\Moth\\Moth.mdx"},
|
||||
{id=21432, tex="MothSkinBlue", unique=true, modelPath="Creature\\Moth\\Moth.mdx"},
|
||||
{id=21433, tex="mothskingrey", unique=true, modelPath="Creature\\Moth\\Moth.mdx"},
|
||||
{id=21434, tex="MothSkinRed", unique=true, modelPath="Creature\\Moth\\Moth.mdx"},
|
||||
{id=21435, tex="MothSkinWhite", unique=true, modelPath="Creature\\Moth\\Moth.mdx"},
|
||||
{id=21436, tex="mothskinyellow", unique=true, modelPath="Creature\\Moth\\Moth.mdx"},
|
||||
},
|
||||
["Owls"] = {
|
||||
{id=4566, tex="OwlBrown", unique=false, modelPath="Creature\\Owl\\Owl.mdx"},
|
||||
{id=4877, tex="OwlGrey", unique=false, modelPath="Creature\\Owl\\Owl.mdx"},
|
||||
{id=6212, tex="OwlWhite", unique=false, modelPath="Creature\\Owl\\Owl.mdx"},
|
||||
{id=6298, tex="OwlBlue", unique=true, modelPath="Creature\\Owl\\Owl.mdx"},
|
||||
{id=6299, tex="OwlBlack", unique=true, modelPath="Creature\\Owl\\Owl.mdx"},
|
||||
{id=18338, tex="Eagle", unique=false, modelPath="Creature\\Eagle\\Eagle.mdx"},
|
||||
{id=18339, tex="BrownEagle", unique=true, modelPath="Creature\\Eagle\\Eagle.mdx"},
|
||||
{id=18368, tex="OwlSpirit", unique=true, modelPath="Creature\\Owl\\Owl.mdx"},
|
||||
{id=18746, tex="EagleRaven", unique=true, modelPath="Creature\\Eagle\\Eagle.mdx"},
|
||||
{id=21109, tex="OwlRuby", unique=true, modelPath="Creature\\Owl\\Owl.mdx"},
|
||||
{id=21110, tex="OwlSapphire", unique=true, modelPath="Creature\\Owl\\Owl.mdx"},
|
||||
},
|
||||
["Raptors"] = {
|
||||
{id=180, tex="RaptorSkinOrange", unique=false, modelPath="Creature\\Raptor\\Raptor.mdx"},
|
||||
{id=322, tex="RaptorSkinMottledDarkGreen", unique=false, modelPath="Creature\\Raptor\\Raptor.mdx"},
|
||||
{id=675, tex="RaptorSkinMottledBlueGreen", unique=false, modelPath="Creature\\Raptor\\Raptor.mdx"},
|
||||
{id=787, tex="RaptorSkinYellow", unique=false, modelPath="Creature\\Raptor\\Raptor.mdx"},
|
||||
{id=960, tex="RaptorSkinViolet", unique=false, modelPath="Creature\\Raptor\\Raptor.mdx"},
|
||||
{id=1337, tex="RaptorSkinGrey", unique=false, modelPath="Creature\\Raptor\\Raptor.mdx"},
|
||||
{id=1959, tex="RaptorSkinRed", unique=false, modelPath="Creature\\Raptor\\Raptor.mdx"},
|
||||
{id=5291, tex="RidingRaptorSkinObsidian", unique=false, modelPath="Creature\\Raptor\\Raptor.mdx"},
|
||||
},
|
||||
["Scorpids"] = {
|
||||
{id=2414, tex="ScorpionskinPink", unique=false, modelPath="Creature\\Scorpion\\Scorpion.mdx"},
|
||||
{id=2485, tex="ScorpionskinBeige", unique=false, modelPath="Creature\\Scorpion\\Scorpion.mdx"},
|
||||
{id=2487, tex="ScorpionskinYellow", unique=false, modelPath="Creature\\Scorpion\\Scorpion.mdx"},
|
||||
{id=2488, tex="ScorpionskinBlack", unique=false, modelPath="Creature\\Scorpion\\Scorpion.mdx"},
|
||||
{id=2489, tex="ScorpionskinRed", unique=false, modelPath="Creature\\Scorpion\\Scorpion.mdx"},
|
||||
{id=2729, tex="ScorpionskinGolden", unique=false, modelPath="Creature\\Scorpion\\Scorpion.mdx"},
|
||||
{id=2730, tex="ScorpionskinBlue", unique=false, modelPath="Creature\\Scorpion\\Scorpion.mdx"},
|
||||
{id=7469, tex="SilithidScarabSkinBlack", unique=false, modelPath="Creature\\SILITHIDSCARAB\\SilithidScarab.mdx"},
|
||||
{id=8971, tex="SilithidScarabSkinRed", unique=false, modelPath="Creature\\SILITHIDSCARAB\\SilithidScarab.mdx"},
|
||||
{id=9028, tex="SilithidScarabSkinWhite", unique=false, modelPath="Creature\\SILITHIDSCARAB\\SilithidScarab.mdx"},
|
||||
{id=9469, tex="SilithidScarabSkinYellow", unique=false, modelPath="Creature\\SILITHIDSCARAB\\SilithidScarab.mdx"},
|
||||
{id=10983, tex="ScorpionskinSilver", unique=false, modelPath="Creature\\Scorpion\\Scorpion.mdx"},
|
||||
{id=11093, tex="SilithidScarabSkinTeal", unique=false, modelPath="Creature\\SILITHIDSCARAB\\SilithidScarab.mdx"},
|
||||
{id=11104, tex="SilithidScarabSkinGold", unique=false, modelPath="Creature\\SILITHIDSCARAB\\SilithidScarab.mdx"},
|
||||
{id=11107, tex="SilithidScarabSkinPurple", unique=false, modelPath="Creature\\SILITHIDSCARAB\\SilithidScarab.mdx"},
|
||||
{id=11143, tex="SilithidScarabSkinTan", unique=false, 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"},
|
||||
},
|
||||
["Serpents"] = {
|
||||
{id=1206, tex="SnakeSkinBlack", unique=false, modelPath="Creature\\snake\\snake.mdx"},
|
||||
{id=1986, tex="SnakeSkinDarkGreenYellow", unique=false, modelPath="Creature\\snake\\snake.mdx"},
|
||||
{id=1987, tex="SnakeSkinYellowBlack", unique=false, modelPath="Creature\\snake\\snake.mdx"},
|
||||
{id=2954, tex="SnakeSkinRedWhiteBlack", unique=true, modelPath="Creature\\snake\\snake.mdx"},
|
||||
{id=2955, tex="SnakeSkinWhite", unique=false, modelPath="Creature\\snake\\snake.mdx"},
|
||||
{id=2956, tex="SnakeSkinBlue", unique=false, modelPath="Creature\\snake\\snake.mdx"},
|
||||
{id=2957, tex="SnakeSkinBrown", unique=true, modelPath="Creature\\snake\\snake.mdx"},
|
||||
{id=2958, tex="SnakeSkinGreen", unique=false, modelPath="Creature\\snake\\snake.mdx"},
|
||||
{id=4305, tex="SerpantSkinWhite", unique=false, modelPath="Creature\\Serpent\\Serpent.mdx"},
|
||||
{id=4312, tex="SerpantSkinPurple", unique=false, modelPath="Creature\\Serpent\\Serpent.mdx"},
|
||||
{id=4317, tex="SerpantSkinBlue", unique=false, modelPath="Creature\\Serpent\\Serpent.mdx"},
|
||||
{id=4435, tex="SerpantSkinGreen", unique=false, modelPath="Creature\\Serpent\\Serpent.mdx"},
|
||||
{id=6303, tex="SnakeSkinRed", unique=true, modelPath="Creature\\snake\\snake.mdx"},
|
||||
{id=11034, tex="SerpantSkinOlive", unique=false, modelPath="Creature\\Serpent\\Serpent.mdx"},
|
||||
{id=15182, tex="SerpantSkinBrown", unique=true, modelPath="Creature\\Serpent\\Serpent.mdx"},
|
||||
{id=20633, tex="SerpantSkinViolet", unique=true, modelPath="Creature\\Serpent\\Serpent.mdx"},
|
||||
{id=20634, tex="SerpantSkinRuby", unique=true, modelPath="Creature\\Serpent\\Serpent.mdx"},
|
||||
{id=21269, tex="SerpentSkinRuby", unique=true, modelPath="Creature\\Serpent\\Serpent.mdx"},
|
||||
},
|
||||
["Spiders"] = {
|
||||
{id=30, tex="MineSpiderSkinSteel", unique=false, modelPath="Creature\\MineSpider\\MineSpider.mdx"},
|
||||
{id=283, tex="MineSpiderSkinGreen", unique=false, modelPath="Creature\\MineSpider\\MineSpider.mdx"},
|
||||
{id=336, tex="TarantulaSkinGreen", unique=false, modelPath="Creature\\Tarantula\\Tarantula.mdx"},
|
||||
{id=366, tex="TarantulaSkinOrange", unique=false, modelPath="Creature\\Tarantula\\Tarantula.mdx"},
|
||||
{id=513, tex="MineSpiderSkinOlive", unique=false, modelPath="Creature\\MineSpider\\MineSpider.mdx"},
|
||||
{id=520, tex="TarantulaSkinBrown", unique=false, modelPath="Creature\\Tarantula\\Tarantula.mdx"},
|
||||
{id=711, tex="MineSpiderSkinWetLands", unique=false, modelPath="Creature\\MineSpider\\MineSpider.mdx"},
|
||||
{id=955, tex="MineSpiderSkinCave", unique=false, modelPath="Creature\\MineSpider\\MineSpider.mdx"},
|
||||
{id=963, tex="MineSpiderSkinBlood", unique=false, modelPath="Creature\\MineSpider\\MineSpider.mdx"},
|
||||
{id=1091, tex="TarantulaSkinGrey", unique=false, modelPath="Creature\\Tarantula\\Tarantula.mdx"},
|
||||
{id=2536, tex="MineSpiderSkinJungle", unique=false, modelPath="Creature\\MineSpider\\MineSpider.mdx"},
|
||||
{id=4456, tex="MineSpiderSkinCrystal", unique=false, modelPath="Creature\\MineSpider\\MineSpider.mdx"},
|
||||
{id=4457, tex="TarantulaSkinMagma", unique=false, modelPath="Creature\\Tarantula\\Tarantula.mdx"},
|
||||
{id=15937, tex="MineSpiderSkinViolet", unique=true, modelPath="Creature\\MineSpider\\MineSpider.mdx"},
|
||||
},
|
||||
["Tallstriders"] = {
|
||||
{id=38, tex="TallStriderSkinTurquoise", unique=false, modelPath="Creature\\Tallstrider\\TallStrider.mdx"},
|
||||
{id=178, tex="TallStriderSkinBrown", unique=false, modelPath="Creature\\Tallstrider\\TallStrider.mdx"},
|
||||
{id=1220, tex="TallStriderSkinGray", unique=false, modelPath="Creature\\Tallstrider\\TallStrider.mdx"},
|
||||
{id=1221, tex="TallStriderSkinIvory", unique=false, modelPath="Creature\\Tallstrider\\TallStrider.mdx"},
|
||||
{id=1281, tex="TallStriderSkinPurple", unique=true, modelPath="Creature\\Tallstrider\\TallStrider.mdx"},
|
||||
{id=1961, tex="TallStriderSkinPink", unique=true, modelPath="Creature\\Tallstrider\\TallStrider.mdx"},
|
||||
{id=20509, tex="HawkstriderBlue", unique=true, modelPath="Creature\\Hawkstrider\\Hawkstrider.mdx"},
|
||||
{id=20510, tex="HawkstriderGold", 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=20513, tex="HawkstriderWhite", unique=true, modelPath="Creature\\Hawkstrider\\Hawkstrider.mdx"},
|
||||
{id=21554, tex="TallStriderSkinBlue", unique=true, modelPath="Creature\\Tallstrider\\TallStrider.mdx"},
|
||||
{id=21555, tex="TallStriderSkinViolet", unique=true, modelPath="Creature\\Tallstrider\\TallStrider.mdx"},
|
||||
},
|
||||
["Turtles"] = {
|
||||
{id=1244, tex="SeaTurtleSkin", unique=false, modelPath="Creature\\SeaTurtle\\SeaTurtle.mdx"},
|
||||
{id=2307, tex="SeaTurtleSkinWhite", unique=false, modelPath="Creature\\SeaTurtle\\SeaTurtle.mdx"},
|
||||
{id=4829, tex="SeaTurtleSkinGrey", unique=false, modelPath="Creature\\SeaTurtle\\SeaTurtle.mdx"},
|
||||
{id=5026, tex="SeaTurtleSkinRed", unique=false, modelPath="Creature\\SeaTurtle\\SeaTurtle.mdx"},
|
||||
{id=5126, tex="SeaTurtleSkinBlue", unique=false, modelPath="Creature\\SeaTurtle\\SeaTurtle.mdx"},
|
||||
{id=16259, tex="TurtleSkinGreen", unique=false, modelPath="Creature\\Turtle\\Turtle.mdx"},
|
||||
{id=16360, tex="TurtleSkinBrown", unique=true, modelPath="Creature\\Turtle\\Turtle.mdx"},
|
||||
{id=16361, tex="TurtleSkinBlack", unique=true, modelPath="Creature\\Turtle\\Turtle.mdx"},
|
||||
},
|
||||
["Wind Serpents"] = {
|
||||
{id=1336, tex="WindSerpentSkin", unique=false, modelPath="Creature\\WindSerpent\\WindSerpent.mdx"},
|
||||
{id=2699, tex="WindSerpentSkinRed", unique=false, modelPath="Creature\\WindSerpent\\WindSerpent.mdx"},
|
||||
{id=2700, tex="WindSerpentSkinGreen", unique=false, modelPath="Creature\\WindSerpent\\WindSerpent.mdx"},
|
||||
{id=2703, tex="WindSerpentSkinWhite", unique=false, modelPath="Creature\\WindSerpent\\WindSerpent.mdx"},
|
||||
{id=3006, tex="WindSerpentSkinBlack", unique=false, modelPath="Creature\\WindSerpent\\WindSerpent.mdx"},
|
||||
{id=18386, tex="WindSerpentSkinOarnge", unique=true, modelPath="Creature\\WindSerpent\\WindSerpent.mdx"},
|
||||
{id=20514, tex="ManaWurmSkinBlack", unique=true, modelPath="Creature\\Manawurm\\manawurm.mdx"},
|
||||
{id=20515, tex="MANAWURMSKINGREEN", unique=true, modelPath="Creature\\Manawurm\\manawurm.mdx"},
|
||||
{id=20516, tex="ManaWurmSkinPurple", unique=true, modelPath="Creature\\Manawurm\\manawurm.mdx"},
|
||||
{id=20517, tex="ManaWurmSkinQuel", unique=true, modelPath="Creature\\Manawurm\\manawurm.mdx"},
|
||||
{id=20518, tex="ManaWurmSkinSilver1", unique=true, modelPath="Creature\\Manawurm\\manawurm.mdx"},
|
||||
{id=20519, tex="ManaWurmSkinWhite", unique=true, modelPath="Creature\\Manawurm\\manawurm.mdx"},
|
||||
},
|
||||
["Wolves"] = {
|
||||
{id=73, tex="Direwolfskinbrown", unique=true, modelPath="Creature\\DireWolf\\DireWolf.mdx"},
|
||||
{id=161, tex="WolfSkinCoyote", unique=false, modelPath="Creature\\Wolf\\Wolf.mdx"},
|
||||
{id=165, tex="WolfSkinTimber", unique=false, modelPath="Creature\\Wolf\\Wolf.mdx"},
|
||||
{id=246, tex="DireWolfSkinDarkBlack", unique=false, modelPath="Creature\\DireWolf\\DireWolf.mdx"},
|
||||
{id=644, tex="WolfSkinBlack", unique=false, modelPath="Creature\\Wolf\\Wolf.mdx"},
|
||||
{id=720, tex="DireWolfSkinLightBlue", unique=false, modelPath="Creature\\DireWolf\\DireWolf.mdx"},
|
||||
{id=776, tex="WolfSkinArctic", unique=false, modelPath="Creature\\Wolf\\Wolf.mdx"},
|
||||
{id=868, tex="WolfSkinArcticAlpha", unique=true, modelPath="Creature\\Wolf\\Wolf.mdx"},
|
||||
{id=1950, tex="WolfSkin_Ghost", unique=true, modelPath="Creature\\Wolf\\Wolf.mdx"},
|
||||
{id=3916, tex="HoundSkinBlue", unique=false, modelPath="Creature\\DarkHound\\DarkHound.mdx"},
|
||||
{id=4124, tex="WolfSkinDiseased", unique=false, modelPath="Creature\\Wolf\\Wolf.mdx"},
|
||||
{id=6195, tex="HoundSkinGrey", unique=false, modelPath="Creature\\DarkHound\\DarkHound.mdx"},
|
||||
{id=7890, tex="HoundSkinPurple", unique=false, modelPath="Creature\\DarkHound\\DarkHound.mdx"},
|
||||
{id=8180, tex="HoundSkinRed", unique=false, modelPath="Creature\\DarkHound\\DarkHound.mdx"},
|
||||
{id=9369, tex="DireWolfSkinReddishBrown", unique=false, modelPath="Creature\\DireWolf\\DireWolf.mdx"},
|
||||
{id=9564, tex="DireWolfSkinLightGrey", unique=false, modelPath="Creature\\DireWolf\\DireWolf.mdx"},
|
||||
{id=9567, tex="DireWolfSkinBlueBrown", unique=true, modelPath="Creature\\DireWolf\\DireWolf.mdx"},
|
||||
{id=9568, tex="DireWolfSkinDarkBrown", unique=false, modelPath="Creature\\DireWolf\\DireWolf.mdx"},
|
||||
{id=11414, tex="DireWolfSkinDarkGrey", unique=true, modelPath="Creature\\DireWolf\\DireWolf.mdx"},
|
||||
{id=14312, tex="HoundSkinWhite", unique=false, modelPath="Creature\\DarkHound\\DarkHound.mdx"},
|
||||
},
|
||||
}
|
||||
|
||||
-- Maps any beast displayId to the canonical skin id used in MTH_DS_BeastSkins
|
||||
-- Total: 577 entries
|
||||
MTH_DS_DisplayToSkin = {
|
||||
[368] = 30,
|
||||
[372] = 165,
|
||||
[380] = 165,
|
||||
[382] = 366,
|
||||
[389] = 193,
|
||||
[418] = 30,
|
||||
[447] = 165,
|
||||
[471] = 320,
|
||||
[498] = 366,
|
||||
[499] = 193,
|
||||
[503] = 193,
|
||||
[538] = 513,
|
||||
[539] = 30,
|
||||
[545] = 283,
|
||||
[557] = 161,
|
||||
[566] = 520,
|
||||
[598] = 320,
|
||||
[604] = 165,
|
||||
[607] = 381,
|
||||
[613] = 599,
|
||||
[614] = 320,
|
||||
[615] = 322,
|
||||
[633] = 599,
|
||||
[641] = 342,
|
||||
[643] = 161,
|
||||
[647] = 165,
|
||||
[648] = 322,
|
||||
[649] = 180,
|
||||
[651] = 366,
|
||||
[659] = 513,
|
||||
[666] = 165,
|
||||
[670] = 180,
|
||||
[671] = 180,
|
||||
[672] = 180,
|
||||
[673] = 180,
|
||||
[674] = 322,
|
||||
[676] = 322,
|
||||
[677] = 675,
|
||||
[695] = 322,
|
||||
[698] = 320,
|
||||
[699] = 342,
|
||||
[703] = 377,
|
||||
[704] = 377,
|
||||
[707] = 706,
|
||||
[709] = 336,
|
||||
[719] = 706,
|
||||
[741] = 246,
|
||||
[744] = 381,
|
||||
[749] = 748,
|
||||
[755] = 675,
|
||||
[759] = 336,
|
||||
[760] = 336,
|
||||
[762] = 706,
|
||||
[768] = 283,
|
||||
[780] = 644,
|
||||
[781] = 644,
|
||||
[782] = 644,
|
||||
[783] = 165,
|
||||
[784] = 644,
|
||||
[785] = 776,
|
||||
[788] = 180,
|
||||
[801] = 776,
|
||||
[802] = 776,
|
||||
[814] = 807,
|
||||
[815] = 807,
|
||||
[821] = 520,
|
||||
[827] = 520,
|
||||
[831] = 807,
|
||||
[834] = 833,
|
||||
[835] = 807,
|
||||
[837] = 792,
|
||||
[839] = 809,
|
||||
[841] = 792,
|
||||
[842] = 838,
|
||||
[843] = 838,
|
||||
[844] = 792,
|
||||
[845] = 809,
|
||||
[855] = 776,
|
||||
[869] = 776,
|
||||
[902] = 822,
|
||||
[903] = 165,
|
||||
[909] = 520,
|
||||
[910] = 520,
|
||||
[913] = 865,
|
||||
[917] = 632,
|
||||
[918] = 632,
|
||||
[945] = 180,
|
||||
[948] = 180,
|
||||
[949] = 675,
|
||||
[954] = 748,
|
||||
[957] = 283,
|
||||
[958] = 955,
|
||||
[959] = 955,
|
||||
[961] = 787,
|
||||
[982] = 822,
|
||||
[996] = 979,
|
||||
[997] = 981,
|
||||
[998] = 979,
|
||||
[999] = 981,
|
||||
[1000] = 979,
|
||||
[1001] = 981,
|
||||
[1006] = 822,
|
||||
[1007] = 806,
|
||||
[1008] = 632,
|
||||
[1030] = 720,
|
||||
[1034] = 807,
|
||||
[1035] = 925,
|
||||
[1036] = 925,
|
||||
[1037] = 833,
|
||||
[1038] = 925,
|
||||
[1039] = 833,
|
||||
[1040] = 38,
|
||||
[1041] = 178,
|
||||
[1042] = 178,
|
||||
[1043] = 632,
|
||||
[1055] = 632,
|
||||
[1058] = 1056,
|
||||
[1059] = 1056,
|
||||
[1080] = 807,
|
||||
[1087] = 955,
|
||||
[1088] = 513,
|
||||
[1089] = 513,
|
||||
[1090] = 955,
|
||||
[1094] = 809,
|
||||
[1095] = 599,
|
||||
[1100] = 161,
|
||||
[1103] = 1091,
|
||||
[1104] = 1091,
|
||||
[1105] = 388,
|
||||
[1106] = 388,
|
||||
[1157] = 955,
|
||||
[1160] = 955,
|
||||
[1164] = 161,
|
||||
[1167] = 193,
|
||||
[1192] = 507,
|
||||
[1207] = 776,
|
||||
[1208] = 377,
|
||||
[1210] = 490,
|
||||
[1219] = 178,
|
||||
[1222] = 161,
|
||||
[1228] = 388,
|
||||
[1229] = 388,
|
||||
[1250] = 833,
|
||||
[1251] = 833,
|
||||
[1259] = 180,
|
||||
[1283] = 178,
|
||||
[1284] = 1221,
|
||||
[1338] = 960,
|
||||
[1339] = 1337,
|
||||
[1340] = 1337,
|
||||
[1535] = 1534,
|
||||
[1742] = 1336,
|
||||
[1744] = 960,
|
||||
[1746] = 1337,
|
||||
[1747] = 960,
|
||||
[1873] = 513,
|
||||
[1938] = 1307,
|
||||
[1939] = 1307,
|
||||
[1955] = 1954,
|
||||
[1960] = 1959,
|
||||
[1962] = 1959,
|
||||
[1971] = 1057,
|
||||
[1972] = 1057,
|
||||
[1973] = 1057,
|
||||
[1974] = 1336,
|
||||
[1975] = 1336,
|
||||
[1977] = 1057,
|
||||
[1978] = 1933,
|
||||
[1989] = 336,
|
||||
[1990] = 822,
|
||||
[2031] = 1056,
|
||||
[2239] = 979,
|
||||
[2278] = 1056,
|
||||
[2279] = 616,
|
||||
[2300] = 1056,
|
||||
[2301] = 1536,
|
||||
[2305] = 410,
|
||||
[2308] = 2307,
|
||||
[2352] = 246,
|
||||
[2378] = 822,
|
||||
[2424] = 366,
|
||||
[2433] = 30,
|
||||
[2437] = 599,
|
||||
[2453] = 2450,
|
||||
[2486] = 2485,
|
||||
[2491] = 2488,
|
||||
[2537] = 2536,
|
||||
[2538] = 2536,
|
||||
[2539] = 2536,
|
||||
[2540] = 283,
|
||||
[2541] = 283,
|
||||
[2542] = 366,
|
||||
[2543] = 366,
|
||||
[2544] = 366,
|
||||
[2545] = 366,
|
||||
[2546] = 366,
|
||||
[2548] = 925,
|
||||
[2549] = 925,
|
||||
[2550] = 807,
|
||||
[2570] = 1959,
|
||||
[2571] = 1959,
|
||||
[2573] = 1959,
|
||||
[2574] = 1959,
|
||||
[2609] = 1534,
|
||||
[2702] = 2699,
|
||||
[2705] = 2703,
|
||||
[2706] = 2700,
|
||||
[2707] = 2700,
|
||||
[2708] = 2700,
|
||||
[2711] = 2710,
|
||||
[2712] = 2710,
|
||||
[2715] = 2714,
|
||||
[2716] = 2714,
|
||||
[2731] = 2730,
|
||||
[2732] = 2487,
|
||||
[2741] = 1220,
|
||||
[2765] = 2729,
|
||||
[2766] = 2729,
|
||||
[2850] = 1609,
|
||||
[2864] = 2488,
|
||||
[2902] = 1244,
|
||||
[2995] = 2958,
|
||||
[2996] = 1609,
|
||||
[3027] = 3026,
|
||||
[3030] = 3029,
|
||||
[3031] = 3029,
|
||||
[3035] = 3026,
|
||||
[3126] = 1206,
|
||||
[3187] = 3186,
|
||||
[3188] = 3186,
|
||||
[3200] = 806,
|
||||
[3201] = 806,
|
||||
[3202] = 165,
|
||||
[3203] = 165,
|
||||
[3204] = 2699,
|
||||
[3205] = 2699,
|
||||
[3247] = 2489,
|
||||
[3248] = 490,
|
||||
[4065] = 2699,
|
||||
[4090] = 1609,
|
||||
[4091] = 2700,
|
||||
[4167] = 2956,
|
||||
[4268] = 1206,
|
||||
[4343] = 1986,
|
||||
[4440] = 1987,
|
||||
[4442] = 960,
|
||||
[4458] = 4457,
|
||||
[4472] = 748,
|
||||
[4480] = 4312,
|
||||
[4613] = 161,
|
||||
[4615] = 4566,
|
||||
[4636] = 2710,
|
||||
[4689] = 2709,
|
||||
[4716] = 4713,
|
||||
[4732] = 3956,
|
||||
[4733] = 4185,
|
||||
[4734] = 3956,
|
||||
[4767] = 4317,
|
||||
[4768] = 4435,
|
||||
[5027] = 5026,
|
||||
[5030] = 5026,
|
||||
[5052] = 2307,
|
||||
[5066] = 1933,
|
||||
[5067] = 599,
|
||||
[5068] = 3029,
|
||||
[5069] = 632,
|
||||
[5127] = 5126,
|
||||
[5242] = 960,
|
||||
[5244] = 792,
|
||||
[5245] = 838,
|
||||
[5290] = 675,
|
||||
[5292] = 960,
|
||||
[5294] = 792,
|
||||
[5295] = 838,
|
||||
[5296] = 838,
|
||||
[5510] = 822,
|
||||
[5557] = 342,
|
||||
[5558] = 981,
|
||||
[5559] = 979,
|
||||
[5560] = 1307,
|
||||
[5905] = 2488,
|
||||
[5966] = 4305,
|
||||
[5985] = 2489,
|
||||
[6068] = 2488,
|
||||
[6069] = 2488,
|
||||
[6070] = 2488,
|
||||
[6073] = 1091,
|
||||
[6076] = 1220,
|
||||
[6082] = 1056,
|
||||
[6122] = 6121,
|
||||
[6126] = 1244,
|
||||
[6196] = 6195,
|
||||
[6210] = 616,
|
||||
[6213] = 1091,
|
||||
[6214] = 1091,
|
||||
[6248] = 616,
|
||||
[6300] = 4877,
|
||||
[6368] = 5126,
|
||||
[6468] = 5291,
|
||||
[6805] = 3029,
|
||||
[6807] = 3026,
|
||||
[6808] = 336,
|
||||
[6942] = 1056,
|
||||
[6943] = 599,
|
||||
[7046] = 5126,
|
||||
[7114] = 5126,
|
||||
[7339] = 644,
|
||||
[7347] = 2489,
|
||||
[7348] = 490,
|
||||
[7349] = 490,
|
||||
[7409] = 1206,
|
||||
[7470] = 7469,
|
||||
[7510] = 4457,
|
||||
[7511] = 7469,
|
||||
[7569] = 2703,
|
||||
[7619] = 7469,
|
||||
[7691] = 2703,
|
||||
[7829] = 3006,
|
||||
[7836] = 4829,
|
||||
[7837] = 4829,
|
||||
[7839] = 4829,
|
||||
[7840] = 4829,
|
||||
[7891] = 7890,
|
||||
[7892] = 7890,
|
||||
[7893] = 7890,
|
||||
[7894] = 4185,
|
||||
[7896] = 1954,
|
||||
[7897] = 4185,
|
||||
[7906] = 2699,
|
||||
[8014] = 520,
|
||||
[8050] = 2714,
|
||||
[8129] = 840,
|
||||
[8173] = 2955,
|
||||
[8174] = 1987,
|
||||
[8181] = 8180,
|
||||
[8271] = 4456,
|
||||
[8472] = 675,
|
||||
[8473] = 960,
|
||||
[8808] = 4185,
|
||||
[8837] = 865,
|
||||
[8838] = 806,
|
||||
[8839] = 792,
|
||||
[8840] = 806,
|
||||
[8842] = 865,
|
||||
[8843] = 706,
|
||||
[8844] = 3186,
|
||||
[8870] = 381,
|
||||
[8871] = 8869,
|
||||
[8969] = 2487,
|
||||
[8970] = 2487,
|
||||
[9019] = 8180,
|
||||
[9020] = 3916,
|
||||
[9021] = 3916,
|
||||
[9022] = 7890,
|
||||
[9029] = 9028,
|
||||
[9050] = 675,
|
||||
[9074] = 1954,
|
||||
[9276] = 1083,
|
||||
[9277] = 1083,
|
||||
[9278] = 4124,
|
||||
[9280] = 4124,
|
||||
[9287] = 644,
|
||||
[9354] = 7469,
|
||||
[9370] = 9369,
|
||||
[9371] = 9369,
|
||||
[9372] = 9369,
|
||||
[9509] = 644,
|
||||
[9511] = 644,
|
||||
[9535] = 3956,
|
||||
[9558] = 644,
|
||||
[9562] = 246,
|
||||
[9563] = 246,
|
||||
[9565] = 981,
|
||||
[9566] = 979,
|
||||
[9569] = 9568,
|
||||
[9570] = 342,
|
||||
[9571] = 342,
|
||||
[9572] = 9568,
|
||||
[9573] = 979,
|
||||
[9749] = 2488,
|
||||
[9750] = 4735,
|
||||
[9755] = 4456,
|
||||
[9756] = 4456,
|
||||
[9829] = 513,
|
||||
[9910] = 30,
|
||||
[9913] = 2699,
|
||||
[9929] = 4456,
|
||||
[9934] = 336,
|
||||
[9950] = 9949,
|
||||
[9951] = 9949,
|
||||
[9953] = 616,
|
||||
[9955] = 9949,
|
||||
[9957] = 9949,
|
||||
[9990] = 9989,
|
||||
[9992] = 9230,
|
||||
[9993] = 9230,
|
||||
[9997] = 4456,
|
||||
[10015] = 193,
|
||||
[10031] = 8971,
|
||||
[10033] = 1954,
|
||||
[10055] = 1934,
|
||||
[10113] = 10054,
|
||||
[10114] = 1934,
|
||||
[10133] = 840,
|
||||
[10183] = 2699,
|
||||
[10209] = 246,
|
||||
[10270] = 2726,
|
||||
[10271] = 2726,
|
||||
[10273] = 507,
|
||||
[10274] = 776,
|
||||
[10278] = 720,
|
||||
[10618] = 865,
|
||||
[10824] = 388,
|
||||
[10825] = 410,
|
||||
[10826] = 507,
|
||||
[10827] = 490,
|
||||
[10828] = 6212,
|
||||
[10829] = 4877,
|
||||
[10830] = 4877,
|
||||
[10831] = 4877,
|
||||
[10832] = 4877,
|
||||
[10833] = 6212,
|
||||
[10902] = 2726,
|
||||
[10903] = 2713,
|
||||
[10904] = 2713,
|
||||
[10947] = 2307,
|
||||
[10984] = 2487,
|
||||
[10985] = 2487,
|
||||
[10986] = 2414,
|
||||
[10987] = 2414,
|
||||
[10988] = 10983,
|
||||
[10991] = 2700,
|
||||
[11029] = 320,
|
||||
[11031] = 320,
|
||||
[11032] = 3956,
|
||||
[11089] = 9469,
|
||||
[11094] = 11093,
|
||||
[11098] = 2485,
|
||||
[11105] = 11104,
|
||||
[11108] = 11107,
|
||||
[11144] = 11143,
|
||||
[11315] = 1959,
|
||||
[11316] = 787,
|
||||
[11317] = 960,
|
||||
[11318] = 675,
|
||||
[11319] = 322,
|
||||
[11348] = 366,
|
||||
[11411] = 246,
|
||||
[11412] = 720,
|
||||
[11413] = 9564,
|
||||
[11415] = 9564,
|
||||
[11416] = 776,
|
||||
[11417] = 9564,
|
||||
[11418] = 9564,
|
||||
[11419] = 9564,
|
||||
[11420] = 9369,
|
||||
[11421] = 246,
|
||||
[11422] = 720,
|
||||
[11444] = 9958,
|
||||
[11445] = 9958,
|
||||
[11446] = 616,
|
||||
[11447] = 320,
|
||||
[11449] = 321,
|
||||
[11450] = 321,
|
||||
[11451] = 1056,
|
||||
[11452] = 599,
|
||||
[11453] = 11448,
|
||||
[11454] = 3029,
|
||||
[11455] = 320,
|
||||
[11829] = 4735,
|
||||
[11908] = 820,
|
||||
[11909] = 820,
|
||||
[11910] = 599,
|
||||
[12151] = 11093,
|
||||
[12156] = 11107,
|
||||
[12157] = 11104,
|
||||
[12159] = 9469,
|
||||
[12433] = 410,
|
||||
[12966] = 2710,
|
||||
[13096] = 7469,
|
||||
[13097] = 10983,
|
||||
[13111] = 963,
|
||||
[13589] = 1609,
|
||||
[14256] = 925,
|
||||
[14313] = 490,
|
||||
[14315] = 822,
|
||||
[14316] = 822,
|
||||
[14318] = 11448,
|
||||
[14319] = 507,
|
||||
[14364] = 9956,
|
||||
[14557] = 11034,
|
||||
[14558] = 4435,
|
||||
[14559] = 4305,
|
||||
[14562] = 3956,
|
||||
[14572] = 599,
|
||||
[14657] = 5126,
|
||||
[14658] = 4829,
|
||||
[14659] = 1244,
|
||||
[14660] = 5026,
|
||||
[14661] = 2307,
|
||||
[14780] = 1954,
|
||||
[14853] = 711,
|
||||
[14935] = 599,
|
||||
[14950] = 955,
|
||||
[14952] = 955,
|
||||
[15072] = 711,
|
||||
[15132] = 4317,
|
||||
[15133] = 4435,
|
||||
[15135] = 4312,
|
||||
[15136] = 711,
|
||||
[15137] = 3006,
|
||||
[15138] = 320,
|
||||
[15145] = 833,
|
||||
[15150] = 4317,
|
||||
[15151] = 320,
|
||||
[15180] = 9369,
|
||||
[15181] = 14312,
|
||||
[15204] = 9369,
|
||||
[15227] = 4735,
|
||||
[15275] = 2699,
|
||||
[15302] = 3186,
|
||||
[15327] = 2489,
|
||||
[15336] = 2485,
|
||||
[15339] = 11104,
|
||||
[15383] = 10983,
|
||||
[15384] = 2729,
|
||||
[15385] = 10983,
|
||||
[15422] = 2730,
|
||||
[15423] = 2730,
|
||||
[15433] = 2488,
|
||||
[15464] = 9028,
|
||||
[15467] = 11104,
|
||||
[15468] = 11143,
|
||||
[15469] = 2485,
|
||||
[15470] = 2729,
|
||||
[15471] = 2489,
|
||||
[15533] = 2414,
|
||||
[15534] = 6212,
|
||||
[15682] = 11107,
|
||||
[15878] = 776,
|
||||
[15929] = 7469,
|
||||
[15938] = 513,
|
||||
[15939] = 2536,
|
||||
[15964] = 14312,
|
||||
[15969] = 3916,
|
||||
[16145] = 5126,
|
||||
[16359] = 16259,
|
||||
[16622] = 5585,
|
||||
[18115] = 9492,
|
||||
[18177] = 18008,
|
||||
[18353] = 18338,
|
||||
[18493] = 18006,
|
||||
[20369] = 18027,
|
||||
[20370] = 1933,
|
||||
[20371] = 11448,
|
||||
[20372] = 321,
|
||||
[20373] = 9230,
|
||||
[20374] = 18432,
|
||||
[20375] = 18431,
|
||||
[20376] = 18433,
|
||||
[20377] = 18430,
|
||||
[20378] = 18427,
|
||||
[20379] = 18434,
|
||||
[20380] = 18428,
|
||||
[20381] = 18429,
|
||||
[20382] = 9956,
|
||||
[20383] = 18426,
|
||||
[20384] = 11448,
|
||||
[20385] = 321,
|
||||
[20386] = 9230,
|
||||
[20387] = 1933,
|
||||
[20394] = 20388,
|
||||
[20395] = 20389,
|
||||
[20396] = 20390,
|
||||
[20397] = 20391,
|
||||
[20398] = 20392,
|
||||
[20399] = 20393,
|
||||
}
|
||||
+32590
-6387
File diff suppressed because it is too large
Load Diff
+11602
-11602
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
@@ -137,6 +137,11 @@ local MTH_DS_AtlasSources = {
|
||||
[9426] = {["boss"] = true, },
|
||||
[9456] = {["boss"] = true, },
|
||||
[9487] = {["boss"] = true, },
|
||||
[42198] = {["crafted"] = true, },
|
||||
[42199] = {["crafted"] = true, },
|
||||
[42200] = {["crafted"] = true, },
|
||||
[42201] = {["crafted"] = true, },
|
||||
[42202] = {["crafted"] = true, },
|
||||
}
|
||||
|
||||
for itemId, sourceMap in pairs(MTH_DS_AtlasSources) do
|
||||
|
||||
@@ -6308,6 +6308,13 @@ MTH_DS_ItemOrigins = {
|
||||
["level"] = 25,
|
||||
["classification"] = 0,
|
||||
},
|
||||
{
|
||||
["id"] = 62906,
|
||||
["name"] = "Elendon Truebough",
|
||||
["tag"] = "Weapons",
|
||||
["level"] = 44,
|
||||
["classification"] = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -11066,6 +11073,12 @@ MTH_DS_ItemOrigins = {
|
||||
["level"] = 40,
|
||||
["classification"] = 0,
|
||||
},
|
||||
{
|
||||
["id"] = 62843,
|
||||
["name"] = "Ornala",
|
||||
["level"] = 53,
|
||||
["classification"] = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -11747,6 +11760,19 @@ MTH_DS_ItemOrigins = {
|
||||
["level"] = 25,
|
||||
["classification"] = 0,
|
||||
},
|
||||
{
|
||||
["id"] = 62906,
|
||||
["name"] = "Elendon Truebough",
|
||||
["tag"] = "Weapons",
|
||||
["level"] = 44,
|
||||
["classification"] = 0,
|
||||
},
|
||||
{
|
||||
["id"] = 62843,
|
||||
["name"] = "Ornala",
|
||||
["level"] = 53,
|
||||
["classification"] = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1121,6 +1121,51 @@ MTH_DS_AmmoItems = {
|
||||
[13219] = 0,
|
||||
},
|
||||
},
|
||||
[42198] = {
|
||||
["name"] = "Bright Wood Arrows",
|
||||
["level"] = 35,
|
||||
["reqlevel"] = 30,
|
||||
["icon"] = "INV_Ammo_Arrow_02",
|
||||
["subtype"] = "arrow",
|
||||
["dps"] = 10.5,
|
||||
["crafted"] = true,
|
||||
},
|
||||
[42199] = {
|
||||
["name"] = "Shade Wood Arrows",
|
||||
["level"] = 45,
|
||||
["reqlevel"] = 40,
|
||||
["icon"] = "INV_Ammo_Arrow_02",
|
||||
["subtype"] = "arrow",
|
||||
["dps"] = 14.5,
|
||||
["crafted"] = true,
|
||||
},
|
||||
[42200] = {
|
||||
["name"] = "Smooth Ironfeather Arrows",
|
||||
["level"] = 55,
|
||||
["reqlevel"] = 50,
|
||||
["icon"] = "INV_Ammo_Arrow_02",
|
||||
["subtype"] = "arrow",
|
||||
["dps"] = 17.5,
|
||||
["crafted"] = true,
|
||||
},
|
||||
[42201] = {
|
||||
["name"] = "Starfeather Arrows",
|
||||
["level"] = 60,
|
||||
["reqlevel"] = 55,
|
||||
["icon"] = "INV_Ammo_Arrow_02",
|
||||
["subtype"] = "arrow",
|
||||
["dps"] = 19,
|
||||
["crafted"] = true,
|
||||
},
|
||||
[42202] = {
|
||||
["name"] = "Enchanted Thorium Shells",
|
||||
["level"] = 60,
|
||||
["reqlevel"] = 55,
|
||||
["icon"] = "INV_Ammo_Bullet_03",
|
||||
["subtype"] = "bullet",
|
||||
["dps"] = 19,
|
||||
["crafted"] = true,
|
||||
},
|
||||
}
|
||||
|
||||
MTH_DS_Items = MTH_DS_AmmoItems
|
||||
+125
-117
@@ -2,120 +2,128 @@ if not MTH_DS then MTH_DS = {} end
|
||||
|
||||
MTH_DS_MinimapSizes = {
|
||||
[0] = { 0, 0 },
|
||||
[1] = { 4925, 3283.34 },
|
||||
[3] = { 2487.5, 1658.34 },
|
||||
[4] = { 3350, 2233.3 },
|
||||
[8] = { 2293.75, 1529.17 },
|
||||
[10] = { 2700, 1800.03 },
|
||||
[11] = { 4135.42, 2756.25 },
|
||||
[12] = { 3470.84, 2314.62 },
|
||||
[14] = { 5287.5, 3525 },
|
||||
[15] = { 5250, 3500 },
|
||||
[16] = { 5070.84, 3381.25 },
|
||||
[17] = { 10133.34, 6756.25 },
|
||||
[25] = { 711.56, 468.68 },
|
||||
[28] = { 4300, 2866.67 },
|
||||
[33] = { 6381.25, 4254.1 },
|
||||
[36] = { 2800, 1866.67 },
|
||||
[38] = { 2758.33, 1839.58 },
|
||||
[40] = { 3500, 2333.3 },
|
||||
[41] = { 2500, 1666.63 },
|
||||
[44] = { 2170.84, 1447.9 },
|
||||
[45] = { 3600, 2400 },
|
||||
[46] = { 2929.16, 1952.08 },
|
||||
[47] = { 3850, 2566.67 },
|
||||
[51] = { 2231.25, 1487.5 },
|
||||
[85] = { 4518.75, 3012.5 },
|
||||
[130] = { 4200, 2800 },
|
||||
[139] = { 3870.83, 2581.25 },
|
||||
[141] = { 5091.66, 3393.7 },
|
||||
[148] = { 6550, 4366.66 },
|
||||
[209] = { 381, 254 },
|
||||
[215] = { 5137.5, 3425 },
|
||||
[267] = { 3200, 2133.33 },
|
||||
[331] = { 5766.67, 3843.75 },
|
||||
[357] = { 6950, 4633.33 },
|
||||
[361] = { 5750, 3833.33 },
|
||||
[400] = { 4400, 2933.33 },
|
||||
[405] = { 4495.83, 2997.91 },
|
||||
[406] = { 6018, 4010 },
|
||||
[408] = { 3092.1, 2047 },
|
||||
[409] = { 2901.45, 1915.9 },
|
||||
[440] = { 6900, 4600 },
|
||||
[490] = { 3700, 2466.66 },
|
||||
[491] = { 736.45, 490.96 },
|
||||
[493] = { 2308.33, 1539.59 },
|
||||
[616] = { 3206, 2142 },
|
||||
[618] = { 7100, 4733.33 },
|
||||
[717] = { 378.15, 252.1 },
|
||||
[718] = { 572.78, 381.85 },
|
||||
[719] = { 1221.87, 806.42 },
|
||||
[721] = { 769.67, 513.11 },
|
||||
[722] = { 881, 589 },
|
||||
[796] = { 203.66, 135.04 },
|
||||
[876] = { 828, 541 },
|
||||
[1176] = { 1383.33, 922.91 },
|
||||
[1337] = { 893.67, 595.78 },
|
||||
[1377] = { 3483.33, 2322.92 },
|
||||
[1477] = { 695.03, 463.35 },
|
||||
[1497] = { 959.37, 640.11 },
|
||||
[1519] = { 1737.5, 1158.34 },
|
||||
[1537] = { 790.63, 527.61 },
|
||||
[1581] = { 449.89, 300 },
|
||||
[1583] = { 886.84, 591.23 },
|
||||
[1584] = { 1985, 1268 },
|
||||
[1637] = { 1402.61, 935.42 },
|
||||
[1638] = { 1043.75, 695.83 },
|
||||
[1657] = { 1058.33, 705.71 },
|
||||
[1941] = { 1348.24, 888.09 },
|
||||
[1977] = { 2120.83, 1414.6 },
|
||||
[2017] = { 1185.35, 789.86 },
|
||||
[2040] = { 1468, 976 },
|
||||
[2057] = { 320.05, 213.37 },
|
||||
[2100] = { 2112.09, 1410.89 },
|
||||
[2159] = { 483.11, 322.08 },
|
||||
[2257] = { 312, 208 },
|
||||
[2366] = { 1085.86, 726.61 },
|
||||
[2437] = { 738.86, 492.57 },
|
||||
[2557] = { 1324, 869 },
|
||||
[2597] = { 4237.5, 2825 },
|
||||
[2677] = { 499.43, 332.95 },
|
||||
[2717] = { 1495, 983 },
|
||||
[3277] = { 1145.84, 764.58 },
|
||||
[3358] = { 1756.25, 1170.83 },
|
||||
[3428] = { 977.56, 651.7 },
|
||||
[3429] = { 2512.5, 1675 },
|
||||
[3456] = { 1991.69, 1318.42 },
|
||||
[3457] = { 823, 549 },
|
||||
[3478] = { 4139.02, 2946 },
|
||||
[4012] = { 3159, 2108 },
|
||||
[5023] = { 988.63, 1393.17 },
|
||||
[5024] = { 1608, 1075 },
|
||||
[5053] = { 1007.7, 671.8 },
|
||||
[5077] = { 2643.21, 1751.16 },
|
||||
[5086] = { 546.75, 391.9 },
|
||||
[5087] = { 354.5, 234.74 },
|
||||
[5097] = { 1273.1, 853.72 },
|
||||
[5103] = { 752.12, 510.33 },
|
||||
[5121] = { 3227, 2187 },
|
||||
[5130] = { 1432, 977 },
|
||||
[5135] = { 320.19, 213.46 },
|
||||
[5136] = { 619.98, 413.32 },
|
||||
[5138] = { 656.59, 434.97 },
|
||||
[5144] = { 309, 208 },
|
||||
[5147] = { 2777.54, 1851.69 },
|
||||
[5148] = { 652.1, 439.67 },
|
||||
[5153] = { 612.69, 408.46 },
|
||||
[5163] = { 703.3, 468.87 },
|
||||
[5179] = { 3666, 2442 },
|
||||
[5204] = { 1271.99, 845.48 },
|
||||
[5208] = { 1250.18, 837.44 },
|
||||
[5225] = { 3082, 2061 },
|
||||
[5536] = { 2472, 1665 },
|
||||
[5557] = { 2800, 1868 },
|
||||
[5561] = { 3098, 2068 },
|
||||
[5581] = { 3241, 2157 },
|
||||
[5601] = { 1634, 1073 },
|
||||
[5602] = { 5387, 3584 },
|
||||
[5628] = { 1980, 1350 },
|
||||
}
|
||||
[9] = { 5137.50, 3425.00 }, -- Mulgore
|
||||
[11] = { 2487.50, 1658.34 }, -- Barrens
|
||||
[15] = { 2170.84, 1447.90 }, -- Alterac
|
||||
[19] = { 5287.50, 3525.00 }, -- BlastedLands
|
||||
[20] = { 4518.75, 3012.50 }, -- Tirisfal
|
||||
[21] = { 4200.00, 2800.00 }, -- Silverpine
|
||||
[22] = { 2231.25, 1487.50 }, -- WesternPlaguelands
|
||||
[23] = { 3870.83, 2581.25 }, -- EasternPlaguelands
|
||||
[24] = { 3200.00, 2133.33 }, -- Hilsbrad
|
||||
[26] = { 3850.00, 2566.67 }, -- Hinterlands
|
||||
[27] = { 4925.00, 3283.34 }, -- DunMorogh
|
||||
[29] = { 2929.16, 1952.08 }, -- BurningSteppes
|
||||
[30] = { 3470.84, 2314.62 }, -- Elwynn
|
||||
[32] = { 5091.66, 3393.70 }, -- DeadwindPass
|
||||
[34] = { 2700.00, 1800.03 }, -- Duskwood
|
||||
[35] = { 2293.75, 1529.17 }, -- LochModan
|
||||
[37] = { 6381.25, 4254.10 }, -- Stranglethorn
|
||||
[39] = { 4135.42, 2756.25 }, -- Westfall
|
||||
[40] = { 10133.34, 6756.25 }, -- Wetlands
|
||||
[41] = { 5250.00, 3500.00 }, -- Teldrassil
|
||||
[42] = { 6550.00, 4366.66 }, -- Darkshore
|
||||
[43] = { 5766.67, 3843.75 }, -- Ashenvale
|
||||
[61] = { 4400.00, 2933.33 }, -- ThousandNeedles
|
||||
[81] = { 6018.00, 4010.00 }, -- StonetalonMountains
|
||||
[101] = { 4495.83, 2997.91 }, -- Desolace
|
||||
[121] = { 6950.00, 4633.33 }, -- Feralas
|
||||
[141] = { 2800.00, 1866.67 }, -- Dustwallow
|
||||
[161] = { 6900.00, 4600.00 }, -- Tanaris
|
||||
[181] = { 3600.00, 2400.00 }, -- Azshara
|
||||
[182] = { 5750.00, 3833.33 }, -- Felwood
|
||||
[201] = { 3700.00, 2466.66 }, -- UngoroCrater
|
||||
[241] = { 2308.33, 1539.59 }, -- Moonglade
|
||||
[261] = { 3483.33, 2322.92 }, -- Silithus
|
||||
[281] = { 7100.00, 4733.33 }, -- Winterspring
|
||||
[301] = { 1737.50, 1158.34 }, -- Stormwind
|
||||
[321] = { 1402.61, 935.42 }, -- Orgrimmar
|
||||
[341] = { 790.63, 527.61 }, -- Ironforge
|
||||
[362] = { 1043.75, 695.83 }, -- ThunderBluff
|
||||
[381] = { 1058.33, 705.71 }, -- Darnassus
|
||||
[382] = { 959.37, 640.11 }, -- Undercity
|
||||
[401] = { 4237.50, 2825.00 }, -- AlteracValley
|
||||
[443] = { 1145.84, 764.58 }, -- WarsongGulch
|
||||
[461] = { 1756.25, 1170.83 }, -- ArathiBasin
|
||||
[500] = { 828.00, 541.00 }, -- pfQ876
|
||||
[501] = { 3206.00, 2142.00 }, -- pfQ616
|
||||
[502] = { 3159.00, 2108.00 }, -- pfQ4012
|
||||
[503] = { 988.63, 1393.17 }, -- pfQ5023
|
||||
[504] = { 2901.45, 1915.90 }, -- pfQ409
|
||||
[505] = { 3092.10, 2047.00 }, -- pfQ408
|
||||
[507] = { 3227.00, 2187.00 }, -- pfQ5121
|
||||
[509] = { 1468.00, 976.00 }, -- pfQ2040
|
||||
[510] = { 3666.00, 2442.00 }, -- pfQ5179
|
||||
[511] = { 1608.00, 1075.00 }, -- pfQ5024
|
||||
[512] = { 2472.00, 1665.00 }, -- pfQ5536
|
||||
[513] = { 3082.00, 2061.00 }, -- pfQ5225
|
||||
[514] = { 449.89, 300.00 }, -- pfQ1581
|
||||
[516] = { 572.78, 381.85 }, -- pfQ718
|
||||
[517] = { 2112.09, 1410.89 }, -- pfQ2100
|
||||
[518] = { 769.67, 513.11 }, -- pfQ721
|
||||
[519] = { 711.56, 468.68 }, -- pfQ25
|
||||
[520] = { 203.66, 135.04 }, -- pfQ796
|
||||
[521] = { 893.67, 595.78 }, -- pfQ1337
|
||||
[522] = { 4139.02, 2946.00 }, -- pfQ3478
|
||||
[523] = { 1348.24, 888.09 }, -- pfQ1941
|
||||
[601] = { 1432.00, 977.00 }, -- pfQ5130
|
||||
[603] = { 738.86, 492.57 }, -- pfQ2437
|
||||
[605] = { 1383.33, 922.91 }, -- pfQ1176
|
||||
[607] = { 695.03, 463.35 }, -- pfQ1477
|
||||
[609] = { 1221.87, 806.42 }, -- pfQ719
|
||||
[611] = { 378.15, 252.10 }, -- pfQ717
|
||||
[617] = { 1495.00, 983.00 }, -- pfQ2717
|
||||
[619] = { 2120.83, 1414.60 }, -- pfQ1977
|
||||
[623] = { 1985.00, 1268.00 }, -- pfQ1584
|
||||
[625] = { 2512.50, 1675.00 }, -- pfQ3429
|
||||
[627] = { 483.11, 322.08 }, -- pfQ2159
|
||||
[629] = { 886.84, 591.23 }, -- pfQ1583
|
||||
[635] = { 499.43, 332.95 }, -- pfQ2677
|
||||
[637] = { 656.59, 434.97 }, -- pfQ5138
|
||||
[639] = { 881.00, 589.00 }, -- pfQ722
|
||||
[641] = { 736.45, 490.96 }, -- pfQ491
|
||||
[643] = { 619.98, 413.32 }, -- pfQ5136
|
||||
[644] = { 320.19, 213.46 }, -- pfQ5135
|
||||
[645] = { 612.69, 408.46 }, -- pfQ5153
|
||||
[646] = { 703.30, 468.87 }, -- pfQ5163
|
||||
[648] = { 320.05, 213.37 }, -- pfQ2057
|
||||
[650] = { 381.00, 254.00 }, -- pfQ209
|
||||
[652] = { 1185.35, 789.86 }, -- pfQ2017
|
||||
[654] = { 977.56, 651.70 }, -- pfQ3428
|
||||
[655] = { 2777.54, 1851.69 }, -- pfQ5147
|
||||
[657] = { 619.00, 410.00 }, -- pfQ5723
|
||||
[659] = { 312.00, 208.00 }, -- pfQ2257
|
||||
[662] = { 1271.99, 845.48 }, -- pfQ5204
|
||||
[663] = { 1085.86, 726.61 }, -- pfQ2366
|
||||
[665] = { 1250.18, 837.44 }, -- pfQ5208
|
||||
[667] = { 1991.69, 1318.42 }, -- pfQ3456
|
||||
[668] = { 652.10, 439.67 }, -- pfQ5148
|
||||
[670] = { 2643.21, 1751.16 }, -- pfQ5077
|
||||
[672] = { 752.12, 510.33 }, -- pfQ5103
|
||||
[674] = { 546.75, 391.90 }, -- pfQ5086
|
||||
[676] = { 354.50, 234.74 }, -- pfQ5087
|
||||
[678] = { 1273.10, 853.72 }, -- pfQ5097
|
||||
[680] = { 1007.70, 671.80 }, -- pfQ5053
|
||||
[682] = { 823.00, 549.00 }, -- pfQ3457
|
||||
[683] = { 2800.00, 1868.00 }, -- pfQ5557
|
||||
[684] = { 5387.00, 3584.00 }, -- pfQ5602
|
||||
[685] = { 3098.00, 2068.00 }, -- pfQ5561
|
||||
[686] = { 3241.00, 2157.00 }, -- pfQ5581
|
||||
[689] = { 1324.00, 869.00 }, -- pfQ2557
|
||||
[691] = { 1634.00, 1073.00 }, -- pfQ5601
|
||||
[693] = { 1980.00, 1350.00 }, -- pfQ5628
|
||||
[698] = { 1234.00, 829.00 }, -- pfQ5641
|
||||
[699] = { 7856.00, 5241.00 }, -- pfQ5642
|
||||
[700] = { 861.00, 607.00 }, -- pfQ1769
|
||||
[701] = { 1347.00, 971.00 }, -- pfQ5640
|
||||
[702] = { 1047.00, 694.00 }, -- pfQ5722
|
||||
[704] = { 1011.00, 653.00 }, -- pfQ5734
|
||||
[705] = { 440.00, 279.00 }, -- pfQ5731
|
||||
[613] = { 1125.00, 740.00 },
|
||||
[615] = { 893.67, 595.78 },
|
||||
[621] = { 1919.00, 1250.00 },
|
||||
[631] = { 1170.00, 785.00 },
|
||||
[633] = { 2112.09, 1410.89 },
|
||||
[696] = { 1425.00, 962.00 },
|
||||
[5144] = { 309.00, 208.00 },
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
-- MetaHunt: Pet spell DBC acquire-method overlay (learnMethod, minRank, nextSpellId)
|
||||
-- AUTO-GENERATED by .tools — do not edit by hand.
|
||||
-- Source DBC(s): SkillLineAbility.dbc, SkillLine.dbc
|
||||
-- Generated: 2026-03-20 13:57 UTC
|
||||
|
||||
-- This file patches MTH_DS_PetSpells.allSpells entries with DBC-authoritative
|
||||
-- learnMethod, minRank, and nextSpellId values.
|
||||
-- Load order: after ds-pet-spells.lua and ds-pet-spells-trainer.lua
|
||||
|
||||
if not MTH_DS_PetSpells or not MTH_DS_PetSpells.allSpells then return end
|
||||
|
||||
local _acquire = {
|
||||
[1747] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[1748] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[1749] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[1750] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[1751] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[1853] = { learnMethod="unknown(1)", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[2975] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[2976] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[2977] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[2980] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[2981] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[2982] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[3666] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[3667] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[4195] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[4196] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[4197] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[4198] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[4199] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[4200] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[4201] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[4202] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[5048] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[5049] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[5149] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[7370] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[14922] = { learnMethod="unknown(1)", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[14923] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[14924] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[14925] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[14926] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[14927] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[16698] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[17254] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[17262] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[17263] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[17264] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[17265] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[17266] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[17267] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[17268] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[23100] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[23111] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[23112] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[23146] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[23149] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[23150] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[23163] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[23166] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[23167] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24424] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24440] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24441] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24451] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24454] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24455] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24463] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24464] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24475] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24476] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24477] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24478] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24490] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24494] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24495] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24508] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24509] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24510] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24511] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24512] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24513] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24514] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24515] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24516] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24547] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24556] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24557] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24558] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24559] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24560] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24561] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24562] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24580] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24581] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24582] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24584] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24588] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24589] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24599] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24607] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24608] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24609] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24631] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24632] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24641] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[24845] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[25013] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[25014] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[25015] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[25016] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[25017] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[25077] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[26065] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[26094] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[26184] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[26185] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[26186] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[26189] = { 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 },
|
||||
[28343] = { learnMethod="trainer", minRank=1, nextSpellId=0, skillLineId=261 },
|
||||
[46023] = { learnMethod="trainer", minRank=0, nextSpellId=0, skillLineId=261 },
|
||||
[46303] = { learnMethod="trainer", minRank=0, nextSpellId=0, skillLineId=261 },
|
||||
[46307] = { 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 },
|
||||
[51157] = { learnMethod="trainer", minRank=0, nextSpellId=0, skillLineId=261 },
|
||||
}
|
||||
|
||||
for _, spell in ipairs(MTH_DS_PetSpells.allSpells) do
|
||||
local meta = _acquire[spell.id]
|
||||
if meta then
|
||||
spell.learnMethod = meta.learnMethod
|
||||
spell.minRank = meta.minRank
|
||||
spell.nextSpellId = meta.nextSpellId
|
||||
spell.skillLineId = meta.skillLineId
|
||||
end
|
||||
end
|
||||
+59
-19
@@ -25,6 +25,7 @@ MTH_DS_PetSpells = {
|
||||
"Strider Presence",
|
||||
"Thunderstomp",
|
||||
"Web",
|
||||
"Pollen Burst",
|
||||
},
|
||||
["allSpells"] = {
|
||||
{
|
||||
@@ -1355,14 +1356,15 @@ MTH_DS_PetSpells = {
|
||||
{
|
||||
["ability"] = "Roar of Fortitude",
|
||||
["castTime"] = "Instant",
|
||||
["categoryCooldown"] = "180 seconds",
|
||||
["cooldown"] = "n/a",
|
||||
["cost"] = "None",
|
||||
["description"] = "Increases max hitpoints of allies in your party by 200 for 120 sec",
|
||||
["categoryCooldown"] = "n/a",
|
||||
["cooldown"] = "120 seconds",
|
||||
["cost"] = "50 mana",
|
||||
["description"] = "Let out a fortifying roar, reducing damage taken by 8% and increasing all damage dealt by 3% for your party members within 30 yards for 12 sec.",
|
||||
["effects"] = {
|
||||
"(6) Apply Aura #34: Mod Increase Health Value: 200 Radius: 20 yards",
|
||||
"(6) Apply Aura #87: Mod Dmg % Taken (127) Value: -8 Radius: 30 yards",
|
||||
"(6) Apply Aura #79: Mod Dmg % (127) Value: 3 Radius: 30 yards",
|
||||
},
|
||||
["icon"] = "Ability_BullRush",
|
||||
["icon"] = "Ability_Druid_ChallangingRoar",
|
||||
["id"] = 36535,
|
||||
["name"] = "Roar of Fortitude",
|
||||
["range"] = "0 yards (Self Only)",
|
||||
@@ -1803,15 +1805,30 @@ MTH_DS_PetSpells = {
|
||||
"(6) Apply Aura #26: Root",
|
||||
},
|
||||
["icon"] = "Ability_Ensnare",
|
||||
["id"] = 4167,
|
||||
["id"] = 36533,
|
||||
["name"] = "Web",
|
||||
["range"] = "20 yards (Short Range)",
|
||||
["rank"] = "",
|
||||
["rankNumber"] = 0,
|
||||
["school"] = "Physical",
|
||||
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=4167",
|
||||
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=36533",
|
||||
["trainLevel"] = 22,
|
||||
},
|
||||
{
|
||||
["ability"] = "Pollen Burst",
|
||||
["castTime"] = "Instant",
|
||||
["cooldown"] = "30 seconds",
|
||||
["cost"] = "40 Focus",
|
||||
["description"] = "Heal party members within 30 yards for 308 to 338 and reduce the attack speed of targets within 10 yards by 20% for 8 sec.",
|
||||
["icon"] = "pollen_burst_2",
|
||||
["id"] = 42051,
|
||||
["name"] = "Pollen Burst",
|
||||
["rank"] = "",
|
||||
["rankNumber"] = 0,
|
||||
["school"] = "Nature",
|
||||
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=42051",
|
||||
["trainLevel"] = 1,
|
||||
},
|
||||
},
|
||||
["byAbility"] = {
|
||||
["Bite"] = {
|
||||
@@ -3245,14 +3262,15 @@ MTH_DS_PetSpells = {
|
||||
{
|
||||
["ability"] = "Roar of Fortitude",
|
||||
["castTime"] = "Instant",
|
||||
["categoryCooldown"] = "180 seconds",
|
||||
["cooldown"] = "n/a",
|
||||
["cost"] = "None",
|
||||
["description"] = "Increases max hitpoints of allies in your party by 200 for 120 sec",
|
||||
["categoryCooldown"] = "n/a",
|
||||
["cooldown"] = "120 seconds",
|
||||
["cost"] = "50 mana",
|
||||
["description"] = "Let out a fortifying roar, reducing damage taken by 8% and increasing all damage dealt by 3% for your party members within 30 yards for 12 sec.",
|
||||
["effects"] = {
|
||||
"(6) Apply Aura #34: Mod Increase Health Value: 200 Radius: 20 yards",
|
||||
"(6) Apply Aura #87: Mod Dmg % Taken (127) Value: -8 Radius: 30 yards",
|
||||
"(6) Apply Aura #79: Mod Dmg % (127) Value: 3 Radius: 30 yards",
|
||||
},
|
||||
["icon"] = "Ability_BullRush",
|
||||
["icon"] = "Ability_Druid_ChallangingRoar",
|
||||
["id"] = 36535,
|
||||
["name"] = "Roar of Fortitude",
|
||||
["range"] = "0 yards (Self Only)",
|
||||
@@ -3742,17 +3760,39 @@ MTH_DS_PetSpells = {
|
||||
"(6) Apply Aura #26: Root",
|
||||
},
|
||||
["icon"] = "Ability_Ensnare",
|
||||
["id"] = 4167,
|
||||
["id"] = 36533,
|
||||
["name"] = "Web",
|
||||
["range"] = "20 yards (Short Range)",
|
||||
["rank"] = "",
|
||||
["rankNumber"] = 0,
|
||||
["school"] = "Physical",
|
||||
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=4167",
|
||||
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=36533",
|
||||
["trainLevel"] = 22,
|
||||
},
|
||||
},
|
||||
},
|
||||
["Pollen Burst"] = {
|
||||
["ability"] = "Pollen Burst",
|
||||
["searchUrl"] = "https://database.turtlecraft.gg/?search=Pollen+Burst",
|
||||
["spellCount"] = 1,
|
||||
["spells"] = {
|
||||
{
|
||||
["ability"] = "Pollen Burst",
|
||||
["castTime"] = "Instant",
|
||||
["cooldown"] = "30 seconds",
|
||||
["cost"] = "40 Focus",
|
||||
["description"] = "Heal party members within 30 yards for 308 to 338 and reduce the attack speed of targets within 10 yards by 20% for 8 sec.",
|
||||
["icon"] = "pollen_burst_2",
|
||||
["id"] = 42051,
|
||||
["name"] = "Pollen Burst",
|
||||
["rank"] = "",
|
||||
["rankNumber"] = 0,
|
||||
["school"] = "Nature",
|
||||
["sourceUrl"] = "https://database.turtlecraft.gg/?spell=42051",
|
||||
["trainLevel"] = 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
["cleanedBy"] = "post-process quality rules v2 hard-gate",
|
||||
["droppedDuplicates"] = {
|
||||
@@ -4291,14 +4331,14 @@ MTH_DS_PetSpells = {
|
||||
{
|
||||
["ability"] = "Web",
|
||||
["droppedId"] = 12023,
|
||||
["keptId"] = 4167,
|
||||
["keptId"] = 36533,
|
||||
["mode"] = "lower-score",
|
||||
["rankNumber"] = 0,
|
||||
},
|
||||
{
|
||||
["ability"] = "Web",
|
||||
["droppedId"] = 36533,
|
||||
["keptId"] = 4167,
|
||||
["droppedId"] = 4167,
|
||||
["keptId"] = 36533,
|
||||
["mode"] = "lower-score",
|
||||
["rankNumber"] = 0,
|
||||
},
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
-- MetaHunt: Stable slot prices
|
||||
-- AUTO-GENERATED by .tools — do not edit by hand.
|
||||
-- Source DBC(s): StableSlotPrices.dbc
|
||||
-- Generated: 2026-03-20 13:57 UTC
|
||||
|
||||
if not MTH_DS then MTH_DS = {} end
|
||||
|
||||
MTH_DS_StableSlotPrices = {
|
||||
[1] = {
|
||||
["cost_copper"] = 500,
|
||||
["cost_gold"] = 0,
|
||||
["cost_silver"] = 5,
|
||||
["cost_copper_remainder"] = 0,
|
||||
["display"] = "0g 5s 0c",
|
||||
["acquireMethod"] = "gold",
|
||||
},
|
||||
[2] = {
|
||||
["cost_copper"] = 50000,
|
||||
["cost_gold"] = 5,
|
||||
["cost_silver"] = 0,
|
||||
["cost_copper_remainder"] = 0,
|
||||
["display"] = "5g 0s 0c",
|
||||
["acquireMethod"] = "gold",
|
||||
},
|
||||
[3] = {
|
||||
["cost_copper"] = 2500000,
|
||||
["cost_gold"] = 250,
|
||||
["cost_silver"] = 0,
|
||||
["cost_copper_remainder"] = 0,
|
||||
["display"] = "250g 0s 0c",
|
||||
["acquireMethod"] = "gold",
|
||||
},
|
||||
[4] = {
|
||||
["cost_copper"] = 0,
|
||||
["cost_gold"] = 0,
|
||||
["cost_silver"] = 0,
|
||||
["cost_copper_remainder"] = 0,
|
||||
["display"] = "Shop",
|
||||
["acquireMethod"] = "shop",
|
||||
},
|
||||
}
|
||||
+23493
-23493
File diff suppressed because it is too large
Load Diff
+223
-167
File diff suppressed because it is too large
Load Diff
+219
-219
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,97 @@
|
||||
-- MetaHunt: Zone DBC enrichment (worldBounds, dbcAreaId, dbcMapId, dbcName)
|
||||
-- AUTO-GENERATED by .tools — do not edit by hand.
|
||||
-- Source DBC(s): WorldMapArea.dbc, AreaTable.dbc
|
||||
-- Generated: 2026-03-20 13:57 UTC
|
||||
|
||||
if not MTH_DS_Zones then return end
|
||||
|
||||
-- WMA ID=301 map=0 'Stormwind'
|
||||
if MTH_DS_Zones[1519] then
|
||||
MTH_DS_Zones[1519]["dbcAreaId"] = 1519
|
||||
MTH_DS_Zones[1519]["dbcMapId"] = 0
|
||||
MTH_DS_Zones[1519]["dbcName"] = "Stormwind"
|
||||
MTH_DS_Zones[1519]["worldBounds"] = {
|
||||
["left"] = 1722.92,
|
||||
["right"] = -14.58,
|
||||
["top"] = -7995.8301,
|
||||
["bottom"] = -9154.1699,
|
||||
}
|
||||
end
|
||||
|
||||
-- WMA ID=321 map=1 'Ogrimmar'
|
||||
if MTH_DS_Zones[1637] then
|
||||
MTH_DS_Zones[1637]["dbcAreaId"] = 1637
|
||||
MTH_DS_Zones[1637]["dbcMapId"] = 1
|
||||
MTH_DS_Zones[1637]["dbcName"] = "Ogrimmar"
|
||||
MTH_DS_Zones[1637]["worldBounds"] = {
|
||||
["left"] = -3680.6001,
|
||||
["right"] = -5083.21,
|
||||
["top"] = 2273.8799,
|
||||
["bottom"] = 1338.46,
|
||||
}
|
||||
end
|
||||
|
||||
-- WMA ID=362 map=1 'ThunderBluff'
|
||||
if MTH_DS_Zones[1638] then
|
||||
MTH_DS_Zones[1638]["dbcAreaId"] = 1638
|
||||
MTH_DS_Zones[1638]["dbcMapId"] = 1
|
||||
MTH_DS_Zones[1638]["dbcName"] = "ThunderBluff"
|
||||
MTH_DS_Zones[1638]["worldBounds"] = {
|
||||
["left"] = 516.67,
|
||||
["right"] = -527.08,
|
||||
["top"] = -850.0,
|
||||
["bottom"] = -1545.83,
|
||||
}
|
||||
end
|
||||
|
||||
-- WMA ID=381 map=1 'Darnassis'
|
||||
if MTH_DS_Zones[1657] then
|
||||
MTH_DS_Zones[1657]["dbcAreaId"] = 1657
|
||||
MTH_DS_Zones[1657]["dbcMapId"] = 1
|
||||
MTH_DS_Zones[1657]["dbcName"] = "Darnassis"
|
||||
MTH_DS_Zones[1657]["worldBounds"] = {
|
||||
["left"] = 2938.3601,
|
||||
["right"] = 1880.03,
|
||||
["top"] = 10238.3203,
|
||||
["bottom"] = 9532.5898,
|
||||
}
|
||||
end
|
||||
|
||||
-- WMA ID=382 map=0 'Undercity'
|
||||
if MTH_DS_Zones[1497] then
|
||||
MTH_DS_Zones[1497]["dbcAreaId"] = 1497
|
||||
MTH_DS_Zones[1497]["dbcMapId"] = 0
|
||||
MTH_DS_Zones[1497]["dbcName"] = "Undercity"
|
||||
MTH_DS_Zones[1497]["worldBounds"] = {
|
||||
["left"] = 873.19,
|
||||
["right"] = -86.18,
|
||||
["top"] = 1877.95,
|
||||
["bottom"] = 1237.84,
|
||||
}
|
||||
end
|
||||
|
||||
-- WMA ID=508 map=1 'AmaniAlor'
|
||||
if MTH_DS_Zones[2041] then
|
||||
MTH_DS_Zones[2041]["dbcAreaId"] = 2041
|
||||
MTH_DS_Zones[2041]["dbcMapId"] = 1
|
||||
MTH_DS_Zones[2041]["dbcName"] = "AmaniAlor"
|
||||
MTH_DS_Zones[2041]["worldBounds"] = {
|
||||
["left"] = 3112.0,
|
||||
["right"] = 1599.0,
|
||||
["top"] = 3437.0,
|
||||
["bottom"] = 2434.0,
|
||||
}
|
||||
end
|
||||
|
||||
-- WMA ID=509 map=0 'AlahThalas'
|
||||
if MTH_DS_Zones[2040] then
|
||||
MTH_DS_Zones[2040]["dbcAreaId"] = 2040
|
||||
MTH_DS_Zones[2040]["dbcMapId"] = 0
|
||||
MTH_DS_Zones[2040]["dbcName"] = "AlahThalas"
|
||||
MTH_DS_Zones[2040]["worldBounds"] = {
|
||||
["left"] = -2169.0,
|
||||
["right"] = -3637.0,
|
||||
["top"] = 4907.0,
|
||||
["bottom"] = 3931.0,
|
||||
}
|
||||
end
|
||||
@@ -72,4 +72,6 @@ MTH_DS_ZoneNamesFallback = {
|
||||
[5581] = "Northwind",
|
||||
[5601] = "Dragonmaw Retreat",
|
||||
[5602] = "Grim Reaches",
|
||||
[5641] = "Windhorn Canyon",
|
||||
[5642] = "Moonwhisper Coast",
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
-1052
File diff suppressed because it is too large
Load Diff
@@ -56,6 +56,11 @@ local function MTH_DS_ApplyCapturedProjectileQualities()
|
||||
[18042] = 2,
|
||||
[19316] = 2,
|
||||
[19317] = 2,
|
||||
[42198] = 2,
|
||||
[42199] = 2,
|
||||
[42200] = 2,
|
||||
[42201] = 3,
|
||||
[42202] = 3,
|
||||
}
|
||||
|
||||
for itemId, quality in pairs(capturedQualityByItemId) do
|
||||
|
||||
+13
-1
@@ -1,7 +1,6 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
|
||||
..\FrameXML\UI.xsd">
|
||||
<Include file="..\api\constants.lua"/>
|
||||
<Include file="..\api\debug-frame.lua"/>
|
||||
<Include file="..\api\minimap-button.lua"/>
|
||||
<Include file="..\api\AutoStrip.xml"/>
|
||||
<Include file="..\api\AutoStrip.lua"/>
|
||||
@@ -15,6 +14,11 @@
|
||||
<Include file="..\api\options-chronometer.lua"/>
|
||||
<Include file="..\api\options-credits.lua"/>
|
||||
<Include file="..\api\options-autobuy.lua"/>
|
||||
<Include file="..\api\options-autoquest.lua"/>
|
||||
<Include file="..\api\options-icu.lua"/>
|
||||
<Include file="..\api\options-expammo.lua"/>
|
||||
<Include file="..\api\profile.lua"/>
|
||||
<Include file="..\api\options-profiles.lua"/>
|
||||
<Include file="..\api\options-shell.lua"/>
|
||||
<Include file="..\api\options-zbuttons.lua"/>
|
||||
<Include file="..\api\options-feedomatic.lua"/>
|
||||
@@ -27,11 +31,19 @@
|
||||
<Include file="..\api\hunterbook-tab-npcfinder.lua"/>
|
||||
<Include file="..\api\hunterbook-tab-stable.lua"/>
|
||||
<Include file="..\api\hunterbook-tab-pethistory.lua"/>
|
||||
<Include file="..\api\hunterbook-model-viewer.lua"/>
|
||||
<Include file="..\api\map-markers.lua"/>
|
||||
<Include file="..\api\debug-frame.lua"/>
|
||||
<Include file="..\api\core-framework.lua"/>
|
||||
<Include file="..\api\core-scan-stablemaster.lua"/>
|
||||
<Include file="..\api\pets-service-lifecycle.lua"/>
|
||||
<Include file="..\api\pets-service-vitals.lua"/>
|
||||
<Include file="..\api\pets-service-runaway.lua"/>
|
||||
<Include file="..\api\pets-service-stablescan.lua"/>
|
||||
<Include file="..\api\core-scan-beasttraining.lua"/>
|
||||
<Include file="..\api\core-scan-spellbookpet.lua"/>
|
||||
<Include file="..\api\beastlore-scan.lua"/>
|
||||
<Include file="..\api\core-scan-huntertalents.lua"/>
|
||||
<Include file="..\api\core.lua"/>
|
||||
<Include file="..\api\version-check.lua"/>
|
||||
<Include file="..\api\localization.lua"/>
|
||||
|
||||
@@ -20,4 +20,13 @@ MetaHunt Module Loader
|
||||
|
||||
<!-- AutoBuy Module - ENABLED -->
|
||||
<Include file="..\modules\autobuy\loader.xml"/>
|
||||
|
||||
<!-- Auto Quest Module - ENABLED -->
|
||||
<Include file="..\modules\autoquest\loader.xml"/>
|
||||
|
||||
<!-- ICU Module - ENABLED (runtime default: disabled) -->
|
||||
<Include file="..\modules\icu\loader.xml"/>
|
||||
|
||||
<!-- Experimental Ammunition Module - ENABLED -->
|
||||
<Include file="..\modules\expammo\loader.xml"/>
|
||||
</Ui>
|
||||
|
||||
@@ -2,6 +2,11 @@ MTH_LocaleData = MTH_LocaleData or {}
|
||||
MTH_LocaleData.spells = MTH_LocaleData.spells or {}
|
||||
|
||||
MTH_LocaleData.spells.deDE = {
|
||||
["Aimed Shot"] = "Gezielter Schuss",
|
||||
["Kill Command"] = "Todesbefehl",
|
||||
["Lock and Load"] = "Lock and Load",
|
||||
["Scent of Blood"] = "Blutgeruch",
|
||||
["Aspect of the Viper"] = "Aspekt der Viper",
|
||||
["Banish"] = "Verbannen",
|
||||
["Bestial Wrath"] = "Zorn des Wildtiers",
|
||||
["Concussive Shot"] = "Erschütternder Schuss",
|
||||
|
||||
@@ -2,6 +2,11 @@ MTH_LocaleData = MTH_LocaleData or {}
|
||||
MTH_LocaleData.spells = MTH_LocaleData.spells or {}
|
||||
|
||||
MTH_LocaleData.spells.enUS = {
|
||||
["Aimed Shot"] = "Aimed Shot",
|
||||
["Kill Command"] = "Kill Command",
|
||||
["Lock and Load"] = "Lock and Load",
|
||||
["Scent of Blood"] = "Scent of Blood",
|
||||
["Aspect of the Viper"] = "Aspect of the Viper",
|
||||
["Banish"] = "Banish",
|
||||
["Bestial Wrath"] = "Bestial Wrath",
|
||||
["Concussive Shot"] = "Concussive Shot",
|
||||
|
||||
@@ -2,6 +2,11 @@ MTH_LocaleData = MTH_LocaleData or {}
|
||||
MTH_LocaleData.spells = MTH_LocaleData.spells or {}
|
||||
|
||||
MTH_LocaleData.spells.esES = {
|
||||
["Aimed Shot"] = "Aimed Shot",
|
||||
["Aspect of the Viper"] = "Aspect of the Viper",
|
||||
["Kill Command"] = "Kill Command",
|
||||
["Lock and Load"] = "Lock and Load",
|
||||
["Scent of Blood"] = "Scent of Blood",
|
||||
["Banish"] = "Banish",
|
||||
["Bestial Wrath"] = "Bestial Wrath",
|
||||
["Concussive Shot"] = "Concussive Shot",
|
||||
|
||||
@@ -2,6 +2,11 @@ MTH_LocaleData = MTH_LocaleData or {}
|
||||
MTH_LocaleData.spells = MTH_LocaleData.spells or {}
|
||||
|
||||
MTH_LocaleData.spells.ptBR = {
|
||||
["Aimed Shot"] = "Aimed Shot",
|
||||
["Aspect of the Viper"] = "Aspect of the Viper",
|
||||
["Kill Command"] = "Kill Command",
|
||||
["Lock and Load"] = "Lock and Load",
|
||||
["Scent of Blood"] = "Scent of Blood",
|
||||
["Banish"] = "Banish",
|
||||
["Bestial Wrath"] = "Bestial Wrath",
|
||||
["Concussive Shot"] = "Concussive Shot",
|
||||
|
||||
@@ -2,6 +2,11 @@ MTH_LocaleData = MTH_LocaleData or {}
|
||||
MTH_LocaleData.spells = MTH_LocaleData.spells or {}
|
||||
|
||||
MTH_LocaleData.spells.ruRU = {
|
||||
["Aimed Shot"] = "Прицельный выстрел",
|
||||
["Aspect of the Viper"] = "Аспект гадюки",
|
||||
["Kill Command"] = "Приказ убивать",
|
||||
["Lock and Load"] = "Lock and Load",
|
||||
["Scent of Blood"] = "Запах крови",
|
||||
["Banish"] = "Изгнание",
|
||||
["Bestial Wrath"] = "Звериный гнев",
|
||||
["Concussive Shot"] = "Контузящий выстрел",
|
||||
|
||||
@@ -2,6 +2,11 @@ MTH_LocaleData = MTH_LocaleData or {}
|
||||
MTH_LocaleData.spells = MTH_LocaleData.spells or {}
|
||||
|
||||
MTH_LocaleData.spells.zhCN = {
|
||||
["Aimed Shot"] = "瞄准射击",
|
||||
["Aspect of the Viper"] = "毒蛇图腾",
|
||||
["Kill Command"] = "猎杀命令",
|
||||
["Lock and Load"] = "Lock and Load",
|
||||
["Scent of Blood"] = "血腥气息",
|
||||
["Banish"] = "放逐术",
|
||||
["Bestial Wrath"] = "狂野怒火",
|
||||
["Concussive Shot"] = "震荡射击",
|
||||
|
||||
@@ -9,9 +9,6 @@ local Engine = MTH_AutoBuyEngine
|
||||
local AB_AMMO_BY_NAME = nil
|
||||
local AB_FOOD_DIET_BY_ITEM_ID = nil
|
||||
|
||||
local function AB_Trace(message)
|
||||
return
|
||||
end
|
||||
|
||||
local function AB_ParseItemIdFromLink(link)
|
||||
if type(link) ~= "string" then
|
||||
@@ -632,7 +629,7 @@ end
|
||||
function Engine:EnsureDefaults()
|
||||
local store = self:GetConfigStore()
|
||||
if store.enabled == nil then
|
||||
store.enabled = true
|
||||
store.enabled = false
|
||||
end
|
||||
if type(store.food) ~= "table" then
|
||||
store.food = {}
|
||||
@@ -647,13 +644,13 @@ function Engine:EnsureDefaults()
|
||||
store.petFood = {}
|
||||
end
|
||||
if store.food.enabled == nil then
|
||||
store.food.enabled = true
|
||||
store.food.enabled = false
|
||||
end
|
||||
if store.ammo.enabled == nil then
|
||||
store.ammo.enabled = true
|
||||
store.ammo.enabled = false
|
||||
end
|
||||
if store.projectiles.enabled == nil then
|
||||
store.projectiles.enabled = true
|
||||
store.projectiles.enabled = false
|
||||
end
|
||||
if store.petFood.enabled == nil then
|
||||
store.petFood.enabled = false
|
||||
@@ -1180,7 +1177,6 @@ end
|
||||
|
||||
function Engine:ExecutePlan(plan)
|
||||
if type(plan) ~= "table" or type(plan.actions) ~= "table" then
|
||||
AB_Trace("ExecutePlan skipped: invalid plan table")
|
||||
return 0, 0
|
||||
end
|
||||
local executedActions = 0
|
||||
@@ -1189,10 +1185,6 @@ function Engine:ExecutePlan(plan)
|
||||
if type(action) == "table" and action.index then
|
||||
local stacksToBuy = math.floor(tonumber(action.quantityStacks) or 0)
|
||||
if stacksToBuy > 0 then
|
||||
AB_Trace("ExecutePlan action index=" .. tostring(action.index)
|
||||
.. " itemId=" .. tostring(action.itemId)
|
||||
.. " stacks=" .. tostring(stacksToBuy)
|
||||
.. " reason=" .. tostring(plan.reason or ""))
|
||||
for i = 1, stacksToBuy do
|
||||
BuyMerchantItem(action.index)
|
||||
end
|
||||
@@ -1201,7 +1193,6 @@ function Engine:ExecutePlan(plan)
|
||||
end
|
||||
end
|
||||
end
|
||||
AB_Trace("ExecutePlan done actions=" .. tostring(executedActions) .. " stacks=" .. tostring(requestedStacks) .. " reason=" .. tostring(plan.reason or ""))
|
||||
return executedActions, requestedStacks
|
||||
end
|
||||
|
||||
@@ -1264,42 +1255,30 @@ local function AB_AnnouncePurchases(actions)
|
||||
end
|
||||
|
||||
function Engine:OnMerchantEvent(eventName)
|
||||
AB_Trace("OnMerchantEvent start event=" .. tostring(eventName)
|
||||
.. " sessionExecuted=" .. tostring(self._merchantSessionExecuted and true or false)
|
||||
.. " engineEnabled=" .. tostring(self:IsEnabled() and true or false))
|
||||
|
||||
if eventName == "MERCHANT_SHOW" then
|
||||
self._merchantSessionExecuted = false
|
||||
AB_Trace("MERCHANT_SHOW resets session execution flag")
|
||||
elseif eventName == "MERCHANT_UPDATE" and self._merchantSessionExecuted then
|
||||
AB_Trace("MERCHANT_UPDATE ignored: already executed this merchant session")
|
||||
return
|
||||
end
|
||||
|
||||
if not self:IsEnabled() then
|
||||
AB_Trace("event ignored: autobuy module disabled")
|
||||
return
|
||||
end
|
||||
|
||||
local snapshot = self:ScanMerchant()
|
||||
AB_Trace("snapshot rows=" .. tostring(snapshot and snapshot.count or 0))
|
||||
local foodPlan = self:BuildFoodPlan(snapshot)
|
||||
local ammoPlan = self:BuildAmmoPlan(snapshot)
|
||||
|
||||
AB_Trace("foodPlan reason=" .. tostring(foodPlan.reason) .. " actions=" .. tostring(table.getn(foodPlan.actions or {})))
|
||||
for i = 1, table.getn(foodPlan.debugLines or {}) do
|
||||
AB_Trace("food#" .. tostring(i) .. " " .. tostring(foodPlan.debugLines[i]))
|
||||
end
|
||||
AB_Trace("ammoPlan reason=" .. tostring(ammoPlan.reason) .. " actions=" .. tostring(table.getn(ammoPlan.actions or {})))
|
||||
for i = 1, table.getn(ammoPlan.debugLines or {}) do
|
||||
AB_Trace("ammo#" .. tostring(i) .. " " .. tostring(ammoPlan.debugLines[i]))
|
||||
end
|
||||
|
||||
local totalRequestedStacks = 0
|
||||
if table.getn(foodPlan.actions or {}) > 0 then
|
||||
local _, requestedStacks = self:ExecutePlan(foodPlan)
|
||||
totalRequestedStacks = totalRequestedStacks + requestedStacks
|
||||
AB_Trace("food plan executed requestedStacks=" .. tostring(requestedStacks))
|
||||
if requestedStacks > 0 then
|
||||
AB_AnnouncePurchases(foodPlan.actions)
|
||||
end
|
||||
@@ -1308,19 +1287,15 @@ function Engine:OnMerchantEvent(eventName)
|
||||
if table.getn(ammoPlan.actions or {}) > 0 then
|
||||
local _, requestedStacks = self:ExecutePlan(ammoPlan)
|
||||
totalRequestedStacks = totalRequestedStacks + requestedStacks
|
||||
AB_Trace("ammo plan executed requestedStacks=" .. tostring(requestedStacks))
|
||||
if requestedStacks > 0 then
|
||||
local moved = AB_MoveAmmoStacksToSpecialBags(300)
|
||||
AB_Trace("ammo restack moved=" .. tostring(moved))
|
||||
AB_AnnouncePurchases(ammoPlan.actions)
|
||||
end
|
||||
end
|
||||
|
||||
if totalRequestedStacks > 0 then
|
||||
self._merchantSessionExecuted = true
|
||||
AB_Trace("session marked executed requestedStacks=" .. tostring(totalRequestedStacks))
|
||||
else
|
||||
AB_Trace("no purchases requested in this event")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
local MTH_AutoBuy = {
|
||||
name = "autobuy",
|
||||
enabled = false,
|
||||
version = "1.0.5",
|
||||
version = "1.4.0",
|
||||
events = {
|
||||
"VARIABLES_LOADED",
|
||||
"MERCHANT_SHOW",
|
||||
@@ -24,16 +24,13 @@ end
|
||||
|
||||
local AB_Engine
|
||||
|
||||
local function AB_Trace(message)
|
||||
return
|
||||
end
|
||||
|
||||
local function AB_EnsureBridgeFrame(moduleRef)
|
||||
if MTH_AutoBuy._bridgeFrame then
|
||||
return MTH_AutoBuy._bridgeFrame
|
||||
end
|
||||
|
||||
local frame = CreateFrame("Frame", "MTH_AutoBuyBridgeFrame")
|
||||
local frame = CreateFrame("Frame", "MTH_AutoBuyBridge")
|
||||
if not frame then
|
||||
AB_Log("failed to create bridge frame", "error")
|
||||
return nil
|
||||
@@ -42,19 +39,16 @@ local function AB_EnsureBridgeFrame(moduleRef)
|
||||
frame:RegisterEvent("MERCHANT_SHOW")
|
||||
frame:RegisterEvent("MERCHANT_UPDATE")
|
||||
frame:RegisterEvent("MERCHANT_CLOSED")
|
||||
frame:SetScript("OnEvent", function(_, eventName)
|
||||
eventName = eventName or event
|
||||
frame:SetScript("OnEvent", function()
|
||||
local eventName = event
|
||||
local engine = AB_Engine()
|
||||
if not engine then
|
||||
AB_Trace("bridge event=" .. tostring(eventName) .. " engine missing")
|
||||
return
|
||||
end
|
||||
|
||||
if eventName == "MERCHANT_SHOW" or eventName == "MERCHANT_UPDATE" then
|
||||
AB_Trace("bridge " .. tostring(eventName) .. " -> engine")
|
||||
engine:OnMerchantEvent(eventName)
|
||||
elseif eventName == "MERCHANT_CLOSED" then
|
||||
AB_Trace("bridge MERCHANT_CLOSED -> engine")
|
||||
if engine.OnMerchantClosed then
|
||||
engine:OnMerchantClosed()
|
||||
end
|
||||
@@ -77,10 +71,8 @@ local function AB_SetBridgeActive(active)
|
||||
frame:RegisterEvent("MERCHANT_UPDATE")
|
||||
frame:RegisterEvent("MERCHANT_CLOSED")
|
||||
MTH_AutoBuy._bridgeActive = true
|
||||
AB_Trace("bridge active=true")
|
||||
else
|
||||
MTH_AutoBuy._bridgeActive = false
|
||||
AB_Trace("bridge active=false (frame missing)")
|
||||
end
|
||||
return
|
||||
end
|
||||
@@ -91,7 +83,6 @@ local function AB_SetBridgeActive(active)
|
||||
frame:UnregisterEvent("MERCHANT_CLOSED")
|
||||
end
|
||||
MTH_AutoBuy._bridgeActive = false
|
||||
AB_Trace("bridge active=false")
|
||||
end
|
||||
|
||||
AB_Engine = function()
|
||||
@@ -102,15 +93,12 @@ function MTH_AutoBuy:init()
|
||||
local engine = AB_Engine()
|
||||
if not engine then
|
||||
AB_Log("init failed: engine missing", "error")
|
||||
AB_Trace("init failed: engine missing")
|
||||
return
|
||||
end
|
||||
engine:Init()
|
||||
self.initialized = true
|
||||
AB_SetBridgeActive(self.enabled and true or false)
|
||||
AB_Trace("init done")
|
||||
if self.enabled then
|
||||
AB_Log("module initialized", "debug")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -120,53 +108,38 @@ function MTH_AutoBuy:setEnabled(enabled)
|
||||
end
|
||||
local engine = AB_Engine()
|
||||
if not engine then
|
||||
AB_Trace("setEnabled ignored: engine missing")
|
||||
return
|
||||
end
|
||||
local store = engine:EnsureDefaults()
|
||||
store.enabled = enabled and true or false
|
||||
AB_SetBridgeActive(store.enabled and true or false)
|
||||
AB_Trace("setEnabled store.enabled=" .. tostring(store.enabled))
|
||||
end
|
||||
|
||||
function MTH_AutoBuy:onEvent(event)
|
||||
local engine = AB_Engine()
|
||||
if not engine then
|
||||
AB_Log("onEvent ignored: engine missing, event=" .. tostring(event), "debug")
|
||||
AB_Trace("engine missing, event=" .. tostring(event))
|
||||
return
|
||||
end
|
||||
if self._bridgeActive and (event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" or event == "MERCHANT_CLOSED") then
|
||||
return
|
||||
end
|
||||
|
||||
AB_Log("onEvent event=" .. tostring(event) .. " module.enabled=" .. tostring(self.enabled), "debug")
|
||||
|
||||
if event == "VARIABLES_LOADED" then
|
||||
engine:Init()
|
||||
AB_SetBridgeActive(self.enabled and true or false)
|
||||
AB_Log("onEvent VARIABLES_LOADED -> engine init", "debug")
|
||||
local store = engine:EnsureDefaults()
|
||||
AB_Trace("VARIABLES_LOADED module.enabled=" .. tostring(self.enabled)
|
||||
.. " store.enabled=" .. tostring(store and store.enabled)
|
||||
.. " projectiles.enabled=" .. tostring(store and store.projectiles and store.projectiles.enabled))
|
||||
engine:EnsureDefaults()
|
||||
return
|
||||
end
|
||||
|
||||
if not self.enabled then
|
||||
AB_Log("onEvent ignored: module disabled", "debug")
|
||||
if event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" then
|
||||
AB_Trace(tostring(event) .. " ignored: module disabled")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" then
|
||||
AB_Log("onEvent merchant event forwarded: " .. tostring(event), "debug")
|
||||
AB_Trace("forwarding " .. tostring(event) .. " to engine")
|
||||
engine:OnMerchantEvent(event)
|
||||
elseif event == "MERCHANT_CLOSED" then
|
||||
AB_Trace("forwarding MERCHANT_CLOSED to engine")
|
||||
if engine.OnMerchantClosed then
|
||||
engine:OnMerchantClosed()
|
||||
end
|
||||
@@ -174,7 +147,6 @@ function MTH_AutoBuy:onEvent(event)
|
||||
end
|
||||
|
||||
function MTH_AutoBuy:cleanup()
|
||||
AB_Log("module cleanup", "debug")
|
||||
end
|
||||
|
||||
MTH:RegisterModule("autobuy", MTH_AutoBuy)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<!--
|
||||
MetaHunt Auto Quest Module Loader
|
||||
-->
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
||||
<Include file="module.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,952 @@
|
||||
------------------------------------------------------
|
||||
-- MetaHunt: Quest Automation Module
|
||||
-- SHIFT-rightclick automation for specific quest flows
|
||||
------------------------------------------------------
|
||||
|
||||
local MTH_AutoQuest = {
|
||||
name = "autoquest",
|
||||
enabled = false,
|
||||
version = "1.4.0",
|
||||
events = {
|
||||
"GOSSIP_SHOW",
|
||||
"QUEST_GREETING",
|
||||
"QUEST_DETAIL",
|
||||
"QUEST_PROGRESS",
|
||||
"QUEST_COMPLETE",
|
||||
},
|
||||
initialized = false,
|
||||
}
|
||||
|
||||
local QA_SCORPOK_QUEST_ID = 2586
|
||||
local QA_SCORPOK_QUEST_TITLE = "Salt of the Scorpok"
|
||||
local QA_SCORPOK_NPC_ID = 7505
|
||||
local QA_SCORPOK_NPC_NAME = "Bloodmage Drazial"
|
||||
local QA_SISSIES_QUEST_ID = 7342
|
||||
local QA_SISSIES_QUEST_TITLE = "Arrows Are For Sissies"
|
||||
local QA_SISSIES_NPC_ID = 14183
|
||||
local QA_SISSIES_NPC_NAME = "Artilleryman Sheldonore"
|
||||
local QA_ITEM_SCORPOK_PINCER_ID = 8393
|
||||
local QA_ITEM_BLASTED_BOAR_LUNG_ID = 8392
|
||||
local QA_ITEM_VULTURE_GIZZARD_ID = 8396
|
||||
local QA_ITEM_GROUND_SCORPOK_ASSAY_ID = 8412
|
||||
local QA_ITEM_SCORPOK_PINCER_NAME = "Scorpok Pincer"
|
||||
local QA_ITEM_BLASTED_BOAR_LUNG_NAME = "Blasted Boar Lung"
|
||||
local QA_ITEM_VULTURE_GIZZARD_NAME = "Vulture Gizzard"
|
||||
local QA_ITEM_GROUND_SCORPOK_ASSAY_NAME = "Ground Scorpok Assay"
|
||||
|
||||
local QA_TooltipHooked = false
|
||||
local QA_TooltipPollFrame = nil
|
||||
local QA_TooltipRefreshFrame = nil
|
||||
|
||||
local function QA_Debug(message)
|
||||
return
|
||||
end
|
||||
|
||||
local function QA_CopyValue(value)
|
||||
if type(value) ~= "table" then
|
||||
return value
|
||||
end
|
||||
local copy = {}
|
||||
for key, entry in pairs(value) do
|
||||
copy[key] = QA_CopyValue(entry)
|
||||
end
|
||||
return copy
|
||||
end
|
||||
|
||||
local function QA_GetOptionsStore()
|
||||
if type(MTH_CharSavedVariables) ~= "table" then
|
||||
MTH_CharSavedVariables = {}
|
||||
end
|
||||
if type(MTH_CharSavedVariables.autoquest) ~= "table" then
|
||||
MTH_CharSavedVariables.autoquest = {}
|
||||
end
|
||||
local store = MTH_CharSavedVariables.autoquest
|
||||
|
||||
if store._migrated ~= true then
|
||||
if type(MTH_CharSavedVariables.questautomation) == "table" then
|
||||
local legacyStore = MTH_CharSavedVariables.questautomation
|
||||
if legacyStore.scorpokDrazial ~= nil and store.scorpokDrazial == nil then
|
||||
store.scorpokDrazial = legacyStore.scorpokDrazial and true or false
|
||||
end
|
||||
if legacyStore.scorpokTooltip ~= nil and store.scorpokTooltip == nil then
|
||||
store.scorpokTooltip = legacyStore.scorpokTooltip and true or false
|
||||
end
|
||||
end
|
||||
local legacyChar = nil
|
||||
local legacyAccount = nil
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
legacyChar = MTH:GetModuleCharSavedVariables("autoquest")
|
||||
if type(legacyChar) ~= "table" then
|
||||
legacyChar = MTH:GetModuleCharSavedVariables("questautomation")
|
||||
end
|
||||
end
|
||||
if MTH and MTH.GetModuleSavedVariables then
|
||||
legacyAccount = MTH:GetModuleSavedVariables("autoquest")
|
||||
if type(legacyAccount) ~= "table" then
|
||||
legacyAccount = MTH:GetModuleSavedVariables("questautomation")
|
||||
end
|
||||
end
|
||||
if type(legacyChar) == "table" and legacyChar.scorpokDrazial ~= nil and store.scorpokDrazial == nil then
|
||||
store.scorpokDrazial = legacyChar.scorpokDrazial and true or false
|
||||
elseif type(legacyAccount) == "table" and legacyAccount.scorpokDrazial ~= nil and store.scorpokDrazial == nil then
|
||||
store.scorpokDrazial = legacyAccount.scorpokDrazial and true or false
|
||||
elseif store.scorpokDrazial == nil and MTH and MTH.GetModuleCharSavedVariables then
|
||||
local autobuyStore = MTH:GetModuleCharSavedVariables("autobuy")
|
||||
if type(autobuyStore) == "table"
|
||||
and type(autobuyStore.questAutomation) == "table"
|
||||
and autobuyStore.questAutomation.scorpokDrazial ~= nil then
|
||||
store.scorpokDrazial = autobuyStore.questAutomation.scorpokDrazial and true or false
|
||||
end
|
||||
end
|
||||
store._migrated = true
|
||||
end
|
||||
|
||||
if store.scorpokDrazial == nil then
|
||||
store.scorpokDrazial = false
|
||||
end
|
||||
if store.arrowsForSissies == nil then
|
||||
store.arrowsForSissies = false
|
||||
end
|
||||
if store.scorpokTooltip == nil then
|
||||
store.scorpokTooltip = false
|
||||
end
|
||||
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
|
||||
if type(moduleStore) == "table" then
|
||||
moduleStore.scorpokDrazial = store.scorpokDrazial and true or false
|
||||
moduleStore.arrowsForSissies = store.arrowsForSissies and true or false
|
||||
moduleStore.scorpokTooltip = store.scorpokTooltip and true or false
|
||||
end
|
||||
end
|
||||
|
||||
return store
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:GetStore()
|
||||
return QA_GetOptionsStore()
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:SetScorpokDrazialEnabled(enabled)
|
||||
local store = QA_GetOptionsStore()
|
||||
store.scorpokDrazial = enabled and true or false
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
|
||||
if type(moduleStore) == "table" then
|
||||
moduleStore.scorpokDrazial = store.scorpokDrazial and true or false
|
||||
end
|
||||
end
|
||||
QA_Debug("option write: scorpokDrazial=" .. tostring(store.scorpokDrazial and true or false))
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:SetArrowsForSissiesEnabled(enabled)
|
||||
local store = QA_GetOptionsStore()
|
||||
store.arrowsForSissies = enabled and true or false
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
|
||||
if type(moduleStore) == "table" then
|
||||
moduleStore.arrowsForSissies = store.arrowsForSissies and true or false
|
||||
end
|
||||
end
|
||||
QA_Debug("option write: arrowsForSissies=" .. tostring(store.arrowsForSissies and true or false))
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:SetScorpokTooltipEnabled(enabled)
|
||||
local store = QA_GetOptionsStore()
|
||||
store.scorpokTooltip = enabled and true or false
|
||||
if MTH and MTH.GetModuleCharSavedVariables then
|
||||
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
|
||||
if type(moduleStore) == "table" then
|
||||
moduleStore.scorpokTooltip = store.scorpokTooltip and true or false
|
||||
end
|
||||
end
|
||||
QA_Debug("option write: scorpokTooltip=" .. tostring(store.scorpokTooltip and true or false))
|
||||
end
|
||||
|
||||
local function QA_IsScorpokAutomationEnabled()
|
||||
local store = QA_GetOptionsStore()
|
||||
return store and store.scorpokDrazial and true or false
|
||||
end
|
||||
|
||||
local function QA_IsArrowsForSissiesAutomationEnabled()
|
||||
local store = QA_GetOptionsStore()
|
||||
return store and store.arrowsForSissies and true or false
|
||||
end
|
||||
|
||||
local function QA_IsScorpokTooltipEnabled()
|
||||
local store = QA_GetOptionsStore()
|
||||
return store and store.scorpokTooltip and true or false
|
||||
end
|
||||
|
||||
local function QA_NormalizeText(value)
|
||||
local text = string.lower(tostring(value or ""))
|
||||
text = string.gsub(text, "[^%a%d]", "")
|
||||
return text
|
||||
end
|
||||
|
||||
local function QA_IsTitleMatch(title, expectedTitle)
|
||||
if type(title) ~= "string" or title == "" then
|
||||
return false
|
||||
end
|
||||
return QA_NormalizeText(title) == QA_NormalizeText(expectedTitle)
|
||||
end
|
||||
|
||||
local function QA_IsScorpokTitle(title)
|
||||
return QA_IsTitleMatch(title, QA_SCORPOK_QUEST_TITLE)
|
||||
end
|
||||
|
||||
local function QA_IsArrowsForSissiesTitle(title)
|
||||
return QA_IsTitleMatch(title, QA_SISSIES_QUEST_TITLE)
|
||||
end
|
||||
|
||||
local function QA_IsQuestContext(title, expectedQuestId, titleMatcher)
|
||||
if type(GetQuestID) == "function" then
|
||||
local questId = tonumber(GetQuestID())
|
||||
if questId and questId == expectedQuestId then
|
||||
return true
|
||||
end
|
||||
end
|
||||
if type(titleMatcher) == "function" then
|
||||
return titleMatcher(title)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function QA_IsScorpokQuestContext(title)
|
||||
return QA_IsQuestContext(title, QA_SCORPOK_QUEST_ID, QA_IsScorpokTitle)
|
||||
end
|
||||
|
||||
local function QA_IsArrowsForSissiesQuestContext(title)
|
||||
return QA_IsQuestContext(title, QA_SISSIES_QUEST_ID, QA_IsArrowsForSissiesTitle)
|
||||
end
|
||||
|
||||
local function QA_GetNpcIdFromGuid(guid)
|
||||
if type(guid) ~= "string" or guid == "" then
|
||||
return nil
|
||||
end
|
||||
|
||||
local _, _, _, _, _, npcId = string.find(guid, "^Creature%-%d+%-%d+%-%d+%-%d+%-(%d+)%-%x+$")
|
||||
if npcId then
|
||||
return tonumber(npcId)
|
||||
end
|
||||
|
||||
if string.sub(guid, 1, 2) == "0x" and string.len(guid) >= 12 then
|
||||
local hex = string.sub(guid, 9, 12)
|
||||
local parsed = tonumber(hex, 16)
|
||||
if parsed and parsed > 0 then
|
||||
return parsed
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function QA_ColorByThreshold(count, threshold)
|
||||
local value = math.floor(tonumber(count) or 0)
|
||||
if value <= 0 then
|
||||
return "|cffff0000" .. tostring(value) .. "|r"
|
||||
end
|
||||
local modFn = nil
|
||||
if type(rawget) == "function" and type(math) == "table" then
|
||||
modFn = rawget(math, "mod") or rawget(math, "fmod")
|
||||
elseif type(math) == "table" then
|
||||
modFn = math.fmod
|
||||
end
|
||||
if threshold > 0 and type(modFn) == "function" and modFn(value, threshold) == 0 then
|
||||
return "|cff00ff00" .. tostring(value) .. "|r"
|
||||
end
|
||||
return "|cffffa500" .. tostring(value) .. "|r"
|
||||
end
|
||||
|
||||
local function QA_ColorAssay(count)
|
||||
local value = math.floor(tonumber(count) or 0)
|
||||
if value > 0 then
|
||||
return "|cff66ccff" .. tostring(value) .. "|r"
|
||||
end
|
||||
return tostring(value)
|
||||
end
|
||||
|
||||
local function QA_MatchesItem(itemId, itemName, expectedId, expectedName)
|
||||
if expectedId and tonumber(itemId) == tonumber(expectedId) then
|
||||
return true
|
||||
end
|
||||
if type(itemName) == "string" and type(expectedName) == "string" and QA_NormalizeText(itemName) == QA_NormalizeText(expectedName) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function QA_CountItemInBags(expectedId, expectedName)
|
||||
local getContainerNumSlots = _G and _G["GetContainerNumSlots"] or nil
|
||||
local getContainerItemLink = _G and _G["GetContainerItemLink"] or nil
|
||||
local getContainerItemInfo = _G and _G["GetContainerItemInfo"] or nil
|
||||
local getItemInfo = _G and _G["GetItemInfo"] or nil
|
||||
if type(getContainerNumSlots) ~= "function" or type(getContainerItemLink) ~= "function" then
|
||||
return 0
|
||||
end
|
||||
|
||||
local total = 0
|
||||
for bag = 0, 4 do
|
||||
local slots = math.floor(tonumber(getContainerNumSlots(bag)) or 0)
|
||||
for slot = 1, slots do
|
||||
local link = getContainerItemLink(bag, slot)
|
||||
if type(link) == "string" and link ~= "" then
|
||||
local _, _, itemIdStr = string.find(link, "item:(%d+)")
|
||||
local itemId = tonumber(itemIdStr)
|
||||
local itemName = nil
|
||||
if type(getItemInfo) == "function" then
|
||||
itemName = getItemInfo(link)
|
||||
end
|
||||
if QA_MatchesItem(itemId, itemName, expectedId, expectedName) then
|
||||
local texture, stackCount = nil, nil
|
||||
if type(getContainerItemInfo) == "function" then
|
||||
texture, stackCount = getContainerItemInfo(bag, slot)
|
||||
end
|
||||
total = total + math.floor(tonumber(stackCount) or 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return total
|
||||
end
|
||||
|
||||
local function QA_TooltipTrace(message, force)
|
||||
return
|
||||
end
|
||||
|
||||
local function QA_GetTooltipNpc(tooltip)
|
||||
if not tooltip or type(tooltip.GetUnit) ~= "function" then
|
||||
return nil, nil, nil, nil
|
||||
end
|
||||
local ok, unitA, unitB = pcall(function()
|
||||
return tooltip:GetUnit()
|
||||
end)
|
||||
local unit = nil
|
||||
if ok then
|
||||
if type(unitB) == "string" and unitB ~= "" then
|
||||
unit = unitB
|
||||
elseif type(unitA) == "string" and unitA ~= "" then
|
||||
unit = unitA
|
||||
end
|
||||
end
|
||||
if (type(unit) ~= "string" or unit == "") and type(UnitExists) == "function" and UnitExists("mouseover") then
|
||||
unit = "mouseover"
|
||||
end
|
||||
if type(unit) ~= "string" or unit == "" then
|
||||
local left1 = (type(getglobal) == "function" and getglobal("GameTooltipTextLeft1")) or (_G and _G["GameTooltipTextLeft1"])
|
||||
local title = left1 and left1.GetText and left1:GetText() or nil
|
||||
if type(title) == "string" and title ~= "" then
|
||||
return nil, title, nil, title
|
||||
end
|
||||
return nil, nil, nil, nil
|
||||
end
|
||||
local guid = UnitGUID and UnitGUID(unit) or nil
|
||||
local npcId = QA_GetNpcIdFromGuid(guid)
|
||||
local name = UnitName and UnitName(unit) or nil
|
||||
local title = nil
|
||||
if (type(name) ~= "string" or name == "") then
|
||||
local left1 = (type(getglobal) == "function" and getglobal("GameTooltipTextLeft1")) or (_G and _G["GameTooltipTextLeft1"])
|
||||
title = left1 and left1.GetText and left1:GetText() or nil
|
||||
if type(title) == "string" and title ~= "" then
|
||||
name = title
|
||||
end
|
||||
end
|
||||
return npcId, name, unit, title
|
||||
end
|
||||
|
||||
local function QA_TooltipAlreadyExtended(tooltip)
|
||||
if not tooltip or type(tooltip.NumLines) ~= "function" then
|
||||
return false
|
||||
end
|
||||
local lines = math.floor(tonumber(tooltip:NumLines()) or 0)
|
||||
for i = 1, lines do
|
||||
local line = (type(getglobal) == "function" and getglobal("GameTooltipTextLeft" .. tostring(i))) or (_G and _G["GameTooltipTextLeft" .. tostring(i)])
|
||||
local text = line and line.GetText and line:GetText() or nil
|
||||
if type(text) == "string" and QA_NormalizeText(text) == QA_NormalizeText("Quest Automation") then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function QA_IsTooltipDrazial(tooltip)
|
||||
local npcId, npcName = QA_GetTooltipNpc(tooltip)
|
||||
if tonumber(npcId) == QA_SCORPOK_NPC_ID then
|
||||
return true
|
||||
end
|
||||
if type(npcName) == "string" and npcName ~= "" and QA_NormalizeText(npcName) == QA_NormalizeText(QA_SCORPOK_NPC_NAME) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function QA_AppendDrazialTooltip(tooltip, sourceTag)
|
||||
sourceTag = tostring(sourceTag or "unknown")
|
||||
if not (MTH_AutoQuest and MTH_AutoQuest.enabled) then
|
||||
QA_TooltipTrace("skip: module disabled source=" .. sourceTag)
|
||||
return
|
||||
end
|
||||
if not QA_IsScorpokAutomationEnabled() or not QA_IsScorpokTooltipEnabled() then
|
||||
QA_TooltipTrace("skip: option disabled source=" .. sourceTag)
|
||||
return
|
||||
end
|
||||
local npcId, npcName, unitToken, title = QA_GetTooltipNpc(tooltip)
|
||||
local isMatch = tonumber(npcId) == QA_SCORPOK_NPC_ID
|
||||
if not isMatch and type(npcName) == "string" and npcName ~= "" and QA_NormalizeText(npcName) == QA_NormalizeText(QA_SCORPOK_NPC_NAME) then
|
||||
isMatch = true
|
||||
end
|
||||
if not isMatch then
|
||||
QA_TooltipTrace("skip: npc mismatch source=" .. sourceTag
|
||||
.. " unit=" .. tostring(unitToken)
|
||||
.. " id=" .. tostring(npcId)
|
||||
.. " name='" .. tostring(npcName or "") .. "'"
|
||||
.. " title='" .. tostring(title or "") .. "'")
|
||||
return
|
||||
end
|
||||
if QA_TooltipAlreadyExtended(tooltip) then
|
||||
QA_TooltipTrace("skip: already-extended source=" .. sourceTag)
|
||||
return
|
||||
end
|
||||
|
||||
local pincerCount = QA_CountItemInBags(QA_ITEM_SCORPOK_PINCER_ID, QA_ITEM_SCORPOK_PINCER_NAME)
|
||||
local gizzardCount = QA_CountItemInBags(QA_ITEM_VULTURE_GIZZARD_ID, QA_ITEM_VULTURE_GIZZARD_NAME)
|
||||
local lungCount = QA_CountItemInBags(QA_ITEM_BLASTED_BOAR_LUNG_ID, QA_ITEM_BLASTED_BOAR_LUNG_NAME)
|
||||
local assayCount = QA_CountItemInBags(QA_ITEM_GROUND_SCORPOK_ASSAY_ID, QA_ITEM_GROUND_SCORPOK_ASSAY_NAME)
|
||||
|
||||
tooltip:AddLine(" ")
|
||||
tooltip:AddLine("|cffffff00Quest Automation|r")
|
||||
tooltip:AddLine("Scorpok Pincer: " .. QA_ColorByThreshold(pincerCount, 3), 1, 1, 1)
|
||||
tooltip:AddLine("Vulture Gizzard: " .. QA_ColorByThreshold(gizzardCount, 2), 1, 1, 1)
|
||||
tooltip:AddLine("Blasted Boar Lung: " .. QA_ColorByThreshold(lungCount, 1), 1, 1, 1)
|
||||
tooltip:AddLine("Ground Scorpok Assay: " .. QA_ColorAssay(assayCount), 1, 1, 1)
|
||||
tooltip:AddLine("Spam SHIFT-click!", 0.7, 0.9, 1)
|
||||
tooltip:AddLine("Recipes: 3x Pincer, 2x Gizzard, 1x Lung", 0.7, 0.7, 0.7)
|
||||
tooltip:Show()
|
||||
QA_TooltipTrace("added: source=" .. sourceTag
|
||||
.. " id=" .. tostring(npcId)
|
||||
.. " name='" .. tostring(npcName or "") .. "'", true)
|
||||
end
|
||||
|
||||
local function QA_EnsureTooltipHook()
|
||||
if QA_TooltipHooked then
|
||||
return
|
||||
end
|
||||
if not GameTooltip then
|
||||
return
|
||||
end
|
||||
|
||||
local hasGetScript = type(GameTooltip.GetScript) == "function"
|
||||
local hasSetScript = type(GameTooltip.SetScript) == "function"
|
||||
local hasHookScript = type(GameTooltip.HookScript) == "function"
|
||||
|
||||
local onTooltipSetUnitExists = false
|
||||
local onShowExists = false
|
||||
if hasGetScript then
|
||||
local okSetUnit, existingSetUnit = pcall(function()
|
||||
return GameTooltip:GetScript("OnTooltipSetUnit")
|
||||
end)
|
||||
onTooltipSetUnitExists = okSetUnit and type(existingSetUnit) == "function"
|
||||
|
||||
local okShow, existingShow = pcall(function()
|
||||
return GameTooltip:GetScript("OnShow")
|
||||
end)
|
||||
onShowExists = okShow and type(existingShow) == "function"
|
||||
end
|
||||
|
||||
if hasHookScript and onTooltipSetUnitExists then
|
||||
pcall(function()
|
||||
GameTooltip:HookScript("OnTooltipSetUnit", function()
|
||||
QA_AppendDrazialTooltip(this, "hook:setunit")
|
||||
end)
|
||||
end)
|
||||
elseif hasSetScript and hasGetScript and onTooltipSetUnitExists then
|
||||
local okGetPrev, previous = pcall(function()
|
||||
return GameTooltip:GetScript("OnTooltipSetUnit")
|
||||
end)
|
||||
if okGetPrev then
|
||||
pcall(function()
|
||||
GameTooltip:SetScript("OnTooltipSetUnit", function()
|
||||
if type(previous) == "function" then
|
||||
previous()
|
||||
end
|
||||
QA_AppendDrazialTooltip(this, "script:setunit")
|
||||
end)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
if hasHookScript and onShowExists then
|
||||
pcall(function()
|
||||
GameTooltip:HookScript("OnShow", function()
|
||||
QA_AppendDrazialTooltip(this, "hook:show")
|
||||
end)
|
||||
end)
|
||||
elseif hasSetScript and hasGetScript and onShowExists then
|
||||
local okGetPrevShow, previousShow = pcall(function()
|
||||
return GameTooltip:GetScript("OnShow")
|
||||
end)
|
||||
if okGetPrevShow then
|
||||
pcall(function()
|
||||
GameTooltip:SetScript("OnShow", function()
|
||||
if type(previousShow) == "function" then
|
||||
previousShow()
|
||||
end
|
||||
QA_AppendDrazialTooltip(this, "script:show")
|
||||
end)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
QA_TooltipHooked = true
|
||||
end
|
||||
|
||||
local function QA_EnsureTooltipPoller()
|
||||
if QA_TooltipPollFrame then
|
||||
return
|
||||
end
|
||||
local frame = CreateFrame("Frame", "MTH_AQTooltipPoll")
|
||||
if not frame then
|
||||
return
|
||||
end
|
||||
frame._mthElapsed = 0
|
||||
frame:SetScript("OnUpdate", function()
|
||||
this._mthElapsed = (this._mthElapsed or 0) + (arg1 or 0)
|
||||
if this._mthElapsed < 0.20 then
|
||||
return
|
||||
end
|
||||
this._mthElapsed = 0
|
||||
if not (MTH_AutoQuest and MTH_AutoQuest.enabled) then
|
||||
return
|
||||
end
|
||||
if GameTooltip and type(GameTooltip.IsVisible) == "function" and GameTooltip:IsVisible() then
|
||||
QA_AppendDrazialTooltip(GameTooltip, "poll")
|
||||
end
|
||||
end)
|
||||
QA_TooltipPollFrame = frame
|
||||
end
|
||||
|
||||
local function QA_GetInteractedNpcId()
|
||||
local getGuid = _G and _G["UnitGUID"] or nil
|
||||
if type(getGuid) ~= "function" then
|
||||
return nil
|
||||
end
|
||||
local npcGuid = getGuid("npc")
|
||||
local npcId = QA_GetNpcIdFromGuid(npcGuid)
|
||||
if npcId then
|
||||
return npcId
|
||||
end
|
||||
return QA_GetNpcIdFromGuid(getGuid("target"))
|
||||
end
|
||||
|
||||
local function QA_GetInteractedNpcName()
|
||||
local getName = _G and _G["UnitName"] or nil
|
||||
if type(getName) ~= "function" then
|
||||
return nil
|
||||
end
|
||||
local name = getName("npc")
|
||||
if type(name) == "string" and name ~= "" then
|
||||
return name
|
||||
end
|
||||
name = getName("target")
|
||||
if type(name) == "string" and name ~= "" then
|
||||
return name
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function QA_IsInteractedNpc(expectedNpcId, expectedNpcName)
|
||||
local npcId = QA_GetInteractedNpcId()
|
||||
if tonumber(npcId) == tonumber(expectedNpcId) then
|
||||
return true
|
||||
end
|
||||
local npcName = QA_GetInteractedNpcName()
|
||||
if type(npcName) == "string" and npcName ~= "" and QA_NormalizeText(npcName) == QA_NormalizeText(expectedNpcName) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function QA_IsScorpokNpc()
|
||||
return QA_IsInteractedNpc(QA_SCORPOK_NPC_ID, QA_SCORPOK_NPC_NAME)
|
||||
end
|
||||
|
||||
local function QA_IsArrowsForSissiesNpc()
|
||||
return QA_IsInteractedNpc(QA_SISSIES_NPC_ID, QA_SISSIES_NPC_NAME)
|
||||
end
|
||||
|
||||
local function QA_RefreshMouseoverTooltip()
|
||||
local tooltip = _G and _G["GameTooltip"] or GameTooltip
|
||||
if not tooltip then
|
||||
return
|
||||
end
|
||||
if type(UnitExists) == "function" and UnitExists("mouseover") and type(tooltip.SetUnit) == "function" then
|
||||
tooltip:SetUnit("mouseover")
|
||||
if type(tooltip.Show) == "function" then
|
||||
tooltip:Show()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function QA_RequestTooltipRefresh(delaySeconds)
|
||||
delaySeconds = tonumber(delaySeconds) or 0.10
|
||||
if not QA_TooltipRefreshFrame then
|
||||
QA_TooltipRefreshFrame = CreateFrame("Frame", "MTH_AQTooltipRefresh")
|
||||
if not QA_TooltipRefreshFrame then
|
||||
return
|
||||
end
|
||||
QA_TooltipRefreshFrame:SetScript("OnUpdate", function()
|
||||
local frameRef = this or QA_TooltipRefreshFrame
|
||||
if not frameRef then
|
||||
return
|
||||
end
|
||||
frameRef._elapsed = (frameRef._elapsed or 0) + (arg1 or 0)
|
||||
if frameRef._elapsed < (frameRef._delay or 0.10) then
|
||||
return
|
||||
end
|
||||
frameRef._elapsed = 0
|
||||
frameRef._delay = 0
|
||||
frameRef:SetScript("OnUpdate", nil)
|
||||
QA_RefreshMouseoverTooltip()
|
||||
end)
|
||||
end
|
||||
QA_TooltipRefreshFrame._delay = delaySeconds
|
||||
QA_TooltipRefreshFrame._elapsed = 0
|
||||
QA_TooltipRefreshFrame:SetScript("OnUpdate", QA_TooltipRefreshFrame:GetScript("OnUpdate"))
|
||||
end
|
||||
|
||||
local QA_PROFILE_SCORPOK = {
|
||||
key = "scorpokDrazial",
|
||||
label = "Scorpok",
|
||||
optionCheck = QA_IsScorpokAutomationEnabled,
|
||||
npcCheck = QA_IsScorpokNpc,
|
||||
titleCheck = QA_IsScorpokTitle,
|
||||
questContextCheck = QA_IsScorpokQuestContext,
|
||||
lastActionField = "_scorpokLastActionAt",
|
||||
refreshTooltipOnComplete = true,
|
||||
}
|
||||
|
||||
local QA_PROFILE_SISSIES = {
|
||||
key = "arrowsForSissies",
|
||||
label = "ArrowsForSissies",
|
||||
optionCheck = QA_IsArrowsForSissiesAutomationEnabled,
|
||||
npcCheck = QA_IsArrowsForSissiesNpc,
|
||||
titleCheck = QA_IsArrowsForSissiesTitle,
|
||||
questContextCheck = QA_IsArrowsForSissiesQuestContext,
|
||||
lastActionField = "_sissiesLastActionAt",
|
||||
refreshTooltipOnComplete = false,
|
||||
}
|
||||
|
||||
local QA_LastActionAt = {}
|
||||
|
||||
local function QA_GetLastActionAt(profile)
|
||||
local key = type(profile) == "table" and tostring(profile.lastActionField or "") or ""
|
||||
if key == "" then
|
||||
return 0
|
||||
end
|
||||
return tonumber(QA_LastActionAt[key]) or 0
|
||||
end
|
||||
|
||||
local function QA_SetLastActionAt(profile, value)
|
||||
local key = type(profile) == "table" and tostring(profile.lastActionField or "") or ""
|
||||
if key == "" then
|
||||
return
|
||||
end
|
||||
QA_LastActionAt[key] = tonumber(value) or 0
|
||||
end
|
||||
|
||||
local function QA_CanRunProfile(profile)
|
||||
if type(profile) ~= "table" then
|
||||
return false
|
||||
end
|
||||
if type(profile.optionCheck) ~= "function" or not profile.optionCheck() then
|
||||
QA_Debug("[" .. tostring(profile.label or "AutoQuest") .. "] skip: option disabled")
|
||||
return false
|
||||
end
|
||||
if type(IsShiftKeyDown) ~= "function" or not IsShiftKeyDown() then
|
||||
QA_Debug("[" .. tostring(profile.label or "AutoQuest") .. "] skip: SHIFT not held")
|
||||
return false
|
||||
end
|
||||
local npcOk = type(profile.npcCheck) == "function" and profile.npcCheck() or false
|
||||
if not npcOk then
|
||||
QA_Debug("[" .. tostring(profile.label or "AutoQuest") .. "] skip: NPC mismatch (id=" .. tostring(QA_GetInteractedNpcId()) .. ", name='" .. tostring(QA_GetInteractedNpcName() or "") .. "')")
|
||||
end
|
||||
return npcOk
|
||||
end
|
||||
|
||||
local function QA_FindGossipQuestIndex(rawEntries, count, profile)
|
||||
if type(rawEntries) ~= "table" or tonumber(count) == nil or tonumber(count) <= 0 then
|
||||
return nil
|
||||
end
|
||||
if type(profile) ~= "table" or type(profile.titleCheck) ~= "function" then
|
||||
return nil
|
||||
end
|
||||
local entryCount = math.floor(tonumber(count) or 0)
|
||||
local tupleSize = math.floor(table.getn(rawEntries) / entryCount)
|
||||
if tupleSize < 1 then
|
||||
tupleSize = 1
|
||||
end
|
||||
for i = 1, entryCount do
|
||||
local title = tostring(rawEntries[((i - 1) * tupleSize) + 1] or "")
|
||||
if profile.titleCheck(title) then
|
||||
return i
|
||||
end
|
||||
end
|
||||
if entryCount == 1 and type(profile.npcCheck) == "function" and profile.npcCheck() then
|
||||
QA_Debug("[" .. tostring(profile.label or "AutoQuest") .. "] gossip fallback: single quest entry -> selecting index 1")
|
||||
return 1
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function QA_FindQuestGreetingIndex(isActive, profile)
|
||||
local getCount = isActive and _G and _G["GetNumActiveQuests"] or _G and _G["GetNumAvailableQuests"]
|
||||
local getTitle = isActive and _G and _G["GetActiveTitle"] or _G and _G["GetAvailableTitle"]
|
||||
if type(getCount) ~= "function" or type(getTitle) ~= "function" or type(profile) ~= "table" or type(profile.titleCheck) ~= "function" then
|
||||
return nil
|
||||
end
|
||||
local count = math.floor(tonumber(getCount()) or 0)
|
||||
if count <= 0 then
|
||||
return nil
|
||||
end
|
||||
for i = 1, count do
|
||||
local title = tostring(getTitle(i) or "")
|
||||
if profile.titleCheck(title) then
|
||||
return i
|
||||
end
|
||||
end
|
||||
if count == 1 and type(profile.npcCheck) == "function" and profile.npcCheck() then
|
||||
QA_Debug("[" .. tostring(profile.label or "AutoQuest") .. "] quest greeting fallback: single quest entry -> selecting index 1")
|
||||
return 1
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function QA_GetFrameText(frame)
|
||||
if type(frame) ~= "table" then
|
||||
return ""
|
||||
end
|
||||
if type(frame.GetText) == "function" then
|
||||
return tostring(frame:GetText() or "")
|
||||
end
|
||||
if type(frame.GetName) == "function" then
|
||||
local name = frame:GetName()
|
||||
if type(name) == "string" and name ~= "" then
|
||||
local textRegion = _G and _G[name .. "Text"] or nil
|
||||
if textRegion and type(textRegion.GetText) == "function" then
|
||||
return tostring(textRegion:GetText() or "")
|
||||
end
|
||||
end
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
local function QA_ClickGossipTitleButtonFallback(profile)
|
||||
if type(profile) ~= "table" or type(profile.titleCheck) ~= "function" then
|
||||
return false
|
||||
end
|
||||
for i = 1, 40 do
|
||||
local button = _G and _G["GossipTitleButton" .. tostring(i)] or nil
|
||||
if button then
|
||||
local visible = true
|
||||
if type(button.IsVisible) == "function" then
|
||||
visible = button:IsVisible() and true or false
|
||||
end
|
||||
if visible then
|
||||
local title = QA_GetFrameText(button)
|
||||
if profile.titleCheck(title) then
|
||||
QA_Debug("action: GossipTitleButton" .. tostring(i) .. " click title='" .. tostring(title) .. "'")
|
||||
if type(button.Click) == "function" then
|
||||
button:Click()
|
||||
return true
|
||||
end
|
||||
local onClick = type(button.GetScript) == "function" and button:GetScript("OnClick") or nil
|
||||
if type(onClick) == "function" then
|
||||
onClick(button)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function QA_RunProfileAutomation(eventName, profile)
|
||||
if type(profile) ~= "table" then
|
||||
return
|
||||
end
|
||||
QA_Debug("[" .. tostring(profile.label or "AutoQuest") .. "] event=" .. tostring(eventName))
|
||||
if not QA_CanRunProfile(profile) then
|
||||
return
|
||||
end
|
||||
|
||||
local getTimeFn = _G and _G["GetTime"] or nil
|
||||
if eventName == "GOSSIP_SHOW" and type(getTimeFn) == "function" then
|
||||
local now = tonumber(getTimeFn()) or 0
|
||||
local last = QA_GetLastActionAt(profile)
|
||||
if (now - last) < 0.05 then
|
||||
QA_Debug("skip: throttled dt=" .. tostring(now - last))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if eventName == "QUEST_GREETING" then
|
||||
local selectAvailableQuest = _G and _G["SelectAvailableQuest"] or nil
|
||||
local selectActiveQuest = _G and _G["SelectActiveQuest"] or nil
|
||||
local availableIndex = QA_FindQuestGreetingIndex(false, profile)
|
||||
if availableIndex and type(selectAvailableQuest) == "function" then
|
||||
QA_Debug("action: SelectAvailableQuest (compat) index=" .. tostring(availableIndex))
|
||||
selectAvailableQuest()
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
return
|
||||
end
|
||||
local activeIndex = QA_FindQuestGreetingIndex(true, profile)
|
||||
if activeIndex and type(selectActiveQuest) == "function" then
|
||||
QA_Debug("action: SelectActiveQuest (compat) index=" .. tostring(activeIndex))
|
||||
selectActiveQuest()
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
return
|
||||
end
|
||||
for i = 1, 40 do
|
||||
local button = _G and _G["QuestTitleButton" .. tostring(i)] or nil
|
||||
if button and (type(button.IsVisible) ~= "function" or button:IsVisible()) then
|
||||
local title = QA_GetFrameText(button)
|
||||
if profile.titleCheck(title) then
|
||||
QA_Debug("action: QuestTitleButton" .. tostring(i) .. " click title='" .. tostring(title) .. "'")
|
||||
if type(button.Click) == "function" then
|
||||
button:Click()
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
QA_Debug("quest greeting: no action taken")
|
||||
return
|
||||
end
|
||||
|
||||
if eventName == "GOSSIP_SHOW" then
|
||||
local getNumGossipAvailableQuests = _G and _G["GetNumGossipAvailableQuests"] or nil
|
||||
local getGossipAvailableQuests = _G and _G["GetGossipAvailableQuests"] or nil
|
||||
local selectGossipAvailableQuest = _G and _G["SelectGossipAvailableQuest"] or nil
|
||||
QA_Debug("api available: numAvail=" .. tostring(type(getNumGossipAvailableQuests) == "function")
|
||||
.. " getAvail=" .. tostring(type(getGossipAvailableQuests) == "function")
|
||||
.. " selAvail=" .. tostring(type(selectGossipAvailableQuest) == "function"))
|
||||
if type(getNumGossipAvailableQuests) == "function" and type(getGossipAvailableQuests) == "function" and type(selectGossipAvailableQuest) == "function" then
|
||||
local availableCount = math.floor(tonumber(getNumGossipAvailableQuests()) or 0)
|
||||
QA_Debug("gossip available count=" .. tostring(availableCount))
|
||||
if availableCount > 0 then
|
||||
local availableIndex = QA_FindGossipQuestIndex({ getGossipAvailableQuests() }, availableCount, profile)
|
||||
if availableIndex then
|
||||
QA_Debug("action: SelectGossipAvailableQuest index=" .. tostring(availableIndex))
|
||||
selectGossipAvailableQuest(availableIndex)
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
return
|
||||
end
|
||||
QA_Debug("gossip available: no Scorpok match")
|
||||
end
|
||||
end
|
||||
local getNumGossipActiveQuests = _G and _G["GetNumGossipActiveQuests"] or nil
|
||||
local getGossipActiveQuests = _G and _G["GetGossipActiveQuests"] or nil
|
||||
local selectGossipActiveQuest = _G and _G["SelectGossipActiveQuest"] or nil
|
||||
QA_Debug("api active: numActive=" .. tostring(type(getNumGossipActiveQuests) == "function")
|
||||
.. " getActive=" .. tostring(type(getGossipActiveQuests) == "function")
|
||||
.. " selActive=" .. tostring(type(selectGossipActiveQuest) == "function"))
|
||||
if type(getNumGossipActiveQuests) == "function" and type(getGossipActiveQuests) == "function" and type(selectGossipActiveQuest) == "function" then
|
||||
local activeCount = math.floor(tonumber(getNumGossipActiveQuests()) or 0)
|
||||
QA_Debug("gossip active count=" .. tostring(activeCount))
|
||||
if activeCount > 0 then
|
||||
local activeIndex = QA_FindGossipQuestIndex({ getGossipActiveQuests() }, activeCount, profile)
|
||||
if activeIndex then
|
||||
QA_Debug("action: SelectGossipActiveQuest index=" .. tostring(activeIndex))
|
||||
selectGossipActiveQuest(activeIndex)
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
return
|
||||
end
|
||||
QA_Debug("gossip active: no Scorpok match")
|
||||
end
|
||||
end
|
||||
if QA_ClickGossipTitleButtonFallback(profile) then
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
return
|
||||
end
|
||||
QA_Debug("gossip: no action taken")
|
||||
return
|
||||
end
|
||||
|
||||
local title = type(GetTitleText) == "function" and tostring(GetTitleText() or "") or ""
|
||||
QA_Debug("quest frame title='" .. tostring(title) .. "'")
|
||||
if type(profile.questContextCheck) ~= "function" or not profile.questContextCheck(title) then
|
||||
QA_Debug("skip: quest context mismatch")
|
||||
return
|
||||
end
|
||||
|
||||
if eventName == "QUEST_DETAIL" then
|
||||
if type(AcceptQuest) == "function" then
|
||||
QA_Debug("action: AcceptQuest")
|
||||
AcceptQuest()
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
end
|
||||
elseif eventName == "QUEST_PROGRESS" then
|
||||
if type(CompleteQuest) == "function" then
|
||||
if type(IsQuestCompletable) ~= "function" or IsQuestCompletable() then
|
||||
QA_Debug("action: CompleteQuest")
|
||||
CompleteQuest()
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
else
|
||||
QA_Debug("skip: quest not completable yet")
|
||||
end
|
||||
end
|
||||
elseif eventName == "QUEST_COMPLETE" then
|
||||
if type(GetQuestReward) == "function" then
|
||||
local choices = type(GetNumQuestChoices) == "function" and math.floor(tonumber(GetNumQuestChoices()) or 0) or 0
|
||||
if choices <= 1 then
|
||||
QA_Debug("action: GetQuestReward(1)")
|
||||
GetQuestReward(1)
|
||||
QA_SetLastActionAt(profile, type(getTimeFn) == "function" and getTimeFn() or 0)
|
||||
if profile.refreshTooltipOnComplete then
|
||||
QA_RequestTooltipRefresh(0.10)
|
||||
end
|
||||
else
|
||||
QA_Debug("skip: multiple reward choices=" .. tostring(choices))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- NOTE: QA_DirectEventFrame removed (Phase 2 fix #22b)
|
||||
-- The central event router already dispatches GOSSIP_SHOW, QUEST_GREETING,
|
||||
-- QUEST_DETAIL, QUEST_PROGRESS, QUEST_COMPLETE to MTH_AutoQuest:onEvent().
|
||||
-- Having a second frame register the same events caused double-dispatch.
|
||||
|
||||
function MTH_AutoQuest:init()
|
||||
local store = QA_GetOptionsStore()
|
||||
self.initialized = true
|
||||
QA_Debug("init: module active=" .. tostring(self.enabled and true or false)
|
||||
.. ", option scorpokDrazial=" .. tostring(store and store.scorpokDrazial and true or false)
|
||||
.. ", option arrowsForSissies=" .. tostring(store and store.arrowsForSissies and true or false)
|
||||
.. ", option scorpokTooltip=" .. tostring(store and store.scorpokTooltip and true or false))
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:setEnabled(enabled)
|
||||
self.enabled = enabled and true or false
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:onEvent(eventName)
|
||||
if eventName == "GOSSIP_SHOW"
|
||||
or eventName == "QUEST_GREETING"
|
||||
or eventName == "QUEST_DETAIL"
|
||||
or eventName == "QUEST_PROGRESS"
|
||||
or eventName == "QUEST_COMPLETE" then
|
||||
QA_Debug("onEvent=" .. tostring(eventName))
|
||||
QA_RunProfileAutomation(eventName, QA_PROFILE_SCORPOK)
|
||||
QA_RunProfileAutomation(eventName, QA_PROFILE_SISSIES)
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_AutoQuest:cleanup()
|
||||
-- no-op: direct event frame removed in Phase 2
|
||||
end
|
||||
|
||||
MTH:RegisterModule("autoquest", MTH_AutoQuest)
|
||||
@@ -28,6 +28,8 @@ function MTH_ChronometerHunterInstallData(engine)
|
||||
engine:AddTimer(engine.SPELL, BS["Flare"], 30, 0, 0, 0, { cr = "YELLOW", rc = true })
|
||||
engine:AddTimer(engine.SPELL, BS["Hunter's Mark"], 120, 1, 0, 0, { cr = "RED", rc = true })
|
||||
engine:AddTimer(engine.SPELL, BS["Immolation Trap"], 60, 0, 0, 0, { gr = 1, cr = "ORANGE", ea = { [BS["Immolation Trap Effect"]] = 60 } })
|
||||
engine:AddTimer(engine.SPELL, BS["Aimed Shot"], 20, 0, 0, 0, { cr = "RED", rc = true, d = { tn = BS["Swiftshot"], tb = -2, ts = -2 } }) -- base 20s; Swiftshot reduces by 2s/rank (max -6s at rank 3)
|
||||
engine:AddTimer(engine.SPELL, BS["Kill Command"], 12, 0, 0, 0, { cr = "RED", rc = true })
|
||||
engine:AddTimer(engine.SPELL, BS["Rapid Fire"], 15, 0, 1, 1, { cr = "RED" })
|
||||
engine:AddTimer(engine.SPELL, BS["Scare Beast"], 10, 1, 0, 0, { cr = "BLUE", rc = true, d = { rs = 5 } })
|
||||
engine:AddTimer(engine.SPELL, BS["Scatter Shot"], 4, 1, 0, 0, { cr = "MAROON" })
|
||||
@@ -43,10 +45,18 @@ function MTH_ChronometerHunterInstallData(engine)
|
||||
engine:AddTimer(engine.EVENT, BS["Frost Trap Aura"], 30, 0, 0, 0, { gr = 1, cr = "CYAN", a = 1, d = { tn = BS["Clever Traps"], tb = 0.15, tp = 1 }, xn = BS["Frost Trap"] })
|
||||
engine:AddTimer(engine.EVENT, BS["Immolation Trap Effect"], 15, 1, 0, 1, { gr = 1, cr = "ORANGE", a = 1, xn = BS["Immolation Trap"] })
|
||||
engine:AddTimer(engine.EVENT, BS["Improved Concussive Shot"], 3, 1, 0, 0, { a = 1, cr = "BLUE", xn = BS["Concussive Shot"] })
|
||||
engine:AddTimer(engine.EVENT, BS["Improved Wing Clip"], 5, 1, 0, 0, { a = 1, cr = "YELLOW", xn = BS["Wing Clip"] })
|
||||
engine:AddTimer(engine.EVENT, BS["Improved Wing Clip"], 5, 1, 0, 0, { a = 1, cr = "MAROON", xn = BS["Wing Clip"] })
|
||||
engine:AddTimer(engine.EVENT, BS["Lock and Load"], 10, 0, 1, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\ability_hunter_lockandload" }) -- 10s (tooltip confirmed; expires on Aimed Shot cast)
|
||||
engine:AddTimer(engine.EVENT, BS["Scent of Blood"], 8, 0, 1, 1, { a = 1, cr = "RED" })
|
||||
engine:AddTimer(engine.EVENT, BS["Piercing Shot"], 8, 1, 0, 1, { a = 1, cr = "PURPLE", tx = "Interface\\Icons\\Ability_Hunter_DisarmingShot" })
|
||||
engine:AddTimer(engine.EVENT, BS["Entrapment"], 5, 1, 0, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\Spell_Nature_StrangleVines" })
|
||||
engine:AddTimer(engine.EVENT, BS["Quick Shots"], 12, 0, 1, 1, { a = 1, cr = "MAROON", tx = "Interface\\Icons\\Ability_Warrior_InnerRage" })
|
||||
engine:AddTimer(engine.EVENT, BS["Wing Clip"], 10, 1, 0, 1, { a = 1, cr = "YELLOW" })
|
||||
-- Experimental Ammunition: target-side debuffs (from consumed ammo state)
|
||||
-- Poisonous Ammunition consumed: reduces target armor 15s (Nature)
|
||||
engine:AddTimer(engine.EVENT, BS["Poisonous Ammunition"], 15, 1, 0, 1, { a = 1, cr = "GREEN", tx = "Interface\\Icons\\Ability_PoisonArrow" })
|
||||
-- Enchanted Ammunition consumed: magic resist debuff 6s (Arcane)
|
||||
engine:AddTimer(engine.EVENT, BS["Enchanted Ammunition"], 6, 1, 0, 1, { a = 1, cr = "PURPLE", tx = "Interface\\Icons\\Ability_TheBlackArrow" })
|
||||
engine:AddTimer(engine.EVENT, BS["Scorpid Poison"], 10, 1, 0, 0, { gr = 3, cr = "PURPLE", a = 1, dn = 1 })
|
||||
engine:AddTimer(engine.EVENT, BS["Devilsaur Fury"], 20, 0, 1, 1, { a = 1, cr = "PURPLE", xn = BS["Devilsaur Eye"], tx = "Interface\\Icons\\Ability_Hunter_Pet_Raptor" })
|
||||
engine:AddTimer(engine.EVENT, BS["Restless Strength"], 20, 0, 1, 1, { a = 1, cr = "PURPLE", xn = BS["Zandalarian Hero Medallion"], tx = "Interface\\Icons\\INV_Jewelry_Necklace_13" })
|
||||
|
||||
+305
-24
@@ -60,6 +60,34 @@ local latins = { I = 1, II = 2, III = 3, IV = 4, V = 5, VI = 6, VII = 7, VIII =
|
||||
local BAR_GROUP = "MTHChronometer"
|
||||
local PARSER_OWNER = "MTHChronometerHunter"
|
||||
|
||||
|
||||
local function MTH_CHRON_FormatBarPosition(profile)
|
||||
local bp = profile and profile.barposition
|
||||
if type(bp) ~= "table" then
|
||||
return "<none>"
|
||||
end
|
||||
return tostring(bp.point or "nil")
|
||||
.. "/" .. tostring(bp.relativePoint or "nil")
|
||||
.. " @(" .. tostring(bp.x) .. "," .. tostring(bp.y) .. ")"
|
||||
end
|
||||
|
||||
local function MTH_CHRON_DescribePoint(frame)
|
||||
if not (frame and frame.GetPoint) then
|
||||
return "<no-frame>"
|
||||
end
|
||||
local point, relTo, relPoint, x, y = frame:GetPoint()
|
||||
local relName = "nil"
|
||||
if type(relTo) == "table" and relTo.GetName then
|
||||
relName = tostring(relTo:GetName() or "<anon>")
|
||||
elseif relTo then
|
||||
relName = tostring(relTo)
|
||||
end
|
||||
return tostring(point or "nil")
|
||||
.. "->" .. relName
|
||||
.. ":" .. tostring(relPoint or "nil")
|
||||
.. " @(" .. tostring(x) .. "," .. tostring(y) .. ")"
|
||||
end
|
||||
|
||||
local COLOR_NAME_MAP = {
|
||||
white = { 1.0, 1.0, 1.0 },
|
||||
black = { 0.0, 0.0, 0.0 },
|
||||
@@ -163,6 +191,28 @@ local function ensureProfile()
|
||||
if type(store) ~= "table" then
|
||||
return shallowCopy(DEFAULTS)
|
||||
end
|
||||
if type(store.profile) ~= "table"
|
||||
and type(MTH_CharSavedVariables) == "table"
|
||||
and type(MTH_CharSavedVariables.chronometer) == "table"
|
||||
then
|
||||
local legacyChar = MTH_CharSavedVariables.chronometer
|
||||
if type(legacyChar.profile) == "table" then
|
||||
store.profile = deepCopyValue(legacyChar.profile)
|
||||
elseif type(legacyChar.barposition) == "table" then
|
||||
store.profile = { barposition = deepCopyValue(legacyChar.barposition) }
|
||||
end
|
||||
end
|
||||
if type(store.profile) ~= "table"
|
||||
and type(MTH_SavedVariables) == "table"
|
||||
and type(MTH_SavedVariables.chronometer) == "table"
|
||||
then
|
||||
local legacyAccount = MTH_SavedVariables.chronometer
|
||||
if type(legacyAccount.profile) == "table" then
|
||||
store.profile = deepCopyValue(legacyAccount.profile)
|
||||
elseif type(legacyAccount.barposition) == "table" then
|
||||
store.profile = { barposition = deepCopyValue(legacyAccount.barposition) }
|
||||
end
|
||||
end
|
||||
if type(store.profile) ~= "table" and MTH.GetModuleSavedVariables then
|
||||
local accountStore = MTH:GetModuleSavedVariables("chronometer")
|
||||
if type(accountStore) == "table" and type(accountStore.profile) == "table" then
|
||||
@@ -172,6 +222,19 @@ local function ensureProfile()
|
||||
if type(store.profile) ~= "table" then
|
||||
store.profile = {}
|
||||
end
|
||||
if type(store.profile.barposition) ~= "table" and type(store.barposition) == "table" then
|
||||
store.profile.barposition = deepCopyValue(store.barposition)
|
||||
end
|
||||
if type(store.profile.barposition) ~= "table" and MTH.GetModuleSavedVariables then
|
||||
local accountStore = MTH:GetModuleSavedVariables("chronometer")
|
||||
if type(accountStore) == "table" then
|
||||
if type(accountStore.barposition) == "table" then
|
||||
store.profile.barposition = deepCopyValue(accountStore.barposition)
|
||||
elseif type(accountStore.profile) == "table" and type(accountStore.profile.barposition) == "table" then
|
||||
store.profile.barposition = deepCopyValue(accountStore.profile.barposition)
|
||||
end
|
||||
end
|
||||
end
|
||||
local profile = store.profile
|
||||
|
||||
for key, value in pairs(DEFAULTS) do
|
||||
@@ -198,9 +261,61 @@ local function ensureProfile()
|
||||
profile.disabledSpells.HUNTER = {}
|
||||
end
|
||||
|
||||
|
||||
return profile
|
||||
end
|
||||
|
||||
local function MTH_CHRON_PersistAnchorPosition(self, reason)
|
||||
if not (self and self.anchor and self.anchor.GetPoint) then
|
||||
return false
|
||||
end
|
||||
if type(self.profile) ~= "table" then
|
||||
return false
|
||||
end
|
||||
if type(self.profile.barposition) ~= "table" then
|
||||
self.profile.barposition = {}
|
||||
end
|
||||
local point, _, relPoint, x, y = self.anchor:GetPoint()
|
||||
x = tonumber(x)
|
||||
y = tonumber(y)
|
||||
if not (point and relPoint and x and y) then
|
||||
return false
|
||||
end
|
||||
x = math.floor(x + 0.5)
|
||||
y = math.floor(y + 0.5)
|
||||
self.profile.barposition.point = point
|
||||
self.profile.barposition.relativePoint = relPoint
|
||||
self.profile.barposition.x = x
|
||||
self.profile.barposition.y = y
|
||||
return true
|
||||
end
|
||||
|
||||
local function MTH_CHRON_RestoreAnchorFromProfile(self, reason)
|
||||
if not (self and self.anchor and self.anchor.ClearAllPoints and self.anchor.SetPoint) then
|
||||
return false
|
||||
end
|
||||
if type(self.profile) ~= "table" then
|
||||
return false
|
||||
end
|
||||
local bp = self.profile.barposition
|
||||
if type(bp) ~= "table" then
|
||||
return false
|
||||
end
|
||||
local px = tonumber(bp.x)
|
||||
local py = tonumber(bp.y)
|
||||
local ppoint = tostring(bp.point or "")
|
||||
local prelpoint = tostring(bp.relativePoint or "")
|
||||
if not (px and py and ppoint ~= "") then
|
||||
return false
|
||||
end
|
||||
if prelpoint == "" then
|
||||
prelpoint = ppoint
|
||||
end
|
||||
self.anchor:ClearAllPoints()
|
||||
self.anchor:SetPoint(ppoint, UIParent, prelpoint, px, py)
|
||||
return true
|
||||
end
|
||||
|
||||
local function MTH_CHRON_IsPersistedEnabled()
|
||||
if MTH and MTH.IsModuleEnabled then
|
||||
return MTH:IsModuleEnabled("chronometer", true) and true or false
|
||||
@@ -272,22 +387,92 @@ local function parseRankNumber(text)
|
||||
return 0
|
||||
end
|
||||
|
||||
local function resolvePlayerClassBucket(profile)
|
||||
profile = profile or {}
|
||||
local buckets = profile.disabledSpells
|
||||
if type(buckets) ~= "table" then
|
||||
return "HUNTER"
|
||||
end
|
||||
|
||||
local localizedClass, classToken = UnitClass("player")
|
||||
local candidates = {
|
||||
classToken,
|
||||
localizedClass,
|
||||
string.upper(tostring(classToken or "")),
|
||||
string.upper(tostring(localizedClass or "")),
|
||||
"HUNTER",
|
||||
}
|
||||
|
||||
for i = 1, table.getn(candidates) do
|
||||
local key = tostring(candidates[i] or "")
|
||||
if key ~= "" and type(buckets[key]) == "table" then
|
||||
return key
|
||||
end
|
||||
end
|
||||
|
||||
return tostring(classToken or localizedClass or "HUNTER")
|
||||
end
|
||||
|
||||
local function normalizeTimerName(name)
|
||||
local normalized = tostring(name or "")
|
||||
normalized = string.gsub(normalized, "^%s+", "")
|
||||
normalized = string.gsub(normalized, "%s+$", "")
|
||||
normalized = string.gsub(normalized, "%s+", " ")
|
||||
normalized = string.lower(normalized)
|
||||
return normalized
|
||||
end
|
||||
|
||||
local function isTimerDisabled(profile, timerClass, timerName)
|
||||
local disabledSpells = profile and profile.disabledSpells
|
||||
if type(disabledSpells) ~= "table" then
|
||||
return false, "no-disabled-table"
|
||||
end
|
||||
|
||||
local classBucket = disabledSpells[timerClass]
|
||||
if type(classBucket) ~= "table" then
|
||||
return false, "no-class-bucket"
|
||||
end
|
||||
|
||||
if classBucket[timerName] ~= nil then
|
||||
return true, "exact"
|
||||
end
|
||||
|
||||
local wanted = normalizeTimerName(timerName)
|
||||
if wanted == "" then
|
||||
return false, "empty-name"
|
||||
end
|
||||
|
||||
for key, value in pairs(classBucket) do
|
||||
if value ~= nil and normalizeTimerName(key) == wanted then
|
||||
return true, "normalized"
|
||||
end
|
||||
end
|
||||
|
||||
return false, "miss"
|
||||
end
|
||||
|
||||
local function getActionSpell(slot)
|
||||
if GetActionText(slot) or not HasAction(slot) then
|
||||
return nil, 0
|
||||
end
|
||||
|
||||
if not Chronometer._scanTooltip then
|
||||
Chronometer._scanTooltip = CreateFrame("GameTooltip", "MTH_ChronometerScanTooltip", UIParent, "GameTooltipTemplate")
|
||||
Chronometer._scanTooltip:SetOwner(UIParent, "ANCHOR_NONE")
|
||||
local tip = CreateFrame("GameTooltip", "MTH_ChrBarProbe", UIParent)
|
||||
tip:SetOwner(UIParent, "ANCHOR_NONE")
|
||||
for i = 1, 4 do
|
||||
local L = tip:CreateFontString("MTH_ChrBarProbeTextLeft"..i, "ARTWORK", "GameTooltipText")
|
||||
local R = tip:CreateFontString("MTH_ChrBarProbeTextRight"..i, "ARTWORK", "GameTooltipText")
|
||||
tip:AddFontStrings(L, R)
|
||||
end
|
||||
Chronometer._scanTooltip = tip
|
||||
end
|
||||
|
||||
local tooltip = Chronometer._scanTooltip
|
||||
tooltip:ClearLines()
|
||||
tooltip:SetAction(slot)
|
||||
|
||||
local left1 = getglobal("MTH_ChronometerScanTooltipTextLeft1")
|
||||
local left2 = getglobal("MTH_ChronometerScanTooltipTextLeft2")
|
||||
local left1 = getglobal("MTH_ChrBarProbeTextLeft1")
|
||||
local left2 = getglobal("MTH_ChrBarProbeTextLeft2")
|
||||
local spellName = left1 and left1:GetText() or nil
|
||||
if not spellName or spellName == "" then
|
||||
return nil, 0
|
||||
@@ -373,6 +558,9 @@ function Chronometer:OnEnable()
|
||||
self.profile = ensureProfile()
|
||||
self:SetCandyBarGroupGrowth(BAR_GROUP, self.profile.growup and true or false)
|
||||
self:SetCandyBarGroupVerticalSpacing(BAR_GROUP, self.profile.spacing or 0)
|
||||
if self.anchor then
|
||||
end
|
||||
MTH_CHRON_RestoreAnchorFromProfile(self, "OnEnable")
|
||||
|
||||
self.groups = {}
|
||||
self.timers = {}
|
||||
@@ -450,16 +638,37 @@ function Chronometer:OnEnable()
|
||||
self:RegisterEvent("SPELLCAST_INTERRUPTED")
|
||||
self:RegisterEvent("SPELLCAST_START")
|
||||
self:RegisterEvent("SPELLCAST_STOP")
|
||||
self:RegisterEvent("UNIT_AURA")
|
||||
self:RegisterEvent("PLAYER_DEAD")
|
||||
self:RegisterEvent("VARIABLES_LOADED")
|
||||
self:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
self:RegisterEvent("PLAYER_LOGOUT")
|
||||
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_SELF_DAMAGE", function(event, info) self:SELF_DAMAGE(event, info) end)
|
||||
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF", function(event, info) self:SELF_DAMAGE(event, info) end)
|
||||
self.parser:RegisterEvent(PARSER_OWNER, "CHAT_MSG_SPELL_FAILED_LOCALPLAYER", function(event, info) self:SPELL_FAILED(event, info) end)
|
||||
end
|
||||
|
||||
function Chronometer:VARIABLES_LOADED()
|
||||
self.profile = ensureProfile()
|
||||
MTH_CHRON_RestoreAnchorFromProfile(self, "VARIABLES_LOADED")
|
||||
end
|
||||
|
||||
function Chronometer:PLAYER_ENTERING_WORLD()
|
||||
self.profile = ensureProfile()
|
||||
MTH_CHRON_RestoreAnchorFromProfile(self, "PLAYER_ENTERING_WORLD")
|
||||
end
|
||||
|
||||
function Chronometer:PLAYER_LOGOUT()
|
||||
MTH_CHRON_PersistAnchorPosition(self, "PLAYER_LOGOUT")
|
||||
end
|
||||
|
||||
function Chronometer:OnDisable()
|
||||
if not self._mth_enabled then
|
||||
return
|
||||
end
|
||||
if self.anchor then
|
||||
end
|
||||
MTH_CHRON_PersistAnchorPosition(self, "OnDisable")
|
||||
self._mth_enabled = false
|
||||
|
||||
if self.bars then
|
||||
@@ -563,9 +772,12 @@ function Chronometer:StartTimer(timer, name, target, rank, durmod)
|
||||
end
|
||||
end
|
||||
|
||||
local _, class = UnitClass("player")
|
||||
local timerClass = timer.x.cl == nil and class or timer.x.cl
|
||||
if self.profile.disabledSpells[timerClass] and self.profile.disabledSpells[timerClass][name] ~= nil then
|
||||
local timerClass = timer.x.cl
|
||||
if timerClass == nil then
|
||||
timerClass = resolvePlayerClassBucket(self.profile)
|
||||
end
|
||||
local blocked, reason = isTimerDisabled(self.profile, timerClass, name)
|
||||
if blocked then
|
||||
return
|
||||
end
|
||||
|
||||
@@ -948,7 +1160,7 @@ function Chronometer:ToggleAnchor()
|
||||
end
|
||||
|
||||
function Chronometer:CreateAnchor(text, r, g, b)
|
||||
local frame = CreateFrame("Button", "MTHChronometerAnchor", UIParent)
|
||||
local frame = CreateFrame("Button", "MTH_ChronometerAnchor", UIParent)
|
||||
frame:SetWidth(220)
|
||||
frame:SetHeight(25)
|
||||
frame.owner = self
|
||||
@@ -958,31 +1170,37 @@ function Chronometer:CreateAnchor(text, r, g, b)
|
||||
|
||||
local px = tonumber(self.profile and self.profile.barposition and self.profile.barposition.x)
|
||||
local py = tonumber(self.profile and self.profile.barposition and self.profile.barposition.y)
|
||||
local ppoint = tostring(self.profile and self.profile.barposition and self.profile.barposition.point or "")
|
||||
local prelpoint = tostring(self.profile and self.profile.barposition and self.profile.barposition.relativePoint or "")
|
||||
if px ~= nil and py ~= nil then
|
||||
if ppoint == "" then
|
||||
ppoint = "TOPLEFT"
|
||||
end
|
||||
if prelpoint == "" then
|
||||
prelpoint = ppoint
|
||||
end
|
||||
frame:ClearAllPoints()
|
||||
frame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", px, py)
|
||||
frame:SetPoint(ppoint, UIParent, prelpoint, px, py)
|
||||
else
|
||||
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 50)
|
||||
end
|
||||
|
||||
frame:SetScript("OnDragStart", function(self)
|
||||
self = self or this
|
||||
if not self or not self.StartMoving then
|
||||
frame:SetScript("OnDragStart", function()
|
||||
if not this or not this.StartMoving then
|
||||
return
|
||||
end
|
||||
self:StartMoving()
|
||||
this:StartMoving()
|
||||
end)
|
||||
frame:SetScript("OnDragStop", function(self)
|
||||
self = self or this
|
||||
if not self then
|
||||
frame:SetScript("OnDragStop", function()
|
||||
if not this then
|
||||
return
|
||||
end
|
||||
|
||||
if self.StopMovingOrSizing then
|
||||
self:StopMovingOrSizing()
|
||||
if this.StopMovingOrSizing then
|
||||
this:StopMovingOrSizing()
|
||||
end
|
||||
|
||||
local point, _, _, x, y = self:GetPoint()
|
||||
local point, _, _, x, y = this:GetPoint()
|
||||
x = tonumber(x)
|
||||
y = tonumber(y)
|
||||
if not x or not y then
|
||||
@@ -991,12 +1209,14 @@ function Chronometer:CreateAnchor(text, r, g, b)
|
||||
|
||||
x = math.floor(x + 0.5)
|
||||
y = math.floor(y + 0.5)
|
||||
self:ClearAllPoints()
|
||||
self:SetPoint(point or "TOPLEFT", UIParent, point or "TOPLEFT", x, y)
|
||||
this:ClearAllPoints()
|
||||
this:SetPoint(point or "TOPLEFT", UIParent, point or "TOPLEFT", x, y)
|
||||
|
||||
if self.owner and self.owner.profile and type(self.owner.profile.barposition) == "table" then
|
||||
self.owner.profile.barposition.x = x
|
||||
self.owner.profile.barposition.y = y
|
||||
if this.owner and this.owner.profile and type(this.owner.profile.barposition) == "table" then
|
||||
this.owner.profile.barposition.point = point or "TOPLEFT"
|
||||
this.owner.profile.barposition.relativePoint = point or "TOPLEFT"
|
||||
this.owner.profile.barposition.x = x
|
||||
this.owner.profile.barposition.y = y
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -1042,9 +1262,11 @@ function Chronometer:SPELL_FADE(event, info)
|
||||
if not self.profile.fadeonfade then return end
|
||||
if info.skill == BS["Banish"] then return end
|
||||
if info.type == "fade" then
|
||||
-- Only act when the fade is on the player or on their target, not on other players
|
||||
if info.victim == ParserLib_SELF then
|
||||
return self:KillBar(info.skill)
|
||||
end
|
||||
if info.source and info.source ~= ParserLib_SELF then return end
|
||||
return self:KillBar(info.skill, info.victim)
|
||||
end
|
||||
end
|
||||
@@ -1052,6 +1274,9 @@ end
|
||||
function Chronometer:SPELL_PERIODIC(event, info)
|
||||
local aura, rank, unit, isgain
|
||||
|
||||
-- Ignore events not caused by the player (e.g. other players' DOTs/traps nearby)
|
||||
if info.source and info.source ~= ParserLib_SELF then return end
|
||||
|
||||
if info.type == "buff" then
|
||||
isgain = 1
|
||||
elseif info.type == "debuff" then
|
||||
@@ -1122,6 +1347,62 @@ function Chronometer:PLAYER_DEAD()
|
||||
end
|
||||
end
|
||||
|
||||
function Chronometer:UNIT_AURA(unit)
|
||||
local auraUnit = unit
|
||||
if (not auraUnit or auraUnit == "") and type(arg1) == "string" then
|
||||
auraUnit = arg1
|
||||
end
|
||||
if auraUnit ~= "pet" then
|
||||
return
|
||||
end
|
||||
if not (UnitExists and UnitExists("pet")) then
|
||||
return
|
||||
end
|
||||
|
||||
local feedSpell = BS and BS["Feed Pet"] or "Feed Pet"
|
||||
local timer = self.timers and self.timers[self.SPELL] and self.timers[self.SPELL][feedSpell]
|
||||
if not timer then
|
||||
return
|
||||
end
|
||||
|
||||
local hasFeedAura = false
|
||||
if type(UnitBuff) == "function" then
|
||||
for i = 1, 32 do
|
||||
local texture = UnitBuff("pet", i)
|
||||
if not texture then
|
||||
break
|
||||
end
|
||||
local tex = tostring(texture)
|
||||
if string.find(tex, "Ability_Hunter_BeastTraining", 1, true)
|
||||
or string.find(tex, "INV_Misc_Fork&Knife", 1, true)
|
||||
then
|
||||
hasFeedAura = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not hasFeedAura then
|
||||
return
|
||||
end
|
||||
|
||||
local petName = UnitName and UnitName("pet") or "none"
|
||||
if not petName or petName == "" then
|
||||
petName = "none"
|
||||
end
|
||||
|
||||
for i = 1, 20 do
|
||||
local bar = self.bars and self.bars[i]
|
||||
if bar and bar.id and bar.name == feedSpell then
|
||||
if bar.target == petName or bar.target == "none" then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:StartTimer(timer, feedSpell, petName)
|
||||
end
|
||||
|
||||
function Chronometer:UseAction(slot, clicked, onself)
|
||||
local name, rank = getActionSpell(slot)
|
||||
if name then
|
||||
|
||||
@@ -8,7 +8,6 @@ Documentation: http://web.archive.org/web/20070314234510/http://wowace.com/wiki/
|
||||
Description: A timer bars library.
|
||||
Dependencies: AceLibrary, AceOO-2.0, PaintChips-2.0
|
||||
]]
|
||||
local match = string.match
|
||||
local getn,setn,tinsert = table.getn, table.setn,table.insert
|
||||
local vmajor, vminor = "CandyBar-2.0", "$Revision: 16011 $"
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
local MTH_ChronometerModule = {
|
||||
name = "chronometer",
|
||||
enabled = true,
|
||||
version = "1.0.5",
|
||||
version = "1.4.0",
|
||||
events = {},
|
||||
initialized = false,
|
||||
}
|
||||
|
||||
|
||||
|
||||
local function MTH_CHRON_ApplyRuntimeEnabledState(enabled)
|
||||
if not MTH_ChronometerHunter then
|
||||
return
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
<!--
|
||||
MetaHunt: Experimental Ammunition Module Loader
|
||||
-->
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
||||
<Include file="engine.lua"/>
|
||||
</Ui>
|
||||
+862
-176
File diff suppressed because it is too large
Load Diff
@@ -80,7 +80,7 @@ FOM_Emotes = {
|
||||
["Foxes"] = {
|
||||
"Clever fox, clever snack choice.",
|
||||
},
|
||||
["Serpents (Cobra)"] = {
|
||||
["Serpents"] = {
|
||||
"No hissing with your mouth full.",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -53,16 +53,6 @@ function GFWUtils_temp_PrintOnce(message, interval, r, g, b)
|
||||
GFWUtils.PrintOnceCache[message] = GetTime();
|
||||
end
|
||||
|
||||
-- Prints a message to the chat frame only if Debug is set
|
||||
function GFWUtils_temp_DebugLog(message)
|
||||
if (GFWUtils.Debug) then
|
||||
if MTH and MTH.Print then
|
||||
MTH:Print(message, "debug")
|
||||
else
|
||||
DEFAULT_CHAT_FRAME:AddMessage(message, GFW_DEBUG_COLOR.r, GFW_DEBUG_COLOR.g, GFW_DEBUG_COLOR.b);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Prints a message in yellow to the floating messages frame
|
||||
function GFWUtils_temp_Note(message)
|
||||
@@ -177,8 +167,6 @@ if (G.Version == nil or (tonumber(G.Version) ~= nil and G.Version < GFWUTILS_THI
|
||||
|
||||
-- Constants
|
||||
GFW_FONT_COLOR = {r=0.25, g=1.0, b=1.0};
|
||||
GFW_DEBUG_COLOR = {r=1.0, g=0.75, b=0.25};
|
||||
G.Debug = false;
|
||||
|
||||
-- Functions
|
||||
G.Hilite = GFWUtils_temp_HiliteText;
|
||||
@@ -187,7 +175,6 @@ if (G.Version == nil or (tonumber(G.Version) ~= nil and G.Version < GFWUTILS_THI
|
||||
G.LtY = GFWUtils_temp_LightYellowText;
|
||||
G.Print = GFWUtils_temp_Print;
|
||||
G.PrintOnce = GFWUtils_temp_PrintOnce;
|
||||
G.DebugLog = GFWUtils_temp_DebugLog;
|
||||
G.Note = GFWUtils_temp_Note;
|
||||
G.FormatToPattern = GFWUtils_temp_FormatToPattern;
|
||||
G.Split = GFWUtils_temp_Split;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
------------------------------------------------------
|
||||
|
||||
-- Key bindings
|
||||
BINDING_HEADER_FEEDOMATIC = "Fizzwidget Feed-O-Matic";
|
||||
-- NOTE: BINDING_HEADER_FEEDOMATIC is defined in api/localization.lua via the MTH_L() system.
|
||||
BINDING_NAME_FEEDOMATIC = "Feed Pet";
|
||||
|
||||
-- Diet names. These should be the all-lowercase versions of the six diets returned from GetPetFoodTypes(). (Want to get them all nice and quick for your localization? Go tame a bear... they eat anything.)
|
||||
@@ -111,110 +111,6 @@ FOM_OptionsButtonText = {
|
||||
};
|
||||
------------------------------------------------------
|
||||
|
||||
if (GetLocale() == "frFR") then
|
||||
|
||||
-- Diet names. These should be the all-lowercase versions of the six diets returned from GetPetFoodTypes(). (Want to get them all nice and quick for your localization? Go tame a bear... they eat anything.)
|
||||
-- THESE STRINGS MUST BE LOCALIZED for Feed-O-Matic to work properly in other locales.
|
||||
FOM_DIET_MEAT = "viande";
|
||||
FOM_DIET_FISH = "poisson";
|
||||
FOM_DIET_BREAD = "pain";
|
||||
FOM_DIET_CHEESE = "fromage";
|
||||
FOM_DIET_FRUIT = "fruit";
|
||||
FOM_DIET_FUNGUS = "champignon";
|
||||
|
||||
-- If the player has a buff whose icon name contains "Ability_Mount" and whose name contains one of these substrings, we assume the player is mounted. We have to use this rather oblique way to check for mounted because some other buffs use the Ability_Mount_* icons. If these aren't localized, we may not recognize when the player is mounted and still try to feed the pet.
|
||||
FOM_MOUNT_NAME_SUBSTRINGS = { "kodo", "loup", "raptor", "steed", "cheval", "bélier", "tigre", "mécanotrotteur", };
|
||||
|
||||
-- It's not clear whether the 5th and 6th returns from GetItemInfo() are supposed to be localized... so we have localized keys for them just in case. If these aren't localized, we'll just needlessly search your ammo bags for food.
|
||||
FOM_AMMO_POUCH = "Giberne";
|
||||
FOM_QUIVER = "Carquois";
|
||||
|
||||
|
||||
-- From here on down, the localized strings are just for readability... they don't affect whether Feed-O-Matic works.
|
||||
|
||||
-- Two special diets; one is used for tracking food that provides a bonus (or at least, that you don't want to have fed to your pet when the 'savebonus' option is on), and another that's used in the chat-line interface for listing all diets.
|
||||
FOM_DIET_BONUS = "bonus";
|
||||
FOM_DIET_ALL = "tous";
|
||||
|
||||
-- Used in tooltips to indicate food quality.
|
||||
FOM_QUALITY_UNKNOWN = "%s peut le manger, mais n'a jamais essayé.";
|
||||
FOM_QUALITY_UNDER = "%s n'en mange plus désormais.";
|
||||
FOM_QUALITY_MIGHT = "%s en mangera peut-être.";
|
||||
FOM_QUALITY_WILL = "%s en mangera.";
|
||||
FOM_QUALITY_LIKE = "%s aime en manger.";
|
||||
FOM_QUALITY_LOVE = "%s adore en manger.";
|
||||
|
||||
-- User-visible errors
|
||||
FOM_ERROR_NO_PET = "Vous n'avez pas de familier.";
|
||||
FOM_ERROR_PET_DEAD = "Votre familier est mort.";
|
||||
FOM_ERROR_NO_FEEDABLE_PET = "Vous n'avez pas de familier capable de manger.";
|
||||
FOM_ERROR_FOOD_NOT_FOUND = "%s n'a pas trouvé de %s dans votre sac.";
|
||||
FOM_ERROR_NO_FOOD = "%s n'a pas trouvé de nourriture dans votre sac.";
|
||||
|
||||
-- Feeding status messages
|
||||
FOM_FEEDING_EAT_ANOTHER = "%s n'aime pas cette nourriture et va essayer autre chose..."
|
||||
FOM_FEEDING_FEED_ANOTHER = "cherche autre chose à donner à %s...";
|
||||
FOM_FEEDING_EAT = "%s mange un(e) %s.";
|
||||
FOM_FEEDING_FEED = "donne à %s à manger un(e) %s. ";
|
||||
|
||||
-- Beast family names
|
||||
BAT = "Chauve-souris";
|
||||
BEAR = "Ours";
|
||||
BOAR = "Sanglier";
|
||||
CARRION_BIRD = "Charognard";
|
||||
CAT = "Félin";
|
||||
CRAB = "Crabe";
|
||||
CROCOLISK = "Crocilisque";
|
||||
GORILLA = "Gorille";
|
||||
HYENA = "Hyène";
|
||||
OWL = "Chouette";
|
||||
RAPTOR = "Raptor";
|
||||
SCORPID = "Scorpide";
|
||||
SPIDER = "Araignée";
|
||||
TALLSTRIDER = "Haut-trotteur";
|
||||
TURTLE = "Tortue";
|
||||
WIND_SERPENT = "Serpent des vents";
|
||||
WOLF = "Loup";
|
||||
|
||||
FOM_PET_HUNGRY = "%s a faim!";
|
||||
FOM_PET_VERY_HUNGRY = "%s a très faim!";
|
||||
|
||||
FOM_OPTIONS_HEADER = "Feed-O-Matic Options";
|
||||
FOM_OPTIONS_GENERAL = "Options générales:";
|
||||
FOM_OPTIONS_FOOD_CHOICE = "Eviter la nourriture utilisée en cuisine:";
|
||||
FOM_OPTIONS_FEED_NOTIFY = "Prévenir lorsque votre familier est nourrit:";
|
||||
FOM_OPTIONS_WARNING = "Avertir quand votre familier a besoin d'être nourrit:";
|
||||
|
||||
FOM_KEEPOPEN = "Essayer de garder au moins";
|
||||
FOM_KEEPOPEN_SLOTS = "emplacements de sac libres";
|
||||
FOM_KEEPOPEN_INFO = "(Le familier choisira la nourriture des piles les plus petites, sans tenir compte de ses préférences.)";
|
||||
|
||||
FOM_OptionsButtonText = {
|
||||
["Tooltip"] = "Afficher l'avis de votre familier concernant la nourriture",
|
||||
["AvoidQuestFood"] = "Eviter la nourriture utile dans les quêtes",
|
||||
["AvoidBonusFood"] = "Eviter la nourriture donnant un bonus",
|
||||
["PreferHigherQuality"] = "Privilégier la nourriture que votre familier préfère",
|
||||
["Fallback"] = "Utiliser la nourriture évitée s'il n'y en a plus d'autres",
|
||||
["SaveForCook_All"] = "Toutes nourritures utilisées pour la cuisine",
|
||||
["SaveForCook_Green"] = "si elle est utilisée dans les recettes |cff3fbf3f\"faciles\"|r ou supérieures",
|
||||
["SaveForCook_Yellow"] = "si elle est utilisée dans les recettes |cffffff00\"moyennes\"|r ou supérieures",
|
||||
["SaveForCook_Orange"] = "si elle est utilisée dans les recettes |cffff7f3f\"difficiles\"|r",
|
||||
["SaveForCook_None"] = "Ne pas éviter la nourriture utilisée en cuisine",
|
||||
["IconWarning"] = "Clignoter l'icône",
|
||||
["TextWarning"] = "Afficher un texte",
|
||||
["AudioWarning"] = "Jouer un son",
|
||||
["AudioWarningBell"] = "Un son de cloche au lieu du cri du familier",
|
||||
["AlertEmote"] = "Via emote (visible par les autres)",
|
||||
["AlertChat"] = "Dans la fenêtre de discussion (visible uniquement par vous)",
|
||||
["AlertNone"] = "Ne pas prévenir",
|
||||
["LevelContent"] = "quand \"content\"",
|
||||
["LevelUnhappy"] = "quand \"mécontent\"",
|
||||
["LevelOff"] = "Ne pas avertir",
|
||||
};
|
||||
end
|
||||
|
||||
------------------------------------------------------
|
||||
|
||||
if (GetLocale() == "deDE") then
|
||||
|
||||
-- Diet names. These should be the all-lowercase versions of the six diets returned from GetPetFoodTypes(). (Want to get them all nice and quick for your localization? Go tame a bear... they eat anything.)
|
||||
@@ -279,26 +175,4 @@ if (GetLocale() == "deDE") then
|
||||
WIND_SERPENT = "Windnatter";
|
||||
-- WOLF = "Wolf"; -- same as enUS
|
||||
|
||||
end
|
||||
|
||||
------------------------------------------------------
|
||||
|
||||
if (GetLocale() == "koKR") then
|
||||
|
||||
-- Diet names. These should be the all-lowercase versions of the six diets returned from GetPetFoodTypes(). (Want to get them all nice and quick for your localization? Go tame a bear... they eat anything.)
|
||||
-- THESE STRINGS MUST BE LOCALIZED for Feed-O-Matic to work properly in other locales.
|
||||
-- FOM_DIET_MEAT = "meat";
|
||||
-- FOM_DIET_FISH = "fish";
|
||||
-- FOM_DIET_BREAD = "bread";
|
||||
-- FOM_DIET_CHEESE = "cheese";
|
||||
-- FOM_DIET_FRUIT = "fruit";
|
||||
-- FOM_DIET_FUNGUS = "fungus";
|
||||
|
||||
-- If the player has a buff whose icon name contains "Ability_Mount" and whose name contains one of these substrings, we assume the player is mounted. We have to use this rather oblique way to check for mounted because some other buffs use the Ability_Mount_* icons.
|
||||
-- FOM_MOUNT_NAME_SUBSTRINGS = { "kodo", "wolf", "raptor", "steed", "horse", "ram", "saber", "mechanostrider" };
|
||||
|
||||
-- It's not clear whether the 5th and 6th returns from GetItemInfo() are supposed to be localized... so we have localized keys for them just in case.
|
||||
-- FOM_AMMO_POUCH = "Ammo Pouch";
|
||||
FOM_QUIVER = "화살통";
|
||||
|
||||
end
|
||||
@@ -6,7 +6,7 @@
|
||||
local MTH_FeedOMatic = {
|
||||
name = "feedomatic",
|
||||
enabled = false,
|
||||
version = "1.0.5",
|
||||
version = "1.4.0",
|
||||
events = {
|
||||
"VARIABLES_LOADED",
|
||||
"MERCHANT_SHOW",
|
||||
@@ -32,13 +32,13 @@ local MTH_FeedOMatic = {
|
||||
}
|
||||
|
||||
local MTH_PETL_HOOK_BOUNDARY_KEY = "pet-lifecycle-hooks"
|
||||
local MTH_FeedOMatic_MerchantProbeFrame = nil
|
||||
local MTH_FOM_MerchantProbe = nil
|
||||
|
||||
function MTH_FeedOMatic_OnUpdate(elapsed)
|
||||
if not elapsed then
|
||||
return
|
||||
end
|
||||
if not (MTH and MTH.IsModuleEnabled and MTH:IsModuleEnabled("feedomatic", true)) then
|
||||
if not (MTH and MTH.IsModuleEnabled and MTH:IsModuleEnabled("feedomatic", false)) then
|
||||
return
|
||||
end
|
||||
if type(FOM_OnUpdate) == "function" then
|
||||
@@ -47,7 +47,7 @@ function MTH_FeedOMatic_OnUpdate(elapsed)
|
||||
end
|
||||
|
||||
local function MTH_FeedOMatic_GetRuntimeFrame()
|
||||
return getglobal("Frame_GFW_FeedOMatic")
|
||||
return getglobal("MTH_FOM_OnUpdateFrame")
|
||||
end
|
||||
|
||||
local function MTH_FeedOMatic_CaptureHookBoundary()
|
||||
@@ -112,10 +112,6 @@ local function MTH_FeedOMatic_CallLegacyOnEvent(evt, a1, a2, a3, a4, a5, a6, a7,
|
||||
event = oldEvent
|
||||
arg1, arg2, arg3, arg4, arg5 = oldArg1, oldArg2, oldArg3, oldArg4, oldArg5
|
||||
arg6, arg7, arg8, arg9 = oldArg6, oldArg7, oldArg8, oldArg9
|
||||
|
||||
if not ok and MTH and MTH.DebugPrint then
|
||||
MTH:DebugPrint("FeedOMatic legacy OnEvent call failed for event: " .. tostring(evt))
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_FeedOMatic_EnsureVariablesLoaded(module)
|
||||
@@ -166,8 +162,7 @@ end
|
||||
|
||||
local function MTH_FeedOMatic_Log(message, severity)
|
||||
if type(MTH_Log) == "function" then
|
||||
local logSeverity = severity or "debug"
|
||||
MTH_Log("[FeedOMatic] " .. tostring(message or ""), logSeverity)
|
||||
MTH_Log("[FeedOMatic] " .. tostring(message or ""), severity)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -198,10 +193,8 @@ local function MTH_FeedOMatic_DebugMerchantScan(sourceEvent)
|
||||
if type(rows) == "table" then
|
||||
dietCount = table.getn(rows)
|
||||
end
|
||||
MTH_FeedOMatic_Log("diet " .. tostring(dietName) .. ": " .. tostring(dietCount) .. " item(s)", "debug")
|
||||
if type(rows) == "table" then
|
||||
for _, row in rows do
|
||||
MTH_FeedOMatic_Log(" - [" .. tostring(row.id) .. "] " .. tostring(row.name) .. " (slot=" .. tostring(row.index) .. ")", "debug")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -209,34 +202,31 @@ local function MTH_FeedOMatic_DebugMerchantScan(sourceEvent)
|
||||
|
||||
if unknownCount > 0 and type(merchantFoods.unknown) == "table" then
|
||||
for _, row in merchantFoods.unknown do
|
||||
MTH_FeedOMatic_Log("unknown map: [" .. tostring(row.id) .. "] " .. tostring(row.name) .. " (slot=" .. tostring(row.index) .. ")", "debug")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function MTH_FeedOMatic_SetMerchantProbeEnabled(enabled)
|
||||
if not enabled then
|
||||
if MTH_FeedOMatic_MerchantProbeFrame then
|
||||
MTH_FeedOMatic_MerchantProbeFrame:UnregisterEvent("MERCHANT_SHOW")
|
||||
MTH_FeedOMatic_MerchantProbeFrame:UnregisterEvent("MERCHANT_UPDATE")
|
||||
if MTH_FOM_MerchantProbe then
|
||||
MTH_FOM_MerchantProbe:UnregisterEvent("MERCHANT_SHOW")
|
||||
MTH_FOM_MerchantProbe:UnregisterEvent("MERCHANT_UPDATE")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if not MTH_FeedOMatic_MerchantProbeFrame then
|
||||
MTH_FeedOMatic_MerchantProbeFrame = CreateFrame("Frame", "MTH_FeedOMatic_MerchantProbeFrame")
|
||||
MTH_FeedOMatic_MerchantProbeFrame:SetScript("OnEvent", function()
|
||||
if not MTH_FOM_MerchantProbe then
|
||||
MTH_FOM_MerchantProbe = CreateFrame("Frame", "MTH_FOM_MerchantProbe")
|
||||
MTH_FOM_MerchantProbe:SetScript("OnEvent", function()
|
||||
local evt = event
|
||||
if evt == "MERCHANT_SHOW" or evt == "MERCHANT_UPDATE" then
|
||||
MTH_FeedOMatic_Log("probe event received: " .. tostring(evt), "debug")
|
||||
MTH_FeedOMatic_DebugMerchantScan(evt)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
MTH_FeedOMatic_MerchantProbeFrame:RegisterEvent("MERCHANT_SHOW")
|
||||
MTH_FeedOMatic_MerchantProbeFrame:RegisterEvent("MERCHANT_UPDATE")
|
||||
MTH_FeedOMatic_Log("merchant probe enabled", "debug")
|
||||
MTH_FOM_MerchantProbe:RegisterEvent("MERCHANT_SHOW")
|
||||
MTH_FOM_MerchantProbe:RegisterEvent("MERCHANT_UPDATE")
|
||||
end
|
||||
|
||||
function MTH_FeedOMatic:init()
|
||||
@@ -277,8 +267,8 @@ function MTH_FeedOMatic:setEnabled(enabled)
|
||||
MTH_FeedOMatic_SyncSavedVariables()
|
||||
MTH_FeedOMatic_EnsureVariablesLoaded(self)
|
||||
MTH_FeedOMatic_SetMerchantProbeEnabled(false)
|
||||
if FOM_FeedButton then
|
||||
FOM_FeedButton:Show()
|
||||
if MTH_FOM_FeedButton then
|
||||
MTH_FOM_FeedButton:Show()
|
||||
end
|
||||
else
|
||||
-- Disable FeedOMatic functionality
|
||||
@@ -287,8 +277,8 @@ function MTH_FeedOMatic:setEnabled(enabled)
|
||||
FOM_State.ShouldFeed = false
|
||||
end
|
||||
MTH_FeedOMatic_SetMerchantProbeEnabled(false)
|
||||
if FOM_FeedButton then
|
||||
FOM_FeedButton:Hide()
|
||||
if MTH_FOM_FeedButton then
|
||||
MTH_FOM_FeedButton:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -316,8 +306,8 @@ function MTH_FeedOMatic:cleanup()
|
||||
FOM_State.ShouldFeed = false
|
||||
end
|
||||
MTH_FeedOMatic_SetMerchantProbeEnabled(false)
|
||||
if FOM_FeedButton then
|
||||
FOM_FeedButton:Hide();
|
||||
if MTH_FOM_FeedButton then
|
||||
MTH_FOM_FeedButton:Hide();
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ FeedOMatic Runtime Frame Loader (MetaHunt)
|
||||
Minimal runtime XML without legacy options window definitions.
|
||||
-->
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ ..\..\..\FrameXML\UI.xsd">
|
||||
<Frame name="Frame_GFW_FeedOMatic">
|
||||
<Frame name="MTH_FOM_OnUpdateFrame">
|
||||
<Scripts>
|
||||
<OnUpdate>
|
||||
if (MTH_FOM_OnUpdate) then
|
||||
@@ -15,7 +15,7 @@ Minimal runtime XML without legacy options window definitions.
|
||||
</Scripts>
|
||||
</Frame>
|
||||
|
||||
<GameTooltip name="FOMTooltip" frameStrata="TOOLTIP" hidden="true" parent="UIParent" inherits="GameTooltipTemplate">
|
||||
<GameTooltip name="MTH_FOM_Tooltip" frameStrata="TOOLTIP" hidden="true" parent="UIParent" inherits="GameTooltipTemplate">
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
this:SetOwner(UIParent, "ANCHOR_NONE");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,320 @@
|
||||
<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/">
|
||||
<Script file="MTH_ICU.lua"/>
|
||||
<!-- The main ICU frame -->
|
||||
<Frame name="ICU_Frame">
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
ICU_OnLoad();
|
||||
</OnLoad>
|
||||
<OnEvent>
|
||||
ICU_OnEvent(event);
|
||||
</OnEvent>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
<!-- A button template, to be inherited by each button -->
|
||||
<Frame name="ICU_PopupButtonTemplate" virtual="true">
|
||||
<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
|
||||
<BackgroundInsets>
|
||||
<AbsInset left="5" right="5" top="5" bottom="5"/>
|
||||
</BackgroundInsets>
|
||||
<TileSize>
|
||||
<AbsValue val="16"/>
|
||||
</TileSize>
|
||||
<EdgeSize>
|
||||
<AbsValue val="16"/>
|
||||
</EdgeSize>
|
||||
</Backdrop>
|
||||
<Size>
|
||||
<AbsDimension x="30" y="28"/>
|
||||
</Size>
|
||||
<Layers>
|
||||
<Layer level="ARTWORK">
|
||||
<Texture name="$parentButtonPortraitIcon">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Texture>
|
||||
<Texture name="$parentButtonClassIcon">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentButtonPortraitIcon">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Texture>
|
||||
<Texture name="$parentButtonRankIcon">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="RIGHT" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Texture>
|
||||
</Layer>
|
||||
</Layers>
|
||||
<Frames>
|
||||
<Button name="$parentButton" frameStrata="ARTWORK">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<HighlightTexture file="Interface\QuestFrame\UI-QuestTitleHighlight" alphaMode="ADD" setAllPoints="true" hidden="true"/>
|
||||
<NormalText inherits="GameFontNormal">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentClassIcon">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</NormalText>
|
||||
<HighlightText inherits="GameFontHighlight">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentClassIcon">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</HighlightText>
|
||||
<DisabledText inherits="GameFontDisable">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentClassIcon">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</DisabledText>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
ICU_ButtonClick();
|
||||
</OnClick>
|
||||
</Scripts>
|
||||
</Button>
|
||||
<StatusBar name="$parentButtonBar" inherits="TextStatusBar" frameStrata="ARTWORK">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentButtonClassIcon">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<BarTexture file="Interface\TargetingFrame\UI-TargetingFrame-BarFill"/>
|
||||
<BarColor r="0" g="0.8" b="0" a="0.7" />
|
||||
<!--
|
||||
<Layers>
|
||||
<Layer level="OVERLAY">
|
||||
<FontString name="$parentLeftText" inherits="GameFontNormal" text="">
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="10" y="1"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
<FontString name="$parentRightText" inherits="GameFontNormal" text="">
|
||||
<Anchors>
|
||||
<Anchor point="RIGHT" relativePoint="RIGHT">
|
||||
<Offset>
|
||||
<AbsDimension x="-10" y="1"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
</Layer>
|
||||
</Layers>
|
||||
!-->
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
this:SetMinMaxValues(0, 100);
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</StatusBar>
|
||||
<StatusBar name="$parentButtonBGBar" inherits="TextStatusBar" frameStrata="ARTWORK">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="TOP" relativeTo="$parentButtonBar">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<BarTexture file="Interface\TargetingFrame\UI-TargetingFrame-BarFill"/>
|
||||
<BarColor r="0" g="0.8" b="0" a="0.25"/>
|
||||
</StatusBar>
|
||||
</Frames>
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
this:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
|
||||
this:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
<!-- The popup menu -->
|
||||
<Frame name="ICU_Popup" toplevel="true" frameStrata="DIALOG" enableMouse="true" hidden="true" parent="UIParent">
|
||||
<Anchors>
|
||||
<Anchor point="TOPRIGHT" relativeTo="MinimapCluster" relativePoint="BOTTOMRIGHT"/>
|
||||
</Anchors>
|
||||
<!--
|
||||
<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
|
||||
<BackgroundInsets>
|
||||
<AbsInset left="5" right="5" top="5" bottom="5"/>
|
||||
</BackgroundInsets>
|
||||
<TileSize>
|
||||
<AbsValue val="16"/>
|
||||
</TileSize>
|
||||
<EdgeSize>
|
||||
<AbsValue val="16"/>
|
||||
</EdgeSize>
|
||||
</Backdrop>
|
||||
!-->
|
||||
<!-- Within the popup menu, the clickable buttons which to display text -->
|
||||
<Frames>
|
||||
<!-- Button 1 -->
|
||||
<Frame name="ICU_PopupButton1" inherits="ICU_PopupButtonTemplate" id="1" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-6"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 2 -->
|
||||
<Frame name="ICU_PopupButton2" inherits="ICU_PopupButtonTemplate" id="2" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton1" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 3 -->
|
||||
<Frame name="ICU_PopupButton3" inherits="ICU_PopupButtonTemplate" id="3" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton2" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 4 -->
|
||||
<Frame name="ICU_PopupButton4" inherits="ICU_PopupButtonTemplate" id="4" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton3" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 5 -->
|
||||
<Frame name="ICU_PopupButton5" inherits="ICU_PopupButtonTemplate" id="5" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton4" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 6 -->
|
||||
<Frame name="ICU_PopupButton6" inherits="ICU_PopupButtonTemplate" id="6" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton5" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 7 -->
|
||||
<Frame name="ICU_PopupButton7" inherits="ICU_PopupButtonTemplate" id="7" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton6" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 8 -->
|
||||
<Frame name="ICU_PopupButton8" inherits="ICU_PopupButtonTemplate" id="8" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton7" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 9 -->
|
||||
<Frame name="ICU_PopupButton9" inherits="ICU_PopupButtonTemplate" id="9" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton8" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
<!-- Frame 10 -->
|
||||
<Frame name="ICU_PopupButton10" inherits="ICU_PopupButtonTemplate" id="10" ICU_DATA="">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="ICU_PopupButton9" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="4"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame>
|
||||
</Frames>
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
<!-- This makes the dialog look like a normal tooltip -->
|
||||
this:SetBackdropBorderColor( TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b );
|
||||
this:SetBackdropColor( TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b );
|
||||
</OnLoad>
|
||||
<OnUpdate>
|
||||
ICU_Popup_OnUpdate();
|
||||
</OnUpdate>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
<Frame name="ICU_UpdateFrame" hidden="true">
|
||||
<Scripts>
|
||||
<OnUpdate>
|
||||
ICU_MouseOverUpdate();
|
||||
</OnUpdate>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
</Ui>
|
||||
@@ -0,0 +1,8 @@
|
||||
<!--
|
||||
ICU Module Loader
|
||||
Loads ICU runtime and wraps it in the MetaHunt module system.
|
||||
-->
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
||||
<Include file="MTH_ICU.xml"/>
|
||||
<Include file="module.lua"/>
|
||||
</Ui>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user