diff --git a/modules/focus.lua b/modules/focus.lua new file mode 100644 index 0000000..f36de44 --- /dev/null +++ b/modules/focus.lua @@ -0,0 +1,245 @@ +pfUI:RegisterModule("focus", "vanilla:tbc", function () + -- do not go further on disabled UFs + if C.unitframes.disable == "1" then return end + + pfUI.uf.focus = pfUI.uf:CreateUnitFrame("Focus", nil, C.unitframes.focus, .2) + pfUI.uf.focus:UpdateFrameSize() + pfUI.uf.focus:SetPoint("BOTTOMLEFT", UIParent, "BOTTOM", 220, 220) + UpdateMovable(pfUI.uf.focus) + pfUI.uf.focus:Hide() + + pfUI.uf.focustarget = pfUI.uf:CreateUnitFrame("FocusTarget", nil, C.unitframes.focustarget, .2) + pfUI.uf.focustarget:UpdateFrameSize() + pfUI.uf.focustarget:SetPoint("BOTTOMLEFT", pfUI.uf.focus, "TOP", 0, 10) + UpdateMovable(pfUI.uf.focustarget) + pfUI.uf.focustarget:Hide() +end) + +-- register focus emulation commands for vanilla +if pfUI.client > 11200 then return end + +-- Helper: set focus frame to a GUID +local function SetFocusByGUID(guid) + pfUI.uf.focus.unitname = nil + pfUI.uf.focus.label = guid + pfUI.uf.focus.id = "" + + if pfUI.uf.focustarget then + pfUI.uf.focustarget.unitname = nil + pfUI.uf.focustarget.label = guid .. "target" + pfUI.uf.focustarget.id = "" + end +end + +-- Helper: set focus frame by name (fallback, no Nampower) +local function SetFocusByName(name) + pfUI.uf.focus.unitname = strlower(name) + pfUI.uf.focus.label = nil + pfUI.uf.focus.id = nil + + if pfUI.uf.focustarget then + pfUI.uf.focustarget.unitname = strlower(name) .. "target" + pfUI.uf.focustarget.label = nil + pfUI.uf.focustarget.id = nil + end +end + +SLASH_PFFOCUS1, SLASH_PFFOCUS2 = '/focus', '/pffocus' +function SlashCmdList.PFFOCUS(msg) + if not pfUI.uf or not pfUI.uf.focus then return end + + if msg ~= "" then + -- Try to resolve GUID via short target swap + if UnitExists then + local prevGUID = GetUnitGUID("target") + local prevPlayer = UnitIsUnit("target", "player") + + -- Suppress "Unknown unit" errors during targeting attempts (fired async) + UIErrorsFrame:UnregisterEvent("UI_ERROR_MESSAGE") + + -- Try exact match first, then prefix match via /tar + TargetByName(msg, true) + local guid = GetUnitGUID("target") + + if not guid or guid == "0x0000000000000000" then + -- Fallback: prefix match (like /tar storm -> Stormwind Guard) + SlashCmdList.TARGET(msg) + _, guid = UnitExists("target") + end + + -- Re-enable errors next frame (errors are fired async) + local restore = CreateFrame("Frame") + restore:SetScript("OnUpdate", function() + UIErrorsFrame:RegisterEvent("UI_ERROR_MESSAGE") + restore:SetScript("OnUpdate", nil) + end) + + -- Restore previous target + if prevGUID and prevGUID ~= "0x0000000000000000" then + TargetUnit(prevGUID) + elseif prevPlayer then + TargetUnit("player") + else + ClearTarget() + end + + if guid and guid ~= "0x0000000000000000" then + SetFocusByGUID(guid) + return + end + end + + -- Fallback: name-based (non-Nampower clients) + SetFocusByName(msg) + else + -- No msg: use current target + if UnitExists then + local guid = GetUnitGUID("target") + if guid and guid ~= "0x0000000000000000" then + SetFocusByGUID(guid) + return + end + end + + -- Fallback: name-based + local name = UnitName("target") + if name then + SetFocusByName(name) + end + end +end + +SLASH_PFCLEARFOCUS1, SLASH_PFCLEARFOCUS2 = '/clearfocus', '/pfclearfocus' +function SlashCmdList.PFCLEARFOCUS(msg) + if pfUI.uf and pfUI.uf.focus then + pfUI.uf.focus.unitname = nil + pfUI.uf.focus.label = nil + pfUI.uf.focus.id = nil + end + + if pfUI.uf and pfUI.uf.focustarget then + pfUI.uf.focustarget.unitname = nil + pfUI.uf.focustarget.label = nil + pfUI.uf.focustarget.id = nil + end +end + +SLASH_PFCASTFOCUS1, SLASH_PFCASTFOCUS2 = '/castfocus', '/pfcastfocus' +function SlashCmdList.PFCASTFOCUS(msg) + if not pfUI.uf.focus or not pfUI.uf.focus:IsShown() then + UIErrorsFrame:AddMessage(SPELL_FAILED_BAD_TARGETS, 1, 0, 0) + return + end + + local func = pfUI.api.TryMemoizedFuncLoadstringForSpellCasts(msg) + local focusGUID = pfUI.uf.focus.label + local hasGUID = focusGUID and focusGUID ~= "" and focusGUID ~= "0x0000000000000000" + + -- GUID-based cast (Nampower) - no target toggle needed + if hasGUID and CastSpellByName and not func then + CastSpellByName(msg, focusGUID) + return + end + + -- For lua functions with GUID: short target swap via GUID + if hasGUID and func then + local currentGUID = GetUnitGUID("target") + local isPlayer = UnitIsUnit("target", "player") + + TargetUnit(focusGUID) + local newGUID = GetUnitGUID("target") + + if newGUID ~= focusGUID then + -- Could not target focus, restore and fail + if currentGUID and currentGUID ~= "0x0000000000000000" then + TargetUnit(currentGUID) + elseif isPlayer then + TargetUnit("player") + else + TargetLastTarget() + end + UIErrorsFrame:AddMessage(SPELL_FAILED_BAD_TARGETS, 1, 0, 0) + return + end + + func() + + if currentGUID and currentGUID ~= "0x0000000000000000" then + TargetUnit(currentGUID) + elseif isPlayer then + TargetUnit("player") + else + TargetLastTarget() + end + return + end + + -- Fallback: name-based target swap (no Nampower / no GUID) + local skiptarget = false + local player = UnitIsUnit("target", "player") + local unitname = "" + + if pfUI.uf.focus.label and pfUI.uf.focus.id and + UnitIsUnit("target", pfUI.uf.focus.label .. pfUI.uf.focus.id) then + skiptarget = true + else + pfScanActive = true + if pfUI.uf.focus.label and pfUI.uf.focus.id then + unitname = UnitName(pfUI.uf.focus.label .. pfUI.uf.focus.id) + TargetUnit(pfUI.uf.focus.label .. pfUI.uf.focus.id) + else + unitname = pfUI.uf.focus.unitname + TargetByName(pfUI.uf.focus.unitname, true) + end + + if strlower(UnitName("target") or "") ~= strlower(unitname or "") then + pfScanActive = nil + TargetLastTarget() + UIErrorsFrame:AddMessage(SPELL_FAILED_BAD_TARGETS, 1, 0, 0) + return + end + end + + if func then + func() + else + CastSpellByName(msg) + end + + if skiptarget == false then + pfScanActive = nil + if player then + TargetUnit("player") + else + TargetLastTarget() + end + end +end + +SLASH_PFSWAPFOCUS1, SLASH_PFSWAPFOCUS2 = '/swapfocus', '/pfswapfocus' +function SlashCmdList.PFSWAPFOCUS(msg) + if not pfUI.uf or not pfUI.uf.focus then return end + + local _, guid = nil, nil + if UnitExists then + _, guid = UnitExists("target") + end + + if guid and guid ~= "0x0000000000000000" then + local oldGUID = pfUI.uf.focus.label + + SetFocusByGUID(guid) + + -- Target old focus if we had one + if oldGUID and oldGUID ~= "" and oldGUID ~= "0x0000000000000000" then + TargetUnit(oldGUID) + end + else + -- Fallback: name-based swap + local oldunit = UnitExists("target") and strlower(UnitName("target") or "") + if oldunit and pfUI.uf.focus.unitname then + TargetByName(pfUI.uf.focus.unitname, true) + pfUI.uf.focus.unitname = oldunit + end + end +end