mirror of
https://codeberg.org/Duvelcorp/MetaHunt.git
synced 2026-09-22 07:36:58 +00:00
322 lines
11 KiB
Lua
322 lines
11 KiB
Lua
------------------------------------------------------
|
|
-- 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
|