--[[ Things to do.. - Single Target Mode UpdateWidgetContextTargetOnly UpdateIconGrid TargetOnlyEventHandler - Raid-Target Only Mode - More recycling of table entries The Prefilter should discard spells based on a general criteria Allowed spells - SpellID match - Debuffs (right now) - Target GUID Testing /wg emilye nagrand arena Arena UnitID support - Debuffs - Cast bars Idea: Store Recent non-target, non-focus, non-mouseover unitid via the Gameevent system Game events happen before combat log events When a debuff falls off, while marked as a raid-target (and cleared), the rest of the debuffs are cleared. When one debuff falls off, the whole shebang should get re-evaluated with the data table in-mind. -- Widget Object Functions --]] TidyPlatesWidgets.DebuffWidgetBuild = 2 local PlayerGUID = UnitGUID("player") local PolledHideIn = TidyPlatesWidgets.PolledHideIn local FilterFunction = function() return 1 end local AuraMonitor = CreateFrame("Frame") local WatcherIsEnabled = false local WidgetList, WidgetGUID = {}, {} local UpdateWidget local TargetOfGroupMembers = {} local DebuffColumns = 3 local inArena = false local function DefaultDebuffPreFilter() return true end local DebuffPrefilter = DefaultDebuffPreFilter local AURA_TARGET_HOSTILE = 1 local AURA_TARGET_FRIENDLY = 2 local AURA_TYPE_BUFF = 1 local AURA_TYPE_DEBUFF = 6 local _ local AURA_TYPE = { ["Buff"] = 1, ["Curse"] = 2, ["Disease"] = 3, ["Magic"] = 4, ["Poison"] = 5, ["Debuff"] = 6, } local function SetFilter(func) if func and type(func) == "function" then FilterFunction = func end end local function GetAuraWidgetByGUID(guid) if guid then return WidgetGUID[guid] end end local function IsAuraShown(widget, aura) if widget and widget.IsShown then for i = 1, 6 do if widget.AuraIconFrames[i] and widget.AuraIconFrames[i]:IsShown() then return true end end end end local RaidIconBit = { ["STAR"] = 0x00000001, ["CIRCLE"] = 0x00000002, ["DIAMOND"] = 0x00000004, ["TRIANGLE"] = 0x00000008, ["MOON"] = 0x00000010, ["SQUARE"] = 0x00000020, ["CROSS"] = 0x00000040, ["SKULL"] = 0x00000080, } local RaidIconIndex = { "STAR", "CIRCLE", "DIAMOND", "TRIANGLE", "MOON", "SQUARE", "CROSS", "SKULL", } local ByRaidIcon = {} -- Raid Icon to GUID -- ex. ByRaidIcon["SKULL"] = GUID local ByName = {} -- Name to GUID (PVP) local PlayerDispelCapabilities = { ["Curse"] = false, ["Disease"] = false, ["Magic"] = false, ["Poison"] = false, } --[[ local DispelTypes = { ["Curse"] = function() if IsSpellKnown(51886) then return true end -- Cleanse Spirit, Shaman if IsSpellKnown(475) then return true end -- Remove Curse, Mage if IsSpellKnown(2782) then return true end -- Remove Corruption, Druid end, ["Poison"] = function() if IsSpellKnown(2782) then return true end -- Remove Corruption, Druid if IsSpellKnown(32375) then return true end -- Mass Dispel, Priest if IsSpellKnown(527) and IsSpellKnown(33167) then return true end -- Dispel Magic, Priest, Requires Absolution, 33167 if IsSpellKnown(4987) then return true end -- Cleanse, Paladin end, ["Magic"] = function() if IsSpellKnown(4987) and IsSpellKnown(53551) then return true end -- Cleanse, Paladin, Requires Sacred Cleansing, 53551 if IsSpellKnown(2782) and IsSpellKnown(88423) then return true end -- Remove Corruption, Druid, Requires Nature's Cure, 88423 if IsSpellKnown(527) and IsSpellKnown(33167) then return true end -- Dispel Magic, Priest, Requires Absolution, 33167 if IsSpellKnown(32375) then return true end -- Mass Dispel, Priest if IsSpellKnown(51886) and IsSpellKnown(77130) then return true end -- Cleanse Spirit, Shaman, Requires Improved Cleanse Spirit, 77130 end, ["Disease"] = function() if IsSpellKnown(4987) then return true end -- Cleanse, Paladin if IsSpellKnown(528) then return true end -- Cure Disease, Shaman end, } --]] local function UpdatePlayerDispelTypes() PlayerDispelCapabilities["Curse"] = IsSpellKnown(51886) or IsSpellKnown(475) or IsSpellKnown(2782) PlayerDispelCapabilities["Poison"] = IsSpellKnown(2782) or IsSpellKnown(32375) or IsSpellKnown(4987) or (IsSpellKnown(527) and IsSpellKnown(33167)) PlayerDispelCapabilities["Magic"] = (IsSpellKnown(4987) and IsSpellKnown(53551)) or (IsSpellKnown(2782) and IsSpellKnown(88423)) or (IsSpellKnown(527) and IsSpellKnown(33167)) or (IsSpellKnown(51886) and IsSpellKnown(77130)) or IsSpellKnown(32375) PlayerDispelCapabilities["Disease"] = IsSpellKnown(4987) or IsSpellKnown(528) end local function CanPlayerDispel(debuffType) return PlayerDispelCapabilities[debuffType or ""] end ----------------------------------------------------- -- Default Filter ----------------------------------------------------- local function DefaultFilterFunction(debuff) if (debuff.duration < 600) then return true end end ----------------------------------------------------- -- Update Via Search ----------------------------------------------------- local function FindWidgetByGUID(guid) return WidgetGUID[guid] end local function FindWidgetByName(SearchFor) local widget --local SearchFor = strsplit("-", NameString) for widget in pairs(WidgetList) do if widget.unit.name == SearchFor then return widget end end end local function FindWidgetByIcon(raidicon) local widget for widget in pairs(WidgetList) do if widget.unit.isMarked and widget.unit.raidIcon == raidicon then return widget end end end local function CallForWidgetUpdate(guid, raidicon, name) local widget if guid then widget = FindWidgetByGUID(guid) end if (not widget) and name then widget = FindWidgetByName(name) end if (not widget) and raidicon then widget = FindWidgetByIcon(raidicon) end if widget then UpdateWidget(widget) end end ----------------------------------------------------- -- Aura Durations ----------------------------------------------------- TidyPlatesWidgetData.CachedAuraDurations = {} local function GetSpellDuration(spellid) if spellid then return TidyPlatesWidgetData.CachedAuraDurations[spellid] end end local function SetSpellDuration(spellid, duration) if spellid then TidyPlatesWidgetData.CachedAuraDurations[spellid] = duration end end ----------------------------------------------------- -- Aura Instances ----------------------------------------------------- -- New Style local Aura_List = {} -- Two Dimensional local Aura_Spellid = {} local Aura_Spellname = {} local Aura_Expiration = {} local Aura_Stacks = {} local Aura_Caster = {} local Aura_Duration = {} local Aura_Texture = {} local Aura_Type = {} local Aura_Target = {} local function SetAuraInstance(guid, spellid, spellname, expiration, stacks, caster, duration, texture, auratype, auratarget) if guid and spellid and caster and texture then if DebuffPrefilter(spellid, spellname, auratype) ~= true then return end --print("SetAuraInstance", guid, spellid, spellname, expiration, stacks, caster, duration, texture, auratype, auratarget) local aura_id = spellid..(tostring(caster or "UNKNOWN_CASTER")) local aura_instance_id = guid..aura_id Aura_List[guid] = Aura_List[guid] or {} Aura_List[guid][aura_id] = aura_instance_id Aura_Spellid[aura_instance_id] = spellid Aura_Spellname[aura_instance_id] = spellname Aura_Expiration[aura_instance_id] = expiration Aura_Stacks[aura_instance_id] = stacks Aura_Caster[aura_instance_id] = caster Aura_Duration[aura_instance_id] = duration Aura_Texture[aura_instance_id] = texture Aura_Type[aura_instance_id] = auratype Aura_Target[aura_instance_id] = auratarget end end local function GetAuraInstance(guid, aura_id) if guid and aura_id then local aura_instance_id = guid..aura_id local spellid, expiration, stacks, caster, duration, texture, auratype spellid = Aura_Spellid[aura_instance_id] spellname = Aura_Spellname[aura_instance_id] expiration = Aura_Expiration[aura_instance_id] stacks = Aura_Stacks[aura_instance_id] caster = Aura_Caster[aura_instance_id] duration = Aura_Duration[aura_instance_id] texture = Aura_Texture[aura_instance_id] auratype = Aura_Type[aura_instance_id] auratarget = Aura_Target[aura_instance_id] return spellid, spellname, expiration, stacks, caster, duration, texture, auratype, auratarget end end local function WipeUnitAuraList(guid) if guid and Aura_List[guid] then local unit_aura_list = Aura_List[guid] for aura_id, aura_instance_id in pairs(unit_aura_list) do Aura_Spellid[aura_instance_id] = nil Aura_Spellname[aura_instance_id] = nil Aura_Expiration[aura_instance_id] = nil Aura_Stacks[aura_instance_id] = nil Aura_Caster[aura_instance_id] = nil Aura_Duration[aura_instance_id] = nil Aura_Texture[aura_instance_id] = nil Aura_Type[aura_instance_id] = nil Aura_Target[aura_instance_id] = nil unit_aura_list[aura_id] = nil end end end local function GetAuraList(guid) if guid and Aura_List[guid] then return Aura_List[guid] end end local function RemoveAuraInstance(guid, spellid, caster) if guid and spellid and Aura_List[guid] then local aura_instance_id = tostring(guid)..tostring(spellid)..(tostring(caster or "UNKNOWN_CASTER")) local aura_id = spellid..(tostring(caster or "UNKNOWN_CASTER")) if Aura_List[guid][aura_id] then Aura_Spellid[aura_instance_id] = nil Aura_Spellname[aura_instance_id] = nil Aura_Expiration[aura_instance_id] = nil Aura_Stacks[aura_instance_id] = nil Aura_Caster[aura_instance_id] = nil Aura_Duration[aura_instance_id] = nil Aura_Texture[aura_instance_id] = nil Aura_Type[aura_instance_id] = nil Aura_Target[aura_instance_id] = nil Aura_List[guid][aura_id] = nil end end end local function CleanAuraLists() -- Removes expired auras from the lists local currentTime = GetTime() for guid, instance_list in pairs(Aura_List) do local auracount = 0 for aura_id, aura_instance_id in pairs(instance_list) do local expiration = Aura_Expiration[aura_instance_id] if expiration and expiration < currentTime then Aura_List[guid][aura_id] = nil Aura_Spellid[aura_instance_id] = nil Aura_Spellname[aura_instance_id] = nil Aura_Expiration[aura_instance_id] = nil Aura_Stacks[aura_instance_id] = nil Aura_Caster[aura_instance_id] = nil Aura_Duration[aura_instance_id] = nil Aura_Texture[aura_instance_id] = nil Aura_Type[aura_instance_id] = nil Aura_Target[aura_instance_id] = nil else auracount = auracount + 1 end end if auracount == 0 then Aura_List[guid] = nil end end end ----------------------------------------------------- -- Aura Updating Via UnitID (Via UnitDebuff API function and UNIT_AURA events) ----------------------------------------------------- local function UpdateAurasByUnitID(unitid) local unitType if UnitIsFriend("player", unitid) then unitType = AURA_TARGET_FRIENDLY else unitType = AURA_TARGET_HOSTILE end --if unitType == AURA_TARGET_FRIENDLY then return end -- If the unit is hostile, quit. Right now. -- Check the UnitIDs Debuffs local index local guid = UnitGUID(unitid) -- Reset Auras for a guid WipeUnitAuraList(guid) -- Debuffs for index = 1, 40 do local spellname , _, texture, count, dispelType, duration, expirationTime, unitCaster, _, _, spellid, _, isBossDebuff = UnitDebuff(unitid, index) if not spellname then break end SetSpellDuration(spellid, duration) -- Caches the aura data for times when the duration cannot be determined (ie. via combat log) SetAuraInstance(guid, spellid, spellname, expirationTime, count, UnitGUID(unitCaster or ""), duration, texture, AURA_TYPE[dispelType or "Debuff"], unitType) end -- Buffs (Only for friendly units) if unitType == AURA_TARGET_FRIENDLY then for index = 1, 40 do local spellname , _, texture, count, dispelType, duration, expirationTime, unitCaster, _, _, spellid, _, isBossDebuff = UnitBuff(unitid, index) if not spellname then break end SetSpellDuration(spellid, duration) -- Caches the aura data for times when the duration cannot be determined (ie. via combat log) SetAuraInstance(guid, spellid, spellname, expirationTime, count, UnitGUID(unitCaster or ""), duration, texture, AURA_TYPE_BUFF, AURA_TARGET_FRIENDLY) end end local raidicon, name if UnitPlayerControlled(unitid) then name = UnitName(unitid) end raidicon = RaidIconIndex[GetRaidTargetIndex(unitid) or ""] if raidicon then ByRaidIcon[raidicon] = guid end CallForWidgetUpdate(guid, raidicon, name) end --[[ local LocalUnitLookup = {} local LocalUnitIdList = {} do -- Populate Unit ID List LocalUnitIdList["target"] = true LocalUnitIdList["focus"] = true LocalUnitIdList["mouseover"] = true for i = 1, 4 do LocalUnitIdList["boss"..i] = true LocalUnitIdList["party"..i] = true end for i = 1, 5 do LocalUnitIdList["arena"..i] = true end for i = 1, 40 do LocalUnitIdList["raid"..i] = true end end --]] ----------------------------------------------------- -- Aura Updating Via Combat Log -- local sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags, spellid, spellName, spellSchool, auraType, stackCount = ... ----------------------------------------------------- local function CombatLog_ApplyAura(...) local timestamp, sourceGUID, destGUID, destName, spellid, spellname, stackCount = ... local duration = GetSpellDuration(spellid) local texture = GetSpellTexture(spellid) SetAuraInstance(destGUID, spellid, spellname, GetTime() + (duration or 0), 1, sourceGUID, duration, texture, AURA_TYPE_DEBUFF, AURA_TARGET_HOSTILE) end local function CombatLog_RemoveAura(...) local timestamp, sourceGUID, destGUID, destName, spellid = ... RemoveAuraInstance(destGUID, spellid, sourceGUID) end local function CombatLog_UpdateAuraStacks(...) local timestamp, sourceGUID, destGUID, destName, spellid, spellname, stackCount = ... local duration = GetSpellDuration(spellid) local texture = GetSpellTexture(spellid) SetAuraInstance(destGUID, spellid, spellname, GetTime() + (duration or 0), stackCount, sourceGUID, duration, texture, AURA_TYPE_DEBUFF, AURA_TARGET_HOSTILE) end ----------------------------------------------------- -- General Events ----------------------------------------------------- --[[ local function EventUnitTarget() TargetOfGroupMembers = wipe(TargetOfGroupMembers) for name, unitid in pairs(TidyPlatesUtility.GroupMembers.UnitId) do local targetOf = unitid..("target" or "") if UnitExists(targetOf) then TargetOfGroupMembers[UnitGUID(targetOf)] = targetOf end end end --]] --[[ local function EventPlayerTarget() -- if UnitExists("target") then UpdateAurasByUnitID("target") end local guid = UnitGUID("target") if guid then LocalUnitLookup[guid] = "target" end end --]] local function EventUnitAura(unitid) if inArena or unitid == "target" or unitid == "target" or unitid == "focus" then UpdateAurasByUnitID(unitid) end end local function EventPlayerEnterWorld() CleanAuraLists() local isInstance, instanceType = IsInInstance() --[[ instanceType... arena - Player versus player arena none - Not inside an instance party - 5-man instance pvp - Player versus player battleground raid - Raid instance --]] if instanceType and instanceType == "arena" then inArena = true else inArena = false end end --[[ local function EventLocalUnitUpdate() local unitid, guid LocalUnitLookup = wipe(LocalUnitLookup) -- Party for i = 1, 5 do unitid = "party"..i guid = UnitGUID(unitid) if guid then LocalUnitLookup[guid] = unitid end end -- Arena Opponent for i = 1, 5 do unitid = "arena"..i guid = UnitGUID(unitid) if guid then LocalUnitLookup[guid] = unitid end end -- Raid for i = 1, 40 do unitid = "raid"..i guid = UnitGUID(unitid) if guid then LocalUnitLookup[guid] = unitid end end --RAID_ROSTER_UPDATE --PARTY_MEMBERS_CHANGED --ARENA_OPPONENT_UPDATE --ARENA_TEAM_UPDATE end --]] ----------------------------------------------------- -- Function Reference Lists ----------------------------------------------------- local CombatLogEvents = { -- Refresh Expire Time ["SPELL_AURA_APPLIED"] = CombatLog_ApplyAura, ["SPELL_AURA_REFRESH"] = CombatLog_ApplyAura, -- Add a stack ["SPELL_AURA_APPLIED_DOSE"] = CombatLog_UpdateAuraStacks, -- Remove a stack ["SPELL_AURA_REMOVED_DOSE"] = CombatLog_UpdateAuraStacks, -- Expires Aura ["SPELL_AURA_BROKEN"] = CombatLog_RemoveAura, ["SPELL_AURA_BROKEN_SPELL"] = CombatLog_RemoveAura, ["SPELL_AURA_REMOVED"] = CombatLog_RemoveAura, } local GeneralEvents = { --["UNIT_TARGET"] = EventUnitTarget, ["UNIT_AURA"] = EventUnitAura, ["PLAYER_ENTERING_WORLD"] = EventPlayerEnterWorld, ["PLAYER_REGEN_ENABLED"] = CleanAuraLists, --["PLAYER_TALENT_UPDATE"] = UpdatePlayerDispelTypes, --["ACTIVE_TALENT_GROUP_CHANGED"] = UpdatePlayerDispelTypes, --["RAID_ROSTER_UPDATE"] = EventLocalUnitUpdate, --["PARTY_MEMBERS_CHANGED"] = EventLocalUnitUpdate, --["ARENA_OPPONENT_UPDATE"] = EventLocalUnitUpdate, --["ARENA_TEAM_UPDATE"] = EventLocalUnitUpdate, --["PLAYER_TARGET"] = EventPlayerTarget, } local function TargetOnlyEventHandler(frame, event, unitid) if unitid == "target" then UpdateAurasByUnitID("target") end end local function GuidIsLocalUnitId(guid) if guid == UnitGUID("target") or guid == UnitGUID("mouseover") or guid == UnitGUID("focus") then return true --elseif LocalUnitLookup[guid] then -- return true else return false end end local GetCombatEventResults --if (tonumber((select(2, GetBuildInfo()))) >= 14299) then else end function GetCombatEventResults(...) local timestamp, combatevent, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlag, spellid, spellname = ... -- WoW 4.2 local auraType, stackCount = select(15, ...) return timestamp, combatevent, sourceGUID, destGUID, destName, destFlags, destRaidFlag, auraType, spellid, spellname, stackCount end local function CombatEventHandler(frame, event, ...) -- General Events, Passthrough if event ~= "COMBAT_LOG_EVENT_UNFILTERED" then if GeneralEvents[event] then GeneralEvents[event](...) end return elseif inArena then return end -- Combat Log Unfiltered local timestamp, combatevent, sourceGUID, destGUID, destName, destFlags, destRaidFlag, auraType, spellid, spellname, stackCount = GetCombatEventResults(...) -- Evaluate only for enemy units, for now if (bit.band(destFlags, COMBATLOG_OBJECT_REACTION_FRIENDLY) == 0) then -- FILTER: ENEMY UNIT local CombatLogUpdateFunction = CombatLogEvents[combatevent] -- Evaluate only for certain combat log events if CombatLogUpdateFunction then -- Evaluate only for debuffs if auraType == "DEBUFF" then -- FILTER: DEBUFF -- Update Auras via API/UnitID Search --if not UpdateAuraByLookup(destGUID) then --- REMOVE this function, and replace with a function that checks to see if the detected unit is a unitid matcher if not GuidIsLocalUnitId(destGUID) then --- REMOVE this function, and replace with a function that checks to see if the detected unit is a unitid match -- Update Auras via Combat Log CombatLogUpdateFunction(timestamp, sourceGUID, destGUID, destName, spellid, spellname, stackCount) end -- To Do: Need to write something to detect when a change was made to the destID -- Return values on functions? local name, raidicon -- Cache Unit Name for alternative lookup strategy if bit.band(destFlags, COMBATLOG_OBJECT_CONTROL_PLAYER) > 0 then local rawName = strsplit("-", destName) -- Strip server name from players ByName[rawName] = destGUID name = rawName end -- Cache Raid Icon Data for alternative lookup strategy for iconname, bitmask in pairs(RaidIconBit) do if bit.band(destRaidFlag, bitmask) > 0 then ByRaidIcon[iconname] = destGUID raidicon = iconname break end end CallForWidgetUpdate(destGUID, raidicon, name) end end end end ------------------------------------------------------------- -- Widget Object Functions ------------------------------------------------------------- local function DefaultFilterFunction(debuff, unit) if (debuff.duration < auraDurationFilter) then return true end end local function UpdateWidgetTime(frame, expiration) local timeleft = expiration-GetTime() if timeleft > 60 then frame.TimeLeft:SetText(floor(timeleft/60).."m") else frame.TimeLeft:SetText(floor(timeleft)) --frame.TimeLeft:SetText(floor(timeleft*10)/10) end end local function UpdateIcon(frame, texture, expiration, stacks) if frame and texture and expiration then -- Icon frame.Icon:SetTexture(texture) -- Stacks if stacks > 1 then frame.Stacks:SetText(stacks) else frame.Stacks:SetText("") end -- Expiration UpdateWidgetTime(frame, expiration) frame:Show() PolledHideIn(frame, expiration) elseif frame then PolledHideIn(frame, 0) end end local AuraSlotspellid = {} -- auraSlot[slot] = spellid local AuraSlotPriority = {} -- auraSlot[slot] = priority local function debuffSort(a,b) return a.priority < b.priority end local DebuffCache = {} local CurrentAura = {} local function UpdateIconGrid(frame, guid) local AuraIconFrames = frame.AuraIconFrames local AurasOnUnit = GetAuraList(guid) local AuraSlotIndex = 1 local instanceid local DebuffLimit = DebuffColumns * 2 DebuffCache = wipe(DebuffCache) local debuffCount = 0 local currentAuraIndex = 0 local aura -- Cache displayable debuffs if AurasOnUnit then frame:Show() for instanceid in pairs(AurasOnUnit) do currentAuraIndex = debuffCount + 1 --local aura = {} CurrentAura[currentAuraIndex] = wipe(CurrentAura[currentAuraIndex] or {}) aura = CurrentAura[currentAuraIndex] aura.spellid, aura.name, aura.expiration, aura.stacks, aura.caster, aura.duration, aura.texture, aura.type, aura.reaction = GetAuraInstance(guid, instanceid) if tonumber(aura.spellid) then aura.unit = frame.unit -- Call Filter Function local show, priority = frame.Filter(aura) --local show, priority = true, 10 -- Testing aura.priority = priority or 10 -- Get Order/Priority if show and aura.expiration > GetTime() then debuffCount = debuffCount + 1 DebuffCache[debuffCount] = aura --DebuffCache[debuffCount] = instanceid end --print("UpdateIconGrid", aura.spellid, aura.name, aura.expiration, aura.stacks, aura.caster, aura.duration, aura.texture, aura.type, aura.reaction, show, aura.priority) end end end -- Display Auras if debuffCount > 0 then sort(DebuffCache, debuffSort) for index = 1, #DebuffCache do local cachedaura = DebuffCache[index] if cachedaura.spellid and cachedaura.expiration then --print("UpdateIcon", AuraIconFrames[AuraSlotIndex], cachedaura.texture, cachedaura.expiration, cachedaura.stacks) UpdateIcon(AuraIconFrames[AuraSlotIndex], cachedaura.texture, cachedaura.expiration, cachedaura.stacks) AuraSlotIndex = AuraSlotIndex + 1 end if AuraSlotIndex > DebuffLimit then break end end end -- Clear Extra Slots for AuraSlotIndex = AuraSlotIndex, DebuffLimit do UpdateIcon(AuraIconFrames[AuraSlotIndex]) end DebuffCache = wipe(DebuffCache) end function UpdateWidget(frame) -- Check for ID local unit = frame.unit if not unit then return end local guid = unit.guid if not guid then -- Attempt to ID widget via Name or Raid Icon if unit.type == "PLAYER" then guid = ByName[unit.name] elseif unit.isMarked then guid = ByRaidIcon[unit.raidIcon] end if guid then unit.guid = guid -- Feed data back into unit table -- Testing else frame:Hide() return end end UpdateIconGrid(frame, guid) TidyPlates:RequestDelegateUpdate() -- Delegate Update, For Debuff Widget-Controlled Scale and Opacity Functions end local function UpdateWidgetTarget(frame) UpdateIconGrid(frame, UnitGUID("target")) end -- Context Update (mouseover, target change) local function UpdateWidgetContextFull(frame, unit) local guid = unit.guid frame.unit = unit frame.guidcache = guid WidgetList[frame] = true if guid then WidgetGUID[guid] = frame end if unit.isTarget then UpdateAurasByUnitID("target") elseif unit.isMouseover then UpdateAurasByUnitID("mouseover") end local raidicon, name if unit.isMarked then raidicon = unit.raidIcon if guid and raidicon then ByRaidIcon[raidicon] = guid end end if unit.type == "PLAYER" and unit.reaction == "HOSTILE" then name = unit.name end CallForWidgetUpdate(guid, raidicon, name) end local function UpdateWidgetContextTargetOnly(frame, unit) if unit.isTarget then -- UpdateAurasByUnitID("target") end end local UpdateWidgetContext = UpdateWidgetContextFull local function ClearWidgetContext(frame) if frame.guidcache then WidgetGUID[frame.guidcache] = nil frame.unit = nil end WidgetList[frame] = nil end local function ExpireFunction(icon) UpdateWidget(icon.Parent) end ------------------------------------------------------------- -- Widget Frames ------------------------------------------------------------- local WideArt = "Interface\\AddOns\\TidyPlatesWidgets\\Aura\\AuraFrameWide" -- FINISH ART local SquareArt = "Interface\\AddOns\\TidyPlatesWidgets\\Aura\\AuraFrameSquare" -- FINISH ART local AuraGlowArt = "Interface\\AddOns\\TidyPlatesWidgets\\Aura\\AuraGlow" local AuraHighlightArt = "Interface\\AddOns\\TidyPlatesWidgets\\Aura\\CCBorder" -- AuraBorderArt, AuraHighlightArt local AuraTestArt = "" --local AuraFont = "Interface\\Addons\\TidyPlates\\Media\\DefaultFont.ttf" local AuraFont = "FONTS\\ARIALN.TTF" local function Enable() AuraMonitor:SetScript("OnEvent", CombatEventHandler) AuraMonitor:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") for event in pairs(GeneralEvents) do AuraMonitor:RegisterEvent(event) end TidyPlatesUtility:EnableGroupWatcher() WatcherIsEnabled = true if not TidyPlatesWidgetData.CachedAuraDurations then TidyPlatesWidgetData.CachedAuraDurations = {} end end local function EnableForTargetOnly() AuraMonitor:UnregisterAllEvents() AuraMonitor:SetScript("OnEvent", TargetEventHandler) -- AuraMonitor:RegisterEvent("UNIT_TARGET") AuraMonitor:RegisterEvent("UNIT_AURA") TidyPlatesUtility:EnableGroupWatcher() WatcherIsEnabled = true end local function Disable() AuraMonitor:SetScript("OnEvent", nil) AuraMonitor:UnregisterAllEvents() WatcherIsEnabled = false end -- Create an Aura Icon local function CreateWideAuraIconFrame(parent) local frame = CreateFrame("Frame", nil, parent) frame.unit = nil frame.Parent = parent frame:SetWidth(26.5); frame:SetHeight(14.5) -- Icon frame.Icon = frame:CreateTexture(nil, "BACKGROUND") frame.Icon:SetAllPoints(frame) --frame.Icon:SetTexCoord(.07, 1-.07, .23, 1-.23) -- obj:SetTexCoord(left,right,top,bottom) frame.Icon:SetTexCoord(.07, 1-.07, .23, 1-.23) -- obj:SetTexCoord(left,right,top,bottom) -- Border frame.Border = frame:CreateTexture(nil, "ARTWORK") frame.Border:SetWidth(32); frame.Border:SetHeight(32) frame.Border:SetPoint("CENTER", 1, -2) frame.Border:SetTexture(WideArt) -- Glow --frame.Glow = frame:CreateTexture(nil, "ARTWORK") --frame.Glow:SetAllPoints(frame.Border) --frame.Glow:SetTexture(AuraGlowArt) -- Time Text frame.TimeLeft = frame:CreateFontString(nil, "OVERLAY") frame.TimeLeft:SetFont(AuraFont ,9, "OUTLINE") frame.TimeLeft:SetShadowOffset(1, -1) frame.TimeLeft:SetShadowColor(0,0,0,1) frame.TimeLeft:SetPoint("RIGHT", 0, 8) frame.TimeLeft:SetWidth(26) frame.TimeLeft:SetHeight(16) frame.TimeLeft:SetJustifyH("RIGHT") -- Stacks frame.Stacks = frame:CreateFontString(nil, "OVERLAY") frame.Stacks:SetFont(AuraFont,10, "OUTLINE") frame.Stacks:SetShadowOffset(1, -1) frame.Stacks:SetShadowColor(0,0,0,1) frame.Stacks:SetPoint("RIGHT", 0, -6) frame.Stacks:SetWidth(26) frame.Stacks:SetHeight(16) frame.Stacks:SetJustifyH("RIGHT") -- Information about the currently displayed aura frame.AuraInfo = { Name = "", Icon = "", Stacks = 0, Expiration = 0, Type = "", } --frame.Poll = UpdateWidgetTime frame.Expire = ExpireFunction -- UpdateWidget(frame) frame.Poll = parent.PollFunction frame:Hide() return frame end -- Create an Aura Icon local function CreateSquareAuraIconFrame(parent) local frame = CreateFrame("Frame", nil, parent) frame.Parent = parent frame:SetWidth(25); frame:SetHeight(20) -- Icon frame.Icon = frame:CreateTexture(nil, "BACKGROUND") frame.Icon:SetAllPoints(frame) frame.Icon:SetTexCoord(.07, 1-.07, .23, 1-.23) -- obj:SetTexCoord(left,right,top,bottom) -- Border -- [[ frame.Border = frame:CreateTexture(nil, "ARTWORK") frame.Border:SetWidth(47); frame.Border:SetHeight(44) frame.Border:SetPoint("CENTER", 1, -2) frame.Border:SetTexture(SquareArt) --]] -- Time Text frame.TimeLeft = frame:CreateFontString(nil, "OVERLAY") frame.TimeLeft:SetFont(AuraFont ,9, "OUTLINE") frame.TimeLeft:SetShadowOffset(1, -1) frame.TimeLeft:SetShadowColor(0,0,0,1) frame.TimeLeft:SetPoint("RIGHT", 0, 8) frame.TimeLeft:SetWidth(26) frame.TimeLeft:SetHeight(16) frame.TimeLeft:SetJustifyH("RIGHT") -- Stacks frame.Stacks = frame:CreateFontString(nil, "OVERLAY") frame.Stacks:SetFont(AuraFont,10, "OUTLINE") frame.Stacks:SetShadowOffset(1, -1) frame.Stacks:SetShadowColor(0,0,0,1) frame.Stacks:SetPoint("RIGHT", 0, -6) frame.Stacks:SetWidth(26) frame.Stacks:SetHeight(16) frame.Stacks:SetJustifyH("RIGHT") -- Information about the currently displayed aura frame.AuraInfo = { Name = "", Icon = "", Stacks = 0, Expiration = 0, Type = "", } --frame.Poll = UpdateWidgetTime frame.Poll = parent.PollFunction frame:Hide() return frame end local CreateIconFrame = CreateWideAuraIconFrame -- Create the Main Widget Body and Icon Array local function CreateAuraWidget(parent, style) --if not WatcherIsEnabled then Enable() end -- Create Base frame local frame = CreateFrame("Frame", nil, parent) frame:SetWidth(128); frame:SetHeight(32); frame:Show() -- Create Icon Array frame.PollFunction = UpdateWidgetTime frame.AuraIconFrames = {} local AuraIconFrames = frame.AuraIconFrames local DebuffLimit = DebuffColumns * 2 for index = 1, DebuffLimit do AuraIconFrames[index] = CreateIconFrame(frame); end -- Set Anchors AuraIconFrames[1]:SetPoint("LEFT", frame) for index = 2, DebuffColumns do AuraIconFrames[index]:SetPoint("LEFT", AuraIconFrames[index-1], "RIGHT", 5, 0) end AuraIconFrames[DebuffColumns+1]:SetPoint("BOTTOMLEFT", AuraIconFrames[1], "TOPLEFT", 0, 8) for index = (DebuffColumns+2), DebuffLimit do AuraIconFrames[index]:SetPoint("LEFT", AuraIconFrames[index-1], "RIGHT", 5, 0) end -- Functions frame._Hide = frame.Hide frame.Hide = function() ClearWidgetContext(frame); frame:_Hide() end frame:SetScript("OnHide", function() for index = 1, 4 do PolledHideIn(AuraIconFrames[index], 0) end end) frame.Filter = DefaultFilterFunction frame.UpdateContext = UpdateWidgetContext frame.Update = UpdateWidgetContext frame.UpdateTarget = UpdateWidgetTarget return frame end local function UseSquareDebuffIcon() CreateIconFrame = CreateSquareAuraIconFrame DebuffColumns = 5 TidyPlates:ForceUpdate() end local function UseWideDebuffIcon() CreateIconFrame = CreateWideAuraIconFrame DebuffColumns = 3 TidyPlates:ForceUpdate() end local function SetPrefilter(func) DebuffPrefilter = func or DefaultDebuffPreFilter end ----------------------------------------------------- -- External ----------------------------------------------------- TidyPlatesWidgets.GetAuraWidgetByGUID = GetAuraWidgetByGUID TidyPlatesWidgets.IsAuraShown = IsAuraShown TidyPlatesWidgets.CanPlayerDispel = CanPlayerDispel TidyPlatesWidgets.UseSquareDebuffIcon = UseSquareDebuffIcon TidyPlatesWidgets.UseWideDebuffIcon = UseWideDebuffIcon TidyPlatesWidgets.SetDebuffPrefilter = SetPrefilter TidyPlatesWidgets.CreateAuraWidget = CreateAuraWidget TidyPlatesWidgets.EnableAuraWatcher = Enable TidyPlatesWidgets.EnableAuraWatcherTargetOnly = EnableForTargetOnly TidyPlatesWidgets.DisableAuraWatcher = Disable