Files
2026-09-13 09:52:26 +00:00

352 lines
12 KiB
Lua

-- Compatibility layer to use castbars provided by SuperWoW:
-- https://github.com/balakethelock/SuperWoW
-- DLL Status Check Command (always available)
SLASH_PFDLLSTATUS1 = "/pfdll"
SlashCmdList["PFDLLSTATUS"] = function()
local chat = DEFAULT_CHAT_FRAME
chat:AddMessage("|cff33ffccpfUI|r: DLL Status Check")
-- SuperWoW
if SUPERWOW_VERSION then
chat:AddMessage(" |cff00ff00SuperWoW|r: v" .. tostring(SUPERWOW_VERSION))
elseif SpellInfo or SetAutoloot then
chat:AddMessage(" |cffffff00SuperWoW|r: Detected (old version)")
else
chat:AddMessage(" |cffff0000SuperWoW|r: Not detected")
end
-- Nampower
if GetNampowerVersion then
chat:AddMessage(" |cff00ff00Nampower|r: v" .. tostring(GetNampowerVersion()))
else
chat:AddMessage(" |cffff0000Nampower|r: Not detected")
end
-- Check if castbar exists for indicator positioning
if pfUI.castbar and pfUI.castbar.player then
chat:AddMessage(" |cff00ff00Castbar|r: Available for indicator anchoring")
else
chat:AddMessage(" |cffffff00Castbar|r: Not available (indicators use fallback position)")
end
-- Check indicator frames
if pfUI.uf and pfUI.uf.target then
chat:AddMessage(" |cff00ff00Target frame|r: exists")
else
chat:AddMessage(" |cffff0000Target frame|r: NOT found")
end
end
pfUI:RegisterModule("superwow", "vanilla", function ()
if SetAutoloot and SpellInfo and not SUPERWOW_VERSION then
-- Turn every enchanting link that we create in the enchanting frame,
-- from "spell:" back into "enchant:". The enchant-version is what is
-- used by all unmodified game clients. This is required to generate
-- usable links for everyone from the enchant frame while having SuperWoW.
local HookGetCraftItemLink = GetCraftItemLink
_G.GetCraftItemLink = function(index)
local link = HookGetCraftItemLink(index)
return string.gsub(link, "spell:", "enchant:")
end
-- Convert every enchanting link that we receive into a
-- spell link, as for some reason SuperWoW can't handle
-- enchanting links at all and requires it to be a spell.
local HookSetItemRef = SetItemRef
_G.SetItemRef = function(link, text, button)
link = string.gsub(link, "enchant:", "spell:")
HookSetItemRef(link, text, button)
end
local HookGameTooltipSetHyperlink = GameTooltip.SetHyperlink
_G.GameTooltip.SetHyperlink = function(self, link)
link = string.gsub(link, "enchant:", "spell:")
HookGameTooltipSetHyperlink(self, link)
end
DEFAULT_CHAT_FRAME:AddMessage("|cffffffaaAn old version of SuperWoW was detected. Please consider updating:")
DEFAULT_CHAT_FRAME:AddMessage("-> https://github.com/balakethelock/SuperWoW/releases/")
end
if SUPERWOW_VERSION == "1.5" then
QueueFunction(function()
local pfCombatText_AddMessage = _G.CombatText_AddMessage
_G.CombatText_AddMessage = function(message, a, b, c, d, e, f)
local match, _, hex = string.find(message, ".+ %[(0x.+)%]")
if hex and UnitName(hex) then
message = string.gsub(message, hex, UnitName(hex))
end
pfCombatText_AddMessage(message, a, b, c, d, e, f)
end
end)
end
-- TrackUnit API for adding group members to minimap
-- Tracks friendly units on the minimap for easier group coordination
if TrackUnit and C.unitframes.track_group == "1" then
local trackFrame = CreateFrame("Frame")
trackFrame:RegisterEvent("PARTY_MEMBERS_CHANGED")
trackFrame:RegisterEvent("RAID_ROSTER_UPDATE")
trackFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
trackFrame:RegisterEvent("PLAYER_LOGOUT")
trackFrame:SetScript("OnEvent", function()
-- Handle shutdown to prevent crash 132
if event == "PLAYER_LOGOUT" then
this:UnregisterAllEvents()
this:SetScript("OnEvent", nil)
return
end
-- Track party members
for i = 1, 4 do
local unit = "party" .. i
if UnitExists(unit) and UnitIsConnected(unit) then
pcall(TrackUnit, unit)
end
end
-- Track raid members
for i = 1, 40 do
local unit = "raid" .. i
if UnitExists(unit) and UnitIsConnected(unit) and not UnitIsUnit(unit, "player") then
pcall(TrackUnit, unit)
end
end
end)
end
-- Raid Marker Targeting API
-- Allows targeting units by raid marker ("mark1" to "mark8")
if SUPERWOW_VERSION then
pfUI.api.GetMarkedUnit = function(markIndex)
local markUnit = "mark" .. markIndex
if UnitExists(markUnit) then
return markUnit
end
return nil
end
pfUI.api.TargetMark = function(markIndex)
local markUnit = "mark" .. markIndex
if UnitExists(markUnit) then
TargetUnit(markUnit)
return true
end
return false
end
-- Get owner of pet/totem using "owner" suffix
pfUI.api.GetUnitOwner = function(unit)
local ownerUnit = unit .. "owner"
if UnitExists(ownerUnit) then
return UnitName(ownerUnit), ownerUnit
end
return nil
end
end
-- Clickthrough Mode API
-- Allows clicking through corpses to loot underneath
if Clickthrough then
pfUI.api.SetClickthrough = function(enabled)
Clickthrough(enabled and 1 or 0)
end
pfUI.api.GetClickthrough = function()
return Clickthrough() == 1
end
pfUI.api.ToggleClickthrough = function()
local current = Clickthrough()
Clickthrough(current == 1 and 0 or 1)
return Clickthrough() == 1
end
-- Add slash command for clickthrough toggle
SLASH_PFCLICKTHROUGH1 = "/clickthrough"
SLASH_PFCLICKTHROUGH2 = "/ct"
SlashCmdList["PFCLICKTHROUGH"] = function()
local enabled = pfUI.api.ToggleClickthrough()
DEFAULT_CHAT_FRAME:AddMessage("|cff33ffccpfUI|r: Clickthrough mode " .. (enabled and "|cff00ff00enabled|r" or "|cffff0000disabled|r"))
end
end
-- Autoloot Control API
if SetAutoloot then
pfUI.api.SetAutoloot = function(enabled)
SetAutoloot(enabled and 1 or 0)
end
pfUI.api.GetAutoloot = function()
return SetAutoloot() == 1
end
pfUI.api.ToggleAutoloot = function()
local current = SetAutoloot()
SetAutoloot(current == 1 and 0 or 1)
return SetAutoloot() == 1
end
end
-- GetPlayerBuffID wrapper
if GetPlayerBuffID then
pfUI.api.GetPlayerBuffSpellId = function(buffIndex)
return GetPlayerBuffID(buffIndex)
end
end
-- CombatLogAdd wrapper for logging
if CombatLogAdd then
pfUI.api.LogToCombatLog = function(text, raw)
CombatLogAdd(text, raw and 1 or nil)
end
end
-- Local Raid Markers (marks only visible to self)
if SetRaidTarget then
local origSetRaidTarget = SetRaidTarget
pfUI.api.SetLocalRaidTarget = function(unit, index)
origSetRaidTarget(unit, index, "local")
end
end
-- Weapon Enchant Info on other players
if GetWeaponEnchantInfo then
local origGetWeaponEnchantInfo = GetWeaponEnchantInfo
pfUI.api.GetUnitWeaponEnchants = function(unit)
if unit and unit ~= "player" then
local mhName, ohName = GetWeaponEnchantInfo(unit)
return {
mainHand = mhName,
offHand = ohName,
}
else
local hasMainHandEnchant, mainHandExpiration, mainHandCharges, hasOffHandEnchant, offHandExpiration, offHandCharges = origGetWeaponEnchantInfo()
return {
mainHand = hasMainHandEnchant and true or false,
mainHandExpiration = mainHandExpiration,
mainHandCharges = mainHandCharges,
offHand = hasOffHandEnchant and true or false,
offHandExpiration = offHandExpiration,
offHandCharges = offHandCharges,
}
end
end
end
-- Enhance libcast with SuperWoW data for NPCs and other players
-- Player casts use SPELLCAST_* events for proper pushback handling
local supercast = CreateFrame("Frame")
local playerGuid = nil
supercast:RegisterEvent("PLAYER_ENTERING_WORLD")
supercast:RegisterEvent("UNIT_CASTEVENT")
supercast:RegisterEvent("PLAYER_LOGOUT")
supercast:SetScript("OnEvent", function()
-- Handle shutdown to prevent crash 132
if event == "PLAYER_LOGOUT" then
this:UnregisterAllEvents()
this:SetScript("OnEvent", nil)
return
end
if event == "PLAYER_ENTERING_WORLD" then
-- Cache player GUID
if UnitExists then
local guid = GetUnitGUID("player")
playerGuid = guid
end
return
end
local guid = arg1
local isPlayer = guid == playerGuid
-- For non-player units: disable combat parsing events (one-time init)
if not isPlayer and not supercast.init then
-- disable combat parsing events in superwow mode (for non-player units)
libcast:UnregisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE")
libcast:UnregisterEvent("CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE")
libcast:UnregisterEvent("CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF")
libcast:UnregisterEvent("CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE")
libcast:UnregisterEvent("CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF")
libcast:UnregisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS")
libcast:UnregisterEvent("CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS")
libcast:UnregisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE")
libcast:UnregisterEvent("CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE")
libcast:UnregisterEvent("CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE")
libcast:UnregisterEvent("CHAT_MSG_SPELL_PARTY_DAMAGE")
libcast:UnregisterEvent("CHAT_MSG_SPELL_PARTY_BUFF")
libcast:UnregisterEvent("CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE")
libcast:UnregisterEvent("CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS")
libcast:UnregisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE")
libcast:UnregisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS")
libcast:UnregisterEvent("CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE")
libcast:UnregisterEvent("CHAT_MSG_SPELL_CREATURE_VS_CREATURE_BUFF")
supercast.init = true
end
if arg3 == "START" or arg3 == "CAST" or arg3 == "CHANNEL" then
local target = arg2
local event_type = arg3
local spell_id = arg4
local timer = arg5
-- get spell info from spell id
local spell, icon, _
if GetSpellRec then
local rec = GetSpellRec(spell_id)
if rec then
spell = rec.name
local iconID = rec.spellIconID
icon = iconID and GetSpellIconTexture(iconID) or nil
end
elseif SpellInfo and SpellInfo(spell_id) then
spell, _, icon = SpellInfo(spell_id)
end
-- set fallback values
spell = spell or UNKNOWN
icon = icon or "Interface\\Icons\\INV_Misc_QuestionMark"
-- skip on buff procs during cast
if event_type == "CAST" then
if not libcast.db[guid] or libcast.db[guid].cast ~= spell then
-- ignore casts without 'START' event, while there is already another cast.
-- those events can be for example a frost shield proc while casting frostbolt.
-- we want to keep the cast itself, so we simply skip those.
return
end
end
-- For player: store in libcast.db[playerName] so pushback tracking works
-- For others: store by GUID
local dbKey = isPlayer and UnitName("player") or guid
-- add cast action to the database
if not libcast.db[dbKey] then libcast.db[dbKey] = {} end
libcast.db[dbKey].cast = spell
libcast.db[dbKey].rank = nil
libcast.db[dbKey].start = GetTime()
libcast.db[dbKey].casttime = timer or 0
libcast.db[dbKey].icon = icon
libcast.db[dbKey].channel = event_type == "CHANNEL" or false
elseif arg3 == "FAIL" then
-- For player: use playerName, for others: use GUID
local dbKey = isPlayer and UnitName("player") or guid
-- delete all cast entries
if libcast.db[dbKey] then
libcast.db[dbKey].cast = nil
libcast.db[dbKey].rank = nil
libcast.db[dbKey].start = nil
libcast.db[dbKey].casttime = nil
libcast.db[dbKey].icon = nil
libcast.db[dbKey].channel = nil
end
end
end)
end)