diff --git a/api/beastlore-scan.lua b/api/beastlore-scan.lua deleted file mode 100644 index 13e2240..0000000 --- a/api/beastlore-scan.lua +++ /dev/null @@ -1,8 +0,0 @@ ------------------------------------------------------- --- MetaHunt: Beast Lore Scanner (removed) ------------------------------------------------------- --- This file previously contained a feature that recorded --- unknown beasts to SavedVariables when scanned with --- Beast Lore. The feature has been removed; the static --- beast database (ds-beasts) is now the sole data source. ------------------------------------------------------- diff --git a/api/options-smartpet.lua b/api/options-smartpet.lua deleted file mode 100644 index bfb9b51..0000000 --- a/api/options-smartpet.lua +++ /dev/null @@ -1,321 +0,0 @@ ------------------------------------------------------- --- MetaHunt: SmartPet Options Panel --- TWoW 1.18.1 ------------------------------------------------------- - -local function MTH_SP_OPT_Ready() - return type(MTH_GetFrame) == "function" - and type(MTH_CreateCheckbox) == "function" - and type(MTH_CreateSlider) == "function" -end - -local function MTH_SP_OPT_GetCfg() - if not MTH_SmartPet or not MTH_SmartPet.GetConfig then return {} end - return MTH_SmartPet.GetConfig() -end - -local MTH_SP_OPT_built = false - --- Layout constants -local OPT_L = 16 -- left column X -local OPT_R = 290 -- right column X -local OPT_CW = 250 -- column width (for tip text wrapping) - --- Spacing constants -local GAP_SECTION = 34 -- between sections -local GAP_CB = 24 -- checkbox height (icon + text) -local GAP_TIP = 16 -- small tip text height -local GAP_BTN = 28 -- button height + margin -local GAP_SLIDER = 52 -- slider total height (label + track + value) -local GAP_CB_SLIDER = 40 -- checkbox to slider (checkbox + slider label above track) - --- Helper: checkbox with click handler -local function SP_CB(container, name, label, yOff, xOff, isChecked, onClick) - local cb = MTH_CreateCheckbox(container, name, label, yOff, xOff or OPT_L) - 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 SP_Header(container, text, yOff, xOff) - local fs = container:CreateFontString(nil, "ARTWORK", "GameFontNormal") - fs:SetPoint("TOPLEFT", container, "TOPLEFT", xOff or OPT_L, yOff) - fs:SetText("|cffff9900" .. text .. "|r") - return fs -end - --- Helper: small descriptive text -local function SP_Tip(container, text, yOff, xOff) - local fs = container:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall") - fs:SetPoint("TOPLEFT", container, "TOPLEFT", xOff or OPT_L, yOff) - fs:SetWidth(OPT_CW) - fs:SetJustifyH("LEFT") - fs:SetTextColor(0.4, 0.6, 1.0) - fs:SetText(text) - return fs -end - --- Taunt Mode cycle -local TAUNT_MODES = { "auto", "growl", "cower", "off" } -local TAUNT_LABELS = { - auto = "Auto (solo=Growl, tank=Cower)", - growl = "Always Growl", - cower = "Always Cower", - off = "Off (manual)", -} - -local function SP_NextTauntMode(current) - for i = 1, 4 do - if TAUNT_MODES[i] == current then - return TAUNT_MODES[math.mod(i, 4) + 1] - end - end - return "auto" -end - --- Channel cycle -local CHANNELS = { "SAY", "PARTY", "RAID", "GUILD" } - -local function SP_NextChannel(current) - for i = 1, 4 do - if CHANNELS[i] == current then - return CHANNELS[math.mod(i, 4) + 1] - end - end - return "SAY" -end - --- Build the UI -local function MTH_SP_OPT_BuildUI(container) - if MTH_SP_OPT_built then return end - MTH_SP_OPT_built = true - - local cfg = MTH_SP_OPT_GetCfg() - local api = MTH_SmartPet or {} - - --------------------------------------------------------------------------- - -- Title (large, like ExpAmmo) - --------------------------------------------------------------------------- - local title = container:CreateFontString(nil, "ARTWORK", "GameFontHighlightLarge") - title:SetPoint("TOPLEFT", container, "TOPLEFT", OPT_L, -16) - title:SetText("Smart Pet - Pet Combat Management") - - --------------------------------------------------------------------------- - -- Module enable checkbox - --------------------------------------------------------------------------- - local moduleEnabled = true - if MTH and MTH.IsModuleEnabled then - moduleEnabled = MTH:IsModuleEnabled("smartpet", false) and true or false - end - SP_CB(container, "MTH_SP_OPT_ModuleEnable", "Enable Smart Pet module", - -46, OPT_L, moduleEnabled, function(v) - if MTH and MTH.SetModuleEnabled then MTH:SetModuleEnabled("smartpet", v) end - end) - - -- Columns start below the module checkbox - local COL_TOP = -80 - - -- Vertical divider - local divider = container:CreateTexture(nil, "BACKGROUND") - divider:SetTexture(0.3, 0.3, 0.3, 0.6) - divider:SetPoint("TOPLEFT", container, "TOPLEFT", OPT_R - 14, COL_TOP) - divider:SetPoint("BOTTOMLEFT", container, "TOPLEFT", OPT_R - 14, -530) - divider:SetWidth(1) - - --------------------------------------------------------------------------- - -- LEFT COLUMN — Focus Management - --------------------------------------------------------------------------- - local y = COL_TOP - - SP_Header(container, "Focus Management", y) - y = y - 22 - - -- Smart Focus - SP_CB(container, "MTH_SP_OPT_SmartFocus", "Enable Smart Focus", - y, OPT_L, cfg.smartFocus, function(v) - if api.SetSmartFocus then api.SetSmartFocus(v) end - end) - y = y - GAP_CB - SP_Tip(container, "Budget pet focus across DPS abilities.", y) - y = y - GAP_TIP - SP_Tip(container, "|cff80ff80High focus|r — all DPS abilities ON.", y) - y = y - GAP_TIP - SP_Tip(container, "|cffffcc00Mid focus|r — expensive ability first, others wait.", y) - y = y - GAP_TIP - SP_Tip(container, "|cffff8080Low focus|r — cheapest ability always ON (never idle).", y) - y = y - GAP_TIP - SP_Tip(container, "Taunt cost is always reserved.", y) - y = y - GAP_SECTION - - --------------------------------------------------------------------------- - -- LEFT COLUMN — Taunt Management - --------------------------------------------------------------------------- - SP_Header(container, "Taunt Management", y) - y = y - GAP_TIP - SP_Tip(container, "Controls Growl/Cower autocast based on party.", y) - y = y - 22 - - local tauntBtn = CreateFrame("Button", "MTH_SP_OPT_TauntBtn", container, "UIPanelButtonTemplate") - tauntBtn:SetPoint("TOPLEFT", container, "TOPLEFT", OPT_L, y) - tauntBtn:SetWidth(250) - tauntBtn:SetHeight(22) - tauntBtn:SetText("Mode: " .. (TAUNT_LABELS[cfg.tauntMode] or "Auto")) - tauntBtn:SetScript("OnClick", function() - local c = MTH_SP_OPT_GetCfg() - local newMode = SP_NextTauntMode(c.tauntMode) - if api.SetTauntMode then api.SetTauntMode(newMode) end - this:SetText("Mode: " .. (TAUNT_LABELS[newMode] or newMode)) - end) - y = y - GAP_BTN - - SP_CB(container, "MTH_SP_OPT_PvpDetaunt", "PVP Auto-Detaunt", - y, OPT_L, cfg.pvpDetaunt, function(v) - if api.SetPvpDetaunt then api.SetPvpDetaunt(v) end - end) - y = y - GAP_SECTION - - --------------------------------------------------------------------------- - -- LEFT COLUMN — CC-Break Prevention - --------------------------------------------------------------------------- - SP_Header(container, "CC-Break Prevention", y) - y = y - 22 - - SP_CB(container, "MTH_SP_OPT_CcBreak", "Check for breakable CC", - y, OPT_L, cfg.ccBreakCheck, function(v) - if api.SetCcBreakCheck then api.SetCcBreakCheck(v) end - end) - y = y - GAP_CB - - local ccLabels = { block = "Block attack", warn = "Warn only" } - local ccModeBtn = CreateFrame("Button", "MTH_SP_OPT_CcModeBtn", container, "UIPanelButtonTemplate") - ccModeBtn:SetPoint("TOPLEFT", container, "TOPLEFT", OPT_L + 20, y) - ccModeBtn:SetWidth(180) - ccModeBtn:SetHeight(20) - ccModeBtn:SetText("CC Mode: " .. (ccLabels[cfg.ccBreakMode] or "Block")) - ccModeBtn:SetScript("OnClick", function() - local c = MTH_SP_OPT_GetCfg() - local newMode = (c.ccBreakMode == "block") and "warn" or "block" - if api.SetCcBreakMode then api.SetCcBreakMode(newMode) end - this:SetText("CC Mode: " .. (ccLabels[newMode] or newMode)) - end) - y = y - GAP_SECTION - - --------------------------------------------------------------------------- - -- RIGHT COLUMN — General - --------------------------------------------------------------------------- - local ry = COL_TOP - - -- The Button - SP_Header(container, "The Button", ry, OPT_R) - ry = ry - 22 - - SP_CB(container, "MTH_SP_OPT_TheButton", "Enable The Button keybind", - ry, OPT_R, cfg.theButton, function(v) - if api.SetTheButton then api.SetTheButton(v) end - end) - ry = ry - GAP_CB - SP_Tip(container, "Enemy=attack, friendly=assist, none=recall.", ry, OPT_R) - ry = ry - GAP_SECTION - - -- Rush on Attack - SP_CB(container, "MTH_SP_OPT_Rush", "Rush on initial attack", - ry, OPT_R, cfg.rushOnAttack, function(v) - if api.SetRushOnAttack then api.SetRushOnAttack(v) end - end) - ry = ry - GAP_CB - SP_Tip(container, "Charge / Dash / Dive when pet is sent to attack.", ry, OPT_R) - ry = ry - GAP_SECTION - - -- NoChase - SP_CB(container, "MTH_SP_OPT_NoChase", "NoChase (recall on mob flee)", - ry, OPT_R, cfg.noChase, function(v) - if api.SetNoChase then api.SetNoChase(v) end - end) - ry = ry - GAP_CB - SP_Tip(container, "Recall pet when target attempts to flee.", ry, OPT_R) - ry = ry - GAP_SECTION - - -- AutoCower - SP_Header(container, "AutoCower", ry, OPT_R) - ry = ry - 22 - - SP_CB(container, "MTH_SP_OPT_AutoCower", "Enable AutoCower on low HP", - ry, OPT_R, cfg.autoCower, function(v) - if api.SetAutoCower then api.SetAutoCower(v) end - end) - ry = ry - GAP_CB_SLIDER - - local acSlider = MTH_CreateSlider(container, "MTH_SP_OPT_AutoCowerSlider", - "HP Threshold (%)", 5, 80, 5, ry) - if acSlider then - acSlider:ClearAllPoints() - acSlider:SetPoint("TOPLEFT", container, "TOPLEFT", OPT_R, ry) - acSlider:SetWidth(200) - acSlider:SetValue(cfg.autoCowerPct or 30) - local valText = getglobal("MTH_SP_OPT_AutoCowerSliderValue") - if valText then valText:SetText(tostring(cfg.autoCowerPct or 30)) end - acSlider.onChange = function(val) - if api.SetAutoCowerPct then api.SetAutoCowerPct(val) end - end - end - ry = ry - GAP_SLIDER - - -- AutoWarn - SP_Header(container, "AutoWarn", ry, OPT_R) - ry = ry - 22 - - SP_CB(container, "MTH_SP_OPT_AutoWarn", "Warn when pet HP is low", - ry, OPT_R, cfg.autoWarn, function(v) - if api.SetAutoWarn then api.SetAutoWarn(v) end - end) - ry = ry - GAP_CB_SLIDER - - local awSlider = MTH_CreateSlider(container, "MTH_SP_OPT_AutoWarnSlider", - "HP Threshold (%)", 5, 60, 5, ry) - if awSlider then - awSlider:ClearAllPoints() - awSlider:SetPoint("TOPLEFT", container, "TOPLEFT", OPT_R, ry) - awSlider:SetWidth(200) - awSlider:SetValue(cfg.autoWarnPct or 20) - local valText = getglobal("MTH_SP_OPT_AutoWarnSliderValue") - if valText then valText:SetText(tostring(cfg.autoWarnPct or 20)) end - awSlider.onChange = function(val) - if api.SetAutoWarnPct then api.SetAutoWarnPct(val) end - end - end - ry = ry - GAP_SLIDER - - local chanBtn = CreateFrame("Button", "MTH_SP_OPT_ChanBtn", container, "UIPanelButtonTemplate") - chanBtn:SetPoint("TOPLEFT", container, "TOPLEFT", OPT_R, ry) - chanBtn:SetWidth(180) - chanBtn:SetHeight(22) - chanBtn:SetText("Channel: " .. (cfg.autoWarnChannel or "SAY")) - chanBtn:SetScript("OnClick", function() - local c = MTH_SP_OPT_GetCfg() - local newChan = SP_NextChannel(c.autoWarnChannel or "SAY") - if api.SetAutoWarnChannel then api.SetAutoWarnChannel(newChan) end - this:SetText("Channel: " .. newChan) - end) - ry = ry - GAP_CB - SP_Tip(container, "Chat channel for low-HP warnings.", ry, OPT_R) -end - --- Public setup function (called by options-shell.lua) -function MTH_SetupSmartPetOptions() - if not MTH_SP_OPT_Ready() then return end - local container = MTH_GetFrame("MetaHuntOptionsSmartPet") - if not container then return end - local ok, err = pcall(MTH_SP_OPT_BuildUI, container) - if not ok then - if MTH and MTH.Print then - MTH:Print("[SmartPet Options] " .. tostring(err), "error") - end - MTH_SP_OPT_built = false - end -end diff --git a/data/ds-pet-spells-acquire.lua b/data/ds-pet-spells-acquire.lua deleted file mode 100644 index df0a7d1..0000000 --- a/data/ds-pet-spells-acquire.lua +++ /dev/null @@ -1,140 +0,0 @@ --- 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 diff --git a/data/ds-stable-prices.lua b/data/ds-stable-prices.lua deleted file mode 100644 index 9bced7e..0000000 --- a/data/ds-stable-prices.lua +++ /dev/null @@ -1,41 +0,0 @@ --- 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", - }, -} diff --git a/data/ds-zones-dbc.lua b/data/ds-zones-dbc.lua deleted file mode 100644 index d784623..0000000 --- a/data/ds-zones-dbc.lua +++ /dev/null @@ -1,97 +0,0 @@ --- 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 diff --git a/data/ds-zones-new-dbc.lua b/data/ds-zones-new-dbc.lua deleted file mode 100644 index 12985b4..0000000 --- a/data/ds-zones-new-dbc.lua +++ /dev/null @@ -1,1475 +0,0 @@ --- MetaHunt: Zones present in DBC but not in MTH_DS_Zones (TWoW custom zones) --- AUTO-GENERATED by .tools — do not edit by hand. --- Source DBC(s): WorldMapArea.dbc, AreaTable.dbc --- Generated: 2026-03-20 13:57 UTC - -if not MTH_DS_Zones then MTH_DS_Zones = {} end - --- DBC WMA ID=4 MapID=1 'Durotar' -if not MTH_DS_Zones[14] then - MTH_DS_Zones[14] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 14, - ["dbcMapId"] = 1, - ["dbcName"] = "Durotar", - ["worldBounds"] = { left=-1962.50, right=-7250.00, top=1808.33, bottom=-1716.67 }, - ["names"] = { ["enUS"] = "Durotar", ["esES"] = "Durotar", ["ptBR"] = "Durotar", ["zhCN"] = "杜隆塔尔" }, - } -end - --- DBC WMA ID=9 MapID=1 'Mulgore' -if not MTH_DS_Zones[215] then - MTH_DS_Zones[215] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 215, - ["dbcMapId"] = 1, - ["dbcName"] = "Mulgore", - ["worldBounds"] = { left=2047.92, right=-3089.58, top=-272.92, bottom=-3697.92 }, - ["names"] = { ["enUS"] = "Mulgore", ["esES"] = "Mulgore", ["ptBR"] = "Mulgore", ["zhCN"] = "莫高雷" }, - } -end - --- DBC WMA ID=11 MapID=1 'Barrens' -if not MTH_DS_Zones[17] then - MTH_DS_Zones[17] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 17, - ["dbcMapId"] = 1, - ["dbcName"] = "Barrens", - ["worldBounds"] = { left=2622.92, right=-7510.42, top=1612.50, bottom=-5143.75 }, - ["names"] = { ["enUS"] = "The Barrens", ["esES"] = "Los Baldíos", ["ptBR"] = "Os Barrens", ["zhCN"] = "贫瘠之地" }, - } -end - --- DBC WMA ID=13 MapID=1 'Kalimdor' -if not MTH_DS_Zones[0] then - MTH_DS_Zones[0] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 0, - ["dbcMapId"] = 1, - ["dbcName"] = "Kalimdor", - ["worldBounds"] = { left=17066.60, right=-19733.21, top=12799.90, bottom=-11733.30 }, - ["names"] = { ["enUS"] = "Kalimdor" }, - } -end - --- DBC WMA ID=14 MapID=0 'Azeroth' -if not MTH_DS_Zones[0] then - MTH_DS_Zones[0] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 0, - ["dbcMapId"] = 0, - ["dbcName"] = "Azeroth", - ["worldBounds"] = { left=16000.00, right=-19199.90, top=7466.60, bottom=-16000.00 }, - ["names"] = { ["enUS"] = "Azeroth" }, - } -end - --- DBC WMA ID=15 MapID=0 'Alterac' -if not MTH_DS_Zones[36] then - MTH_DS_Zones[36] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 36, - ["dbcMapId"] = 0, - ["dbcName"] = "Alterac", - ["worldBounds"] = { left=783.33, right=-2016.67, top=1500.00, bottom=-366.67 }, - ["names"] = { ["enUS"] = "Alterac Mountains", ["esES"] = "Montañas de Alterac", ["ptBR"] = "Montanhas de Alterac", ["zhCN"] = "奥特兰克山脉" }, - } -end - --- DBC WMA ID=16 MapID=0 'Arathi' -if not MTH_DS_Zones[45] then - MTH_DS_Zones[45] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 45, - ["dbcMapId"] = 0, - ["dbcName"] = "Arathi", - ["worldBounds"] = { left=-866.67, right=-4466.67, top=-133.33, bottom=-2533.33 }, - ["names"] = { ["enUS"] = "Arathi Highlands", ["esES"] = "Tierras Altas de Arathi", ["ptBR"] = "Planalto Arathi", ["zhCN"] = "阿拉希高地" }, - } -end - --- DBC WMA ID=17 MapID=0 'Badlands' -if not MTH_DS_Zones[3] then - MTH_DS_Zones[3] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 3, - ["dbcMapId"] = 0, - ["dbcName"] = "Badlands", - ["worldBounds"] = { left=-2079.17, right=-4566.67, top=-5889.58, bottom=-7547.92 }, - ["names"] = { ["enUS"] = "Badlands", ["esES"] = "Tierras Inhóspitas", ["ptBR"] = "Ermos", ["zhCN"] = "荒芜之地" }, - } -end - --- DBC WMA ID=19 MapID=0 'BlastedLands' -if not MTH_DS_Zones[4] then - MTH_DS_Zones[4] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 4, - ["dbcMapId"] = 0, - ["dbcName"] = "BlastedLands", - ["worldBounds"] = { left=-1241.67, right=-4591.67, top=-10566.67, bottom=-12800.00 }, - ["names"] = { ["enUS"] = "Blasted Lands", ["esES"] = "Tierras Devastadas", ["ptBR"] = "Terras Devastadas", ["zhCN"] = "诅咒之地" }, - } -end - --- DBC WMA ID=20 MapID=0 'Tirisfal' -if not MTH_DS_Zones[85] then - MTH_DS_Zones[85] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 85, - ["dbcMapId"] = 0, - ["dbcName"] = "Tirisfal", - ["worldBounds"] = { left=3033.33, right=-1485.42, top=3837.50, bottom=825.00 }, - ["names"] = { ["enUS"] = "Tirisfal Glades", ["esES"] = "Claros de Tirisfal", ["ptBR"] = "Os Bosques de Tirisfal", ["zhCN"] = "提瑞斯法林地" }, - } -end - --- DBC WMA ID=21 MapID=0 'Silverpine' -if not MTH_DS_Zones[130] then - MTH_DS_Zones[130] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 130, - ["dbcMapId"] = 0, - ["dbcName"] = "Silverpine", - ["worldBounds"] = { left=3450.00, right=-750.00, top=1666.67, bottom=-1133.33 }, - ["names"] = { ["enUS"] = "Silverpine Forest", ["esES"] = "Bosque de Argénteos", ["ptBR"] = "Floresta Silverpine", ["zhCN"] = "银松森林" }, - } -end - --- DBC WMA ID=22 MapID=0 'WesternPlaguelands' -if not MTH_DS_Zones[28] then - MTH_DS_Zones[28] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 28, - ["dbcMapId"] = 0, - ["dbcName"] = "WesternPlaguelands", - ["worldBounds"] = { left=416.67, right=-3883.33, top=3366.67, bottom=500.00 }, - ["names"] = { ["enUS"] = "Western Plaguelands", ["esES"] = "Tierras de la Peste del Oeste", ["ptBR"] = "Plaguelands Ocidentais", ["zhCN"] = "西瘟疫之地" }, - } -end - --- DBC WMA ID=23 MapID=0 'EasternPlaguelands' -if not MTH_DS_Zones[139] then - MTH_DS_Zones[139] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 139, - ["dbcMapId"] = 0, - ["dbcName"] = "EasternPlaguelands", - ["worldBounds"] = { left=-2185.42, right=-6056.25, top=3800.00, bottom=1218.75 }, - ["names"] = { ["enUS"] = "Eastern Plaguelands", ["esES"] = "Tierras de la Peste del Este", ["ptBR"] = "Terras Pestilentas Orientais", ["zhCN"] = "东瘟疫之地" }, - } -end - --- DBC WMA ID=24 MapID=0 'Hilsbrad' -if not MTH_DS_Zones[267] then - MTH_DS_Zones[267] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 267, - ["dbcMapId"] = 0, - ["dbcName"] = "Hilsbrad", - ["worldBounds"] = { left=1066.67, right=-2133.33, top=400.00, bottom=-1733.33 }, - ["names"] = { ["enUS"] = "Hillsbrad Foothills", ["esES"] = "Laderas de Trabalomas", ["ptBR"] = "Contrafortes de Eira dos Montes", ["zhCN"] = "希尔斯布莱德丘陵" }, - } -end - --- DBC WMA ID=26 MapID=0 'Hinterlands' -if not MTH_DS_Zones[47] then - MTH_DS_Zones[47] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 47, - ["dbcMapId"] = 0, - ["dbcName"] = "Hinterlands", - ["worldBounds"] = { left=-1575.00, right=-5425.00, top=1466.67, bottom=-1100.00 }, - ["names"] = { ["enUS"] = "The Hinterlands", ["esES"] = "Tierras del Interior", ["ptBR"] = "As Terras Interiores", ["zhCN"] = "辛特兰" }, - } -end - --- DBC WMA ID=27 MapID=0 'DunMorogh' -if not MTH_DS_Zones[1] then - MTH_DS_Zones[1] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 1, - ["dbcMapId"] = 0, - ["dbcName"] = "DunMorogh", - ["worldBounds"] = { left=1802.08, right=-3122.92, top=-3877.08, bottom=-7160.42 }, - ["names"] = { ["enUS"] = "Dun Morogh", ["esES"] = "Dun Morogh", ["ptBR"] = "Dun Morogh", ["zhCN"] = "丹莫罗" }, - } -end - --- DBC WMA ID=28 MapID=0 'SearingGorge' -if not MTH_DS_Zones[51] then - MTH_DS_Zones[51] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 51, - ["dbcMapId"] = 0, - ["dbcName"] = "SearingGorge", - ["worldBounds"] = { left=-322.92, right=-2554.17, top=-6100.00, bottom=-7587.50 }, - ["names"] = { ["enUS"] = "Searing Gorge", ["esES"] = "La Garganta de Fuego", ["ptBR"] = "Desfiladeiro Searing", ["zhCN"] = "灼热峡谷" }, - } -end - --- DBC WMA ID=29 MapID=0 'BurningSteppes' -if not MTH_DS_Zones[46] then - MTH_DS_Zones[46] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 46, - ["dbcMapId"] = 0, - ["dbcName"] = "BurningSteppes", - ["worldBounds"] = { left=-266.67, right=-3195.83, top=-7031.25, bottom=-8983.33 }, - ["names"] = { ["enUS"] = "Burning Steppes", ["esES"] = "Las Estepas Ardientes", ["ptBR"] = "Estepes Ardentes", ["zhCN"] = "燃烧平原" }, - } -end - --- DBC WMA ID=30 MapID=0 'Elwynn' -if not MTH_DS_Zones[12] then - MTH_DS_Zones[12] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 12, - ["dbcMapId"] = 0, - ["dbcName"] = "Elwynn", - ["worldBounds"] = { left=1535.42, right=-1935.42, top=-7939.58, bottom=-10254.17 }, - ["names"] = { ["enUS"] = "Elwynn Forest", ["esES"] = "Bosque de Elwynn", ["ptBR"] = "Floresta de Elwynn", ["zhCN"] = "艾尔文森林" }, - } -end - --- DBC WMA ID=32 MapID=0 'DeadwindPass' -if not MTH_DS_Zones[41] then - MTH_DS_Zones[41] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 41, - ["dbcMapId"] = 0, - ["dbcName"] = "DeadwindPass", - ["worldBounds"] = { left=-833.33, right=-3333.33, top=-9866.67, bottom=-11533.33 }, - ["names"] = { ["enUS"] = "Deadwind Pass", ["esES"] = "Paso de la Muerte", ["ptBR"] = "Desfiladeiro da Morte", ["zhCN"] = "逆风小径" }, - } -end - --- DBC WMA ID=34 MapID=0 'Duskwood' -if not MTH_DS_Zones[10] then - MTH_DS_Zones[10] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 10, - ["dbcMapId"] = 0, - ["dbcName"] = "Duskwood", - ["worldBounds"] = { left=833.33, right=-1866.67, top=-9716.67, bottom=-11516.67 }, - ["names"] = { ["enUS"] = "Duskwood", ["esES"] = "Bosque del Ocaso", ["ptBR"] = "Floresta do Crepúsculo", ["zhCN"] = "暮色森林" }, - } -end - --- DBC WMA ID=35 MapID=0 'LochModan' -if not MTH_DS_Zones[38] then - MTH_DS_Zones[38] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 38, - ["dbcMapId"] = 0, - ["dbcName"] = "LochModan", - ["worldBounds"] = { left=-1993.75, right=-4752.08, top=-4487.50, bottom=-6327.08 }, - ["names"] = { ["enUS"] = "Loch Modan", ["esES"] = "Loch Modan", ["ptBR"] = "Loch Modan", ["zhCN"] = "洛克莫丹" }, - } -end - --- DBC WMA ID=36 MapID=0 'Redridge' -if not MTH_DS_Zones[44] then - MTH_DS_Zones[44] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 44, - ["dbcMapId"] = 0, - ["dbcName"] = "Redridge", - ["worldBounds"] = { left=-1570.83, right=-3741.67, top=-8575.00, bottom=-10022.92 }, - ["names"] = { ["enUS"] = "Redridge Mountains", ["esES"] = "Montañas Crestagrana", ["ptBR"] = "Montanhas Redridge", ["zhCN"] = "赤脊山" }, - } -end - --- DBC WMA ID=37 MapID=0 'Stranglethorn' -if not MTH_DS_Zones[33] then - MTH_DS_Zones[33] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 33, - ["dbcMapId"] = 0, - ["dbcName"] = "Stranglethorn", - ["worldBounds"] = { left=2220.83, right=-4160.42, top=-11168.75, bottom=-15422.92 }, - ["names"] = { ["enUS"] = "Stranglethorn Vale", ["esES"] = "Vega de Tuercespina", ["ptBR"] = "Vale Stranglethorn", ["zhCN"] = "荆棘谷" }, - } -end - --- DBC WMA ID=38 MapID=0 'SwampOfSorrows' -if not MTH_DS_Zones[8] then - MTH_DS_Zones[8] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 8, - ["dbcMapId"] = 0, - ["dbcName"] = "SwampOfSorrows", - ["worldBounds"] = { left=-2222.92, right=-4516.67, top=-9620.83, bottom=-11150.00 }, - ["names"] = { ["enUS"] = "Swamp of Sorrows", ["esES"] = "Pantano de las Penas", ["ptBR"] = "Pantano das Tristezas", ["zhCN"] = "悲伤沼泽" }, - } -end - --- DBC WMA ID=39 MapID=0 'Westfall' -if not MTH_DS_Zones[40] then - MTH_DS_Zones[40] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 40, - ["dbcMapId"] = 0, - ["dbcName"] = "Westfall", - ["worldBounds"] = { left=3016.67, right=-483.33, top=-9400.00, bottom=-11733.33 }, - ["names"] = { ["enUS"] = "Westfall", ["esES"] = "Páramos del Poniente", ["ptBR"] = "Westfall", ["zhCN"] = "西部荒野" }, - } -end - --- DBC WMA ID=40 MapID=0 'Wetlands' -if not MTH_DS_Zones[11] then - MTH_DS_Zones[11] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 11, - ["dbcMapId"] = 0, - ["dbcName"] = "Wetlands", - ["worldBounds"] = { left=-389.58, right=-4525.00, top=-2147.92, bottom=-4904.17 }, - ["names"] = { ["enUS"] = "Wetlands", ["esES"] = "Los Humedales", ["ptBR"] = "Pântanos", ["zhCN"] = "湿地" }, - } -end - --- DBC WMA ID=41 MapID=1 'Teldrassil' -if not MTH_DS_Zones[141] then - MTH_DS_Zones[141] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 141, - ["dbcMapId"] = 1, - ["dbcName"] = "Teldrassil", - ["worldBounds"] = { left=3814.58, right=-1277.08, top=11831.25, bottom=8437.50 }, - ["names"] = { ["enUS"] = "Teldrassil", ["esES"] = "Teldrassil", ["ptBR"] = "Teldrassil", ["zhCN"] = "泰达希尔" }, - } -end - --- DBC WMA ID=42 MapID=1 'Darkshore' -if not MTH_DS_Zones[148] then - MTH_DS_Zones[148] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 148, - ["dbcMapId"] = 1, - ["dbcName"] = "Darkshore", - ["worldBounds"] = { left=2941.67, right=-3608.33, top=8333.33, bottom=3966.67 }, - ["names"] = { ["enUS"] = "Darkshore", ["esES"] = "Costa Oscura", ["ptBR"] = "Costa Negra", ["zhCN"] = "黑海岸" }, - } -end - --- DBC WMA ID=43 MapID=1 'Ashenvale' -if not MTH_DS_Zones[331] then - MTH_DS_Zones[331] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 331, - ["dbcMapId"] = 1, - ["dbcName"] = "Ashenvale", - ["worldBounds"] = { left=1700.00, right=-4066.67, top=4672.92, bottom=829.17 }, - ["names"] = { ["enUS"] = "Ashenvale", ["esES"] = "Vallefresno", ["ptBR"] = "Vale das Cinzas", ["zhCN"] = "灰谷" }, - } -end - --- DBC WMA ID=61 MapID=1 'ThousandNeedles' -if not MTH_DS_Zones[400] then - MTH_DS_Zones[400] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 400, - ["dbcMapId"] = 1, - ["dbcName"] = "ThousandNeedles", - ["worldBounds"] = { left=-433.33, right=-4833.33, top=-3966.67, bottom=-6900.00 }, - ["names"] = { ["enUS"] = "Thousand Needles", ["esES"] = "Las Mil Agujas", ["ptBR"] = "As Mil Agulhas", ["zhCN"] = "千针石林" }, - } -end - --- DBC WMA ID=81 MapID=1 'StonetalonMountains' -if not MTH_DS_Zones[406] then - MTH_DS_Zones[406] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 406, - ["dbcMapId"] = 1, - ["dbcName"] = "StonetalonMountains", - ["worldBounds"] = { left=3245.83, right=-1637.50, top=2916.67, bottom=-339.58 }, - ["names"] = { ["enUS"] = "Stonetalon Mountains", ["esES"] = "Montañas de Colina Roca", ["ptBR"] = "Montanhas Stonetalon", ["zhCN"] = "石爪山脉" }, - } -end - --- DBC WMA ID=101 MapID=1 'Desolace' -if not MTH_DS_Zones[405] then - MTH_DS_Zones[405] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 405, - ["dbcMapId"] = 1, - ["dbcName"] = "Desolace", - ["worldBounds"] = { left=4233.33, right=-262.50, top=452.08, bottom=-2545.83 }, - ["names"] = { ["enUS"] = "Desolace", ["esES"] = "Desolace", ["ptBR"] = "Desolação", ["zhCN"] = "凄凉之地" }, - } -end - --- DBC WMA ID=121 MapID=1 'Feralas' -if not MTH_DS_Zones[357] then - MTH_DS_Zones[357] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 357, - ["dbcMapId"] = 1, - ["dbcName"] = "Feralas", - ["worldBounds"] = { left=5441.67, right=-1508.33, top=-2366.67, bottom=-7000.00 }, - ["names"] = { ["enUS"] = "Feralas", ["esES"] = "Feralas", ["ptBR"] = "Feralas", ["zhCN"] = "菲拉斯" }, - } -end - --- DBC WMA ID=141 MapID=1 'Dustwallow' -if not MTH_DS_Zones[15] then - MTH_DS_Zones[15] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 15, - ["dbcMapId"] = 1, - ["dbcName"] = "Dustwallow", - ["worldBounds"] = { left=-975.00, right=-6225.00, top=-2033.33, bottom=-5533.33 }, - ["names"] = { ["enUS"] = "Dustwallow Marsh", ["esES"] = "Marjal Revolcafango", ["ptBR"] = "Pântano Vadeante", ["zhCN"] = "尘泥沼泽" }, - } -end - --- DBC WMA ID=161 MapID=1 'Tanaris' -if not MTH_DS_Zones[440] then - MTH_DS_Zones[440] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 440, - ["dbcMapId"] = 1, - ["dbcName"] = "Tanaris", - ["worldBounds"] = { left=-218.75, right=-7118.75, top=-5875.00, bottom=-10475.00 }, - ["names"] = { ["enUS"] = "Tanaris", ["esES"] = "Tanaris", ["ptBR"] = "Tanaris", ["zhCN"] = "塔纳利斯" }, - } -end - --- DBC WMA ID=181 MapID=1 'Aszhara' -if not MTH_DS_Zones[16] then - MTH_DS_Zones[16] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 16, - ["dbcMapId"] = 1, - ["dbcName"] = "Aszhara", - ["worldBounds"] = { left=-3277.08, right=-8347.92, top=5341.67, bottom=1960.42 }, - ["names"] = { ["enUS"] = "Azshara", ["esES"] = "Azshara", ["ptBR"] = "Azshara", ["zhCN"] = "艾萨拉" }, - } -end - --- DBC WMA ID=182 MapID=1 'Felwood' -if not MTH_DS_Zones[361] then - MTH_DS_Zones[361] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 361, - ["dbcMapId"] = 1, - ["dbcName"] = "Felwood", - ["worldBounds"] = { left=1641.67, right=-4108.33, top=7133.33, bottom=3300.00 }, - ["names"] = { ["enUS"] = "Felwood", ["esES"] = "Frondavil", ["ptBR"] = "Selva Maleva", ["zhCN"] = "费伍德森林" }, - } -end - --- DBC WMA ID=201 MapID=1 'UngoroCrater' -if not MTH_DS_Zones[490] then - MTH_DS_Zones[490] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 490, - ["dbcMapId"] = 1, - ["dbcName"] = "UngoroCrater", - ["worldBounds"] = { left=533.33, right=-3166.67, top=-5966.67, bottom=-8433.33 }, - ["names"] = { ["enUS"] = "Un'Goro Crater", ["esES"] = "Crater Un'Goro", ["ptBR"] = "Cratera Un'Goro", ["zhCN"] = "安戈洛环形山" }, - } -end - --- DBC WMA ID=241 MapID=1 'Moonglade' -if not MTH_DS_Zones[493] then - MTH_DS_Zones[493] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 493, - ["dbcMapId"] = 1, - ["dbcName"] = "Moonglade", - ["worldBounds"] = { left=-1381.25, right=-3689.58, top=8491.67, bottom=6952.08 }, - ["names"] = { ["enUS"] = "Moonglade", ["esES"] = "Claro de la Luna", ["ptBR"] = "Moonglade", ["zhCN"] = "月光林地" }, - } -end - --- DBC WMA ID=261 MapID=1 'Silithus' -if not MTH_DS_Zones[1377] then - MTH_DS_Zones[1377] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 1377, - ["dbcMapId"] = 1, - ["dbcName"] = "Silithus", - ["worldBounds"] = { left=2537.50, right=-945.83, top=-5958.33, bottom=-8281.25 }, - ["names"] = { ["enUS"] = "Silithus", ["esES"] = "Silithus", ["ptBR"] = "Silithus", ["zhCN"] = "希利苏斯" }, - } -end - --- DBC WMA ID=281 MapID=1 'Winterspring' -if not MTH_DS_Zones[618] then - MTH_DS_Zones[618] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 618, - ["dbcMapId"] = 1, - ["dbcName"] = "Winterspring", - ["worldBounds"] = { left=-316.67, right=-7416.67, top=8533.33, bottom=3800.00 }, - ["names"] = { ["enUS"] = "Winterspring", ["esES"] = "Winterspring", ["ptBR"] = "Inverno", ["zhCN"] = "冬泉谷" }, - } -end - --- DBC WMA ID=341 MapID=0 'Ironforge' -if not MTH_DS_Zones[1537] then - MTH_DS_Zones[1537] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 1537, - ["dbcMapId"] = 0, - ["dbcName"] = "Ironforge", - ["worldBounds"] = { left=-713.59, right=-1504.22, top=-4569.24, bottom=-5096.85 }, - ["names"] = { ["enUS"] = "Ironforge", ["esES"] = "Forjaz", ["ptBR"] = "Altaforja", ["zhCN"] = "铁炉堡" }, - } -end - --- DBC WMA ID=401 MapID=30 'AlteracValley' -if not MTH_DS_Zones[2597] then - MTH_DS_Zones[2597] = { - ["continent"] = 30, - ["parent"] = 30, - ["dbcAreaId"] = 2597, - ["dbcMapId"] = 30, - ["dbcName"] = "AlteracValley", - ["worldBounds"] = { left=1781.25, right=-2456.25, top=1085.42, bottom=-1739.58 }, - ["names"] = { ["enUS"] = "Alterac Valley", ["esES"] = "Valle de Alterac", ["ptBR"] = "Vale Alterac", ["zhCN"] = "奥特兰克山谷" }, - } -end - --- DBC WMA ID=443 MapID=489 'WarsongGulch' -if not MTH_DS_Zones[3277] then - MTH_DS_Zones[3277] = { - ["continent"] = 489, - ["parent"] = 489, - ["dbcAreaId"] = 3277, - ["dbcMapId"] = 489, - ["dbcName"] = "WarsongGulch", - ["worldBounds"] = { left=2041.67, right=895.83, top=1627.08, bottom=862.50 }, - ["names"] = { ["enUS"] = "Warsong Gulch", ["esES"] = "Garganta de Warsong", ["ptBR"] = "Garganta Grito de Guerra", ["zhCN"] = "战歌峡谷" }, - } -end - --- DBC WMA ID=461 MapID=529 'ArathiBasin' -if not MTH_DS_Zones[3358] then - MTH_DS_Zones[3358] = { - ["continent"] = 529, - ["parent"] = 529, - ["dbcAreaId"] = 3358, - ["dbcMapId"] = 529, - ["dbcName"] = "ArathiBasin", - ["worldBounds"] = { left=1858.33, right=102.08, top=1508.33, bottom=337.50 }, - ["names"] = { ["enUS"] = "Arathi Basin", ["esES"] = "Cuenca de Arathi", ["ptBR"] = "Bacia Arathi", ["zhCN"] = "阿拉希盆地" }, - } -end - --- DBC WMA ID=500 MapID=1 'GMIsland' -if not MTH_DS_Zones[876] then - MTH_DS_Zones[876] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 876, - ["dbcMapId"] = 1, - ["dbcName"] = "GMIsland", - ["worldBounds"] = { left=16748.00, right=15920.00, top=16525.00, bottom=15984.00 }, - ["names"] = { ["enUS"] = "GM Island", ["esES"] = "Isla GM", ["ptBR"] = "Ilha GM", ["zhCN"] = "GM岛" }, - } -end - --- DBC WMA ID=501 MapID=1 'Hyjal' -if not MTH_DS_Zones[616] then - MTH_DS_Zones[616] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 616, - ["dbcMapId"] = 1, - ["dbcName"] = "Hyjal", - ["worldBounds"] = { left=-1080.00, right=-4286.00, top=6125.00, bottom=3983.00 }, - ["names"] = { ["enUS"] = "Hyjal", ["esES"] = "Hyjal", ["ptBR"] = "Hyjal", ["zhCN"] = "海加尔山" }, - } -end - --- DBC WMA ID=502 MapID=0 'ScarletEnclave' -if not MTH_DS_Zones[4012] then - MTH_DS_Zones[4012] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 4012, - ["dbcMapId"] = 0, - ["dbcName"] = "ScarletEnclave", - ["worldBounds"] = { left=-4050.00, right=-7209.00, top=3087.00, bottom=979.00 }, - ["names"] = { ["enUS"] = "Scarlet Enclave", ["esES"] = "Enclave Escarlata", ["ptBR"] = "Enclave Scarlet", ["zhCN"] = "东瘟疫之地:血色领地" }, - } -end - --- DBC WMA ID=503 MapID=27 'Sunnyglade' -if not MTH_DS_Zones[5023] then - MTH_DS_Zones[5023] = { - ["continent"] = 27, - ["parent"] = 27, - ["dbcAreaId"] = 5023, - ["dbcMapId"] = 27, - ["dbcName"] = "Sunnyglade", - ["worldBounds"] = { left=719.47, right=-269.16, top=2000.77, bottom=607.60 }, - ["names"] = { ["enUS"] = "Sunnyglade Valley", ["esES"] = "Valle Claro Sol", ["ptBR"] = "Vale Sunnyglade", ["zhCN"] = "阳光林地山谷" }, - } -end - --- DBC WMA ID=504 MapID=0 'Lapidis' -if not MTH_DS_Zones[409] then - MTH_DS_Zones[409] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 409, - ["dbcMapId"] = 0, - ["dbcName"] = "Lapidis", - ["worldBounds"] = { left=4933.33, right=2031.88, top=-11043.48, bottom=-12959.42 }, - ["names"] = { ["enUS"] = "Lapidis Isle", ["esES"] = "Isla Lapidis", ["ptBR"] = "Isla Lapidis", ["zhCN"] = "拉匹迪斯之岛" }, - } -end - --- DBC WMA ID=505 MapID=0 'Gillijim' -if not MTH_DS_Zones[408] then - MTH_DS_Zones[408] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 408, - ["dbcMapId"] = 0, - ["dbcName"] = "Gillijim", - ["worldBounds"] = { left=4436.22, right=1344.12, top=-12528.71, bottom=-14575.72 }, - ["names"] = { ["enUS"] = "Gillijim's Isle", ["esES"] = "Isla de Gillijim", ["ptBR"] = "Ilha de Gillijim", ["zhCN"] = "吉利吉姆之岛" }, - } -end - --- DBC WMA ID=506 MapID=31 'AlteracValleyClassic' -if not MTH_DS_Zones[2597] then - MTH_DS_Zones[2597] = { - ["continent"] = 31, - ["parent"] = 31, - ["dbcAreaId"] = 2597, - ["dbcMapId"] = 31, - ["dbcName"] = "AlteracValleyClassic", - ["worldBounds"] = { left=1781.25, right=-2456.25, top=1085.42, bottom=-1739.58 }, - ["names"] = { ["enUS"] = "Alterac Valley", ["esES"] = "Valle de Alterac", ["ptBR"] = "Vale Alterac", ["zhCN"] = "奥特兰克山谷" }, - } -end - --- DBC WMA ID=507 MapID=1 'TelAbim' -if not MTH_DS_Zones[5121] then - MTH_DS_Zones[5121] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 5121, - ["dbcMapId"] = 1, - ["dbcName"] = "TelAbim", - ["worldBounds"] = { left=-5179.00, right=-8406.00, top=-7184.00, bottom=-9371.00 }, - ["names"] = { ["enUS"] = "Tel'Abim", ["esES"] = "Tel'Abim", ["ptBR"] = "Tel'Abim", ["zhCN"] = "泰拉比姆" }, - } -end - --- DBC WMA ID=510 MapID=0 'Gilneas' -if not MTH_DS_Zones[5179] then - MTH_DS_Zones[5179] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 5179, - ["dbcMapId"] = 0, - ["dbcName"] = "Gilneas", - ["worldBounds"] = { left=3253.00, right=-413.00, top=-359.00, bottom=-2801.00 }, - ["names"] = { ["enUS"] = "Gilneas", ["esES"] = "Gilneas", ["ptBR"] = "Gilneas", ["zhCN"] = "吉尔尼斯" }, - } -end - --- DBC WMA ID=511 MapID=1 'Icepoint' -if not MTH_DS_Zones[5024] then - MTH_DS_Zones[5024] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 5024, - ["dbcMapId"] = 1, - ["dbcName"] = "Icepoint", - ["worldBounds"] = { left=-5595.00, right=-7203.00, top=14405.00, bottom=13330.00 }, - ["names"] = { ["enUS"] = "Icepoint Rock", ["esES"] = "Roca Punto de Hielo", ["ptBR"] = "Roca Punto de Hielo", ["zhCN"] = "冰点岩" }, - } -end - --- DBC WMA ID=512 MapID=1 'BlackstoneIsland' -if not MTH_DS_Zones[5536] then - MTH_DS_Zones[5536] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 5536, - ["dbcMapId"] = 1, - ["dbcName"] = "BlackstoneIsland", - ["worldBounds"] = { left=-6274.00, right=-8746.00, top=799.00, bottom=-866.00 }, - ["names"] = { ["enUS"] = "Blackstone Island", ["esES"] = "Isla Piedra Negra", ["ptBR"] = "Ilha Negrito", ["zhCN"] = "黑石岛" }, - } -end - --- DBC WMA ID=513 MapID=0 'ThalassianHighlands' -if not MTH_DS_Zones[5225] then - MTH_DS_Zones[5225] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 5225, - ["dbcMapId"] = 0, - ["dbcName"] = "ThalassianHighlands", - ["worldBounds"] = { left=-1005.00, right=-4087.00, top=4952.00, bottom=2891.00 }, - ["names"] = { ["enUS"] = "Thalassian Highlands", ["esES"] = "Tierras Altas Thalassianas", ["ptBR"] = "Terras Altas Thalassianas", ["zhCN"] = "萨拉斯高地" }, - } -end - --- DBC WMA ID=514 MapID=0 'DeadminesEntrance' -if not MTH_DS_Zones[1581] then - MTH_DS_Zones[1581] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 1581, - ["dbcMapId"] = 0, - ["dbcName"] = "DeadminesEntrance", - ["worldBounds"] = { left=1793.18, right=1343.29, top=-11054.94, bottom=-11354.86 }, - ["names"] = { ["enUS"] = "The Deadmines", ["esES"] = "Las Minas de la Muerte", ["ptBR"] = "As Minas Mortas", ["zhCN"] = "死亡矿井" }, - } -end - --- DBC WMA ID=516 MapID=1 'WailingCavernsEntrance' -if not MTH_DS_Zones[718] then - MTH_DS_Zones[718] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 718, - ["dbcMapId"] = 1, - ["dbcName"] = "WailingCavernsEntrance", - ["worldBounds"] = { left=-1900.87, right=-2473.65, top=-488.64, bottom=-870.49 }, - ["names"] = { ["enUS"] = "Wailing Caverns", ["esES"] = "Cuevas de los Lamentos", ["ptBR"] = "Cavernas Uivantes", ["zhCN"] = "哀嚎洞穴" }, - } -end - --- DBC WMA ID=517 MapID=1 'MaraudonEntrance' -if not MTH_DS_Zones[2100] then - MTH_DS_Zones[2100] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 2100, - ["dbcMapId"] = 1, - ["dbcName"] = "MaraudonEntrance", - ["worldBounds"] = { left=3208.00, right=2384.00, top=-1096.00, bottom=-1646.00 }, - ["names"] = { ["enUS"] = "Maraudon", ["esES"] = "Maraudon", ["ptBR"] = "Maraudon", ["zhCN"] = "玛拉顿" }, - } -end - --- DBC WMA ID=518 MapID=0 'GnomereganEntrance' -if not MTH_DS_Zones[721] then - MTH_DS_Zones[721] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 721, - ["dbcMapId"] = 0, - ["dbcName"] = "GnomereganEntrance", - ["worldBounds"] = { left=1027.64, right=456.45, top=-4806.32, bottom=-5185.46 }, - ["names"] = { ["enUS"] = "Gnomeregan", ["esES"] = "Gnomeregan", ["ptBR"] = "Gnomeregan", ["zhCN"] = "诺莫瑞根" }, - } -end - --- DBC WMA ID=519 MapID=0 'BlackrockMountain' -if not MTH_DS_Zones[25] then - MTH_DS_Zones[25] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 25, - ["dbcMapId"] = 0, - ["dbcName"] = "BlackrockMountain", - ["worldBounds"] = { left=-760.94, right=-1472.50, top=-7327.82, bottom=-7796.50 }, - ["names"] = { ["enUS"] = "Blackrock Mountain", ["esES"] = "Montaña Roca Negra", ["ptBR"] = "Montanha Rocha Negra", ["zhCN"] = "黑石山" }, - } -end - --- DBC WMA ID=520 MapID=0 'ScarletMonasteryEntrance' -if not MTH_DS_Zones[796] then - MTH_DS_Zones[796] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 796, - ["dbcMapId"] = 0, - ["dbcName"] = "ScarletMonasteryEntrance", - ["worldBounds"] = { left=-659.96, right=-863.62, top=2947.37, bottom=2812.33 }, - ["names"] = { ["enUS"] = "Scarlet Monastery", ["esES"] = "Monasterio Escarlata", ["ptBR"] = "Monastério Scarlet", ["zhCN"] = "血色修道院" }, - } -end - --- DBC WMA ID=521 MapID=0 'UldamanEntrance' -if not MTH_DS_Zones[1337] then - MTH_DS_Zones[1337] = { - ["continent"] = 0, - ["parent"] = 0, - ["dbcAreaId"] = 1337, - ["dbcMapId"] = 0, - ["dbcName"] = "UldamanEntrance", - ["worldBounds"] = { left=-2747.15, right=-3310.46, top=-5953.41, bottom=-6329.51 }, - ["names"] = { ["enUS"] = "Uldaman", ["esES"] = "Uldaman", ["ptBR"] = "Uldaman", ["zhCN"] = "奥达曼" }, - } -end - --- DBC WMA ID=522 MapID=1 'AhnQirajEntrance' -if not MTH_DS_Zones[3478] then - MTH_DS_Zones[3478] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 3478, - ["dbcMapId"] = 1, - ["dbcName"] = "AhnQirajEntrance", - ["worldBounds"] = { left=3932.67, right=-206.35, top=-8005.20, bottom=-10951.25 }, - ["names"] = { ["enUS"] = "Gates of Ahn'Qiraj", ["esES"] = "Puertas de Ahn'Qiraj", ["ptBR"] = "Portões de Ahn'Qiraj", ["zhCN"] = "安其拉之门" }, - } -end - --- DBC WMA ID=523 MapID=1 'CavernsOfTime' -if not MTH_DS_Zones[1941] then - MTH_DS_Zones[1941] = { - ["continent"] = 1, - ["parent"] = 1, - ["dbcAreaId"] = 1941, - ["dbcMapId"] = 1, - ["dbcName"] = "CavernsOfTime", - ["worldBounds"] = { left=-3695.85, right=-5044.09, top=-8023.09, bottom=-8911.18 }, - ["names"] = { ["enUS"] = "Caverns of Time", ["esES"] = "Cavernas del Tiempo", ["ptBR"] = "Cavernas do Tempo", ["zhCN"] = "时光之穴" }, - } -end - --- DBC WMA ID=601 MapID=813 'WinterVeilVale' -if not MTH_DS_Zones[5130] then - MTH_DS_Zones[5130] = { - ["continent"] = 813, - ["parent"] = 813, - ["dbcAreaId"] = 5130, - ["dbcMapId"] = 813, - ["dbcName"] = "WinterVeilVale", - ["worldBounds"] = { left=1916.00, right=484.00, top=-2332.00, bottom=-3309.00 }, - ["names"] = { ["enUS"] = "Winter Veil Vale", ["esES"] = "Valle del Velo Invernal", ["ptBR"] = "Vale do Véu de Inverno", ["zhCN"] = "冬幕谷" }, - } -end - --- DBC WMA ID=603 MapID=389 'Ragefire' -if not MTH_DS_Zones[2437] then - MTH_DS_Zones[2437] = { - ["continent"] = 389, - ["parent"] = 389, - ["dbcAreaId"] = 2437, - ["dbcMapId"] = 389, - ["dbcName"] = "Ragefire", - ["worldBounds"] = { left=452.87, right=-285.99, top=39.62, bottom=-452.95 }, - ["names"] = { ["enUS"] = "Ragefire Chasm", ["esES"] = "Sima Ígnea", ["ptBR"] = "Cavernas Ragefire", ["zhCN"] = "怒焰裂谷" }, - } -end - --- DBC WMA ID=605 MapID=209 'ZulFarrak' -if not MTH_DS_Zones[1176] then - MTH_DS_Zones[1176] = { - ["continent"] = 209, - ["parent"] = 209, - ["dbcAreaId"] = 1176, - ["dbcMapId"] = 209, - ["dbcName"] = "ZulFarrak", - ["worldBounds"] = { left=1625.00, right=241.67, top=2052.08, bottom=1129.17 }, - ["names"] = { ["enUS"] = "Zul'Farrak", ["esES"] = "Zul'Farrak", ["ptBR"] = "Zul'Farrak", ["zhCN"] = "祖尔法拉克" }, - } -end - --- DBC WMA ID=607 MapID=109 'TheTempleOfAtalHakkar' -if not MTH_DS_Zones[1477] then - MTH_DS_Zones[1477] = { - ["continent"] = 109, - ["parent"] = 109, - ["dbcAreaId"] = 1477, - ["dbcMapId"] = 109, - ["dbcName"] = "TheTempleOfAtalHakkar", - ["worldBounds"] = { left=442.76, right=-252.27, top=-255.17, bottom=-718.52 }, - ["names"] = { ["enUS"] = "The Temple of Atal'Hakkar", ["esES"] = "Templo de Atal'Hakkar", ["ptBR"] = "O Templo de Atal'Hakkar", ["zhCN"] = "阿塔哈卡神庙" }, - } -end - --- DBC WMA ID=609 MapID=48 'BlackFathomDeeps' -if not MTH_DS_Zones[719] then - MTH_DS_Zones[719] = { - ["continent"] = 48, - ["parent"] = 48, - ["dbcAreaId"] = 719, - ["dbcMapId"] = 48, - ["dbcName"] = "BlackFathomDeeps", - ["worldBounds"] = { left=485.41, right=-736.46, top=-107.91, bottom=-914.33 }, - ["names"] = { ["enUS"] = "Blackfathom Deeps", ["esES"] = "Cavernas de Brazanegra", ["ptBR"] = "Profundezas Negras", ["zhCN"] = "黑暗深渊" }, - } -end - --- DBC WMA ID=611 MapID=34 'TheStockade' -if not MTH_DS_Zones[717] then - MTH_DS_Zones[717] = { - ["continent"] = 34, - ["parent"] = 34, - ["dbcAreaId"] = 717, - ["dbcMapId"] = 34, - ["dbcName"] = "TheStockade", - ["worldBounds"] = { left=189.82, right=-188.33, top=220.63, bottom=-31.47 }, - ["names"] = { ["enUS"] = "The Stockade", ["esES"] = "La Mazmorras", ["ptBR"] = "A Prisão", ["zhCN"] = "监狱" }, - } -end - --- DBC WMA ID=613 MapID=90 'Gnomeregan' -if not MTH_DS_Zones[721] then - MTH_DS_Zones[721] = { - ["continent"] = 90, - ["parent"] = 90, - ["dbcAreaId"] = 721, - ["dbcMapId"] = 90, - ["dbcName"] = "Gnomeregan", - ["worldBounds"] = { left=491.90, right=-277.77, top=-180.89, bottom=-694.00 }, - ["names"] = { ["enUS"] = "Gnomeregan", ["esES"] = "Gnomeregan", ["ptBR"] = "Gnomeregan", ["zhCN"] = "诺莫瑞根" }, - } -end - --- DBC WMA ID=615 MapID=70 'Uldaman' -if not MTH_DS_Zones[1337] then - MTH_DS_Zones[1337] = { - ["continent"] = 70, - ["parent"] = 70, - ["dbcAreaId"] = 1337, - ["dbcMapId"] = 70, - ["dbcName"] = "Uldaman", - ["worldBounds"] = { left=645.12, right=-248.55, top=204.31, bottom=-391.47 }, - ["names"] = { ["enUS"] = "Uldaman", ["esES"] = "Uldaman", ["ptBR"] = "Uldaman", ["zhCN"] = "奥达曼" }, - } -end - --- DBC WMA ID=617 MapID=409 'MoltenCore' -if not MTH_DS_Zones[2717] then - MTH_DS_Zones[2717] = { - ["continent"] = 409, - ["parent"] = 409, - ["dbcAreaId"] = 2717, - ["dbcMapId"] = 409, - ["dbcName"] = "MoltenCore", - ["worldBounds"] = { left=-130.76, right=-1395.56, top=1303.06, bottom=459.86 }, - ["names"] = { ["enUS"] = "Molten Core", ["esES"] = "Núcleo de Magma", ["ptBR"] = "Núcleo Derretido", ["zhCN"] = "熔火之心" }, - } -end - --- DBC WMA ID=619 MapID=309 'ZulGurub' -if not MTH_DS_Zones[1977] then - MTH_DS_Zones[1977] = { - ["continent"] = 309, - ["parent"] = 309, - ["dbcAreaId"] = 1977, - ["dbcMapId"] = 309, - ["dbcName"] = "ZulGurub", - ["worldBounds"] = { left=-612.50, right=-2733.33, top=-11225.00, bottom=-12639.58 }, - ["names"] = { ["enUS"] = "Zul'Gurub", ["esES"] = "Zul'Gurub", ["ptBR"] = "Zul'Gurub", ["zhCN"] = "祖尔格拉布" }, - } -end - --- DBC WMA ID=621 MapID=429 'DireMaul' -if not MTH_DS_Zones[2557] then - MTH_DS_Zones[2557] = { - ["continent"] = 429, - ["parent"] = 429, - ["dbcAreaId"] = 2557, - ["dbcMapId"] = 429, - ["dbcName"] = "DireMaul", - ["worldBounds"] = { left=887.50, right=-387.50, top=1050.00, bottom=200.00 }, - ["names"] = { ["enUS"] = "Dire Maul", ["esES"] = "La Masacre", ["ptBR"] = "Gládio Cruel", ["zhCN"] = "厄运之槌" }, - } -end - --- DBC WMA ID=623 MapID=230 'BlackrockDepths' -if not MTH_DS_Zones[1584] then - MTH_DS_Zones[1584] = { - ["continent"] = 230, - ["parent"] = 230, - ["dbcAreaId"] = 1584, - ["dbcMapId"] = 230, - ["dbcName"] = "BlackrockDepths", - ["worldBounds"] = { left=522.34, right=-884.72, top=1186.68, bottom=248.64 }, - ["names"] = { ["enUS"] = "Blackrock Depths", ["esES"] = "Profundidades de Roca Negra", ["ptBR"] = "Abismo Rocha Negra", ["zhCN"] = "黑石深渊" }, - } -end - --- DBC WMA ID=625 MapID=509 'RuinsofAhnQiraj' -if not MTH_DS_Zones[3429] then - MTH_DS_Zones[3429] = { - ["continent"] = 509, - ["parent"] = 509, - ["dbcAreaId"] = 3429, - ["dbcMapId"] = 509, - ["dbcName"] = "RuinsofAhnQiraj", - ["worldBounds"] = { left=3035.42, right=522.92, top=-8233.33, bottom=-9908.33 }, - ["names"] = { ["enUS"] = "Ruins of Ahn'Qiraj", ["esES"] = "Ruinas de Ahn'Qiraj", ["ptBR"] = "Ruínas de Ahn'Qiraj", ["zhCN"] = "安其拉废墟" }, - } -end - --- DBC WMA ID=627 MapID=249 'OnyxiasLair' -if not MTH_DS_Zones[2159] then - MTH_DS_Zones[2159] = { - ["continent"] = 249, - ["parent"] = 249, - ["dbcAreaId"] = 2159, - ["dbcMapId"] = 249, - ["dbcName"] = "OnyxiasLair", - ["worldBounds"] = { left=111.38, right=-371.73, top=98.25, bottom=-223.83 }, - ["names"] = { ["enUS"] = "Onyxia's Lair", ["esES"] = "Guarida de Onyxia", ["ptBR"] = "Caverna de Onyxia", ["zhCN"] = "奥妮克希亚的巢穴" }, - } -end - --- DBC WMA ID=629 MapID=229 'BlackrockSpire' -if not MTH_DS_Zones[1583] then - MTH_DS_Zones[1583] = { - ["continent"] = 229, - ["parent"] = 229, - ["dbcAreaId"] = 1583, - ["dbcMapId"] = 229, - ["dbcName"] = "BlackrockSpire", - ["worldBounds"] = { left=10.59, right=-876.25, top=304.40, bottom=-286.83 }, - ["names"] = { ["enUS"] = "Blackrock Spire", ["esES"] = "Cumbre de Roca Negra", ["ptBR"] = "Pico Rocha Negra", ["zhCN"] = "黑石塔" }, - } -end - --- DBC WMA ID=631 MapID=43 'WailingCaverns' -if not MTH_DS_Zones[718] then - MTH_DS_Zones[718] = { - ["continent"] = 43, - ["parent"] = 43, - ["dbcAreaId"] = 718, - ["dbcMapId"] = 43, - ["dbcName"] = "WailingCaverns", - ["worldBounds"] = { left=790.00, right=-380.00, top=215.00, bottom=-570.00 }, - ["names"] = { ["enUS"] = "Wailing Caverns", ["esES"] = "Cuevas de los Lamentos", ["ptBR"] = "Cavernas Uivantes", ["zhCN"] = "哀嚎洞穴" }, - } -end - --- DBC WMA ID=633 MapID=349 'Maraudon' -if not MTH_DS_Zones[2100] then - MTH_DS_Zones[2100] = { - ["continent"] = 349, - ["parent"] = 349, - ["dbcAreaId"] = 2100, - ["dbcMapId"] = 349, - ["dbcName"] = "Maraudon", - ["worldBounds"] = { left=485.41, right=-1626.68, top=1199.76, bottom=-211.13 }, - ["names"] = { ["enUS"] = "Maraudon", ["esES"] = "Maraudon", ["ptBR"] = "Maraudon", ["zhCN"] = "玛拉顿" }, - } -end - --- DBC WMA ID=635 MapID=469 'BlackwingLair' -if not MTH_DS_Zones[2677] then - MTH_DS_Zones[2677] = { - ["continent"] = 469, - ["parent"] = 469, - ["dbcAreaId"] = 2677, - ["dbcMapId"] = 469, - ["dbcName"] = "BlackwingLair", - ["worldBounds"] = { left=-844.62, right=-1344.05, top=-7394.12, bottom=-7727.07 }, - ["names"] = { ["enUS"] = "Blackwing Lair", ["esES"] = "Guarida Alanegra", ["ptBR"] = "Covil Asa Negra", ["zhCN"] = "黑翼之巢" }, - } -end - --- DBC WMA ID=637 MapID=36 'TheDeadmines' -if not MTH_DS_Zones[5138] then - MTH_DS_Zones[5138] = { - ["continent"] = 36, - ["parent"] = 36, - ["dbcAreaId"] = 5138, - ["dbcMapId"] = 36, - ["dbcName"] = "TheDeadmines", - ["worldBounds"] = { left=-322.94, right=-979.53, top=36.93, bottom=-398.04 }, - ["names"] = { ["enUS"] = "The Deadmines", ["esES"] = "Las Minas de la Muerte", ["ptBR"] = "As Minas Mortas", ["zhCN"] = "死亡矿井" }, - } -end - --- DBC WMA ID=639 MapID=129 'RazorfenDowns' -if not MTH_DS_Zones[722] then - MTH_DS_Zones[722] = { - ["continent"] = 129, - ["parent"] = 129, - ["dbcAreaId"] = 722, - ["dbcMapId"] = 129, - ["dbcName"] = "RazorfenDowns", - ["worldBounds"] = { left=1279.94, right=570.89, top=2682.55, bottom=2209.85 }, - ["names"] = { ["enUS"] = "Razorfen Downs", ["esES"] = "Tierras Bajas de Rajacieno", ["ptBR"] = "Razorfen Downs", ["zhCN"] = "剃刀高地" }, - } -end - --- DBC WMA ID=641 MapID=47 'RazorfenKraul' -if not MTH_DS_Zones[491] then - MTH_DS_Zones[491] = { - ["continent"] = 47, - ["parent"] = 47, - ["dbcAreaId"] = 491, - ["dbcMapId"] = 47, - ["dbcName"] = "RazorfenKraul", - ["worldBounds"] = { left=2058.92, right=1322.47, top=2349.64, bottom=1858.68 }, - ["names"] = { ["enUS"] = "Razorfen Kraul", ["esES"] = "Madriguera de Rajacieno", ["ptBR"] = "Razorfen Kraul", ["zhCN"] = "剃刀沼泽" }, - } -end - --- DBC WMA ID=643 MapID=189 'ScarletMonastery' -if not MTH_DS_Zones[5136] then - MTH_DS_Zones[5136] = { - ["continent"] = 189, - ["parent"] = 189, - ["dbcAreaId"] = 5136, - ["dbcMapId"] = 189, - ["dbcName"] = "ScarletMonastery", - ["worldBounds"] = { left=1567.97, right=947.99, top=2030.18, bottom=1616.86 }, - ["names"] = { ["enUS"] = "Scarlet Monastery Graveyard", ["esES"] = "Cementerio Monasterio Escarlata", ["ptBR"] = "Cemitério do Monastério Escarlate", ["zhCN"] = "血色修道院-墓地" }, - } -end - --- DBC WMA ID=644 MapID=189 'ScarletMonastery2f' -if not MTH_DS_Zones[5135] then - MTH_DS_Zones[5135] = { - ["continent"] = 189, - ["parent"] = 189, - ["dbcAreaId"] = 5135, - ["dbcMapId"] = 189, - ["dbcName"] = "ScarletMonastery2f", - ["worldBounds"] = { left=-162.27, right=-482.46, top=307.37, bottom=93.91 }, - ["names"] = { ["enUS"] = "Scarlet Monastery Library", ["esES"] = "Biblioteca Monasterio Escarlata", ["ptBR"] = "Biblioteca do Monastério Escarlate", ["zhCN"] = "血色修道院-图书馆" }, - } -end - --- DBC WMA ID=645 MapID=189 'ScarletMonastery3f' -if not MTH_DS_Zones[5153] then - MTH_DS_Zones[5153] = { - ["continent"] = 189, - ["parent"] = 189, - ["dbcAreaId"] = 5153, - ["dbcMapId"] = 189, - ["dbcName"] = "ScarletMonastery3f", - ["worldBounds"] = { left=50.27, right=-562.42, top=2009.10, bottom=1600.64 }, - ["names"] = { ["enUS"] = "Scarlet Monastery Armory", ["esES"] = "Armería Monasterio Escarlata", ["ptBR"] = "Arsenal do Monastério Escarlate", ["zhCN"] = "血色修道院-军械库" }, - } -end - --- DBC WMA ID=646 MapID=189 'ScarletMonastery4f' -if not MTH_DS_Zones[5163] then - MTH_DS_Zones[5163] = { - ["continent"] = 189, - ["parent"] = 189, - ["dbcAreaId"] = 5163, - ["dbcMapId"] = 189, - ["dbcName"] = "ScarletMonastery4f", - ["worldBounds"] = { left=1743.99, right=1040.69, top=1281.29, bottom=812.42 }, - ["names"] = { ["enUS"] = "Scarlet Monastery Cathedral", ["esES"] = "Catedral Monasterio Escarlata", ["ptBR"] = "Catedral do Monastério Escarlate", ["zhCN"] = "血色修道院-大教堂" }, - } -end - --- DBC WMA ID=648 MapID=289 'Scholomance' -if not MTH_DS_Zones[2057] then - MTH_DS_Zones[2057] = { - ["continent"] = 289, - ["parent"] = 289, - ["dbcAreaId"] = 2057, - ["dbcMapId"] = 289, - ["dbcName"] = "Scholomance", - ["worldBounds"] = { left=251.41, right=-68.64, top=317.70, bottom=104.33 }, - ["names"] = { ["enUS"] = "Scholomance", ["esES"] = "Scholomance", ["ptBR"] = "Scholomance", ["zhCN"] = "通灵学院" }, - } -end - --- DBC WMA ID=650 MapID=33 'ShadowfangKeep' -if not MTH_DS_Zones[209] then - MTH_DS_Zones[209] = { - ["continent"] = 33, - ["parent"] = 33, - ["dbcAreaId"] = 209, - ["dbcMapId"] = 33, - ["dbcName"] = "ShadowfangKeep", - ["worldBounds"] = { left=2436.00, right=2055.00, top=-61.00, bottom=-315.00 }, - ["names"] = { ["enUS"] = "Shadowfang Keep", ["esES"] = "Fortaleza Colmillo Oscuro", ["ptBR"] = "Fortaleza Shadowfang", ["zhCN"] = "影牙城堡" }, - } -end - --- DBC WMA ID=652 MapID=329 'Stratholme' -if not MTH_DS_Zones[2017] then - MTH_DS_Zones[2017] = { - ["continent"] = 329, - ["parent"] = 329, - ["dbcAreaId"] = 2017, - ["dbcMapId"] = 329, - ["dbcName"] = "Stratholme", - ["worldBounds"] = { left=-2639.83, right=-3825.18, top=4163.90, bottom=3374.04 }, - ["names"] = { ["enUS"] = "Stratholme", ["esES"] = "Stratholme", ["ptBR"] = "Stratholme", ["zhCN"] = "斯坦索姆" }, - } -end - --- DBC WMA ID=654 MapID=531 'AhnQiraj' -if not MTH_DS_Zones[3428] then - MTH_DS_Zones[3428] = { - ["continent"] = 531, - ["parent"] = 531, - ["dbcAreaId"] = 3428, - ["dbcMapId"] = 531, - ["dbcName"] = "AhnQiraj", - ["worldBounds"] = { left=2515.63, right=1538.07, top=-8051.80, bottom=-8703.50 }, - ["names"] = { ["enUS"] = "Ahn'Qiraj", ["esES"] = "Ahn'Qiraj", ["ptBR"] = "Ahn'Qiraj", ["zhCN"] = "安其拉" }, - } -end - --- DBC WMA ID=655 MapID=531 'AhnQiraj2f' -if not MTH_DS_Zones[5147] then - MTH_DS_Zones[5147] = { - ["continent"] = 531, - ["parent"] = 531, - ["dbcAreaId"] = 5147, - ["dbcMapId"] = 531, - ["dbcName"] = "AhnQiraj2f", - ["worldBounds"] = { left=2915.62, right=138.08, top=-7659.29, bottom=-9510.98 }, - ["names"] = { ["enUS"] = "Ahn'Qiraj", ["esES"] = "Ahn'Qiraj", ["ptBR"] = "Ahn'Qiraj", ["zhCN"] = "安其拉" }, - } -end - --- DBC WMA ID=657 MapID=532 'Karazhan' -if not MTH_DS_Zones[3457] then - MTH_DS_Zones[3457] = { - ["continent"] = 532, - ["parent"] = 532, - ["dbcAreaId"] = 3457, - ["dbcMapId"] = 532, - ["dbcName"] = "Karazhan", - ["worldBounds"] = { left=-1614.00, right=-2212.00, top=-10780.00, bottom=-11179.00 }, - ["names"] = { ["enUS"] = "Tower of Karazhan", ["esES"] = "Torre de Karazhan", ["ptBR"] = "Karazhan", ["zhCN"] = "卡拉赞" }, - } -end - --- DBC WMA ID=659 MapID=369 'DeeprunTram' -if not MTH_DS_Zones[2257] then - MTH_DS_Zones[2257] = { - ["continent"] = 369, - ["parent"] = 369, - ["dbcAreaId"] = 2257, - ["dbcMapId"] = 369, - ["dbcName"] = "DeeprunTram", - ["worldBounds"] = { left=2623.50, right=2311.50, top=95.50, bottom=-112.50 }, - ["names"] = { ["enUS"] = "Deeprun Tram", ["esES"] = "Tranvía Subterráneo", ["ptBR"] = "Metrô Correfundo", ["zhCN"] = "矿道地铁" }, - } -end - --- DBC WMA ID=660 MapID=369 'DeeprunTram2f' -if not MTH_DS_Zones[5144] then - MTH_DS_Zones[5144] = { - ["continent"] = 369, - ["parent"] = 369, - ["dbcAreaId"] = 5144, - ["dbcMapId"] = 369, - ["dbcName"] = "DeeprunTram2f", - ["worldBounds"] = { left=187.50, right=-121.50, top=95.50, bottom=-112.50 }, - ["names"] = { ["enUS"] = "Deeprun Tram", ["esES"] = "Tranvía Profundocircuito", ["ptBR"] = "Metrô Correfundo", ["zhCN"] = "矿道地铁" }, - } -end - --- DBC WMA ID=662 MapID=269 'BlackMorass' -if not MTH_DS_Zones[5204] then - MTH_DS_Zones[5204] = { - ["continent"] = 269, - ["parent"] = 269, - ["dbcAreaId"] = 5204, - ["dbcMapId"] = 269, - ["dbcName"] = "BlackMorass", - ["worldBounds"] = { left=7338.47, right=6066.48, top=-1247.55, bottom=-2093.03 }, - ["names"] = { ["enUS"] = "The Black Morass", ["esES"] = "El Morass Negro", ["ptBR"] = "Lamaçal Negro", ["zhCN"] = "黑色沼泽" }, - } -end - --- DBC WMA ID=663 MapID=269 'BlackMorass2f' -if not MTH_DS_Zones[2366] then - MTH_DS_Zones[2366] = { - ["continent"] = 269, - ["parent"] = 269, - ["dbcAreaId"] = 2366, - ["dbcMapId"] = 269, - ["dbcName"] = "BlackMorass2f", - ["worldBounds"] = { left=7651.85, right=6565.99, top=-1500.47, bottom=-2227.08 }, - ["names"] = { ["enUS"] = "The Black Morass", ["esES"] = "La Ciénaga Negra", ["ptBR"] = "O Morass Negro", ["zhCN"] = "黑色沼泽" }, - } -end - --- DBC WMA ID=665 MapID=815 'GilneasCity' -if not MTH_DS_Zones[5208] then - MTH_DS_Zones[5208] = { - ["continent"] = 815, - ["parent"] = 815, - ["dbcAreaId"] = 5208, - ["dbcMapId"] = 815, - ["dbcName"] = "GilneasCity", - ["worldBounds"] = { left=3290.32, right=2040.14, top=-760.72, bottom=-1598.16 }, - ["names"] = { ["enUS"] = "Gilneas City", ["esES"] = "Ciudad Gilneas", ["ptBR"] = "Cidade de Gilneas", ["zhCN"] = "吉尔尼斯城" }, - } -end - --- DBC WMA ID=667 MapID=533 'Naxxramas' -if not MTH_DS_Zones[3456] then - MTH_DS_Zones[3456] = { - ["continent"] = 533, - ["parent"] = 533, - ["dbcAreaId"] = 3456, - ["dbcMapId"] = 533, - ["dbcName"] = "Naxxramas", - ["worldBounds"] = { left=-2375.27, right=-4366.96, top=3656.70, bottom=2338.28 }, - ["names"] = { ["enUS"] = "Naxxramas", ["esES"] = "Naxxramas", ["ptBR"] = "Naxxramas", ["zhCN"] = "纳克萨玛斯" }, - } -end - --- DBC WMA ID=668 MapID=533 'Naxxramas2f' -if not MTH_DS_Zones[5148] then - MTH_DS_Zones[5148] = { - ["continent"] = 533, - ["parent"] = 533, - ["dbcAreaId"] = 5148, - ["dbcMapId"] = 533, - ["dbcName"] = "Naxxramas2f", - ["worldBounds"] = { left=-4869.36, right=-5521.46, top=3816.56, bottom=3376.89 }, - ["names"] = { ["enUS"] = "The Upper Necropolis", ["esES"] = "La Necropolis Superior", ["ptBR"] = "Necrópole Superior", ["zhCN"] = "上层大墓地" }, - } -end - --- DBC WMA ID=670 MapID=802 'CrescentGrove' -if not MTH_DS_Zones[5077] then - MTH_DS_Zones[5077] = { - ["continent"] = 802, - ["parent"] = 802, - ["dbcAreaId"] = 5077, - ["dbcMapId"] = 802, - ["dbcName"] = "CrescentGrove", - ["worldBounds"] = { left=1207.72, right=-1435.49, top=882.98, bottom=-868.18 }, - ["names"] = { ["enUS"] = "Crescent Grove", ["esES"] = "Claro de la Media Luna", ["ptBR"] = "Bosque Crescente", ["zhCN"] = "新月林地" }, - } -end - --- DBC WMA ID=672 MapID=808 'HateforgeQuarry' -if not MTH_DS_Zones[5103] then - MTH_DS_Zones[5103] = { - ["continent"] = 808, - ["parent"] = 808, - ["dbcAreaId"] = 5103, - ["dbcMapId"] = 808, - ["dbcName"] = "HateforgeQuarry", - ["worldBounds"] = { left=-3024.33, right=-3776.45, top=-7888.28, bottom=-8398.61 }, - ["names"] = { ["enUS"] = "Hateforge Quarry", ["esES"] = "Cantera Hateforge", ["ptBR"] = "Pedreira Forja do Ódio", ["zhCN"] = "仇恨熔炉采石场" }, - } -end - --- DBC WMA ID=674 MapID=800 'KarazhanCrypt' -if not MTH_DS_Zones[5086] then - MTH_DS_Zones[5086] = { - ["continent"] = 800, - ["parent"] = 800, - ["dbcAreaId"] = 5086, - ["dbcMapId"] = 800, - ["dbcName"] = "KarazhanCrypt", - ["worldBounds"] = { left=-1302.51, right=-1849.26, top=-10916.17, bottom=-11308.14 }, - ["names"] = { ["enUS"] = "Karazhan Crypt", ["esES"] = "Cripta de Karazhan", ["ptBR"] = "Cripta Karazhan", ["zhCN"] = "卡拉赞墓穴" }, - } -end - --- DBC WMA ID=676 MapID=35 'StormwindVault' -if not MTH_DS_Zones[5087] then - MTH_DS_Zones[5087] = { - ["continent"] = 35, - ["parent"] = 35, - ["dbcAreaId"] = 5087, - ["dbcMapId"] = 35, - ["dbcName"] = "StormwindVault", - ["worldBounds"] = { left=314.34, right=-40.16, top=89.30, bottom=-145.44 }, - ["names"] = { ["enUS"] = "Stormwind Vault", ["esES"] = "Bóveda de Ventormenta", ["ptBR"] = "Cofre Stormwind", ["zhCN"] = "暴风城地牢" }, - } -end - --- DBC WMA ID=678 MapID=807 'EmeraldSanctum' -if not MTH_DS_Zones[5097] then - MTH_DS_Zones[5097] = { - ["continent"] = 807, - ["parent"] = 807, - ["dbcAreaId"] = 5097, - ["dbcMapId"] = 807, - ["dbcName"] = "EmeraldSanctum", - ["worldBounds"] = { left=3939.10, right=2666.00, top=3519.72, bottom=2666.00 }, - ["names"] = { ["enUS"] = "Emerald Sanctum", ["esES"] = "Sanctum Esmeralda", ["ptBR"] = "Santuário Esmeralda", ["zhCN"] = "翡翠圣殿" }, - } -end - --- DBC WMA ID=680 MapID=801 'Moomoo' -if not MTH_DS_Zones[5053] then - MTH_DS_Zones[5053] = { - ["continent"] = 801, - ["parent"] = 801, - ["dbcAreaId"] = 5053, - ["dbcMapId"] = 801, - ["dbcName"] = "Moomoo", - ["worldBounds"] = { left=17296.30, right=16288.62, top=17158.52, bottom=16486.73 }, - ["names"] = { ["enUS"] = "Moomoo Grove", ["esES"] = "Claro Moomoo", ["ptBR"] = "Bosque Moomoo", ["zhCN"] = "奶牛树林" }, - } -end - --- DBC WMA ID=682 MapID=814 'UpperKarazhan' -if not MTH_DS_Zones[3457] then - MTH_DS_Zones[3457] = { - ["continent"] = 814, - ["parent"] = 814, - ["dbcAreaId"] = 3457, - ["dbcMapId"] = 814, - ["dbcName"] = "UpperKarazhan", - ["worldBounds"] = { left=-1378.00, right=-2201.00, top=-10887.00, bottom=-11436.00 }, - ["names"] = { ["enUS"] = "Tower of Karazhan", ["esES"] = "Torre de Karazhan", ["ptBR"] = "Karazhan", ["zhCN"] = "卡拉赞" }, - } -end - --- DBC WMA ID=683 MapID=814 'UpperKarazhan2f' -if not MTH_DS_Zones[5557] then - MTH_DS_Zones[5557] = { - ["continent"] = 814, - ["parent"] = 814, - ["dbcAreaId"] = 5557, - ["dbcMapId"] = 814, - ["dbcName"] = "UpperKarazhan2f", - ["worldBounds"] = { left=-1483.00, right=-4283.00, top=-5800.00, bottom=-7668.00 }, - ["names"] = { ["enUS"] = "???", ["esES"] = "???", ["ptBR"] = "???", ["zhCN"] = "外域" }, - } -end diff --git a/init/api.xml b/init/api.xml index 9bc6d81..a73951e 100644 --- a/init/api.xml +++ b/init/api.xml @@ -43,7 +43,6 @@ - diff --git a/modules/smartpet/engine.lua b/modules/smartpet/engine.lua deleted file mode 100644 index 5517f6d..0000000 --- a/modules/smartpet/engine.lua +++ /dev/null @@ -1,1293 +0,0 @@ ------------------------------------------------------- --- MetaHunt: SmartPet — Pet Combat Management --- TWoW 1.18.1 ------------------------------------------------------- --- --- Integrated pet combat manager inspired by SmartPet v2.5.1. --- Handles taunt management, focus budgeting, CC-break --- prevention, PVP auto-detaunt, The Button keybind, --- NoChase, Dash/Dive on attack, auto-cower, and --- low-health chat warnings. ------------------------------------------------------- - --- ── Localised ability names ────────────────────────────────── --- Resolved from MTH_LocaleData.spells via MTH:LocalizeSpell(). --- PET_ACTION_FOLLOW / PET_ACTION_ATTACK are built-in WoW tokens, --- not localised spell names. -local L_GROWL, L_COWER, L_CLAW, L_BITE, L_DASH, L_DIVE -local L_LIGHTNING_BREATH, L_SCREECH, L_SCORPID_POISON -local L_CHARGE, L_DEATH_ROLL, L_FURIOUS_HOWL, L_SAVAGE_REND -local L_THUNDERSTOMP, L_POISON_SPIT, L_POLLEN_BURST -local L_PROWL, L_SHELL_SHIELD, L_GRACE, L_BUBBLE_BARRIER -local L_WEB, L_ROAR_OF_FORTITUDE, L_PACKLEADER, L_STRIDER_PRESENCE -local L_FOLLOW = "PET_ACTION_FOLLOW" -local L_ATTACK = "PET_ACTION_ATTACK" -local L_FLEE = "attempts to run away in fear" - --- ── CC debuff token list (English keys into spell locale) ──── -local CC_DEBUFF_TOKENS = { - "Gouge", "Sap", "Charm", "Seduction", "Sheep", "Polymorph", - "Tame Beast", "Scare Beast", "Sleep", "Hibernate", "Fear", - "Mind Control", "Blind", "Scatter Shot", "Enslave Demon", - "Shackle Undead", "Reckless Charge", "Freezing Trap Effect", - "Intimidating Shout", "Repentance", "Wyvern Sting", -} - --- Populated once MTH:LocalizeSpell is available (VARIABLES_LOADED) -local CC_DEBUFF_SET = {} - --- Maps localised ability names to rt.slot keys. -local ABILITY_MAP = {} -local function BuildAbilityMap() - ABILITY_MAP = { - [L_GROWL] = "growl", - [L_COWER] = "cower", - [L_CLAW] = "claw", - [L_BITE] = "bite", - [L_FOLLOW] = "follow", - [L_ATTACK] = "attack", - [L_DASH] = "dash", - [L_DIVE] = "dive", - } - -- Conditionally add family-specific abilities (nil-safe: L_ vars may be nil before locale resolution) - if L_LIGHTNING_BREATH then ABILITY_MAP[L_LIGHTNING_BREATH] = "lightningBreath" end - if L_SCREECH then ABILITY_MAP[L_SCREECH] = "screech" end - if L_SCORPID_POISON then ABILITY_MAP[L_SCORPID_POISON] = "scorpidPoison" end - if L_CHARGE then ABILITY_MAP[L_CHARGE] = "charge" end - if L_DEATH_ROLL then ABILITY_MAP[L_DEATH_ROLL] = "deathRoll" end - if L_FURIOUS_HOWL then ABILITY_MAP[L_FURIOUS_HOWL] = "furiousHowl" end - if L_SAVAGE_REND then ABILITY_MAP[L_SAVAGE_REND] = "savageRend" end - if L_THUNDERSTOMP then ABILITY_MAP[L_THUNDERSTOMP] = "thunderstomp" end - if L_POISON_SPIT then ABILITY_MAP[L_POISON_SPIT] = "poisonSpit" end - if L_POLLEN_BURST then ABILITY_MAP[L_POLLEN_BURST] = "pollenBurst" end - if L_PROWL then ABILITY_MAP[L_PROWL] = "prowl" end - if L_SHELL_SHIELD then ABILITY_MAP[L_SHELL_SHIELD] = "shellShield" end - if L_GRACE then ABILITY_MAP[L_GRACE] = "grace" end - if L_BUBBLE_BARRIER then ABILITY_MAP[L_BUBBLE_BARRIER] = "bubbleBarrier" end - if L_WEB then ABILITY_MAP[L_WEB] = "web" end - if L_ROAR_OF_FORTITUDE then ABILITY_MAP[L_ROAR_OF_FORTITUDE] = "roarOfFortitude" end - if L_PACKLEADER then ABILITY_MAP[L_PACKLEADER] = "packleader" end - if L_STRIDER_PRESENCE then ABILITY_MAP[L_STRIDER_PRESENCE] = "striderPresence" end -end - --- Called at VARIABLES_LOADED when the locale system is ready -local function ResolveLocaleStrings() - if not (MTH and MTH.LocalizeSpell) then return end - - L_GROWL = MTH:LocalizeSpell("Growl") - L_COWER = MTH:LocalizeSpell("Cower") - L_CLAW = MTH:LocalizeSpell("Claw") - L_BITE = MTH:LocalizeSpell("Bite") - L_DASH = MTH:LocalizeSpell("Dash") - L_DIVE = MTH:LocalizeSpell("Dive") - - -- Family-specific abilities - L_LIGHTNING_BREATH = MTH:LocalizeSpell("Lightning Breath") - L_SCREECH = MTH:LocalizeSpell("Screech") - L_SCORPID_POISON = MTH:LocalizeSpell("Scorpid Poison") - L_CHARGE = MTH:LocalizeSpell("Charge") - L_DEATH_ROLL = MTH:LocalizeSpell("Death Roll") - L_FURIOUS_HOWL = MTH:LocalizeSpell("Furious Howl") - L_SAVAGE_REND = MTH:LocalizeSpell("Savage Rend") - L_THUNDERSTOMP = MTH:LocalizeSpell("Thunderstomp") - L_POISON_SPIT = MTH:LocalizeSpell("Poison Spit") - L_POLLEN_BURST = MTH:LocalizeSpell("Pollen Burst") - L_PROWL = MTH:LocalizeSpell("Prowl") - L_SHELL_SHIELD = MTH:LocalizeSpell("Shell Shield") - L_GRACE = MTH:LocalizeSpell("Grace") - L_BUBBLE_BARRIER = MTH:LocalizeSpell("Bubble Barrier") - L_WEB = MTH:LocalizeSpell("Web") - L_ROAR_OF_FORTITUDE = MTH:LocalizeSpell("Roar of Fortitude") - L_PACKLEADER = MTH:LocalizeSpell("Packleader") - L_STRIDER_PRESENCE = MTH:LocalizeSpell("Strider Presence") - - -- Flee pattern from spell locale (special key) - local spellLocales = MTH_LocaleData and MTH_LocaleData.spells - if spellLocales then - local locale = MTH.currentLocale or "enUS" - local aliases = { enGB = "enUS", esMX = "esES", zhTW = "zhCN" } - if aliases[locale] then locale = aliases[locale] end - local map = spellLocales[locale] or spellLocales.enUS - if map and map["SP_FLEE_PATTERN"] then - L_FLEE = map["SP_FLEE_PATTERN"] - end - end - - -- Rebuild CC debuff set from localised names - CC_DEBUFF_SET = {} - for _, token in ipairs(CC_DEBUFF_TOKENS) do - local localized = MTH:LocalizeSpell(token) - CC_DEBUFF_SET[localized] = true - end - - -- Rebuild ability map with resolved names - BuildAbilityMap() -end - --- ── Constants ──────────────────────────────────────────────── -local FOCUS_REGEN_INTERVAL = 5 -- pet focus ticks roughly every 5s - --- Pet action bar slot count (WoW 1.12) -local NUM_PET_SLOTS = NUM_PET_ACTION_SLOTS or 10 - --- Ability metadata: focus cost and behaviour type. --- type: "taunt", "autocastDPS" (spammable, no meaningful CD), --- "semiAutocast" (short CD, still autocasts frequently), --- "cdDPS" (significant cooldown), "mobility", "defensive", --- "utility", "partyBuff" -local ABILITY_INFO = { - growl = { cost = 15, type = "taunt" }, - cower = { cost = 15, type = "taunt" }, - bite = { cost = 35, type = "autocastDPS" }, - claw = { cost = 25, type = "autocastDPS" }, - lightningBreath = { cost = 50, type = "autocastDPS" }, - scorpidPoison = { cost = 25, type = "semiAutocast" }, - screech = { cost = 20, type = "semiAutocast" }, - charge = { cost = 35, type = "cdDPS" }, - deathRoll = { cost = 50, type = "cdDPS" }, - furiousHowl = { cost = 50, type = "cdDPS" }, - savageRend = { cost = 25, type = "cdDPS" }, - thunderstomp = { cost = 60, type = "cdDPS" }, - poisonSpit = { cost = 35, type = "cdDPS" }, - pollenBurst = { cost = 40, type = "cdDPS" }, - dash = { cost = 20, type = "mobility" }, - dive = { cost = 20, type = "mobility" }, - prowl = { cost = 40, type = "utility" }, - shellShield = { cost = 10, type = "defensive" }, - grace = { cost = 10, type = "defensive" }, - bubbleBarrier = { cost = 20, type = "defensive" }, - web = { cost = 0, type = "utility" }, - roarOfFortitude = { cost = 50, type = "partyBuff" }, - packleader = { cost = 50, type = "partyBuff" }, - striderPresence = { cost = 50, type = "partyBuff" }, -} - --- Ability keys whose autocast is managed by the focus budget system. -local MANAGED_DPS_TYPES = { autocastDPS = true, semiAutocast = true, cdDPS = true } - --- ── Config defaults (persisted per-character) ──────────────── -local CONFIG_DEFAULTS = { - tauntMode = "auto", -- "auto" | "growl" | "cower" | "off" - pvpDetaunt = true, - ccBreakCheck = true, - ccBreakMode = "block", -- "block" | "warn" - theButton = true, - smartFocus = false, - autoCower = false, - autoCowerPct = 30, - noChase = false, - rushOnAttack = true, - autoWarn = false, - autoWarnPct = 20, - autoWarnChannel = "SAY", -} - --- ── Runtime state (not persisted) ──────────────────────────── -local rt = { - inCombat = false, - inPVP = false, - -- Backed-up pre-PVP autocast states - pvpBackup = nil, -- { growl=bool, cower=bool, autoCower=bool } - -- Pet action bar slot indices (-1 = not found) - slot = { - attack = -1, - follow = -1, - growl = -1, - cower = -1, - bite = -1, - claw = -1, - dash = -1, - dive = -1, - lightningBreath = -1, - screech = -1, - scorpidPoison = -1, - charge = -1, - deathRoll = -1, - furiousHowl = -1, - savageRend = -1, - thunderstomp = -1, - poisonSpit = -1, - pollenBurst = -1, - prowl = -1, - shellShield = -1, - grace = -1, - bubbleBarrier = -1, - web = -1, - roarOfFortitude = -1, - packleader = -1, - striderPresence = -1, - }, - -- Pet spellbook indices for rush abilities (used for CastSpell) - spellbook = { - dash = -1, - dive = -1, - charge = -1, - }, - -- Focus tracking - focus1 = 100, - focus2 = 100, - lastFocusTick = 0, - nextFocusTick = 0, - -- Smart Focus: remember which DPS autocasts were ON at combat start - preCombatAutocast = {}, -- { [slotKey] = bool } - -- AutoCower: track if we swapped to cower - autoCowered = false, - -- AutoWarn throttle - lastWarnTime = 0, - lastWarnPct = 0, - -- NoChase recall flag - recallPending = false, - -- TheButton context - theButtonRecall = false, - -- Party has a tank (cached) - partyHasTank = false, -} - --- ── Hidden tooltip for debuff scanning (legacy path) ───────── -local debuffTip = nil -local function EnsureDebuffTip() - if debuffTip then return debuffTip end - debuffTip = CreateFrame("GameTooltip", "MTH_SP_DebuffTip", UIParent, "GameTooltipTemplate") - debuffTip:SetOwner(UIParent, "ANCHOR_NONE") - return debuffTip -end - --- ── Config helpers ─────────────────────────────────────────── -local function GetCfg() - if type(MTH_SavedVariables) ~= "table" then return CONFIG_DEFAULTS end - if type(MTH_SavedVariables.modules) ~= "table" then - MTH_SavedVariables.modules = {} - end - local cfg = MTH_SavedVariables.modules["smartpet"] - if type(cfg) ~= "table" then - cfg = {} - MTH_SavedVariables.modules["smartpet"] = cfg - end - -- Fill defaults for missing keys - for k, v in pairs(CONFIG_DEFAULTS) do - if cfg[k] == nil then - cfg[k] = v - end - end - return cfg -end - -local function IsEnabled() - if not (MTH and MTH.IsModuleEnabled) then return false end - return MTH:IsModuleEnabled("smartpet", false) -end - --- ── Pet action bar helpers ─────────────────────────────────── -local function GetAutocast(slotIndex) - if slotIndex < 1 then return false end - local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(slotIndex) - return autoCastEnabled and true or false -end - -local function SetAutocast(slotIndex, enabled) - if slotIndex < 1 then return end - local current = GetAutocast(slotIndex) - if (current and not enabled) or (not current and enabled) then - TogglePetAutocast(slotIndex) - end -end - --- ── Pet action bar scanning ────────────────────────────────── - -local function ScanPetActionBar() - for key in pairs(rt.slot) do - rt.slot[key] = -1 - end - for i = 1, NUM_PET_SLOTS do - local name = GetPetActionInfo(i) - if name then - local key = ABILITY_MAP[name] - if key then - rt.slot[key] = i - end - end - end -end - --- Scan pet spellbook for rush ability indices (for CastSpell) -local function ScanPetSpellbook() - rt.spellbook.dash = -1 - rt.spellbook.dive = -1 - rt.spellbook.charge = -1 - for i = 1, 20 do - local spellName = GetSpellName(i, BOOKTYPE_PET) - if not spellName then break end - if spellName == L_DASH then - rt.spellbook.dash = i - elseif spellName == L_DIVE then - rt.spellbook.dive = i - elseif spellName == L_CHARGE then - rt.spellbook.charge = i - end - end -end - --- ── Party/tank detection ───────────────────────────────────── -local TANK_CLASSES = { WARRIOR = true, PALADIN = true } --- Druid tanks detected by class + bear form buff (approximate) - -local function ScanPartyForTank() - local members = GetNumPartyMembers and GetNumPartyMembers() or 0 - local raid = GetNumRaidMembers and GetNumRaidMembers() or 0 - - if members == 0 and raid == 0 then - rt.partyHasTank = false - return - end - - -- Raid scan - if raid > 0 then - for i = 1, raid do - local unit = "raid" .. i - if UnitExists(unit) and not UnitIsUnit(unit, "player") then - local _, cls = UnitClass(unit) - if cls and TANK_CLASSES[cls] then - rt.partyHasTank = true - return - end - if cls == "DRUID" then - -- Check for bear form via power type (rage = 1) - if UnitPowerType and UnitPowerType(unit) == 1 then - rt.partyHasTank = true - return - end - end - end - end - rt.partyHasTank = false - return - end - - -- Party scan - for i = 1, members do - local unit = "party" .. i - if UnitExists(unit) then - local _, cls = UnitClass(unit) - if cls and TANK_CLASSES[cls] then - rt.partyHasTank = true - return - end - if cls == "DRUID" then - if UnitPowerType and UnitPowerType(unit) == 1 then - rt.partyHasTank = true - return - end - end - end - end - rt.partyHasTank = false -end - --- ── Taunt Management ───────────────────────────────────────── -local function ApplyTauntMode() - if not IsEnabled() then return end - local cfg = GetCfg() - local mode = cfg.tauntMode - - if mode == "off" then return end - if mode == "growl" then - SetAutocast(rt.slot.growl, true) - SetAutocast(rt.slot.cower, false) - return - end - if mode == "cower" then - SetAutocast(rt.slot.growl, false) - SetAutocast(rt.slot.cower, true) - return - end - -- auto: solo → growl, party with tank → cower - if rt.partyHasTank then - SetAutocast(rt.slot.growl, false) - if rt.slot.cower > 0 then - SetAutocast(rt.slot.cower, true) - end - else - SetAutocast(rt.slot.growl, true) - SetAutocast(rt.slot.cower, false) - end -end - --- ── PVP Auto-Detaunt ───────────────────────────────────────── -local function StartPVP() - if rt.inPVP then return end - local cfg = GetCfg() - if not cfg.pvpDetaunt then return end - - rt.inPVP = true - rt.pvpBackup = { - growl = GetAutocast(rt.slot.growl), - cower = GetAutocast(rt.slot.cower), - autoCower = cfg.autoCower, - } - SetAutocast(rt.slot.growl, false) - SetAutocast(rt.slot.cower, false) -end - -local function EndPVP() - if not rt.inPVP then return end - rt.inPVP = false - if rt.pvpBackup then - SetAutocast(rt.slot.growl, rt.pvpBackup.growl) - SetAutocast(rt.slot.cower, rt.pvpBackup.cower) - -- Restore autoCower setting — it doesn't get toggled on the bar, just the config flag - rt.pvpBackup = nil - end -end - --- ── CC-Break Prevention ────────────────────────────────────── --- Returns true if the target has a breakable CC debuff. -local function TargetHasBreakableCC() - local cfg = GetCfg() - if not cfg.ccBreakCheck then return false end - - -- NamPower path: GetUnitField aura array - if type(GetUnitField) == "function" then - local auras = GetUnitField("target", "aura") - if type(auras) == "table" then - for _, aura in ipairs(auras) do - if type(aura) == "table" then - local auraName = aura.name or (aura.spellId and GetSpellRecField and GetSpellRecField(aura.spellId, "name")) - if auraName and CC_DEBUFF_SET[auraName] then - return true - end - end - end - return false - end - end - - -- Legacy path: hidden tooltip scan - local tip = EnsureDebuffTip() - tip:ClearLines() - for j = 1, 16 do - if not UnitDebuff("target", j) then break end - tip:SetUnitDebuff("target", j) - local nameRegion = getglobal("MTH_SP_DebuffTipTextLeft1") - if nameRegion then - local debuffName = nameRegion:GetText() - if debuffName and CC_DEBUFF_SET[debuffName] then - return true - end - end - end - return false -end - --- ── Rush on attack (Dash / Dive / Charge) ──────────────────── -local function CastChargeAbility() - local cfg = GetCfg() - if not cfg.rushOnAttack then return end - if rt.inCombat then return end -- only on initial engage - - -- Try Charge first (Boar — rush + damage), then Dash, then Dive - local idx = -1 - if rt.spellbook.charge > 0 then - idx = rt.spellbook.charge - elseif rt.spellbook.dash > 0 then - idx = rt.spellbook.dash - elseif rt.spellbook.dive > 0 then - idx = rt.spellbook.dive - end - if idx < 1 then return end - - local start, duration = GetSpellCooldown(idx, BOOKTYPE_PET) - if start == 0 and duration == 0 then - CastSpell(idx, BOOKTYPE_PET) - end -end - --- ── Smart Focus ────────────────────────────────────────────── --- Estimate how many focus-regen ticks will occur during an ability's cooldown. -local function EstimatedFocusRegen(slotIndex) - if slotIndex < 1 then return 0 end - local start, duration = GetPetActionCooldown(slotIndex) - if not start or start == 0 then return 0 end - local remaining = (start + duration) - GetTime() - if remaining <= 0 then return 0 end - -- Each tick gives ~FOCUS_REGEN_INTERVAL worth of focus ticks at ~24 focus per 5s cycle - -- SmartPet used FocusManager * 4.8; we use a simpler remaining/5 * 24 estimate - local ticks = remaining / FOCUS_REGEN_INTERVAL - return ticks * 24 -end - -local function HandleFocusEvent() - if not IsEnabled() then return end - local cfg = GetCfg() - if not cfg.smartFocus and cfg.tauntMode == "off" then return end - if not rt.inCombat then return end - if rt.inPVP then return end - - -- Track focus regen tick timing - rt.focus2 = rt.focus1 - rt.focus1 = UnitMana("pet") or 0 - if rt.focus1 > rt.focus2 then - rt.lastFocusTick = GetTime() - rt.nextFocusTick = rt.lastFocusTick + 4.5 - end - - local currentFocus = rt.focus1 - - -- Determine taunt cost (must always be reservable) - local tauntCost = 0 - if cfg.tauntMode ~= "off" then - if GetAutocast(rt.slot.cower) then - tauntCost = ABILITY_INFO.cower.cost - elseif rt.slot.growl > 0 then - tauntCost = ABILITY_INFO.growl.cost - end - end - - -- Collect managed DPS abilities (on bar AND pre-combat autocast was ON) - local managed = {} -- { {key, cost, slot}, ... } - local managedN = 0 - for key, wasOn in pairs(rt.preCombatAutocast) do - if wasOn and rt.slot[key] > 0 and ABILITY_INFO[key] then - managedN = managedN + 1 - managed[managedN] = { key = key, cost = ABILITY_INFO[key].cost, slot = rt.slot[key] } - end - end - - if managedN == 0 then return end - - -- Sort by cost descending (most expensive = highest priority to keep active) - table.sort(managed, function(a, b) return a.cost > b.cost end) - - if cfg.smartFocus and managedN >= 2 then - -- Smart Focus: reserve taunt cost once, then budget the rest across DPS. - -- Always keep the cheapest ability ON so the pet never sits idle; - -- the worst case is growl is delayed by one regen tick (~5s). - local budget = currentFocus - tauntCost - if budget < 0 then budget = 0 end - if MTH and MTH.Print then - MTH:Print("[SP] focus=" .. currentFocus .. " reserve=" .. tauntCost .. " budget=" .. budget .. " managed=" .. managedN, "debug") - end - local anyEnabled = false - for i = 1, managedN do - local m = managed[i] - if budget >= m.cost then - SetAutocast(m.slot, true) - anyEnabled = true - if MTH and MTH.Print then - MTH:Print("[SP] " .. m.key .. " ON (cost=" .. m.cost .. " left=" .. (budget - m.cost) .. ")", "debug") - end - budget = budget - m.cost - elseif i == managedN and not anyEnabled then - -- Cheapest ability: keep ON so pet isn't idle - SetAutocast(m.slot, true) - if MTH and MTH.Print then - MTH:Print("[SP] " .. m.key .. " ON* (cheapest, waiting for regen)", "debug") - end - else - SetAutocast(m.slot, false) - if MTH and MTH.Print then - MTH:Print("[SP] " .. m.key .. " OFF (cost=" .. m.cost .. " budget=" .. budget .. ")", "debug") - end - end - end - return - end - - -- Basic taunt-priority: disable any DPS ability that would starve the taunt - if cfg.tauntMode ~= "off" and tauntCost > 0 then - for i = 1, managedN do - local m = managed[i] - local regen = EstimatedFocusRegen(m.slot) - if (currentFocus + regen) - m.cost < tauntCost then - SetAutocast(m.slot, false) - if MTH and MTH.Print then - MTH:Print("[SP] tauntGuard " .. m.key .. " OFF (focus=" .. currentFocus .. " regen=" .. math.floor(regen) .. ")", "debug") - end - else - SetAutocast(m.slot, true) - end - end - end -end - --- ── AutoCower on low HP ────────────────────────────────────── -local function HandlePetHealth() - if not IsEnabled() then return end - if not rt.inCombat then return end - local cfg = GetCfg() - - local hp = UnitHealth("pet") or 0 - local hpMax = UnitHealthMax("pet") or 1 - if hpMax == 0 then hpMax = 1 end - local pct = (100 * hp) / hpMax - - -- AutoCower - if cfg.autoCower and rt.slot.cower > 0 then - if pct < cfg.autoCowerPct then - if not rt.autoCowered then - rt.autoCowered = true - SetAutocast(rt.slot.growl, false) - SetAutocast(rt.slot.cower, true) - end - else - if rt.autoCowered then - rt.autoCowered = false - ApplyTauntMode() - end - end - end - - -- AutoWarn - if cfg.autoWarn then - local warnInterval - if pct >= 60 then - warnInterval = 10 - elseif pct >= 50 then - warnInterval = 8 - elseif pct >= 30 then - warnInterval = 6 - else - warnInterval = 4 - end - if pct < cfg.autoWarnPct - and (GetTime() - rt.lastWarnTime) > warnInterval - and rt.lastWarnPct > pct then - local petName = UnitName("pet") or "Pet" - local msg = petName .. " needs healing! (" .. string.format("%d", pct) .. "% Health)" - local chan = string.upper(cfg.autoWarnChannel or "SAY") - -- Validate channel - if chan == "PARTY" then - if not (UnitInParty and UnitInParty("player")) then chan = "SAY" end - elseif chan == "RAID" then - if not (GetNumRaidMembers and GetNumRaidMembers() > 0) then chan = "SAY" end - elseif chan == "GUILD" then - if not (IsInGuild and IsInGuild()) then chan = "SAY" end - elseif chan ~= "SAY" then - chan = "SAY" - end - SendChatMessage(msg, chan) - rt.lastWarnTime = GetTime() - end - rt.lastWarnPct = pct - end -end - --- ── NoChase ────────────────────────────────────────────────── -local function HandleMonsterEmote(emoteText, sourceName) - if not IsEnabled() then return end - local cfg = GetCfg() - if not cfg.noChase then return end - - local petTarget = UnitName("pettarget") - if sourceName and petTarget and sourceName == petTarget - and strfind(emoteText or "", L_FLEE) then - PetFollow() - rt.theButtonRecall = true - if UIErrorsFrame then - UIErrorsFrame:AddMessage("Recall Pet", 0.0, 0.0, 1.0, 1.0, UIERRORS_HOLD_TIME) - end - end -end - --- ── Pet Damage Meter ───────────────────────────────────────── -local meter = { - active = false, - recording = false, -- true while actively collecting data - startTime = 0, - duration = 0, -- 0 = unlimited, >0 = auto-stop after N seconds - totalDmg = 0, - totalHits = 0, - totalCrits = 0, - totalMisses = 0, - abilities = {}, -- [name] = { dmg=N, hits=N, crits=N, misses=N } - petName = "", - autocastSnapshot = "", -- "Bite=ON Claw=ON Growl=OFF ..." -} - -local MeterPrintSummary -- forward declaration -local MeterStop -- forward declaration - -local function MeterReset() - meter.startTime = GetTime() - meter.recording = true - meter.totalDmg = 0 - meter.totalHits = 0 - meter.totalCrits = 0 - meter.totalMisses = 0 - meter.abilities = {} - -- Snapshot pet name - meter.petName = UnitName("pet") or "Unknown" - -- Ensure slot map is current before reading autocast states - ScanPetActionBar() - -- Snapshot all known ability autocast states - local parts = {} - local partN = 0 - for key, info in pairs(ABILITY_INFO) do - if rt.slot[key] and rt.slot[key] > 0 then - local on = GetAutocast(rt.slot[key]) - partN = partN + 1 - parts[partN] = key .. "=" .. (on and "ON" or "OFF") - end - end - table.sort(parts) - meter.autocastSnapshot = table.concat(parts, " ") -end - -MeterStop = function() - meter.recording = false - meter.active = false - if meter.totalDmg > 0 then MeterPrintSummary() end - MTH:Print("|cffff9900[SP Meter]|r Stopped.") -end - -local function MeterGetAbility(name) - if not meter.abilities[name] then - meter.abilities[name] = { dmg = 0, hits = 0, crits = 0, misses = 0 } - end - return meter.abilities[name] -end - -local function MeterParseCombatMsg(msg) - if not meter.recording or not msg then return end - - local ability, dmg = nil, nil - - -- hit: "'s hits for ." - _, _, ability, dmg = strfind(msg, "'s ([%a ]-) hits .+ for (%d+)") - if ability and dmg then - dmg = tonumber(dmg) or 0 - local a = MeterGetAbility(ability) - a.hits = a.hits + 1 - a.dmg = a.dmg + dmg - meter.totalHits = meter.totalHits + 1 - meter.totalDmg = meter.totalDmg + dmg - return - end - - -- crit: "'s crits for ." - _, _, ability, dmg = strfind(msg, "'s ([%a ]-) crits .+ for (%d+)") - if ability and dmg then - dmg = tonumber(dmg) or 0 - local a = MeterGetAbility(ability) - a.crits = a.crits + 1 - a.dmg = a.dmg + dmg - meter.totalCrits = meter.totalCrits + 1 - meter.totalDmg = meter.totalDmg + dmg - return - end - - -- miss/resist: "'s misses" / "'s was resisted" - _, _, ability = strfind(msg, "'s ([%a ]-) misses") - if not ability then - _, _, ability = strfind(msg, "'s ([%a ]-) was ") - end - if ability then - local a = MeterGetAbility(ability) - a.misses = a.misses + 1 - meter.totalMisses = meter.totalMisses + 1 - return - end -end - -local function MeterParsePetMelee(msg) - if not meter.recording or not msg then return end - - local dmg = nil - - -- hit: " hits for ." - _, _, dmg = strfind(msg, " hits .+ for (%d+)") - if dmg then - dmg = tonumber(dmg) or 0 - local a = MeterGetAbility("Melee") - a.hits = a.hits + 1 - a.dmg = a.dmg + dmg - meter.totalHits = meter.totalHits + 1 - meter.totalDmg = meter.totalDmg + dmg - return - end - - -- crit: " crits for ." - _, _, dmg = strfind(msg, " crits .+ for (%d+)") - if dmg then - dmg = tonumber(dmg) or 0 - local a = MeterGetAbility("Melee") - a.crits = a.crits + 1 - a.dmg = a.dmg + dmg - meter.totalCrits = meter.totalCrits + 1 - meter.totalDmg = meter.totalDmg + dmg - return - end - - -- miss: " misses ." - if strfind(msg, " misses ") then - local a = MeterGetAbility("Melee") - a.misses = a.misses + 1 - meter.totalMisses = meter.totalMisses + 1 - return - end -end - -MeterPrintSummary = function() - if not MTH or not MTH.Print then return end - local elapsed = GetTime() - meter.startTime - if elapsed < 1 then elapsed = 1 end - local dps = meter.totalDmg / elapsed - local smartLabel = GetCfg().smartFocus and "ON" or "OFF" - local totalSwings = meter.totalHits + meter.totalCrits + meter.totalMisses - - MTH:Print(string.format( - "[SP Meter] Pet=%s SmartFocus=%s Duration=%.1fs TotalDmg=%d DPS=%.1f Swings=%d (H:%d C:%d M:%d)", - meter.petName, smartLabel, elapsed, meter.totalDmg, dps, totalSwings, - meter.totalHits, meter.totalCrits, meter.totalMisses), "debug") - - MTH:Print("[SP Meter] Autocasts: " .. meter.autocastSnapshot, "debug") - - -- Per-ability breakdown, sorted by damage - local sorted = {} - local sortN = 0 - for name, data in pairs(meter.abilities) do - sortN = sortN + 1 - sorted[sortN] = { name = name, dmg = data.dmg, hits = data.hits, crits = data.crits, misses = data.misses } - end - table.sort(sorted, function(a, b) return a.dmg > b.dmg end) - for i = 1, sortN do - local e = sorted[i] - local uses = e.hits + e.crits + e.misses - local pct = (meter.totalDmg > 0) and (100 * e.dmg / meter.totalDmg) or 0 - MTH:Print(string.format( - " %s: %d dmg (%.0f%%) %d uses (H:%d C:%d M:%d)", - e.name, e.dmg, pct, uses, e.hits, e.crits, e.misses), "debug") - end -end - --- ── Combat lifecycle ───────────────────────────────────────── -local function OnCombatStart() - if not IsEnabled() then return end - ScanPetActionBar() - rt.inCombat = true - rt.theButtonRecall = false - rt.autoCowered = false - rt.lastWarnTime = 0 - rt.lastWarnPct = (100 * (UnitHealth("pet") or 0)) / math.max(UnitHealthMax("pet") or 1, 1) - - -- Reset meter on new fight (only for untimed meters; timed meters keep recording across fights) - if meter.active and meter.duration == 0 then - MeterReset() - end - - -- Record pre-combat autocast states for all managed DPS abilities - rt.preCombatAutocast = {} - for key, info in pairs(ABILITY_INFO) do - if MANAGED_DPS_TYPES[info.type] and rt.slot[key] and rt.slot[key] > 0 then - rt.preCombatAutocast[key] = GetAutocast(rt.slot[key]) - if MTH and MTH.Print then - MTH:Print("[SP] snapshot " .. key .. "=" .. (GetAutocast(rt.slot[key]) and "ON" or "OFF") .. " slot=" .. rt.slot[key] .. " cost=" .. ABILITY_INFO[key].cost, "debug") - end - end - end - - -- Smart Focus initial state: keep only the most expensive ability enabled - local cfg = GetCfg() - if cfg.smartFocus then - local managed = {} - local managedN = 0 - for key, wasOn in pairs(rt.preCombatAutocast) do - if wasOn and ABILITY_INFO[key] then - managedN = managedN + 1 - managed[managedN] = { key = key, cost = ABILITY_INFO[key].cost, slot = rt.slot[key] } - end - end - if MTH and MTH.Print then - MTH:Print("[SP] combatStart smartFocus=ON managedON=" .. managedN, "debug") - end - if managedN >= 2 then - table.sort(managed, function(a, b) return a.cost > b.cost end) - for i = 1, managedN do - local state = (i == 1) and "ON" or "OFF" - if MTH and MTH.Print then - MTH:Print("[SP] init " .. managed[i].key .. "=" .. state .. " (cost=" .. managed[i].cost .. ")", "debug") - end - SetAutocast(managed[i].slot, i == 1) - end - end - else - if MTH and MTH.Print then - MTH:Print("[SP] combatStart smartFocus=OFF", "debug") - end - end -end - -local function OnCombatEnd() - -- Print meter summary on combat end (only for untimed meters) - if meter.active and meter.duration == 0 and meter.totalDmg > 0 then - MeterPrintSummary() - end - - -- Restore all managed DPS autocasts to pre-combat state - if rt.preCombatAutocast then - for key, wasOn in pairs(rt.preCombatAutocast) do - if rt.slot[key] and rt.slot[key] > 0 then - SetAutocast(rt.slot[key], wasOn) - if MTH and MTH.Print then - MTH:Print("[SP] restore " .. key .. "=" .. (wasOn and "ON" or "OFF"), "debug") - end - end - end - end - - if rt.inPVP then EndPVP() end - - rt.inCombat = false - rt.autoCowered = false - rt.theButtonRecall = false - - -- Re-apply taunt mode (restores growl/cower to config state) - ApplyTauntMode() -end - --- ── PetAttack wrapper (used by The Button and hook) ────────── -local MTH_SP_OriginalPetAttack = nil - -local function SmartPetAttack() - if not IsEnabled() then - if MTH_SP_OriginalPetAttack then MTH_SP_OriginalPetAttack() end - return - end - - local cfg = GetCfg() - - -- CC-Break check - if cfg.ccBreakCheck and UnitExists("target") then - if TargetHasBreakableCC() then - if cfg.ccBreakMode == "block" then - if UIErrorsFrame then - UIErrorsFrame:AddMessage("Breakable debuff found — pet attack blocked", 1.0, 0.3, 0.0, 1.0, UIERRORS_HOLD_TIME) - end - return - else - if UIErrorsFrame then - UIErrorsFrame:AddMessage("Warning: target has breakable CC", 1.0, 1.0, 0.0, 1.0, UIERRORS_HOLD_TIME) - end - end - end - end - - -- PVP check - if UnitExists("target") and UnitIsPlayer("target") and UnitCanAttack("player", "target") then - StartPVP() - end - - -- Dash/Dive on attack - CastChargeAbility() - - -- Issue the actual PetAttack - if MTH_SP_OriginalPetAttack then MTH_SP_OriginalPetAttack() end -end - --- ── The Button ─────────────────────────────────────────────── --- Global function called from Bindings.xml -function MTH_SmartPet_TheButton() - if not IsEnabled() then return end - local cfg = GetCfg() - if not cfg.theButton then return end - - -- NoChase recall pending - if rt.theButtonRecall then - PetFollow() - rt.theButtonRecall = false - return - end - - -- No pet alive - if not UnitExists("pet") or UnitIsDead("pet") then return end - - -- No target or dead target → recall - if not UnitExists("target") or UnitIsDead("target") then - PetFollow() - return - end - - -- Friendly target → assist (attack their target) - if UnitIsPlayer("target") and UnitCanCooperate("player", "target") then - if UnitExists("targettarget") and not UnitIsDead("targettarget") - and UnitCanAttack("player", "targettarget") then - AssistUnit("target") - SmartPetAttack() - end - return - end - - -- Enemy target → attack - if UnitCanAttack("player", "target") and not UnitIsDead("target") then - SmartPetAttack() - return - end - - -- Fallback: recall - PetFollow() -end - --- ── Taunt toggle (keybind) ─────────────────────────────────── -function MTH_SmartPet_TauntToggle() - if not IsEnabled() then return end - local growlOn = GetAutocast(rt.slot.growl) - local cowerOn = GetAutocast(rt.slot.cower) - - if growlOn then - -- Switch to cower - SetAutocast(rt.slot.growl, false) - if rt.slot.cower > 0 then SetAutocast(rt.slot.cower, true) end - elseif cowerOn then - -- Switch to growl - SetAutocast(rt.slot.cower, false) - if rt.slot.growl > 0 then SetAutocast(rt.slot.growl, true) end - else - -- Neither on: enable growl - if rt.slot.growl > 0 then SetAutocast(rt.slot.growl, true) end - end -end - --- ── Event frame ────────────────────────────────────────────── -local frame = CreateFrame("Frame", "MTH_SmartPetFrame") -frame:Hide() - --- Meter auto-stop ticker (runs only while meter is active with a duration) -local meterTickFrame = CreateFrame("Frame") -meterTickFrame:Hide() -meterTickFrame:SetScript("OnUpdate", function() - if not meter.active or not meter.recording then - meterTickFrame:Hide() - return - end - if meter.duration > 0 and (GetTime() - meter.startTime) >= meter.duration then - MeterStop() - meterTickFrame:Hide() - end -end) - -frame:RegisterEvent("VARIABLES_LOADED") -frame:RegisterEvent("PET_BAR_UPDATE") -frame:RegisterEvent("PET_UI_UPDATE") -frame:RegisterEvent("PET_ATTACK_START") -frame:RegisterEvent("PET_ATTACK_STOP") -frame:RegisterEvent("PLAYER_DEAD") -frame:RegisterEvent("UNIT_HEALTH") -frame:RegisterEvent("UNIT_FOCUS") -frame:RegisterEvent("PARTY_MEMBERS_CHANGED") -frame:RegisterEvent("RAID_ROSTER_UPDATE") -frame:RegisterEvent("CHAT_MSG_MONSTER_EMOTE") -frame:RegisterEvent("PLAYER_ENTERING_WORLD") -frame:RegisterEvent("CHAT_MSG_SPELL_PET_DAMAGE") -frame:RegisterEvent("CHAT_MSG_COMBAT_PET_HITS") -frame:RegisterEvent("CHAT_MSG_COMBAT_PET_MISSES") - -frame:SetScript("OnEvent", function() - -- Meter events bypass the module-enabled check - if event == "CHAT_MSG_SPELL_PET_DAMAGE" then - if meter.recording then - MTH:Print("[SP Meter] " .. event .. ": " .. (arg1 or "nil"), "debug") - MeterParseCombatMsg(arg1) - end - return - end - if event == "CHAT_MSG_COMBAT_PET_HITS" or event == "CHAT_MSG_COMBAT_PET_MISSES" then - if meter.recording then - MTH:Print("[SP Meter] " .. event .. ": " .. (arg1 or "nil"), "debug") - MeterParsePetMelee(arg1) - end - return - end - - if not IsEnabled() then - -- Even with module off, handle meter start/stop (untimed only) - if meter.active and meter.duration == 0 then - if event == "PET_ATTACK_START" then - MeterReset() - elseif event == "PET_ATTACK_STOP" or event == "PLAYER_DEAD" then - if meter.totalDmg > 0 then MeterPrintSummary() end - end - end - return - end - - if event == "VARIABLES_LOADED" or event == "PLAYER_ENTERING_WORLD" then - ResolveLocaleStrings() - ScanPetActionBar() - ScanPetSpellbook() - ScanPartyForTank() - -- Hook PetAttack once - if not MTH_SP_OriginalPetAttack and type(PetAttack) == "function" then - MTH_SP_OriginalPetAttack = PetAttack - PetAttack = SmartPetAttack - end - ApplyTauntMode() - return - end - - if event == "PET_BAR_UPDATE" or event == "PET_UI_UPDATE" then - ScanPetActionBar() - ScanPetSpellbook() - return - end - - if event == "PET_ATTACK_START" then - OnCombatStart() - return - end - - if event == "PET_ATTACK_STOP" or event == "PLAYER_DEAD" then - OnCombatEnd() - return - end - - if event == "UNIT_FOCUS" and arg1 == "pet" then - HandleFocusEvent() - return - end - - if event == "UNIT_HEALTH" and arg1 == "pet" then - HandlePetHealth() - return - end - - if event == "PARTY_MEMBERS_CHANGED" or event == "RAID_ROSTER_UPDATE" then - ScanPartyForTank() - if not rt.inCombat then - ApplyTauntMode() - end - return - end - - if event == "CHAT_MSG_MONSTER_EMOTE" then - HandleMonsterEmote(arg1, arg2) - return - end -end) - --- ── Public API (for options panel and external access) ──────── -MTH_SmartPet = { - GetConfig = GetCfg, - - SetTauntMode = function(mode) - local cfg = GetCfg() - if mode == "auto" or mode == "growl" or mode == "cower" or mode == "off" then - cfg.tauntMode = mode - if not rt.inCombat then ApplyTauntMode() end - end - end, - - SetPvpDetaunt = function(v) GetCfg().pvpDetaunt = v and true or false end, - - SetCcBreakCheck = function(v) GetCfg().ccBreakCheck = v and true or false end, - SetCcBreakMode = function(mode) - if mode == "block" or mode == "warn" then - GetCfg().ccBreakMode = mode - end - end, - - SetTheButton = function(v) GetCfg().theButton = v and true or false end, - SetSmartFocus = function(v) GetCfg().smartFocus = v and true or false end, - - SetAutoCower = function(v) GetCfg().autoCower = v and true or false end, - SetAutoCowerPct = function(v) - v = tonumber(v) - if v and v >= 1 and v <= 99 then GetCfg().autoCowerPct = v end - end, - - SetNoChase = function(v) GetCfg().noChase = v and true or false end, - SetRushOnAttack = function(v) GetCfg().rushOnAttack = v and true or false end, - - SetAutoWarn = function(v) GetCfg().autoWarn = v and true or false end, - SetAutoWarnPct = function(v) - v = tonumber(v) - if v and v >= 1 and v <= 99 then GetCfg().autoWarnPct = v end - end, - SetAutoWarnChannel = function(chan) - chan = string.upper(tostring(chan or "SAY")) - if chan == "SAY" or chan == "PARTY" or chan == "RAID" or chan == "GUILD" then - GetCfg().autoWarnChannel = chan - end - end, - - -- Force a rescan (useful after pet swap) - Rescan = function() - ScanPetActionBar() - ScanPetSpellbook() - ScanPartyForTank() - if not rt.inCombat then ApplyTauntMode() end - end, - - -- Damage meter (duration=0 for unlimited, >0 for timed auto-stop) - StartMeter = function(duration) - meter.active = true - meter.duration = duration or 0 - MeterReset() - if duration and duration > 0 then - meterTickFrame:Show() - MTH:Print(string.format("|cffff9900[SP Meter]|r ON — recording for %ds.", duration)) - else - MTH:Print("|cffff9900[SP Meter]|r ON — /sp meter to stop.") - end - end, - - StopMeter = function() - if meter.active then - MeterStop() - meterTickFrame:Hide() - else - MTH:Print("|cffff9900[SP Meter]|r Not running.") - end - end, - - -- Reprint last summary - PrintMeter = function() - if meter.totalDmg > 0 then - MeterPrintSummary() - else - MTH:Print("|cffff9900[SP Meter]|r No data recorded.") - end - end, -} - --- ── Register with MTH framework so IsModuleEnabled works ───── -local MTH_SmartPetModule = { - name = "smartpet", - enabled = false, - events = {}, -} - -function MTH_SmartPetModule:init() - self.initialized = true -end - -function MTH_SmartPetModule:setEnabled(enabled) - -- No-op: SmartPet checks IsEnabled() on every event -end - -if MTH and MTH.RegisterModule then - MTH:RegisterModule("smartpet", MTH_SmartPetModule) -end - --- ── Slash command ──────────────────────────────────────────── -SLASH_MTHSmartPet1 = "/sp" -SlashCmdList["MTHSmartPet"] = function(msg) - msg = string.lower(msg or "") - if msg == "meter" then - if meter.active then - MTH_SmartPet.StopMeter() - else - MTH_SmartPet.StartMeter(0) - end - elseif msg == "meter print" then - MTH_SmartPet.PrintMeter() - else - -- "/sp meter 60" — timed start - local _, _, secs = strfind(msg, "^meter (%d+)$") - if secs then - MTH_SmartPet.StartMeter(tonumber(secs)) - else - MTH:Print("|cffff9900[SmartPet]|r /sp meter — toggle damage meter") - MTH:Print("|cffff9900[SmartPet]|r /sp meter 60 — record for 60s then stop") - MTH:Print("|cffff9900[SmartPet]|r /sp meter print — reprint last fight") - end - end -end diff --git a/modules/smartpet/loader.xml b/modules/smartpet/loader.xml deleted file mode 100644 index 6d68df7..0000000 --- a/modules/smartpet/loader.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - -