/
local _,playerClass = UnitClass("player") |
local tinsert = table.insert |
local layoutName = "oUF_Smee2" |
_G[layoutName] = LibStub("AceAddon-3.0"):NewAddon(layoutName,"AceConsole-3.0") |
local addon = _G[layoutName]; |
addon.LSM = LibStub("LibSharedMedia-3.0") |
addon.build = {} |
addon.build.version, addon.build.build, addon.build.date, addon.build.tocversion = GetBuildInfo() |
addon.LSM = LibStub("LibSharedMedia-3.0") |
addon.build = {} |
addon.build.version, addon.build.build, addon.build.date, addon.build.tocversion = GetBuildInfo() |
addon.oUF = oUFSmee2_embed |
oUFSmee2_embed = nil |
--------------- |
-- UI tweaks -- |
-- LDB -- |
--------------- |
local LDB = LibStub:GetLibrary("LibDataBroker-1.1"):NewDataObject(layoutName, { |
label = "|cFF006699oUF|r_|cFFFF3300Smee|r", |
## X-eMail: airtonix@gmail.com |
## Version: 30100.008 |
## SavedVariables: oUF_Smee2DB |
## OptionalDeps: Ace3, SharedMedia, oUF_PowerSpark, oUF_Banzai, oUF_Smooth, oUF_CombatFeedback, oUF_HealComm, oUF_DebuffHighlight, oUF_SpellRange, oUF_ReadyCheck, oUF_TagEditor |
## RequiredDeps: oUF, oUF_TagEditor |
## OptionalDeps: Ace3, SharedMedia, oUF_PowerSpark, oUF_Banzai, oUF_Smooth, oUF_CombatFeedback, oUF_HealComm, oUF_DebuffHighlight, oUF_SpellRange, oUF_ReadyCheck |
## DefaultState: enabled |
## X-oUF: oUFSmee2_embed |
oUFembed/oUF.xml |
## Libraries |
embeds.xml |
## Plugins |
oUF_SmeeRunes.lua |
oUF_HealComm.lua |
## Core |
tagEditor.lua |
settings.lua |
core.lua |
local MAJOR_VERSION = "LibHealComm-3.0"; |
local MINOR_VERSION = 90000 + tonumber(("$Revision: 48 $"):match("%d+")); |
local lib = LibStub:NewLibrary(MAJOR_VERSION, MINOR_VERSION); |
if not lib then return end |
local playerName = UnitName('player'); |
local playerRealm = GetRealmName(); |
local playerClass = select(2, UnitClass('player')); |
local isHealer = (playerClass == "PRIEST") or (playerClass == "SHAMAN") or (playerClass == "DRUID") or (playerClass == "PALADIN"); |
----------------- |
-- Event Frame -- |
----------------- |
lib.EventFrame = lib.EventFrame or CreateFrame("Frame"); |
lib.EventFrame:SetScript("OnEvent", function (this, event, ...) lib[event](lib, ...) end); |
lib.EventFrame:UnregisterAllEvents(); |
-- Register Events |
lib.EventFrame:RegisterEvent("PLAYER_ALIVE"); |
lib.EventFrame:RegisterEvent("LEARNED_SPELL_IN_TAB"); |
lib.EventFrame:RegisterEvent("CHAT_MSG_ADDON"); |
lib.EventFrame:RegisterEvent("UNIT_SPELLCAST_DELAYED"); |
lib.EventFrame:RegisterEvent("UNIT_AURA"); |
lib.EventFrame:RegisterEvent("UNIT_TARGET"); |
lib.EventFrame:RegisterEvent("PLAYER_TARGET_CHANGED"); |
lib.EventFrame:RegisterEvent("PLAYER_FOCUS_CHANGED"); |
lib.EventFrame:RegisterEvent("GLYPH_ADDED"); |
lib.EventFrame:RegisterEvent("GLYPH_REMOVED"); |
lib.EventFrame:RegisterEvent("GLYPH_UPDATED"); |
-- For keeping track of versions |
lib.EventFrame:RegisterEvent("PARTY_MEMBERS_CHANGED"); |
lib.EventFrame:RegisterEvent("RAID_ROSTER_UPDATE"); |
-- Prune data at zone change |
lib.EventFrame:RegisterEvent("PLAYER_ENTERING_WORLD"); |
-- Only listen to these events if player is healing class |
if (isHealer) then |
lib.EventFrame:RegisterEvent("UNIT_SPELLCAST_SENT"); |
lib.EventFrame:RegisterEvent("UNIT_SPELLCAST_START"); |
lib.EventFrame:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED"); |
lib.EventFrame:RegisterEvent("UNIT_SPELLCAST_STOP"); |
end |
---------------------- |
-- Scanning Tooltip -- |
---------------------- |
if (not lib.Tooltip) then |
lib.Tooltip = CreateFrame("GameTooltip"); |
lib.Tooltip:SetOwner(UIParent, "ANCHOR_NONE"); |
for i = 1, 4 do |
lib["TooltipTextLeft" .. i] = lib.Tooltip:CreateFontString(); |
lib["TooltipTextRight" .. i] = lib.Tooltip:CreateFontString(); |
lib.Tooltip:AddFontStrings(lib["TooltipTextLeft" .. i], lib["TooltipTextRight" .. i]); |
end |
end |
------------------------------- |
-- Embed CallbackHandler-1.0 -- |
------------------------------- |
lib.Callbacks = LibStub("CallbackHandler-1.0"):New(lib); |
----------------- |
-- Static Data -- |
----------------- |
-- Cache of spells and heal sizes |
local SpellCache = {}; |
-- Cache of glyphs |
local GlyphCache = {}; |
-- Info about spells being cast by other players |
local HealTime = {}; |
local HealTarget = {}; |
local HealSize = {}; |
-- Healing Modifiers (by name) |
local HealModifier = {}; |
-- Last target name from UNIT_SPELLCAST_SENT |
local SentTargetName; |
-- Last spellCastIndex from UNIT_SPELLCAST_STOP |
local LastSpellCastIndex; |
-- Info about the spell being cast by the player |
local CastInfoIsCasting; |
local CastInfoHealingTargetUnitID; |
local CastInfoHealingTargetNames; |
local CastInfoHealingSize; |
local CastInfoEndTime; |
-- Latency Measurement |
local SentTime = 0; |
local Latency = 0; |
-- Version Information Table |
local Versions = {}; |
-- Battleground/Arena/Group Indicators |
local InBattlegroundOrArena; |
local InRaidOrParty; |
--------------------------------- |
-- Frequently Accessed Globals -- |
--------------------------------- |
local type = type; |
local tonumber = tonumber; |
local math = math; |
local string = string; |
local select = select; |
local pairs = pairs; |
local unpack = unpack; |
local UnitName = UnitName; |
local SendAddonMessage = SendAddonMessage; |
local IsInInstance = IsInInstance; |
local UnitBuff = UnitBuff; |
local UnitDebuff = UnitDebuff; |
local UnitLevel = UnitLevel; |
local GetInventoryItemLink = GetInventoryItemLink; |
local GetTime = GetTime; |
local UnitCastingInfo = UnitCastingInfo; |
local GetSpellBonusHealing = GetSpellBonusHealing; |
local GetTalentInfo = GetTalentInfo; |
local UnitExists = UnitExists; |
local tinsert = table.insert; |
local tconcat = table.concat; |
--------------- |
-- Utilities -- |
--------------- |
local function unitFullName(unit) |
local name, realm = UnitName(unit); |
if (realm and realm ~= "") then |
return name .. "-" .. realm; |
else |
return name; |
end |
end |
local function extractRealm(fullName) |
return fullName:match("^[^%-]+%-(.+)$"); |
end |
-- Convert a remotely generated fully qualified name to |
-- a local fully qualified name. |
local function convertRealm(fullName, remoteRealm) |
if (remoteRealm) then |
local name, realm = fullName:match("^([^%-]+)%-(.+)$"); |
if (not realm) then |
-- Apply remote realm if there is no realm on the target |
return fullName .. "-" .. remoteRealm; |
elseif (realm == playerRealm) then |
-- Strip realm if it is equal to the local realm |
return name; |
end |
end |
return fullName; |
end |
local function commSend(contents, distribution, target) |
SendAddonMessage("HealComm", contents, distribution or (InBattlegroundOrArena and "BATTLEGROUND" or "RAID"), target); |
end |
-- Spellbook Scanner -- |
local function getBaseHealSize(name) |
-- Check if info is already cached |
if (SpellCache[name]) then |
return SpellCache[name]; |
end |
SpellCache[name] = {}; |
-- Gather info (only done if not in cache) |
local i = 1; |
while true do |
local spellName, spellRank = GetSpellName(i, BOOKTYPE_SPELL); |
if (not spellName) then |
break |
end |
if (spellName == name) then |
-- This is the spell we're looking for, gather info |
-- Determine rank |
spellRank = tonumber(spellRank:match("(%d+)")); |
lib.Tooltip:SetSpell(i, BOOKTYPE_SPELL); |
-- Determine healing |
local HealMin, HealMax = select(3, string.find(lib.TooltipTextLeft4:GetText() or lib.TooltipTextLeft3:GetText() or "", "(%d+) ?[\195\160tobisa到~\-]+ ?(%d+)")); |
HealMin, HealMax = tonumber(HealMin) or 0, tonumber(HealMax) or 0; |
local Heal = (HealMin + HealMax) / 2; |
SpellCache[spellName][spellRank] = Heal; |
end |
i = i + 1; |
end |
return SpellCache[name]; |
end |
local function detectGlyph(id) |
-- Check if info is already cached |
if (GlyphCache[id] ~= nil) then |
return GlyphCache[id]; |
end |
GlyphCache[id] = false; |
-- Gather info (only done if not in cache) |
for i = 1, GetNumGlyphSockets() do |
local enabled, _, glyphId = GetGlyphSocketInfo(i); |
if (enabled and glyphId) then |
GlyphCache[glyphId] = true; |
end |
end |
return GlyphCache[id]; |
end |
-- Detects if a buff is present on the unit and returns the application number. |
-- Optionally, if the third argument is provided and is true, then only return |
-- true if the buff was placed by the player. |
local function detectBuff(unit, buffName, mineOnly) |
local name, _, _, count, _, _, _, isMine = UnitBuff(unit, buffName); |
return name and (not mineOnly or isMine) and count or false; |
end |
--[[ |
[GetSpellInfo(604)] = -20, -- Dampen Magic (Rank 1) |
[GetSpellInfo(8450)] = -40, -- Dampen Magic (Rank 2) |
[GetSpellInfo(8451)] = -80, -- Dampen Magic (Rank 3) |
[GetSpellInfo(10173)] = -120, -- Dampen Magic (Rank 4) |
[GetSpellInfo(10174)] = -180, -- Dampen Magic (Rank 5) |
[GetSpellInfo(33944)] = -240, -- Dampen Magic (Rank 6) |
[GetSpellInfo(1008)] = 30, -- Amplify Magic (Rank 1) |
[GetSpellInfo(8455)] = 60, -- Amplify Magic (Rank 2) |
[GetSpellInfo(10169)] = 100, -- Amplify Magic (Rank 3) |
[GetSpellInfo(10170)] = 150, -- Amplify Magic (Rank 4) |
[GetSpellInfo(27130)] = 180, -- Amplify Magic (Rank 5) |
[GetSpellInfo(33946)] = 240, -- Amplify Magic (Rank 6) |
[GetSpellInfo(32858)] = -345 -- Touch of the Forgotten (Auchenai Crypts) |
[GetSpellInfo(38377)] = -690 -- Touch of the Forgotten (Auchenai Crypts) |
]]-- |
local healingBuffs = |
{ |
[GetSpellInfo(706)] = 1.20, -- Demon Armor |
[GetSpellInfo(45234)] = function (count, rank) return (1.0 + (0.04 + 0.03 * (rank - 1)) * count) end, -- Focused Will |
[GetSpellInfo(34123)] = 1.06, -- Tree of Life |
[GetSpellInfo(58549)] = function (count, rank, texture) return ((texture == "Interface\\Icons\\Ability_Warrior_StrengthOfArms") and (1.18 ^ count) or 1.0) end, -- Tenacity (Wintergrasp) |
} |
local healingDebuffs = |
{ |
[GetSpellInfo(25646)] = function (count) return (1.0 - count * 0.10) end, -- Mortal Wound (Temporus - The Black Morass) |
[GetSpellInfo(45347)] = function (count) return (1.0 - count * 0.04) end, -- Dark Touched (Grand Warlock Alythess - Sunwell Plateau) |
[GetSpellInfo(30423)] = function (count) return (1.0 - count * 0.01) end, -- Nether Portal - Dominance (Netherspite - Karazhan) |
[GetSpellInfo(13218)] = function (count) return (1.0 - count * 0.10) end, -- Wound Poison |
[GetSpellInfo(19434)] = 0.50, -- Aimed Shot |
[GetSpellInfo(12294)] = 0.50, -- Mortal Strike |
[GetSpellInfo(40599)] = 0.50, -- Arcing Smash (Gurtogg Bloodboil) |
[GetSpellInfo(23169)] = 0.50, -- Brood Affliction: Green (Chromaggus) |
[GetSpellInfo(34073)] = 0.85, -- Curse of the Bleeding Hollow (Hellfire Peninsula) |
[GetSpellInfo(13583)] = 0.50, -- Curse of the Deadwood (Deadwood Furbolgs - Felwood) |
[GetSpellInfo(36023)] = 0.50, -- Deathblow |
[GetSpellInfo(34625)] = 0.25, -- Demolish (Negatron - Netherstorm) |
[GetSpellInfo(34366)] = 0.75, -- Ebon Poison (Black Morass) |
[GetSpellInfo(32378)] = 0.50, -- Filet (Spectral Chef - Karazhan) |
[GetSpellInfo(19716)] = 0.25, -- Gehennas' Curse (Gehennas - Molten Core) |
[GetSpellInfo(36917)] = 0.50, -- Magma-Thrower's Curse (Sulfuron Magma-Thrower - The Arcatraz) |
[GetSpellInfo(22859)] = 0.50, -- Mortal Cleave (High Priestess Thekal - Zul'Gurub) |
[GetSpellInfo(38572)] = 0.50, -- Mortal Cleave (High Priestess Thekal - Zul'Gurub) |
[GetSpellInfo(39595)] = 0.50, -- Mortal Cleave (High Priestess Thekal - Zul'Gurub) |
[GetSpellInfo(28776)] = 0.10, -- Necrotic Poison (Maexxna - Naxxramas) |
[GetSpellInfo(35189)] = 0.50, -- Solar Strike (The Mechanar) |
[GetSpellInfo(32315)] = 0.50, -- Soul Strike (Ethereal Crypt Raiders - Mana-Tombs) |
[GetSpellInfo(7068)] = 0.25, -- Veil of Shadow (Nefarian - Blackwing Lair) |
[GetSpellInfo(38387)] = 1.50, -- Bane of Infinity (CoT: Escape from Durholde) |
[GetSpellInfo(31977)] = 1.50, -- Curse of Infinity (CoT: Escape from Durholde) |
[GetSpellInfo(41292)] = 0.00, -- Aura of Suffering (Essence of Souls - Black Temple) |
[GetSpellInfo(41350)] = 2.00, -- Aura of Desire (Essence of Souls - Black Temple) |
[GetSpellInfo(30843)] = 0.00, -- Enfeeble (Prince Malchezaar - Karazhan) |
} |
local function calculateHealModifier(unit) |
local modifier = 1.0; |
for i = 1, 40 do |
local name, rank, texture, count = UnitDebuff(unit, i); |
if (not name) then |
break; |
end |
local mark = healingDebuffs[name]; |
if (mark) then |
if (type(mark) == "function") then |
mark = mark(count); |
end |
if (mark < modifier) then |
modifier = mark; |
end |
end |
end |
for i = 1, 40 do |
local name, rank, texture, count = UnitBuff(unit, i); |
if (not name) then |
break; |
end |
local mark = healingBuffs[name]; |
if (mark) then |
if (type(mark) == "function") then |
mark = mark(count, rank and tonumber(rank:match("(%d+)")), texture); |
end |
modifier = modifier * mark; |
end |
end |
return modifier; |
end |
local function getDownrankingFactor(spellLevel, playerLevel) |
local factor = 0.05 * ((spellLevel + 7) - playerLevel) + 1; |
if (factor > 1.0) then |
return 1; |
elseif (factor < 0.0) then |
return 0; |
else |
return factor; |
end |
end |
local relicSlotNumber = GetInventorySlotInfo("RangedSlot"); |
local function getEquippedRelicID() |
local itemLink = GetInventoryItemLink('player', relicSlotNumber); |
if (itemLink) then |
return tonumber(itemLink:match("(%d+):")); |
end |
end |
----------------------------- |
-- Healing Data Management -- |
----------------------------- |
local function entryDelete(healerName) |
local targetNames = HealTarget[healerName]; |
HealTime[healerName] = nil; |
HealTarget[healerName] = nil; |
if (type(targetNames) == "table") then |
for i, targetName in pairs(targetNames) do |
if HealSize[targetName] then |
HealSize[targetName][healerName] = nil; |
end |
end |
elseif (targetNames and HealSize[targetNames]) then |
HealSize[targetNames][healerName] = nil; |
end |
end |
local function entryUpdate(healerName, targetNames, healSize, healTime) |
entryDelete(healerName); |
HealTime[healerName] = healTime; |
HealTarget[healerName] = targetNames; |
if (type(targetNames) == "table") then |
for i, targetName in pairs(targetNames) do |
if (not HealSize[targetName]) then |
HealSize[targetName] = {}; |
end |
HealSize[targetName][healerName] = healSize; |
end |
elseif (targetNames) then |
if (not HealSize[targetNames]) then |
HealSize[targetNames] = {}; |
end |
HealSize[targetNames][healerName] = healSize; |
end |
end |
local function entryRetrieve(healerName) |
local healTime = HealTime[healerName]; |
if (healTime) then |
local targetNames = HealTarget[healerName]; |
if (type(targetNames) == "table") then |
return targetNames, HealSize[targetNames[1]][healerName], healTime; |
elseif (targetNames) then |
return targetNames, HealSize[targetNames][healerName], healTime; |
end |
end |
end |
---------------------- |
-- Public Functions -- |
---------------------- |
--[[ UnitIncomingHealGet(unit, time) |
Description: Retrieve info about the incoming heals to a specific |
target. The second argument specifies a boundary time, |
relative to the current time. Examples: |
UnitIncomingHealGet("Kaki", GetTime() + 3) |
UnitIncomingHealGet("Kaki-Emerald Dream", GetTime() + 3) |
UnitIncomingHealGet("player", GetTime() + 3) |
UnitIncomingHealGet("raid10", GetTime() + 3) |
UnitIncomingHealGet("target", GetTime() + 3) |
Retrieves info about the incoming heals on the specified |
target. incomingHealBefore will contain the sum of heals |
that will land within the next 3 seconds, and |
incomingHealAfter will contain the sum of heals that will |
land after 3 seconds. |
Input: |
unit - The exact name or UnitID of the unit to retrieve information about. |
time - the desired boundary time of the inquiry. |
Output: |
incomingHealBefore - The total size of the incoming heals before the boundary time. |
incomingHealAfter - The total size of the incoming heals after the boundary time. |
nextTime - the time left until the next incoming heal will land. |
nextSize - the size of the next incoming heal. |
nextName - the name of the healer casting the next incoming heal. |
]]-- |
function lib:UnitIncomingHealGet(unit, time) |
if (type(unit) ~= "string") then return end |
if (type(time) ~= "number") then return end |
local targetName = unitFullName(unit); |
if (HealSize[targetName]) then |
local now = GetTime(); |
local incomingHealBefore, incomingHealAfter = 0, 0; |
local nextTime, nextSize, nextName; |
for healerName, size in pairs(HealSize[targetName]) do |
local healTime = HealTime[healerName]; |
if (size and healTime) then |
healTime = healTime + Latency; |
if (healTime > now) then |
if (healTime < time) then |
-- Due before boundary time |
incomingHealBefore = incomingHealBefore + size; |
else |
-- Due after boundary time |
incomingHealAfter = incomingHealAfter + size; |
end |
if ((not nextTime) or (healTime < nextTime)) then |
nextTime = healTime; |
nextSize = size; |
nextName = healerName; |
end |
end |
end |
end |
if ((incomingHealBefore > 0) or (incomingHealAfter > 0)) then |
return incomingHealBefore, incomingHealAfter, nextTime, nextSize, nextName; |
end |
end |
end |
--[[ UnitCastingHealGet(unit) |
Description: Retrieve info about the direct healing spell |
currently being cast by any unit. Examples: |
UnitCastingHealGet("Kaki"); |
UnitCastingHealGet("Kaki-Emerald Dream"); |
UnitCastingHealGet("player") |
UnitCastingHealGet("raid10") |
UnitCastingHealGet("target") |
Input: |
unit - The name or UnitID of the unit to retrieve information about. |
Output: |
healSize - Size of the healing being cast. |
endTime - The time when the healing completes. |
targetName - Name of the unit(s) being targeted for heal. |
]]-- |
function lib:UnitCastingHealGet(unit) |
if (type(unit) ~= "string") then return end |
local healerName = unitFullName(unit); |
if (healerName == playerName) then |
if (CastInfoIsCasting) then |
return CastInfoHealingSize, CastInfoEndTime, CastInfoHealingTargetNames; |
end |
else |
local targetNames, healSize, endTime = entryRetrieve(healerName); |
if (targetNames) then |
return healSize, endTime, targetNames; |
end |
end |
end |
--[[ UnitHealModifierGet(unit) |
Description: Returns the modifier to healing (as a factor) |
caused by buffs and debuffs. Examples: |
UnitHealModifierGet("Kaki"); |
UnitHealModifierGet("Kaki-Emerald Dream"); |
UnitHealModifierGet("player", 3) |
UnitHealModifierGet("raid10", 3) |
UnitHealModifierGet("target", 3) |
Input: |
unit - The name or UnitID of the unit to retrieve information about. |
Output: |
factor - Always a fractional number - will be 1.0 if no buffs/debuffs |
affect healing. |
]]-- |
function lib:UnitHealModifierGet(unit) |
if (type(unit) ~= "string") then return end |
local targetName = unitFullName(unit); |
return HealModifier[targetName] or calculateHealModifier(unit); |
end |
function lib:GetRaidOrPartyVersions() |
local tab = {}; |
if (GetNumRaidMembers() > 0) then |
for i = 1, GetNumRaidMembers() do |
local name = unitFullName('raid' .. i); |
if (not (name == playerName)) then |
tab[name] = Versions[name] or false; |
end |
end |
elseif (GetNumPartyMembers() > 0) then |
for i = 1, GetNumPartyMembers() do |
local name = unitFullName('party' .. i); |
tab[name] = Versions[name] or false; |
end |
end |
tab[playerName] = MINOR_VERSION; |
return tab; |
end |
function lib:GetGuildVersions() |
local tab = {}; |
if (IsInGuild()) then |
GuildRoster(); |
for i = 1, GetNumGuildMembers(false) do |
local name, rank, rankIndex, level, class, zone, note, officernote, online, status = GetGuildRosterInfo(i); |
if (online and not (name == playerName)) then |
tab[name] = Versions[name] or false; |
end |
end |
end |
tab[playerName] = MINOR_VERSION; |
return tab; |
end |
function lib:GetUnitVersion(unit) |
if (type(unit) ~= "string") then return end |
local targetName = unitFullName(unit); |
if (targetName == playerName) then return MINOR_VERSION end |
return Versions[targetName] or false; |
end |
-------------------- |
-- Class Specific -- |
-------------------- |
local HealingSpells; |
--local HotSpells; |
local GetHealSize; |
-- Druid -- |
-- TODO: |
-- Talent: Empowered Rejuvenation. Increase effect of all HOTs by 4%-20% |
-- Idol: Idol of Rejuvenation |
if (playerClass == "DRUID") then |
local tHealingTouch = GetSpellInfo(5185); |
local tRegrowth = GetSpellInfo(8936); |
local tNourish = GetSpellInfo(50464); |
local tRejuvenation = GetSpellInfo(774); |
local tLifebloom = GetSpellInfo(33763); |
local tWildGrowth = GetSpellInfo(48438); |
--[[HotSpells = |
{ |
[tRegrowth] = |
{ |
Level = {17, 23, 29, 35, 41, 47, 53, 59, 65, 70, 76, 80}, |
Duration = 21, |
Ticks = 7, |
Pattern = "(%d+)[^0-9]+%d+[^0-9]+$", |
Type = "HoT", |
}, |
[tRejuvenation] = |
{ |
Level = {9, 15, 21, 27, 33, 39, 45, 51, 57, 59, 62, 68, 74, 79, 80}, |
Duration = 12, |
Ticks = 4, |
Pattern = "(%d+)", |
Type = "HoT", |
}, |
[tLifebloom] = |
{ |
Level = {71, 79, 80}, |
Duration = 7, |
Ticks = 7, |
Pattern = "(%d+)" |
Type = "Lifebloom", |
}, |
}]]-- |
HealingSpells = |
{ |
[tHealingTouch] = |
{ |
Level = {1, 8, 14, 20, 26, 32, 38, 44, 50, 56, 60, 62, 69, 74, 79}, |
Type = "Direct", |
}, |
[tRegrowth] = |
{ |
Level = {12, 18, 24, 30, 36, 42, 48, 54, 60, 65, 71, 77}, |
Type = "Direct", |
}, |
[tNourish] = |
{ |
Level = {80}; |
Type = "Direct", |
} |
} |
local idolsHealingTouch = |
{ |
[28568] = 136, -- Idol of the Avian Heart |
[22399] = 100, -- Idol of Health |
} |
GetHealSize = function(name, rank, target) |
local i, effectiveHeal; |
-- Get static spell info |
local baseHealSize = getBaseHealSize(name)[rank]; |
local nBonus = 0; |
local effectiveHealModifier = 1.0; |
if (not baseHealSize) then |
return nil; |
end |
-- Get +healing bonus |
local bonus = GetSpellBonusHealing(); |
local spellTab = HealingSpells[name]; |
-- Gift of Nature Talent - Increases effective healing by 2% per rank on all spells |
effectiveHealModifier = effectiveHealModifier * (2 * select(5, GetTalentInfo(3, 13)) / 100 + 1); |
-- Process individual spells |
if (name == tHealingTouch) then |
local idolBonus = idolsHealingTouch[getEquippedRelicID()] or 0; |
baseHealSize = baseHealSize + idolBonus; |
-- Glyph of Healing Touch (decreases amount healed by 50%) |
if (detectGlyph(54825)) then |
effectiveHealModifier = effectiveHealModifier * 0.5 |
end |
-- Empowered Touch Talent (increases bonus healing effects by 20% per rank) |
local talentEmpoweredTouch = 20 * select(5, GetTalentInfo(3, 15)) / 100; |
if (rank < 5) then |
nBonus = bonus * (1.88 * (1.0 + rank * 0.5) / 3.5 + talentEmpoweredTouch); |
else |
nBonus = bonus * (1.88 + talentEmpoweredTouch); |
end |
elseif (name == tRegrowth) then |
-- Glyph of Regrowth (increases effective healing by 20% if player's Regrowth is on target) |
if (detectGlyph(54743) and detectBuff(target, tRegrowth, true)) then |
effectiveHealModifier = effectiveHealModifier * 1.2; |
end |
nBonus = bonus * 1.88 * (2.0 / 3.5) * 0.5; |
elseif (name == tNourish) then |
-- Nourish heals for 20% more if player's HoT is on the target. |
if (detectBuff(target, tRejuvenation, true) or detectBuff(target, tRegrowth, true) or detectBuff(target, tLifebloom, true) or detectBuff(target, tWildGrowth, true)) then |
effectiveHealModifier = effectiveHealModifier * 1.2 |
end |
nBonus = bonus * 1.88 * (1.5 / 3.5); |
end |
effectiveHeal = effectiveHealModifier * (baseHealSize + nBonus * getDownrankingFactor(spellTab.Level[rank], UnitLevel('player'))); |
return effectiveHeal; |
end |
end |
-- Paladin -- |
-- TODO: Track Beacon of Light (GetSpellInfo(53563) for name). |
if (playerClass == "PALADIN") then |
local tHolyLight = GetSpellInfo(635); |
local tFlashOfLight = GetSpellInfo(19750); |
local tDivineFavor = GetSpellInfo(20216); |
local tSealOfLight = GetSpellInfo(20167); |
local tAvengingWrath = GetSpellInfo(31884); |
local tDivinePlea = GetSpellInfo(54428); |
HealingSpells = |
{ |
[tHolyLight] = |
{ |
Level = {1, 6, 14, 22, 30, 38, 46, 54, 60, 62, 70, 75, 80}, |
Type = "Direct", |
}, |
[tFlashOfLight] = |
{ |
Level = {20, 26, 34, 42, 50, 58, 66, 74, 79}, |
Type = "Direct", |
}, |
} |
local libramsFlashOfLight = |
{ |
[42614] = 267, -- Deadly Gladiator's Libram of Justice |
[42613] = 236, -- Hateful Gladiator's Libram of Justice |
[42612] = 204, -- Savage Gladiator's Libram of Justice |
[28592] = 89, -- Libram of Souls Redeemed (TODO: may be changed to affect Holy Light in 3.0.3) |
[25644] = 79, -- Blessed Book of Nagrand |
[23006] = 43, -- Libram of Light |
[23201] = 28, -- Libram of Divinity |
} |
local libramsHolyLight = |
{ |
[40268] = 141, -- Libram of Tolerance |
[28296] = 47, -- Libram of the Lightbringer |
} |
GetHealSize = function(name, rank, target) |
local i, effectiveHeal; |
-- Get static spell info |
local baseHealSize = getBaseHealSize(name)[rank]; |
local nBonus = 0; |
local effectiveHealModifier = 1.0; |
if (not baseHealSize) then |
return nil; |
end |
-- Get +healing bonus |
local bonus = GetSpellBonusHealing(); |
local spellTab = HealingSpells[name]; |
-- Divine Favor (100% crit chance on heal spell) |
if (detectBuff('player', tDivineFavor)) then |
effectiveHealModifier = effectiveHealModifier * 1.5; |
end |
-- Avenging Wrath (increase all healing by 20%) |
if (detectBuff('player', tAvengingWrath)) then |
effectiveHealModifier = effectiveHealModifier * 1.2; |
end |
-- Divine Plea (decrease all healing by 50%) |
if (detectBuff('player', tDivinePlea)) then |
effectiveHealModifier = effectiveHealModifier * 0.5; |
end |
-- Glyph of Seal of Light (increases healing by 5% if Seal of Light is active) |
if (detectGlyph(54943) and detectBuff('player', tSealOfLight)) then |
effectiveHealModifier = effectiveHealModifier * 1.05; |
end |
-- Healing Light - Increases healing by 4% per rank on all spells |
effectiveHealModifier = effectiveHealModifier * (4 * select(5, GetTalentInfo(1, 3)) / 100 + 1); |
-- Process individual spells |
if (name == tFlashOfLight) then |
local libramBonus = libramsFlashOfLight[getEquippedRelicID()] or 0; |
nBonus = (bonus + libramBonus) * 1.88 * (1.5 / 3.5) * 1.25; |
elseif (name == tHolyLight) then |
local libramBonus = libramsHolyLight[getEquippedRelicID()] or 0; |
nBonus = (bonus + libramBonus) * 1.88 * (2.5 / 3.5) * 1.25; |
end |
effectiveHeal = effectiveHealModifier * (baseHealSize + nBonus * getDownrankingFactor(spellTab.Level[rank], UnitLevel('player'))); |
return effectiveHeal; |
end |
end |
-- Priest -- |
-- TODO: Talent: Improved Renew: increases renew by 5%-10%-15% |
-- Healing_Done = (Renew_Base + (Healbonus * Downrankfactor) ) * Improved_Renew * Spiritual_Healing |
if (playerClass == "PRIEST") then |
local tLesserHeal = GetSpellInfo(2050); |
local tHeal = GetSpellInfo(2054); |
local tGreaterHeal = GetSpellInfo(2060); |
local tFlashHeal = GetSpellInfo(2061); |
local tBindingHeal = GetSpellInfo(32546); |
local tPrayerOfHealing = GetSpellInfo(596); |
local tPowerWordFortitude = GetSpellInfo(1243); |
--local tRenew = GetSpellInfo(139); |
local tGrace = GetSpellInfo(47930); |
--[[HotSpells = |
{ |
[tRenew] = |
{ |
Level = {8, 14, 20, 26, 32, 38, 44, 50, 56, 60, 65, 74, 79, 80}, |
Duration = 15, |
Ticks = 5, |
Pattern = "(%d+)", |
Type = "HoT", |
}, |
}]]-- |
HealingSpells = |
{ |
[tLesserHeal] = |
{ |
Level = {1, 4, 10}, |
Type = "Direct" |
}, |
[tHeal] = |
{ |
Level = {16, 22, 28, 34}, |
Type = "Direct" |
}, |
[tGreaterHeal] = |
{ |
Level = {40, 46, 52, 58, 60, 63, 68, 73, 78}, |
Type = "Direct", |
}, |
[tFlashHeal] = |
{ |
Level = {20, 26, 32, 38, 44, 50, 56, 61, 67, 73, 79}, |
Type = "Direct", |
}, |
[tBindingHeal] = |
{ |
Level = {64, 72, 78}, |
Type = "Binding" |
}, |
[tPrayerOfHealing] = |
{ |
Level = {30, 40, 50, 60, 60, 68, 76}, |
Type = "Party", |
InRange = function(unit) return IsSpellInRange(tPowerWordFortitude, unit) == 1 end |
}, |
} |
GetHealSize = function(name, rank, target) |
local i, effectiveHeal; |
-- Get static spell info |
local baseHealSize = getBaseHealSize(name)[rank]; |
local nBonus = 0; |
local effectiveHealModifier = 1.0; |
if (not baseHealSize) then |
return nil; |
end |
-- Get +healing bonus |
local bonus = GetSpellBonusHealing(); |
local spellTab = HealingSpells[name]; |
-- Focused Power - Increases healing by 2% per rank on all spells |
effectiveHealModifier = effectiveHealModifier * (2 * select(5, GetTalentInfo(1, 16)) / 100 + 1); |
-- Spiritual Healing - Increases healing by 2% per rank on all spells |
effectiveHealModifier = effectiveHealModifier * (2 * select(5, GetTalentInfo(2, 16)) / 100 + 1); |
-- Grace (increases healing by 2% per application on target if buff was placed by the player) |
if (target) then |
local grace = detectBuff(target, tGrace, true); |
if (grace) then |
effectiveHealModifier = effectiveHealModifier * (1.0 + 0.02 * grace); |
end |
end |
-- Process individual spells |
if (name == tLesserHeal) then |
nBonus = bonus * 1.88 * (1.0 + rank * 0.5) / 3.5; |
elseif (name == tHeal) then |
nBonus = bonus * 1.88 * (3.0 / 3.5); |
elseif (name == tGreaterHeal) then |
local empoweredHealing = 8 * select(5, GetTalentInfo(2, 20)) / 100; |
nBonus = bonus * (1.88 * (3.0 / 3.5) + empoweredHealing); |
elseif (name == tFlashHeal) then |
local empoweredHealing = 4 * select(5, GetTalentInfo(2, 20)) / 100; |
nBonus = bonus * (1.88 * (1.5 / 3.5) + empoweredHealing); |
elseif (name == tBindingHeal) then |
local empoweredHealing = 4 * select(5, GetTalentInfo(2, 20)) / 100; |
nBonus = bonus * (1.88 * (1.5 / 3.5) + empoweredHealing); |
elseif (name == tPrayerOfHealing) then |
nBonus = bonus * 1.88 * (3.0 / 3.5) * 0.5; |
end |
effectiveHeal = effectiveHealModifier * (baseHealSize + nBonus * getDownrankingFactor(spellTab.Level[rank], UnitLevel('player'))); |
return effectiveHeal; |
end |
end |
-- Shaman -- |
-- TODO: Nature's Blessing (GetTalentInfo(3, 21)) is probably not accounted for automatically anymore (or is it?) |
-- TODO: Riptide 51point resto spell (instant cast regrowth (direct + hot)) |
-- TODO: Glyph of Healing Wave (binding heal, but self-heal is percentage of actual target healed) |
if (playerClass == "SHAMAN") then |
local tLesserHealingWave = GetSpellInfo(8004); |
local tHealingWave = GetSpellInfo(331); |
local tChainHeal = GetSpellInfo(1064); |
local tHealingWay = GetSpellInfo(29206); |
local tTidalWaves = GetSpellInfo(51562); |
local tRiptide = GetSpellInfo(61295); |
local tEarthShield = GetSpellInfo(974); |
--[[HotSpells = |
{ |
[tRiptide] = |
{ |
Level = {60, 70, 75, 80}, |
Duration = 15, |
Ticks = 5, |
Pattern = "(%d+)", |
Type = "HoT", |
}, |
}]]-- |
HealingSpells = |
{ |
[tLesserHealingWave] = |
{ |
Level = {20, 28, 36, 44, 52, 60, 66, 72, 77}, |
Type = "Direct", |
}, |
[tHealingWave] = |
{ |
Level = {1, 6, 12, 18, 24, 32, 40, 48, 56, 60, 63, 70, 75, 80}, |
Type = "Direct", |
}, |
[tChainHeal] = |
{ |
Level = {40, 46, 54, 61, 68, 74, 80}, |
Type = "Direct", |
}, |
} |
local totemsLesserHealingWave = |
{ |
[42597] = 267, -- Deadly Gladiator's Totem of the Third Wind |
[42596] = 236, -- Hateful Gladiator's Totem of the Third Wind |
[42595] = 204, -- Savage Gladiator's Totem of the Third Wind |
[25645] = 79, -- Totem of The Plains |
[22396] = 80, -- Totem of Life |
[23200] = 53, -- Totem of Sustaining |
} |
local totemsHealingWave = |
{ |
[27544] = 88, -- Totem of Spontaneous Regrowth |
} |
local totemsChainHeal = |
{ |
[38368] = 102, -- Totem of the Bay |
[28523] = 87, -- Totem of Healing Rains |
} |
GetHealSize = function(name, rank, target) |
local i, effectiveHeal; |
-- Get static spell info |
local baseHealSize = getBaseHealSize(name)[rank]; |
local nBonus = 0; |
local effectiveHealModifier = 1.0; |
if (not baseHealSize) then |
return nil; |
end |
-- Get +healing bonus |
local bonus = GetSpellBonusHealing(); |
-- Purification Talent (increases healing by 2% per rank). |
-- This is factored into effectiveHealModifier in the individual spell section below due to interaction with Improved Chain Heal. |
local talentPurification = 2 * select(5, GetTalentInfo(3, 15)) / 100 + 1; |
local spellTab = HealingSpells[name]; |
-- Process individual spells |
if (name == tLesserHealingWave) then |
local totemBonus = totemsLesserHealingWave[getEquippedRelicID()] or 0; |
effectiveHealModifier = effectiveHealModifier * talentPurification; |
-- Glyph of Lesser Healing Wave (increases effective healing by 20% if player's Earth Shield is on target) |
if (detectGlyph(55438) and detectBuff(target, tEarthShield, true)) then |
effectiveHealModifier = effectiveHealModifier * 1.2; |
end |
-- Tidal Waves Talent (increases bonus healing effects by 2% per rank) |
local talentTidalWaves = 2 * select(5, GetTalentInfo(3, 25)) / 100; |
nBonus = (bonus + totemBonus) * (1.88 * (1.5 / 3.5) + talentTidalWaves); |
elseif (name == tHealingWave) then |
local totemBonus = totemsHealingWave[getEquippedRelicID()] or 0; |
effectiveHealModifier = effectiveHealModifier * talentPurification; |
-- Healing Way Buff (target buff that increases effective healing by 18%) |
if (detectBuff(target, tHealingWay)) then |
effectiveHealModifier = effectiveHealModifier * 1.18; |
end; |
-- Tidal Waves Talent (increases bonus healing effects by 4% per rank) |
local talentTidalWaves = 4 * select(5, GetTalentInfo(3, 25)) / 100; |
-- Determine normalisation |
if (rank < 4) then |
nBonus = (bonus + totemBonus) * (1.88 * (1.0 + rank * 0.5) / 3.5 + talentTidalWaves); |
else |
nBonus = (bonus + totemBonus) * (1.88 * (3.0 / 3.5) + talentTidalWaves); |
end |
elseif (name == tChainHeal) then |
local totemBonus = totemsChainHeal[getEquippedRelicID()] or 0; |
baseHealSize = baseHealSize + totemBonus; |
-- Improved Chain Heal Talent (increases healing by 10% per rank) |
local talentImprovedChainHeal = 10 * select(5, GetTalentInfo(3, 20)) / 100; |
effectiveHealModifier = effectiveHealModifier * (talentPurification + talentImprovedChainHeal); |
-- Riptide Buff (target buff that increases effective healing by 25%) |
if (detectBuff(target, tRiptide, true)) then |
effectiveHealModifier = effectiveHealModifier * 1.25; |
end |
nBonus = bonus * 1.88 * (2.5 / 3.5); |
end |
effectiveHeal = effectiveHealModifier * (baseHealSize + nBonus * getDownrankingFactor(spellTab.Level[rank], UnitLevel('player'))); |
return effectiveHeal; |
end |
end |
-------------------- |
-- Event Handlers -- |
-------------------- |
function lib:PLAYER_FOCUS_CHANGED() |
if (UnitExists('focus')) then |
self:UNIT_AURA('focus'); |
end |
if (UnitExists('focustarget')) then |
self:UNIT_AURA('focustarget'); |
end |
end |
function lib:PLAYER_TARGET_CHANGED() |
if (UnitExists('target')) then |
self:UNIT_AURA('target'); |
end |
if (UnitExists('targettarget')) then |
self:UNIT_AURA('targettarget'); |
end |
end |
function lib:UNIT_TARGET(unit) |
if ((unit == 'target') or (unit == 'focus')) then |
local unitTarget = unit .. "target"; |
if (UnitExists(unitTarget)) then |
self:UNIT_AURA(unitTarget); |
end |
end |
end |
function lib:UNIT_AURA(unit) |
local targetName = unitFullName(unit); |
local oldModifier = HealModifier[targetName]; |
local newModifier = calculateHealModifier(unit); |
if (oldModifier) then |
if (newModifier == oldModifier) then |
return |
end |
else |
if (newModifier == 1.0) then |
return |
end |
end |
HealModifier[targetName] = newModifier; |
self.Callbacks:Fire("HealComm_HealModifierUpdate", unit, targetName, newModifier); |
end |
function lib:LEARNED_SPELL_IN_TAB() |
-- Invalidate cached spell data when learning new spells |
SpellCache = {}; |
end |
function lib:GLYPH_ADDED() |
-- Invalidate cached glyph data when updating glyphs |
GlyphCache = {}; |
end |
function lib:GLYPH_REMOVED() |
-- Invalidate cached glyph data when updating glyphs |
GlyphCache = {}; |
end |
function lib:GLYPH_UPDATED() |
-- Invalidate cached glyph data when updating glyphs |
GlyphCache = {}; |
end |
function lib:UNIT_SPELLCAST_SENT(unit, spellName, spellRank, targetName) |
if (unit ~= 'player') then return end |
-- Latency measurement |
SentTime = GetTime(); |
SentTargetName = targetName; |
end |
function lib:UNIT_SPELLCAST_START(unit, spellName, spellRank) |
if (unit ~= 'player') then return end |
-- Latency measurement |
local currentLatency = GetTime() - SentTime; |
if (currentLatency > 1) then -- Limit to 1 sec |
currentLatency = 1; |
end |
Latency = 0.5 * Latency + 0.70 * currentLatency; |
local spellInfo = HealingSpells[spellName]; |
-- Only process healing spells |
if (spellInfo) then |
if (spellInfo.Type == "Direct") then |
CastInfoHealingTargetNames = SentTargetName; |
CastInfoHealingSize = GetHealSize(spellName, tonumber(spellRank:match("(%d+)")), SentTargetName) or 0; |
CastInfoIsCasting = true; |
CastInfoEndTime = (select(6, UnitCastingInfo('player')) or 0) / 1000; |
self.Callbacks:Fire("HealComm_DirectHealStart", playerName, CastInfoHealingSize, CastInfoEndTime, SentTargetName); |
commSend(string.format("000%05d%s", math.min(CastInfoHealingSize, 99999), SentTargetName)); |
elseif (spellInfo.Type == "Binding") then |
CastInfoHealingTargetNames = {playerName, SentTargetName}; |
CastInfoHealingSize = GetHealSize(spellName, tonumber(spellRank:match("(%d+)")), SentTargetName) or 0; |
CastInfoIsCasting = true; |
CastInfoEndTime = (select(6, UnitCastingInfo('player')) or 0) / 1000; |
self.Callbacks:Fire("HealComm_DirectHealStart", playerName, CastInfoHealingSize, CastInfoEndTime, unpack(CastInfoHealingTargetNames)); |
commSend(string.format("002%05d%s", math.min(CastInfoHealingSize, 99999), SentTargetName)); |
elseif (spellInfo.Type == "Party") then |
CastInfoHealingTargetNames = {}; |
if (spellInfo.InRange('party1')) then tinsert(CastInfoHealingTargetNames, unitFullName('party1')) end |
if (spellInfo.InRange('party2')) then tinsert(CastInfoHealingTargetNames, unitFullName('party2')) end |
if (spellInfo.InRange('party3')) then tinsert(CastInfoHealingTargetNames, unitFullName('party3')) end |
if (spellInfo.InRange('party4')) then tinsert(CastInfoHealingTargetNames, unitFullName('party4')) end |
CastInfoHealingSize = GetHealSize(spellName, tonumber(spellRank:match("(%d+)"))) or 0; |
CastInfoIsCasting = true; |
CastInfoEndTime = (select(6, UnitCastingInfo('player')) or 0) / 1000; |
commSend(string.format("002%05d%s", math.min(CastInfoHealingSize, 99999), tconcat(CastInfoHealingTargetNames, ":"))); |
tinsert(CastInfoHealingTargetNames, 1, playerName); |
self.Callbacks:Fire("HealComm_DirectHealStart", playerName, CastInfoHealingSize, CastInfoEndTime, unpack(CastInfoHealingTargetNames)); |
end |
end |
end |
function lib:CHAT_MSG_ADDON(prefix, msg, distribution, sender) |
if (prefix ~= "HealComm") then return end |
if (sender == playerName) then return end |
-- Workaround: Sometimes in battlegrounds the sender argument is not a |
-- fully qualified name (the realm is missing), even though the sender is |
-- from a different realm. |
if (distribution == "BATTLEGROUND") then |
sender = unitFullName(sender) or sender; |
end |
-- Get message type |
local msgtype = tonumber(msg:sub(1, 3)); |
if (not msgtype) then return end |
if (msgtype == 0) then -- DirectHealStart |
local healSize = tonumber(msg:sub(4, 8)); |
local targetName = msg:sub(9, -1); |
if (healSize and targetName) then |
local endTime = select(6, UnitCastingInfo(sender)); |
if (endTime) then |
if (distribution == "BATTLEGROUND") then |
targetName = convertRealm(targetName, extractRealm(sender)); |
end |
endTime = endTime / 1000; |
entryUpdate(sender, targetName, healSize, endTime); |
self.Callbacks:Fire("HealComm_DirectHealStart", sender, healSize, endTime, targetName); |
end |
end |
elseif (msgtype == 1) then -- HealStop |
local targetNames, healSize = entryRetrieve(sender); |
entryDelete(sender); |
if (type(targetNames) == "table") then |
self.Callbacks:Fire("HealComm_DirectHealStop", sender, healSize, msg:sub(4, 4) == "S", unpack(targetNames)); |
elseif (targetNames) then |
self.Callbacks:Fire("HealComm_DirectHealStop", sender, healSize, msg:sub(4, 4) == "S", targetNames); |
end |
elseif (msgtype == 2) then -- MultiTargetHealStart |
local healSize = tonumber(msg:sub(4, 8)); |
local targetNames = {strsplit(":", msg:sub(9, -1))}; |
if (healSize) then |
local endTime = select(6, UnitCastingInfo(sender)); |
if (endTime) then |
if (distribution == "BATTLEGROUND") then |
local senderRealm = extractRealm(sender); |
for k, targetName in pairs(targetNames) do |
targetNames[k] = convertRealm(targetName, senderRealm); |
end |
end |
endTime = endTime / 1000; |
tinsert(targetNames, 1, sender); |
entryUpdate(sender, targetNames, healSize, endTime); |
self.Callbacks:Fire("HealComm_DirectHealStart", sender, healSize, endTime, unpack(targetNames)); |
end |
end |
elseif (msgtype >= 998) then -- AnnounceVersion |
local version = tonumber(msg:sub(4, -1)); |
if (version) then |
Versions[sender] = version; |
if (msgtype == 999) then -- RequestVersion |
if (distribution ~= "BATTLEGROUND") then |
-- Reply in whisper if possible |
commSend("998" .. tostring(MINOR_VERSION), "WHISPER", sender); |
else |
-- Reply to inbound distribution channel |
commSend("998" .. tostring(MINOR_VERSION), distribution); |
end |
end |
end |
end |
end |
function lib:UNIT_SPELLCAST_DELAYED(unit) |
if (unit == 'player') then |
if (CastInfoIsCasting) then |
local endTime = select(6, UnitCastingInfo('player')); |
if (endTime) then |
CastInfoEndTime = endTime / 1000; |
if (type(CastInfoHealingTargetNames) == "table") then |
self.Callbacks:Fire("HealComm_DirectHealDelayed", playerName, CastInfoHealingSize, CastInfoEndTime, unpack(CastInfoHealingTargetNames)); |
elseif (CastInfoHealingTargetNames) then |
self.Callbacks:Fire("HealComm_DirectHealDelayed", playerName, CastInfoHealingSize, CastInfoEndTime, CastInfoHealingTargetNames); |
end |
end |
end |
elseif (unit ~= 'target' and unit ~= 'focus') then |
local healerName = unitFullName(unit); |
local targetNames, healSize = entryRetrieve(healerName) |
if (targetNames) then |
local endTime = select(6, UnitCastingInfo(healerName)); |
if (endTime) then |
endTime = endTime / 1000; |
HealTime[healerName] = endTime; |
if (type(targetNames) == "table") then |
self.Callbacks:Fire("HealComm_DirectHealDelayed", healerName, healSize, endTime, unpack(targetNames)); |
elseif (targetNames) then |
self.Callbacks:Fire("HealComm_DirectHealDelayed", healerName, healSize, endTime, targetNames); |
end |
end |
end |
end |
end |
function lib:UNIT_SPELLCAST_SUCCEEDED(unit, spellName, spellRank, spellCastIndex) |
if (unit ~= 'player') then return end |
if (CastInfoIsCasting) then |
CastInfoIsCasting = false; |
commSend("001S"); |
if (type(CastInfoHealingTargetNames) == "table") then |
self.Callbacks:Fire("HealComm_DirectHealStop", playerName, CastInfoHealingSize, true, unpack(CastInfoHealingTargetNames)); |
elseif (CastInfoHealingTargetNames) then |
self.Callbacks:Fire("HealComm_DirectHealStop", playerName, CastInfoHealingSize, true, CastInfoHealingTargetNames); |
end |
else |
if (LastSpellCastIndex ~= spellCastIndex) then |
-- Instant Cast Spells |
end |
end |
end |
function lib:UNIT_SPELLCAST_STOP(unit, spellName, spellRank, spellCastIndex) |
if (unit == 'player' and CastInfoIsCasting) then |
LastSpellCastIndex = spellCastIndex; |
CastInfoIsCasting = false; |
commSend("001F"); |
if (type(CastInfoHealingTargetNames) == "table") then |
self.Callbacks:Fire("HealComm_DirectHealStop", playerName, CastInfoHealingSize, false, unpack(CastInfoHealingTargetNames)); |
elseif (CastInfoHealingTargetNames) then |
self.Callbacks:Fire("HealComm_DirectHealStop", playerName, CastInfoHealingSize, false, CastInfoHealingTargetNames); |
end |
end |
end |
function lib:PLAYER_ALIVE() |
-- This event is only fired at initial login, not at reloadui or load-on-demand loading. |
-- The initialisation is triggered again, since none of the initialisation had any effect |
-- prior to this event firing (no messages sent and InBattlegroundOrArena and InRaidOrParty |
-- are probably not correctly initialised). |
lib:Initialise(); |
-- Only receive once |
self.EventFrame:UnregisterEvent("PLAYER_ALIVE"); |
end |
function lib:PLAYER_ENTERING_WORLD() |
HealTime = {}; |
HealTarget = {}; |
HealSize = {}; |
HealModifier = {}; |
end |
function lib:PARTY_MEMBERS_CHANGED() |
local wasInRaidOrParty = InRaidOrParty; |
InRaidOrParty = (GetNumRaidMembers() > 0) or (GetNumPartyMembers() > 0); |
-- Announce and request version when joining a group |
if (not wasInRaidOrParty and InRaidOrParty) then |
commSend("999" .. tostring(MINOR_VERSION)); |
end |
end |
function lib:RAID_ROSTER_UPDATE() |
self:PARTY_MEMBERS_CHANGED(); |
end |
function lib:Initialise() |
local it = select(2, IsInInstance()); |
InBattlegroundOrArena = (it == "pvp") or (it == "arena"); |
InRaidOrParty = (GetNumRaidMembers() > 0) or (GetNumPartyMembers() > 0); |
-- Announce and request version in group and in guild |
commSend("999" .. tostring(MINOR_VERSION)); |
if (IsInGuild()) then |
commSend("999" .. tostring(MINOR_VERSION), "GUILD"); |
end |
end |
lib:Initialise(); |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local _VERSION = GetAddOnMetadata(parent, 'version') |
local function argcheck(value, num, ...) |
assert(type(num) == 'number', "Bad argument #2 to 'argcheck' (number expected, got "..type(num)..")") |
for i=1,select("#", ...) do |
if type(value) == select(i, ...) then return end |
end |
local types = strjoin(", ", ...) |
local name = string.match(debugstack(2,2,0), ": in function [`<](.-)['>]") |
error(("Bad argument #%d to '%s' (%s expected, got %s"):format(num, name, types, type(value)), 3) |
end |
local print = function(a) ChatFrame1:AddMessage("|cff33ff99oUF:|r "..tostring(a)) end |
local error = function(...) print("|cffff0000Error:|r "..string.format(...)) end |
local dummy = function() end |
local function SetManyAttributes(self, ...) |
for i=1,select("#", ...),2 do |
local att,val = select(i, ...) |
if not att then return end |
self:SetAttribute(att,val) |
end |
end |
-- Colors |
local colors = { |
health = {49/255, 207/255, 37/255}, -- Health |
happiness = { |
[1] = {1, 0, 0}, -- need.... | unhappy |
[2] = {1, 1, 0}, -- new..... | content |
[3] = {0, 1, 0}, -- colors.. | happy |
}, |
smooth = { |
1, 0, 0, |
1, 1, 0, |
0, 1, 0 |
}, |
disconnected = {.6, .6, .6}, |
tapped = {.6,.6,.6}, |
class = {}, |
reaction = {}, |
power = {}, |
} |
-- We do this because people edit the vars directly, and changing the default |
-- globals makes SPICE FLOW! |
for eclass, color in next, RAID_CLASS_COLORS do |
colors.class[eclass] = {color.r, color.g, color.b} |
end |
for power, color in next, PowerBarColor do |
if(type(power) == 'string') then |
colors.power[power] = {color.r, color.g, color.b} |
end |
end |
for eclass, color in next, FACTION_BAR_COLORS do |
colors.reaction[eclass] = {color.r, color.g, color.b} |
end |
-- add-on object |
local oUF = CreateFrame"Button" |
local frame_metatable = {__index = oUF} |
local event_metatable = { |
__call = function(funcs, self, ...) |
for _, func in ipairs(funcs) do |
func(self, ...) |
end |
end, |
} |
local styles, style = {} |
local callback, units, objects = {}, {}, {} |
local _G, select, type, tostring, math_modf = |
_G, select, type, tostring, math.modf |
local UnitExists, UnitName = |
UnitExists, UnitName |
local conv = { |
['playerpet'] = 'pet', |
['playertarget'] = 'target', |
} |
local elements = {} |
local enableTargetUpdate = function(object) |
-- updating of "invalid" units. |
local OnTargetUpdate |
do |
local timer = 0 |
OnTargetUpdate = function(self, elapsed) |
if(not self.unit) then |
return |
elseif(timer >= .5) then |
self:PLAYER_ENTERING_WORLD'OnTargetUpdate' |
timer = 0 |
end |
timer = timer + elapsed |
end |
end |
object:SetScript("OnUpdate", OnTargetUpdate) |
end |
-- Events |
local OnEvent = function(self, event, ...) |
if(not self:IsShown() and not self.vehicleUnit) then return end |
self[event](self, event, ...) |
end |
local OnAttributeChanged = function(self, name, value) |
if(name == "unit" and value) then |
units[value] = self |
if(self.unit and self.unit == value) then |
return |
else |
if(self.hasChildren) then |
for _, object in next, objects do |
local unit = SecureButton_GetModifiedUnit(object) |
object.unit = conv[unit] or unit |
object:PLAYER_ENTERING_WORLD() |
end |
end |
self.unit = value |
self.id = value:match"^.-(%d+)" |
self:PLAYER_ENTERING_WORLD() |
end |
end |
end |
-- Gigantic function of doom |
local HandleUnit = function(unit, object) |
if(unit == "player") then |
-- Hide the blizzard stuff |
PlayerFrame:UnregisterAllEvents() |
PlayerFrame.Show = dummy |
PlayerFrame:Hide() |
PlayerFrameHealthBar:UnregisterAllEvents() |
PlayerFrameManaBar:UnregisterAllEvents() |
elseif(unit == "pet")then |
-- Hide the blizzard stuff |
PetFrame:UnregisterAllEvents() |
PetFrame.Show = dummy |
PetFrame:Hide() |
PetFrameHealthBar:UnregisterAllEvents() |
PetFrameManaBar:UnregisterAllEvents() |
elseif(unit == "target") then |
-- Hide the blizzard stuff |
TargetFrame:UnregisterAllEvents() |
TargetFrame.Show = dummy |
TargetFrame:Hide() |
TargetFrameHealthBar:UnregisterAllEvents() |
TargetFrameManaBar:UnregisterAllEvents() |
TargetFrameSpellBar:UnregisterAllEvents() |
ComboFrame:UnregisterAllEvents() |
ComboFrame.Show = dummy |
ComboFrame:Hide() |
-- Enable our shit |
object:RegisterEvent("PLAYER_TARGET_CHANGED", 'PLAYER_ENTERING_WORLD') |
elseif(unit == "focus") then |
FocusFrame:UnregisterAllEvents() |
FocusFrame.Show = dummy |
FocusFrame:Hide() |
FocusFrameHealthBar:UnregisterAllEvents() |
FocusFrameManaBar:UnregisterAllEvents() |
FocusFrameSpellBar:UnregisterAllEvents() |
object:RegisterEvent("PLAYER_FOCUS_CHANGED", 'PLAYER_ENTERING_WORLD') |
elseif(unit == "mouseover") then |
object:RegisterEvent("UPDATE_MOUSEOVER_UNIT", 'PLAYER_ENTERING_WORLD') |
elseif(unit:match"target") then |
-- Hide the blizzard stuff |
if(unit == "targettarget") then |
TargetofTargetFrame:UnregisterAllEvents() |
TargetofTargetFrame.Show = dummy |
TargetofTargetFrame:Hide() |
TargetofTargetHealthBar:UnregisterAllEvents() |
TargetofTargetManaBar:UnregisterAllEvents() |
end |
enableTargetUpdate(object) |
elseif(unit == "party") then |
for i=1,4 do |
local party = "PartyMemberFrame"..i |
local frame = _G[party] |
frame:UnregisterAllEvents() |
frame.Show = dummy |
frame:Hide() |
_G[party..'HealthBar']:UnregisterAllEvents() |
_G[party..'ManaBar']:UnregisterAllEvents() |
end |
end |
end |
local initObject = function(unit, style, ...) |
local num = select('#', ...) |
for i=1, num do |
local object = select(i, ...) |
object.__elements = {} |
object = setmetatable(object, frame_metatable) |
style(object, unit) |
local mt = type(style) == 'table' |
local height = object:GetAttribute'initial-height' or (mt and style['initial-height']) |
local width = object:GetAttribute'initial-width' or (mt and style['initial-width']) |
local scale = object:GetAttribute'initial-scale' or (mt and style['initial-scale']) |
local suffix = object:GetAttribute'unitsuffix' |
if(height) then |
object:SetAttribute('initial-height', height) |
if(unit) then object:SetHeight(height) end |
end |
if(width) then |
object:SetAttribute("initial-width", width) |
if(unit) then object:SetWidth(width) end |
end |
if(scale) then |
object:SetAttribute("initial-scale", scale) |
if(unit) then object:SetScale(scale) end |
end |
if(suffix == 'target') then |
enableTargetUpdate(object) |
end |
if(num > 1 and i == 1) then |
object.hasChildren = true |
end |
object:SetAttribute("*type1", "target") |
object:SetScript("OnEvent", OnEvent) |
object:SetScript("OnAttributeChanged", OnAttributeChanged) |
object:SetScript("OnShow", object.PLAYER_ENTERING_WORLD) |
object:RegisterEvent"PLAYER_ENTERING_WORLD" |
for element in next, elements do |
object:EnableElement(element, unit) |
end |
for _, func in next, callback do |
func(object) |
end |
-- We could use ClickCastFrames only, but it will probably contain frames that |
-- we don't care about. |
table.insert(objects, object) |
_G.ClickCastFrames = ClickCastFrames or {} |
ClickCastFrames[object] = true |
end |
end |
local walkObject = function(object, unit) |
local style = object:GetParent().style or styles[style] |
initObject(unit, style, object, object:GetChildren()) |
end |
function oUF:RegisterInitCallback(func) |
table.insert(callback, func) |
end |
function oUF:RegisterStyle(name, func) |
argcheck(name, 2, 'string') |
argcheck(func, 3, 'function', 'table') |
if(styles[name]) then return error("Style [%s] already registered.", name) end |
if(not style) then style = name end |
styles[name] = func |
end |
function oUF:SetActiveStyle(name) |
argcheck(name, 2, 'string') |
if(not styles[name]) then return error("Style [%s] does not exist.", name) end |
style = name |
end |
function oUF:Spawn(unit, name, template, disableBlizz) |
argcheck(unit, 2, 'string') |
if(not style) then return error("Unable to create frame. No styles have been registered.") end |
local style = styles[style] |
local object |
if(unit == "header") then |
if(not template) then |
template = "SecureGroupHeaderTemplate" |
end |
HandleUnit(disableBlizz or 'party') |
local header = CreateFrame("Frame", name, UIParent, template) |
header:SetAttribute("template", "SecureUnitButtonTemplate") |
header.initialConfigFunction = walkObject |
header.style = style |
header.SetManyAttributes = SetManyAttributes |
return header |
else |
object = CreateFrame("Button", name, UIParent, "SecureUnitButtonTemplate") |
object:SetAttribute("unit", unit) |
object.unit = unit |
object.id = unit:match"^.-(%d+)" |
units[unit] = object |
walkObject(object, unit) |
HandleUnit(unit, object) |
RegisterUnitWatch(object) |
end |
return object |
end |
local RegisterEvent = oUF.RegisterEvent |
function oUF:RegisterEvent(event, func) |
argcheck(event, 2, 'string') |
if(type(func) == 'string' and type(self[func]) == 'function') then |
func = self[func] |
end |
local curev = self[event] |
if(curev and func) then |
if(type(curev) == 'function') then |
self[event] = setmetatable({curev, func}, event_metatable) |
else |
for _, infunc in ipairs(curev) do |
if(infunc == func) then return end |
end |
table.insert(curev, func) |
end |
elseif(self:IsEventRegistered(event)) then |
return |
else |
if(func) then |
self[event] = func |
elseif(not self[event]) then |
return error("Handler for event [%s] on unit [%s] does not exist.", event, self.unit or 'unknown') |
end |
RegisterEvent(self, event) |
end |
end |
local UnregisterEvent = oUF.UnregisterEvent |
function oUF:UnregisterEvent(event, func) |
argcheck(event, 2, 'string') |
local curev = self[event] |
if(type(curev) == 'table' and func) then |
for k, infunc in ipairs(curev) do |
if(infunc == func) then |
curev[k] = nil |
if(#curev == 0) then |
table.remove(curev, k) |
UnregisterEvent(self, event) |
end |
end |
end |
else |
self[event] = nil |
UnregisterEvent(self, event) |
end |
end |
function oUF:AddElement(name, update, enable, disable) |
argcheck(name, 2, 'string') |
argcheck(update, 3, 'function', 'nil') |
argcheck(enable, 4, 'function', 'nil') |
argcheck(disable, 5, 'function', 'nil') |
if(elements[name]) then return error('Element [%s] is already registered.', name) end |
elements[name] = { |
update = update; |
enable = enable; |
disable = disable; |
} |
end |
function oUF:EnableElement(name, unit) |
argcheck(name, 2, 'string') |
argcheck(unit, 3, 'string', 'nil') |
local element = elements[name] |
if(not element) then return end |
if(element.enable(self, unit or self.unit)) then |
table.insert(self.__elements, element.update) |
end |
end |
function oUF:DisableElement(name) |
argcheck(name, 2, 'string') |
local element = elements[name] |
if(not element) then return end |
for k, update in ipairs(self.__elements) do |
if(update == element.update) then |
table.remove(self.__elements, k) |
element.disable(self) |
break |
end |
end |
end |
function oUF:UpdateElement(name) |
argcheck(name, 2, 'string') |
local element = elements[name] |
if(not element) then return end |
element.update(self, 'UpdateElement', self.unit) |
end |
oUF.Enable = RegisterUnitWatch |
function oUF:Disable() |
UnregisterUnitWatch(self) |
self:Hide() |
end |
--[[ |
--:PLAYER_ENTERING_WORLD() |
-- Notes: |
-- - Does a full update of all elements on the object. |
--]] |
function oUF:PLAYER_ENTERING_WORLD(event) |
local unit = self.unit |
if(not UnitExists(unit)) then return end |
for _, func in next, self.__elements do |
func(self, event, unit) |
end |
end |
-- http://www.wowwiki.com/ColorGradient |
function oUF.ColorGradient(perc, ...) |
if perc >= 1 then |
local r, g, b = select(select('#', ...) - 2, ...) |
return r, g, b |
elseif perc <= 0 then |
local r, g, b = ... |
return r, g, b |
end |
local num = select('#', ...) / 3 |
local segment, relperc = math.modf(perc*(num-1)) |
local r1, g1, b1, r2, g2, b2 = select((segment*3)+1, ...) |
return r1 + (r2-r1)*relperc, g1 + (g2-g1)*relperc, b1 + (b2-b1)*relperc |
end |
oUF.version = _VERSION |
oUF.units = units |
oUF.objects = objects |
oUF.colors = colors |
_G[global] = oUF |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local Update = function(self, event, unit) |
if(self.unit ~= unit) then return end |
if(self.Happiness) then |
local happiness = GetPetHappiness() |
local hunterPet = select(2, HasPetUI()) |
if(not (happiness or hunterPet)) then |
return self.Happiness:Hide() |
end |
self.Happiness:Show() |
if(happiness == 1) then |
self.Happiness:SetTexCoord(0.375, 0.5625, 0, 0.359375) |
elseif(happiness == 2) then |
self.Happiness:SetTexCoord(0.1875, 0.375, 0, 0.359375) |
elseif(happiness == 3) then |
self.Happiness:SetTexCoord(0, 0.1875, 0, 0.359375) |
end |
if(self.PostUpdateHappiness) then self:PostUpdateHappiness(event, unit, happiness) end |
end |
end |
local Enable = function(self) |
local happiness = self.Happiness |
if(happiness) then |
self:RegisterEvent("UNIT_HAPPINESS", Update) |
if(happiness:IsObjectType"Texture" and not happiness:GetTexture()) then |
happiness:SetTexture[[Interface\PetPaperDollFrame\UI-PetHappiness]] |
end |
return true |
end |
end |
local Disable = function(self) |
local happiness = self.Happiness |
if(happiness) then |
self:UnregisterEvent("UNIT_HAPPINESS", Update) |
end |
end |
oUF:AddElement('Happiness', Update, Enable, Disable) |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local Update = function(self, event) |
local unit = self.unit |
if((UnitInParty(unit) or UnitInRaid(unit)) and UnitIsPartyLeader(unit)) then |
self.Leader:Show() |
else |
self.Leader:Hide() |
end |
end |
local Enable = function(self) |
local leader = self.Leader |
if(leader) then |
self:RegisterEvent("PARTY_LEADER_CHANGED", Update) |
self:RegisterEvent("PARTY_MEMBERS_CHANGED", Update) |
if(leader:IsObjectType"Texture" and not leader:GetTexture()) then |
leader:SetTexture[[Interface\GroupFrame\UI-Group-LeaderIcon]] |
end |
return true |
end |
end |
local Disable = function(self) |
local leader = self.Leader |
if(leader) then |
self:UnregisterEvent("PARTY_LEADER_CHANGED", Update) |
self:UnregisterEvent("PARTY_MEMBERS_CHANGED", Update) |
end |
end |
oUF:AddElement('Leader', Update, Enable, Disable) |
--[[ |
Elements handled: .Power |
Shared: |
The following settings are listed by priority: |
- colorTapping |
- colorDisconnected |
- colorHappiness |
- colorPower |
- colorClass (Colors player units based on class) |
- colorClassPet (Colors pet units based on class) |
- colorClassNPC (Colors non-player units based on class) |
- colorReaction |
- colorSmooth - will use smoothGradient instead of the internal gradient if set. |
Background: |
- multiplier - number used to manipulate the power background. (default: 1) |
This option will only enable for player and pet. |
- frequentUpdates - do OnUpdate polling of power data. |
Functions that can be overridden from within a layout: |
- :PreUpdatePower(event, unit) |
- :OverrideUpdatePower(event, unit, bar, min, max) - Setting this function |
will disable the above color settings. |
- :PostUpdatePower(event, unit, bar, min, max) |
--]] |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local UnitManaMax = UnitManaMax |
local UnitPowerType = UnitPowerType |
local min, max, bar |
local OnPowerUpdate |
do |
local UnitMana = UnitMana |
OnPowerUpdate = function(self) |
if(self.disconnected) then return end |
local power = UnitMana(self.unit) |
if(power ~= self.min) then |
self.min = power |
self:GetParent():UNIT_MAXMANA("OnPowerUpdate", self.unit) |
end |
end |
end |
local Update = function(self, event, unit) |
if(self.unit ~= unit) then return end |
if(self.PreUpdatePower) then self:PreUpdatePower(event, unit) end |
min, max = UnitMana(unit), UnitManaMax(unit) |
bar = self.Power |
bar:SetMinMaxValues(0, max) |
bar:SetValue(min) |
bar.disconnected = not UnitIsConnected(unit) |
bar.unit = unit |
if(not self.OverrideUpdatePower) then |
local r, g, b, t |
if(bar.colorTapping and UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit)) then |
t = self.colors.tapped |
elseif(bar.colorDisconnected and not UnitIsConnected(unit)) then |
t = self.colors.disconnected |
elseif(bar.colorHappiness and unit == "pet" and GetPetHappiness()) then |
t = self.colors.happiness[GetPetHappiness()] |
elseif(bar.colorPower) then |
local _, ptype = UnitPowerType(unit) |
t = self.colors.power[ptype] |
elseif(bar.colorClass and UnitIsPlayer(unit)) or |
(bar.colorClassNPC and not UnitIsPlayer(unit)) or |
(bar.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then |
local _, class = UnitClass(unit) |
t = self.colors.class[class] |
elseif(bar.colorReaction) then |
t = self.colors.reaction[UnitReaction(unit, "player")] |
elseif(bar.colorSmooth) then |
r, g, b = self.ColorGradient(min / max, unpack(bar.smoothGradient or self.colors.smooth)) |
end |
if(t) then |
r, g, b = t[1], t[2], t[3] |
end |
if(b) then |
bar:SetStatusBarColor(r, g, b) |
local bg = bar.bg |
if(bg) then |
local mu = bg.multiplier or 1 |
bg:SetVertexColor(r * mu, g * mu, b * mu) |
end |
end |
else |
self:OverrideUpdatePower(event, unit, bar, min, max) |
end |
if(self.PostUpdatePower) then self:PostUpdatePower(event, unit, bar, min, max) end |
end |
local Enable = function(self, unit) |
local power = self.Power |
if(power) then |
if(power.frequentUpdates and (unit == 'player' or unit == 'pet')) then |
power.disconnected = true |
power:SetScript("OnUpdate", OnPowerUpdate) |
else |
self:RegisterEvent("UNIT_MANA", Update) |
self:RegisterEvent("UNIT_RAGE", Update) |
self:RegisterEvent("UNIT_FOCUS", Update) |
self:RegisterEvent("UNIT_ENERGY", Update) |
self:RegisterEvent("UNIT_RUNIC_POWER", Update) |
end |
self:RegisterEvent("UNIT_MAXMANA", Update) |
self:RegisterEvent("UNIT_MAXRAGE", Update) |
self:RegisterEvent("UNIT_MAXFOCUS", Update) |
self:RegisterEvent("UNIT_MAXENERGY", Update) |
self:RegisterEvent("UNIT_DISPLAYPOWER", Update) |
self:RegisterEvent("UNIT_MAXRUNIC_POWER", Update) |
self:RegisterEvent('UNIT_HAPPINESS', Update) |
-- For tapping. |
self:RegisterEvent('UNIT_FACTION', Update) |
if(not power:GetStatusBarTexture()) then |
power:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]] |
end |
return true |
end |
end |
local Disable = function(self) |
local power = self.Power |
if(power) then |
if(power:GetScript'OnUpdate') then |
power:SetScript("OnUpdate", nil) |
else |
self:UnregisterEvent("UNIT_MANA", Update) |
self:UnregisterEvent("UNIT_RAGE", Update) |
self:UnregisterEvent("UNIT_FOCUS", Update) |
self:UnregisterEvent("UNIT_ENERGY", Update) |
self:UnregisterEvent("UNIT_RUNIC_POWER", Update) |
end |
self:UnregisterEvent("UNIT_MAXMANA", Update) |
self:UnregisterEvent("UNIT_MAXRAGE", Update) |
self:UnregisterEvent("UNIT_MAXFOCUS", Update) |
self:UnregisterEvent("UNIT_MAXENERGY", Update) |
self:UnregisterEvent("UNIT_DISPLAYPOWER", Update) |
self:UnregisterEvent("UNIT_MAXRUNIC_POWER", Update) |
self:UnregisterEvent('UNIT_HAPPINESS', Update) |
self:UnregisterEvent('UNIT_FACTION', Update) |
end |
end |
oUF:AddElement('Power', Update, Enable, Disable) |
--[[ |
Elements handled: .Range |
Settings: |
- inRangeAlpha - A number for frame alpha when unit is within player range. |
Required. |
- outsideRangeAlpha - A number for frame alpha when unit is outside player |
range. Required. |
--]] |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local objects = oUF.objects |
local OnRangeFrame |
local UnitInRange, UnitIsConnected = |
UnitInRange, UnitIsConnected |
-- updating of range. |
local timer = 0 |
local OnRangeUpdate = function(self, elapsed) |
timer = timer + elapsed |
if(timer >= .25) then |
for _, object in ipairs(objects) do |
if(object:IsShown() and object.Range) then |
if(UnitIsConnected(object.unit) and not UnitInRange(object.unit)) then |
if(object:GetAlpha() == object.inRangeAlpha) then |
object:SetAlpha(object.outsideRangeAlpha) |
end |
elseif(object:GetAlpha() ~= object.inRangeAlpha) then |
object:SetAlpha(object.inRangeAlpha) |
end |
end |
end |
timer = 0 |
end |
end |
local Enable = function(self) |
if(self.Range and not OnRangeFrame) then |
OnRangeFrame = CreateFrame"Frame" |
OnRangeFrame:SetScript("OnUpdate", OnRangeUpdate) |
end |
end |
oUF:AddElement('Range', nil, Enable) |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local GetRaidTargetIndex = GetRaidTargetIndex |
local SetRaidTargetIconTexture = SetRaidTargetIconTexture |
local Update = function(self, event) |
local index = GetRaidTargetIndex(self.unit) |
local icon = self.RaidIcon |
if(index) then |
SetRaidTargetIconTexture(icon, index) |
icon:Show() |
else |
icon:Hide() |
end |
end |
local Enable = function(self) |
local ricon = self.RaidIcon |
if(ricon) then |
self:RegisterEvent("RAID_TARGET_UPDATE", Update) |
if(ricon:IsObjectType"Texture" and not ricon:GetTexture()) then |
ricon:SetTexture[[Interface\TargetingFrame\UI-RaidTargetingIcons]] |
end |
return true |
end |
end |
local Disable = function(self) |
local ricon = self.RaidIcon |
if(ricon) then |
self:UnregisterEvent("RAID_TARGET_UPDATE", Update) |
end |
end |
oUF:AddElement('RaidIcon', Update, Enable, Disable) |
--[[ |
-- Experimental oUF tags |
-- Status: Incomplete |
-- |
-- Credits: Vika, Cladhaire, Tekkub |
-- |
-- TODO: |
-- - Tag and Untag should be able to handle more than one fontstring at a time. |
]] |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local function Hex(r, g, b) |
if type(r) == "table" then |
if r.r then r, g, b = r.r, r.g, r.b else r, g, b = unpack(r) end |
end |
return string.format("|cff%02x%02x%02x", r*255, g*255, b*255) |
end |
local tags |
tags = { |
["[class]"] = function(u) return UnitClass(u) end, |
["[creature]"] = function(u) return UnitCreatureFamily(u) or UnitCreatureType(u) end, |
["[curhp]"] = UnitHealth, |
["[curpp]"] = UnitPower, |
["[dead]"] = function(u) return UnitIsDead(u) and "Dead" or UnitIsGhost(u) and "Ghost" end, |
["[difficulty]"] = function(u) if UnitCanAttack("player", u) then local l = UnitLevel(u); return Hex(GetDifficultyColor((l > 0) and l or 99)) end end, |
["[faction]"] = function(u) return UnitFactionGroup(u) end, |
["[leader]"] = function(u) return UnitIsPartyLeader(u) and "(L)" end, |
["[leaderlong]"] = function(u) return UnitIsPartyLeader(u) and "(Leader)" end, |
["[level]"] = function(u) local l = UnitLevel(u) return (l > 0) and l or "??" end, |
["[maxhp]"] = UnitHealthMax, |
["[maxpp]"] = UnitPowerMax, |
["[missinghp]"] = function(u) return UnitHealthMax(u) - UnitHealth(u) end, |
["[missingpp]"] = function(u) return UnitPowerMax(u) - UnitPower(u) end, |
["[name]"] = function(u, r) return UnitName(r or u) end, |
["[offline]"] = function(u) return (not UnitIsConnected(u) and "Offline") end, |
["[perhp]"] = function(u) local m = UnitHealthMax(u); return m == 0 and 0 or math.floor(UnitHealth(u)/m*100+0.5) end, |
["[perpp]"] = function(u) local m = UnitPowerMax(u); return m == 0 and 0 or math.floor(UnitPower(u)/m*100+0.5) end, |
["[plus]"] = function(u) local c = UnitClassification(u); return (c == "elite" or c == "rareelite") and "+" end, |
["[pvp]"] = function(u) return UnitIsPVP(u) and "PvP" end, |
["[race]"] = function(u) return UnitRace(u) end, |
["[raidcolor]"] = function(u) local _, x = UnitClass(u); return x and Hex(RAID_CLASS_COLORS[x]) end, |
["[rare]"] = function(u) local c = UnitClassification(u); return (c == "rare" or c == "rareelite") and "Rare" end, |
["[resting]"] = function(u) return u == "player" and IsResting() and "zzz" end, |
["[sex]"] = function(u) local s = UnitSex(u) return s == 2 and "Male" or s == 3 and "Female" end, |
["[smartclass]"] = function(u) return UnitIsPlayer(u) and tags["[class]"](u) or tags["[creature]"](u) end, |
["[status]"] = function(u) return UnitIsDead(u) and "Dead" or UnitIsGhost(u) and "Ghost" or not UnitIsConnected(u) and "Offline" or tags["[resting]"](u) end, |
["[threat]"] = function(u) local s = UnitThreatSituation(u) return s == 1 and "++" or s == 2 and "--" or s == 3 and "Aggro" end, |
["[threatcolor]"] = function(u) return Hex(GetThreatStatusColor(UnitThreatSituation(u))) end, |
["[cpoints]"] = function(u) local cp = GetComboPoints(u, 'target') return (cp > 0) and cp end, |
['[smartlevel]'] = function(u) |
local c = UnitClassification(u) |
if(c == 'worldboss') then |
return 'Boss' |
else |
local plus = tags['[plus]'](u) |
local level = tags['[level]'](u) |
if(plus) then |
return level .. plus |
else |
return level |
end |
end |
end, |
["[classification]"] = function(u) |
local c = UnitClassification(u) |
return c == "rare" and "Rare" or c == "eliterare" and "Rare Elite" or c == "elite" and "Elite" or c == "worldboss" and "Boss" |
end, |
["[shortclassification]"] = function(u) |
local c = UnitClassification(u) |
return c == "rare" and "R" or c == "eliterare" and "R+" or c == "elite" and "+" or c == "worldboss" and "B" |
end, |
} |
local tagEvents = { |
["[curhp]"] = "UNIT_HEALTH", |
["[curpp]"] = "UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_RUNIC_POWER", |
["[dead]"] = "UNIT_HEALTH", |
["[leader]"] = "PARTY_LEADER_CHANGED", |
["[leaderlong]"] = "PARTY_LEADER_CHANGED", |
["[level]"] = "UNIT_LEVEL PLAYER_LEVEL_UP", |
["[maxhp]"] = "UNIT_MAXHEALTH", |
["[maxpp]"] = "UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE UNIT_MAXRUNIC_POWER", |
["[missinghp]"] = "UNIT_HEALTH UNIT_MAXHEALTH", |
["[missingpp]"] = "UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_MAXRUNIC_POWER UNIT_RUNIC_POWER", |
["[name]"] = "UNIT_NAME_UPDATE", |
["[offline]"] = "UNIT_HEALTH", |
["[perhp]"] = "UNIT_HEALTH UNIT_MAXHEALTH", |
["[perpp]"] = "UNIT_MAXENERGY UNIT_MAXFOCUS UNIT_MAXMANA UNIT_MAXRAGE UNIT_ENERGY UNIT_FOCUS UNIT_MANA UNIT_RAGE UNIT_MAXRUNIC_POWER UNIT_RUNIC_POWER", |
["[pvp]"] = "UNIT_FACTION", |
["[resting]"] = "PLAYER_UPDATE_RESTING", |
["[status]"] = "UNIT_HEALTH PLAYER_UPDATE_RESTING", |
["[smartlevel]"] = "UNIT_LEVEL PLAYER_LEVEL_UP UNIT_CLASSIFICATION_CHANGED", |
["[threat]"] = "UNIT_THREAT_SITUATION_UPDATE", |
["[threatcolor]"] = "UNIT_THREAT_SITUATION_UPDATE", |
['[cpoints]'] = 'UNIT_COMBO_POINTS UNIT_TARGET', |
['[rare]'] = 'UNIT_CLASSIFICATION_CHANGED', |
['[classification]'] = 'UNIT_CLASSIFICATION_CHANGED', |
['[shortclassification]'] = 'UNIT_CLASSIFICATION_CHANGED', |
} |
local unitlessEvents = { |
PLAYER_TARGET_CHANGED = true, |
PLAYER_FOCUS_CHANGED = true, |
PLAYER_LEVEL_UP = true, |
} |
local events = {} |
local frame = CreateFrame"Frame" |
frame:SetScript('OnEvent', function(self, event, unit) |
local strings = events[event] |
if(strings) then |
for k, fontstring in next, strings do |
if(not unitlessEvents[event] and fontstring.parent.unit == unit and fontstring:IsVisible()) then |
fontstring:UpdateTag() |
end |
end |
end |
end) |
local eventlessUnits = {} |
local timer = .5 |
local lowestTimer = .5 |
local OnUpdate = function(self, elapsed) |
if(timer >= lowestTimer) then |
for k, fs in next, eventlessUnits do |
if(fs.parent:IsShown() and UnitExists(fs.parent.unit)) then |
fs:UpdateTag() |
end |
end |
timer = 0 |
end |
timer = timer + elapsed |
end |
local OnShow = function(self) |
for _, fs in next, self.__tags do |
fs:UpdateTag() |
end |
end |
local RegisterEvent = function(fontstr, event) |
if(not events[event]) then events[event] = {} end |
frame:RegisterEvent(event) |
table.insert(events[event], fontstr) |
end |
local RegisterEvents = function(fontstr, tagstr) |
-- Forcefully strip away any parentheses and the characters in them. |
tagstr = tagstr:gsub('%b()', '') |
for tag in tagstr:gmatch'[%[]%w+[%]]' do |
local tagevents = tagEvents[tag] |
if(tagevents) then |
for event in tagevents:gmatch'%S+' do |
RegisterEvent(fontstr, event) |
end |
end |
end |
end |
local UnregisterEvents = function(fontstr) |
for events, data in pairs(events) do |
for k, tagfsstr in pairs(data) do |
if(tagfsstr == fontstr) then |
if(#data[k] == 1) then frame:UnregisterEvent(event) end |
data[k] = nil |
end |
end |
end |
end |
local tagPool = {} |
local funcPool = {} |
local tmp = {} |
local Tag = function(self, fs, tagstr) |
if(not fs or not tagstr or self == oUF) then return end |
if(not self.__tags) then |
self.__tags = {} |
table.insert(self.__elements, OnShow) |
else |
-- Since people ignore everything that's good practice - unregister the tag |
-- if it already exists. |
for _, tag in pairs(self.__tags) do |
if(fs == tag) then |
-- We don't need to remove it from the __tags table as Untag handles |
-- that for us. |
self:Untag(fs) |
end |
end |
end |
fs.parent = self |
local func = tagPool[tagstr] |
if(not func) then |
-- Using .- in the match prevents use from supporting [] as prepend/append |
-- characters. Supporting these and having a single pattern here is a real |
-- headache however. |
local format = tagstr:gsub('%%', '%%%%'):gsub('[[].-[]]', '%%s') |
local args = {} |
for bracket in tagstr:gmatch'([[](.-)[]])' do |
local tfunc = funcPool[bracket] or tags[bracket] |
if(not tfunc) then |
-- ... |
local pre, tag, ap = bracket:match'[%[](%b())([%w]+)(%b())[%]]' |
if(not pre) then pre, tag = bracket:match'[%[](%b())([%w]+)[%]]' end |
if(not pre) then tag, ap = bracket:match'[%[]([%w]+)(%b())[%]]' end |
tag = (tag and '['.. tag ..']') |
tag = tags[tag] |
if(tag) then |
if(pre and ap) then |
pre = pre:sub(2,-2) |
ap = ap:sub(2,-2) |
tfunc = function(u) |
local str = tag(u) |
if(str) then |
return pre..str..ap |
end |
end |
elseif(pre) then |
pre = pre:sub(2,-2) |
tfunc = function(u) |
local str = tag(u) |
if(str) then |
return pre..str |
end |
end |
elseif(ap) then |
ap = ap:sub(2,-2) |
tfunc = function(u) |
local str = tag(u) |
if(str) then |
return str..ap |
end |
end |
end |
funcPool[bracket] = tfunc |
end |
end |
if(tfunc) then |
table.insert(args,tfunc) |
else |
return error(('Attempted to use invalid tag %s.'):format(bracket), 3) |
end |
end |
func = function(self) |
local unit = self.parent.unit |
local __unit = self.parent.__unit |
for i, func in next, args do |
tmp[i] = func(unit, __unit) or '' |
end |
self:SetFormattedText(format, unpack(tmp)) |
end |
tagPool[tagstr] = func |
end |
fs.UpdateTag = func |
local unit = self.unit |
if((unit and unit:match'%w+target') or fs.frequentUpdates) then |
if(type(fs.frequentUpdates) == 'number') then |
lowestTimer = math.min(fs.frequentUpdates, lowestTimer) |
end |
table.insert(eventlessUnits, fs) |
if(not frame:GetScript'OnUpdate') then |
frame:SetScript('OnUpdate', OnUpdate) |
end |
else |
RegisterEvents(fs, tagstr) |
if(unit == 'focus') then |
RegisterEvent(fs, 'PLAYER_FOCUS_CHANGED') |
elseif(unit == 'target') then |
RegisterEvent(fs, 'PLAYER_TARGET_CHANGED') |
elseif(unit == 'mouseover') then |
RegisterEvent(fs, 'UPDATE_MOUSEOVER_UNIT') |
end |
end |
table.insert(self.__tags, fs) |
end |
local Untag = function(self, fs) |
if(not fs or self == oUF) then return end |
UnregisterEvents(fs) |
for k, fontstr in next, eventlessUnits do |
if(fs == fontstr) then |
table.remove(eventlessUnits, k) |
end |
end |
for k, fontstr in next, self.__tags do |
if(fontstr == fs) then |
table.remove(self.__tags, k) |
end |
end |
fs.UpdateTag = nil |
end |
oUF.Tags = tags |
oUF.TagEvents = tagEvents |
oUF.UnitlessTagEvents = unitlessEvents |
oUF.Tag = Tag |
oUF.Untag = Untag |
--[[ |
Elements handled: .Health |
Shared: |
The following settings are listed by priority: |
- colorTapping |
- colorDisconnected |
- colorHappiness |
- colorClass (Colors player units based on class) |
- colorClassPet (Colors pet units based on class) |
- colorClassNPC (Colors non-player units based on class) |
- colorReaction |
- colorSmooth - will use smoothGradient instead of the internal gradient if set. |
- colorHealth |
Background: |
- multiplier - number used to manipulate the power background. (default: 1) |
WotLK only: |
- frequentUpdates - do OnUpdate polling of health data. |
Functions that can be overridden from within a layout: |
- :PreUpdateHealth(event, unit) |
- :OverrideUpdateHealth(event, unit, bar, min, max) - Setting this function |
will disable the above color settings. |
- :PostUpdateHealth(event, unit, bar, min, max) |
--]] |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local OnHealthUpdate |
do |
local UnitHealth = UnitHealth |
OnHealthUpdate = function(self) |
if(self.disconnected) then return end |
local health = UnitHealth(self.unit) |
if(health ~= self.min) then |
self.min = health |
self:GetParent():UNIT_MAXHEALTH("OnHealthUpdate", self.unit) |
end |
end |
end |
local Update = function(self, event, unit) |
if(self.unit ~= unit) then return end |
if(self.PreUpdateHealth) then self:PreUpdateHealth(event, unit) end |
local min, max = UnitHealth(unit), UnitHealthMax(unit) |
local bar = self.Health |
bar:SetMinMaxValues(0, max) |
bar:SetValue(min) |
bar.disconnected = not UnitIsConnected(unit) |
bar.unit = unit |
if(not self.OverrideUpdateHealth) then |
local r, g, b, t |
if(bar.colorTapping and UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit)) then |
t = self.colors.tapped |
elseif(bar.colorDisconnected and not UnitIsConnected(unit)) then |
t = self.colors.disconnected |
elseif(bar.colorHappiness and unit == "pet" and GetPetHappiness()) then |
t = self.colors.happiness[GetPetHappiness()] |
elseif(bar.colorClass and UnitIsPlayer(unit)) or |
(bar.colorClassNPC and not UnitIsPlayer(unit)) or |
(bar.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then |
local _, class = UnitClass(unit) |
t = self.colors.class[class] |
elseif(bar.colorReaction) then |
t = self.colors.reaction[UnitReaction(unit, "player")] |
elseif(bar.colorSmooth and max ~= 0) then |
r, g, b = self.ColorGradient(min / max, unpack(bar.smoothGradient or self.colors.smooth)) |
elseif(bar.colorHealth) then |
t = self.colors.health |
end |
if(t) then |
r, g, b = t[1], t[2], t[3] |
end |
if(b) then |
bar:SetStatusBarColor(r, g, b) |
local bg = bar.bg |
if(bg) then |
local mu = bg.multiplier or 1 |
bg:SetVertexColor(r * mu, g * mu, b * mu) |
end |
end |
else |
self:OverrideUpdateHealth(event, unit, bar, min, max) |
end |
if(self.PostUpdateHealth) then self:PostUpdateHealth(event, unit, bar, min, max) end |
end |
local Enable = function(self) |
local health = self.Health |
if(health) then |
if(health.frequentUpdates and (self.unit and not self.unit:match'%w+target$') or not self.unit) then |
health.disconnected = true |
health:SetScript('OnUpdate', OnHealthUpdate) |
else |
self:RegisterEvent("UNIT_HEALTH", Update) |
end |
self:RegisterEvent("UNIT_MAXHEALTH", Update) |
self:RegisterEvent('UNIT_HAPPINESS', Update) |
-- For tapping. |
self:RegisterEvent('UNIT_FACTION', Update) |
if(not health:GetStatusBarTexture()) then |
health:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]] |
end |
return true |
end |
end |
local Disable = function(self) |
local health = self.Health |
if(health) then |
if(self:GetScript'OnUpdate') then |
health:SetScript('OnUpdate', nil) |
else |
self:UnregisterEvent('UNIT_HEALTH', Update) |
end |
self:UnregisterEvent('UNIT_MAXHEALTH', Update) |
self:UnregisterEvent('UNIT_HAPPINESS', Update) |
self:UnregisterEvent('UNIT_FACTION', Update) |
end |
end |
oUF:AddElement('Health', Update, Enable, Disable) |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local Update = function(self, event, unit) |
if(unit ~= self.unit) then return end |
if(self.PvP) then |
local factionGroup = UnitFactionGroup(unit) |
if(UnitIsPVPFreeForAll(unit)) then |
self.PvP:SetTexture[[Interface\TargetingFrame\UI-PVP-FFA]] |
self.PvP:Show() |
elseif(factionGroup and UnitIsPVP(unit)) then |
self.PvP:SetTexture([[Interface\TargetingFrame\UI-PVP-]]..factionGroup) |
self.PvP:Show() |
else |
self.PvP:Hide() |
end |
end |
end |
local Enable = function(self) |
if(self.PvP) then |
self:RegisterEvent("UNIT_FACTION", Update) |
return true |
end |
end |
local Disable = function(self) |
if(self.PvP) then |
self:UnregisterEvent("UNIT_FACTION", Update) |
end |
end |
oUF:AddElement('PvP', Update, Enable, Disable) |
--[[ |
Original codebase: |
oUF_Castbar by starlon. |
http://svn.wowace.com/wowace/trunk/oUF_Castbar/ |
Elements handled: .Castbar |
Sub-elements: .Text, .Icon, .Time, .SafeZone, .Spark |
Notes: This element will not work on units that require a OnUpdate. |
(eventless units). |
Functions that can be overridden from within a layout: |
- :CustomDelayText(duration) |
- :CustomTimeText(duration) |
--]] |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local noop = function() end |
local UnitName = UnitName |
local GetTime = GetTime |
local UnitCastingInfo = UnitCastingInfo |
local UnitChannelInfo = UnitChannelInfo |
local UNIT_SPELLCAST_START = function(self, event, unit, spell, spellrank) |
if(self.unit ~= unit) then return end |
local castbar = self.Castbar |
local name, rank, text, texture, startTime, endTime, _, castid = UnitCastingInfo(unit) |
if(not name) then |
castbar:Hide() |
return |
end |
endTime = endTime / 1e3 |
startTime = startTime / 1e3 |
local max = endTime - startTime |
castbar.castid = castid |
castbar.duration = GetTime() - startTime |
castbar.max = max |
castbar.delay = 0 |
castbar.casting = true |
castbar:SetMinMaxValues(0, max) |
castbar:SetValue(0) |
if(castbar.Text) then castbar.Text:SetText(text) end |
if(castbar.Icon) then castbar.Icon:SetTexture(texture) end |
if(castbar.Time) then castbar.Time:SetText() end |
local sf = castbar.SafeZone |
if(sf) then |
sf:ClearAllPoints() |
sf:SetPoint'RIGHT' |
sf:SetPoint'TOP' |
sf:SetPoint'BOTTOM' |
end |
if(self.PostCastStart) then self:PostCastStart(event, unit, name, rank, text, castid) end |
castbar:Show() |
end |
local UNIT_SPELLCAST_FAILED = function(self, event, unit, spellname, spellrank, castid) |
if(self.unit ~= unit) then return end |
local castbar = self.Castbar |
if(castbar.castid ~= castid) then |
return |
end |
castbar.casting = nil |
castbar:SetValue(0) |
castbar:Hide() |
if(self.PostCastFailed) then self:PostCastFailed(event, unit, spellname, spellrank, castid) end |
end |
local UNIT_SPELLCAST_INTERRUPTED = function(self, event, unit, spellname, spellrank, castid) |
if(self.unit ~= unit) then return end |
local castbar = self.Castbar |
if(castbar.castid ~= castid) then |
return |
end |
castbar.casting = nil |
castbar.channeling = nil |
castbar:SetValue(0) |
castbar:Hide() |
if(self.PostCastInterrupted) then self:PostCastInterrupted(event, unit, spellname, spellrank, castid) end |
end |
local UNIT_SPELLCAST_DELAYED = function(self, event, unit, spellname, spellrank) |
if(self.unit ~= unit) then return end |
local name, rank, text, texture, startTime, endTime = UnitCastingInfo(unit) |
if(not startTime) then return end |
local castbar = self.Castbar |
local duration = GetTime() - (startTime / 1000) |
if(duration < 0) then duration = 0 end |
castbar.delay = castbar.delay + castbar.duration - duration |
castbar.duration = duration |
castbar:SetValue(duration) |
if(self.PostCastDelayed) then self:PostCastDelayed(event, unit, name, rank, text) end |
end |
local UNIT_SPELLCAST_STOP = function(self, event, unit, spellname, spellrank, castid) |
if(self.unit ~= unit) then return end |
local castbar = self.Castbar |
if(castbar.castid ~= castid) then |
return |
end |
castbar.casting = nil |
castbar:SetValue(0) |
castbar:Hide() |
if(self.PostCastStop) then self:PostCastStop(event, unit, spellname, spellrank, castid) end |
end |
local UNIT_SPELLCAST_CHANNEL_START = function(self, event, unit, spellname, spellrank) |
if(self.unit ~= unit) then return end |
local castbar = self.Castbar |
local name, rank, text, texture, startTime, endTime = UnitChannelInfo(unit) |
if(not name) then |
return |
end |
endTime = endTime / 1e3 |
startTime = startTime / 1e3 |
local max = (endTime - startTime) |
local duration = endTime - GetTime() |
castbar.duration = duration |
castbar.max = max |
castbar.delay = 0 |
castbar.channeling = true |
castbar:SetMinMaxValues(0, max) |
castbar:SetValue(duration) |
if(castbar.Text) then castbar.Text:SetText(name) end |
if(castbar.Icon) then castbar.Icon:SetTexture(texture) end |
if(castbar.Time) then castbar.Time:SetText() end |
local sf = castbar.SafeZone |
if(sf) then |
sf:ClearAllPoints() |
sf:SetPoint'LEFT' |
sf:SetPoint'TOP' |
sf:SetPoint'BOTTOM' |
end |
if(self.PostChannelStart) then self:PostChannelStart(event, unit, name, rank, text) end |
castbar:Show() |
end |
local UNIT_SPELLCAST_CHANNEL_UPDATE = function(self, event, unit, spellname, spellrank) |
if(self.unit ~= unit) then return end |
local name, rank, text, texture, startTime, endTime, oldStart = UnitChannelInfo(unit) |
if(not name) then |
return |
end |
local castbar = self.Castbar |
local duration = (endTime / 1000) - GetTime() |
castbar.delay = castbar.delay + castbar.duration - duration |
castbar.duration = duration |
castbar.max = (endTime - startTime) / 1000 |
castbar:SetMinMaxValues(0, castbar.max) |
castbar:SetValue(duration) |
if(self.PostChannelUpdate) then self:PostChannelUpdate(event, unit, name, rank, text) end |
end |
local UNIT_SPELLCAST_CHANNEL_STOP = function(self, event, unit, spellname, spellrank) |
if(self.unit ~= unit) then return end |
local castbar = self.Castbar |
if(castbar:IsShown()) then |
castbar.channeling = nil |
castbar:SetValue(castbar.max) |
castbar:Hide() |
if(self.PostChannelStop) then self:PostChannelStop(event, unit, spellname, spellrank) end |
end |
end |
local onUpdate = function(self, elapsed) |
if self.casting then |
local duration = self.duration + elapsed |
if (duration >= self.max) then |
self.casting = nil |
self:Hide() |
end |
if self.SafeZone then |
local width = self:GetWidth() |
local _, _, ms = GetNetStats() |
-- MADNESS! |
local safeZonePercent = (width / self.max) * (ms / 1e5) |
if(safeZonePercent > 1) then safeZonePercent = 1 end |
self.SafeZone:SetWidth(width * safeZonePercent) |
end |
if self.Time then |
if self.delay ~= 0 then |
if(self.CustomDelayText) then |
self:CustomDelayText(duration) |
else |
self.Time:SetFormattedText("%.1f|cffff0000-%.1f|r", duration, self.delay) |
end |
else |
if(self.CustomTimeText) then |
self:CustomTimeText(duration) |
else |
self.Time:SetFormattedText("%.1f", duration) |
end |
end |
end |
self.duration = duration |
self:SetValue(duration) |
if self.Spark then |
self.Spark:SetPoint("CENTER", self, "LEFT", (duration / self.max) * self:GetWidth(), 0) |
end |
elseif self.channeling then |
local duration = self.duration - elapsed |
if(duration <= 0) then |
self.channeling = nil |
self:Hide() |
return |
end |
if(self.SafeZone) then |
local width = self:GetWidth() |
local _, _, ms = GetNetStats() |
-- MADNESS! |
local safeZonePercent = (width / self.max) * (ms / 1e5) |
if(safeZonePercent > 1) then safeZonePercent = 1 end |
self.SafeZone:SetWidth(width * safeZonePercent) |
end |
if self.Time then |
if self.delay ~= 0 then |
if(self.CustomDelayText) then |
self:CustomDelayText(duration) |
else |
self.Time:SetFormattedText("%.1f|cffff0000-%.1f|r", duration, self.delay) |
end |
else |
if(self.CustomTimeText) then |
self:CustomTimeText(duration) |
else |
self.Time:SetFormattedText("%.1f", duration) |
end |
end |
end |
self.duration = duration |
self:SetValue(duration) |
if self.Spark then |
self.Spark:SetPoint("CENTER", self, "LEFT", (duration / self.max) * self:GetWidth(), 0) |
end |
else |
self.unitName = nil |
self.channeling = nil |
self:SetValue(1) |
self:Hide() |
end |
end |
local Enable = function(object, unit) |
local castbar = object.Castbar |
if(castbar) then |
if(not (unit and unit:match'%wtarget$')) then |
object:RegisterEvent("UNIT_SPELLCAST_START", UNIT_SPELLCAST_START) |
object:RegisterEvent("UNIT_SPELLCAST_FAILED", UNIT_SPELLCAST_FAILED) |
object:RegisterEvent("UNIT_SPELLCAST_STOP", UNIT_SPELLCAST_STOP) |
object:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED", UNIT_SPELLCAST_INTERRUPTED) |
object:RegisterEvent("UNIT_SPELLCAST_DELAYED", UNIT_SPELLCAST_DELAYED) |
object:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START", UNIT_SPELLCAST_CHANNEL_START) |
object:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE", UNIT_SPELLCAST_CHANNEL_UPDATE) |
object:RegisterEvent("UNIT_SPELLCAST_CHANNEL_INTERRUPTED", 'UNIT_SPELLCAST_INTERRUPTED') |
object:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP", UNIT_SPELLCAST_CHANNEL_STOP) |
end |
castbar:SetScript("OnUpdate", object.OnCastbarUpdate or onUpdate) |
if object.unit == "player" then |
CastingBarFrame:UnregisterAllEvents() |
CastingBarFrame.Show = noop |
CastingBarFrame:Hide() |
elseif(object.unit == 'pet') then |
PetCastingBarFrame:UnregisterAllEvents() |
PetCastingBarFrame.Show = noop |
PetCastingBarFrame:Hide() |
end |
if(not castbar:GetStatusBarTexture()) then |
castbar:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]] |
end |
local spark = castbar.Spark |
if(spark and spark:IsObjectType'Texture' and not spark:GetTexture()) then |
spark:SetTexture[[Interface\CastingBar\UI-CastingBar-Spark]] |
end |
local sz = castbar.SafeZone |
if(sz and sz:IsObjectType'Texture' and not sz:GetTexture()) then |
sz:SetTexture(1, 0, 0) |
end |
castbar:Hide() |
return true |
end |
end |
local Disable = function(object, unit) |
local castbar = object.Castbar |
if(castbar) then |
object:UnregisterEvent("UNIT_SPELLCAST_START", UNIT_SPELLCAST_START) |
object:UnregisterEvent("UNIT_SPELLCAST_FAILED", UNIT_SPELLCAST_FAILED) |
object:UnregisterEvent("UNIT_SPELLCAST_STOP", UNIT_SPELLCAST_STOP) |
object:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTED", UNIT_SPELLCAST_INTERRUPTED) |
object:UnregisterEvent("UNIT_SPELLCAST_DELAYED", UNIT_SPELLCAST_DELAYED) |
object:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_START", UNIT_SPELLCAST_CHANNEL_START) |
object:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE", UNIT_SPELLCAST_CHANNEL_UPDATE) |
object:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_INTERRUPTED", UNIT_SPELLCAST_CHANNEL_INTERRUPTED) |
object:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_STOP", UNIT_SPELLCAST_CHANNEL_STOP) |
castbar:SetScript("OnUpdate", nil) |
end |
end |
oUF:AddElement('Castbar', function(...) |
UNIT_SPELLCAST_START(...) |
UNIT_SPELLCAST_CHANNEL_START(...) |
end, Enable, Disable) |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local GetComboPoints = GetComboPoints |
local MAX_COMBO_POINTS = MAX_COMBO_POINTS |
local Update = function(self, event, unit) |
local cpoints = self.CPoints |
if(self.unit ~= unit and (cpoints.unit and cpoints.unit ~= unit)) then return end |
local cp = GetComboPoints(cpoints.unit or unit, 'target') |
if(#cpoints == 0) then |
cpoints:SetText((cp > 0) and cp) |
else |
for i=1, MAX_COMBO_POINTS do |
if(i <= cp) then |
cpoints[i]:Show() |
else |
cpoints[i]:Hide() |
end |
end |
end |
end |
local Enable = function(self) |
if(self.CPoints) then |
self:RegisterEvent('UNIT_COMBO_POINTS', Update) |
return true |
end |
end |
local Disable = function(self) |
if(self.CPoints) then |
self:UnregisterEvent('UNIT_COMBO_POINTS', Update) |
end |
end |
oUF:AddElement('CPoints', Update, Enable, Disable) |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local objects = oUF.objects |
local VehicleDriverFrame |
local UpdateVehicleSwitch = function(self, attr, value) |
if attr == "unit" then |
self.unit = value |
if self:GetAttribute("normalUnit") == "player" then |
PlayerFrame.unit = self.unit |
BuffFrame_Update() |
end |
end |
end |
local Enable = function(self, unit) |
if self.disallowVehicleSwap or (unit ~= "player" and unit ~= "pet") then return end |
if not VehicleDriverFrame then |
VehicleDriverFrame = CreateFrame("Frame", nil, UIParent, "SecureHandlerStateTemplate") |
RegisterStateDriver(VehicleDriverFrame, "vehicle", "[target=vehicle,exists,bonusbar:5]vehicle;novehicle") |
VehicleDriverFrame:SetAttribute("_onstate-vehicle", [[ |
if newstate == "vehicle" then |
for idx, frame in pairs(VEHICLE_FRAMES) do |
frame:SetAttribute("unit", frame:GetAttribute("vehicleUnit")) |
end |
else |
for idx, frame in pairs(VEHICLE_FRAMES) do |
frame:SetAttribute("unit", frame:GetAttribute("normalUnit")) |
end |
end |
]]) |
VehicleDriverFrame:Execute([[ |
VEHICLE_FRAMES = newtable() |
]]) |
end |
self:SetAttribute("normalUnit", unit) |
if unit == "player" then |
self:SetAttribute("vehicleUnit", "pet") |
elseif unit == "pet" then |
self:SetAttribute("vehicleUnit", "player") |
end |
VehicleDriverFrame:SetFrameRef("vehicleFrame", self) |
VehicleDriverFrame:Execute([[ |
local frame = self:GetFrameRef("vehicleFrame") |
table.insert(VEHICLE_FRAMES, frame) |
]]) |
self:HookScript("OnAttributeChanged", UpdateVehicleSwitch) |
end |
local Disable = function(self) |
self:SetAttribute("unit", self:GetAttribute("normalUnit")) |
VehicleDriverFrame:SetFrameRef("vehicleFrame", self) |
VehicleDriverFrame:Execute([[ |
local frame = self:GetFrameRef("vehicleFrame") |
for idx, value in pairs(VEHICLE_FRAMES) do |
if value == frame then |
table.remove(VEHICLE_FRAMES, idx) |
return |
end |
end |
]]) |
end |
oUF:AddElement("VehicleSwitch", nil, Enable, Disable) |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local function Update(self, event) |
local unit |
local method, pid, rid = GetLootMethod() |
if(method == 'master') then |
if(pid) then |
if(pid == 0) then |
unit = 'player' |
else |
unit = 'party'..pid |
end |
elseif(rid) then |
unit = 'raid'..rid |
end |
if(UnitIsUnit(unit, self.unit)) then |
self.MasterLooter:Show() |
elseif(self.MasterLooter:IsShown()) then |
self.MasterLooter:Hide() |
end |
elseif(self.MasterLooter:IsShown()) then |
self.MasterLooter:Hide() |
end |
end |
local function Enable(self, unit) |
local masterlooter = self.MasterLooter |
if(masterlooter) then |
self:RegisterEvent('PARTY_LOOT_METHOD_CHANGED', Update) |
self:RegisterEvent('PARTY_MEMBERS_CHANGED', Update) |
if(masterlooter:IsObjectType('Texture') and not masterlooter:GetTexture()) then |
masterlooter:SetTexture([[Interface\GroupFrame\UI-Group-MasterLooter]]) |
end |
return true |
end |
end |
local function Disable(self) |
if(self.MasterLooter) then |
self:UnregisterEvent('PARTY_LOOT_METHOD_CHANGED', Update) |
self:UnregisterEvent('PARTY_MEMBERS_CHANGED', Update) |
end |
end |
oUF:AddElement('MasterLooter', Update, Enable, Disable) |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
do |
local Update = function(self, event) |
if(IsResting()) then |
self.Resting:Show() |
else |
self.Resting:Hide() |
end |
end |
local Enable = function(self, unit) |
if(self.Resting and unit == 'player') then |
self:RegisterEvent("PLAYER_UPDATE_RESTING", Update) |
if(self.Resting:IsObjectType"Texture" and not self.Resting:GetTexture()) then |
self.Resting:SetTexture[[Interface\CharacterFrame\UI-StateIcon]] |
self.Resting:SetTexCoord(0, .5, 0, .421875) |
end |
return true |
end |
end |
local Disable = function(self) |
if(self.Resting) then |
self:UnregisterEvent("PLAYER_UPDATE_RESTING", Update) |
end |
end |
oUF:AddElement('Resting', Update, Enable, Disable) |
end |
do |
local Update = function(self, event) |
if(UnitAffectingCombat"player") then |
self.Combat:Show() |
else |
self.Combat:Hide() |
end |
end |
local Enable = function(self, unit) |
if(self.Combat and unit == 'player') then |
self:RegisterEvent("PLAYER_REGEN_DISABLED", Update) |
self:RegisterEvent("PLAYER_REGEN_ENABLED", Update) |
if(self.Combat:IsObjectType"Texture" and not self.Combat:GetTexture()) then |
self.Combat:SetTexture[[Interface\CharacterFrame\UI-StateIcon]] |
self.Combat:SetTexCoord(.5, 1, 0, .5) |
end |
return true |
end |
end |
local Disable = function(self) |
if(self.Combat) then |
self:UnregisterEvent("PLAYER_REGEN_DISABLED", Update) |
self:UnregisterEvent("PLAYER_REGEN_ENABLED", Update) |
end |
end |
oUF:AddElement('Combat', Update, Enable, Disable) |
end |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local Update = function(self, event, unit) |
if(not UnitIsUnit(self.unit, unit)) then return end |
local portrait = self.Portrait |
if(portrait:IsObjectType'Model') then |
local name = UnitName(unit) |
if(not UnitExists(unit) or not UnitIsConnected(unit) or not UnitIsVisible(unit)) then |
portrait:SetModelScale(4.25) |
portrait:SetPosition(0, 0, -1.5) |
portrait:SetModel"Interface\\Buttons\\talktomequestionmark.mdx" |
elseif(portrait.name ~= name or event == 'UNIT_MODEL_CHANGED') then |
portrait:SetUnit(unit) |
portrait:SetCamera(0) |
portrait.name = name |
else |
portrait:SetCamera(0) |
end |
else |
SetPortraitTexture(portrait, unit) |
end |
end |
local Enable = function(self) |
if(self.Portrait) then |
self:RegisterEvent("UNIT_PORTRAIT_UPDATE", Update) |
self:RegisterEvent("UNIT_MODEL_CHANGED", Update) |
return true |
end |
end |
local Disable = function(self) |
if(self.Portrait) then |
self:UnregisterEvent("UNIT_PORTRAIT_UPDATE", Update) |
self:UnregisterEvent("UNIT_MODEL_CHANGED", Update) |
end |
end |
oUF:AddElement('Portrait', Update, Enable, Disable) |
--[[ |
Elements handled: .Threat |
Functions that can be overridden from within a layout: |
- :PreUpdateThreat(event, unit) |
- :OverrideUpdateThreat(event, unit, status) |
- :PostUpdateThreat(event, unit, status) |
--]] |
if(select(4, GetBuildInfo()) < 3e4) then return end |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local Update = function(self, event, unit) |
if(unit ~= self.unit) then return end |
if(self.PreUpdateThreat) then self:PreUpdateThreat(event, unit) end |
unit = unit or self.unit |
local threat = self.Threat |
local status = UnitThreatSituation(unit) |
if(not self.OverrideUpdateThreat) then |
if(status and status > 0) then |
local r, g, b = GetThreatStatusColor(status) |
threat:SetVertexColor(r, g, b) |
threat:Show() |
else |
threat:Hide() |
end |
else |
self:OverrideUpdateThreat(event, unit, status) |
end |
if(self.PostUpdateThreat) then self:PostUpdateThreat(event, unit, status) end |
end |
local Enable = function(self) |
local threat = self.Threat |
if(threat) then |
self:RegisterEvent("UNIT_THREAT_SITUATION_UPDATE", Update) |
threat:Hide() |
if(threat:IsObjectType"Texture" and not threat:GetTexture()) then |
threat:SetTexture[[Interface\Minimap\ObjectIcons]] |
threat:SetTexCoord(6/8, 7/8, 1/2, 1) |
end |
return true |
end |
end |
local Disable = function(self) |
local threat = self.Threat |
if(threat) then |
self:UnregisterEvent("UNIT_THREAT_SITUATION_UPDATE", Update) |
end |
end |
oUF:AddElement('Threat', Update, Enable, Disable) |
--[[ |
Elements handled: .Auras, .Buffs, .Debuffs |
Shared: |
- spacing: Padding between aura icons. (Default: 0) |
- size: Size of the aura icons. (Default: 16) |
- initialAnchor: Initial anchor in the aura frame. (Default: "BOTTOMLEFT") |
- onlyShowPlayer: Only display icons casted by the player. (Default: nil) |
- growth-x: Growth direction, affected by initialAnchor. (Default: "UP") |
- growth-y: Growth direction, affected by initialAnchor. (Default: "RIGHT") |
- disableCooldown: Disable the Cooldown Spiral on the Aura Icons. (Default: nil) |
- filter: Expects a string with filter. See the UnitAura[1] documentation for |
more information. |
.Auras only: |
- gap: Adds a empty icon to separate buffs and debuffs. (Default: nil) |
- numBuffs: The maximum number of buffs that should be shown. (Default: 32) |
- numDebuffs: The maximum number of debuffs that should be shown. (Default: 40) |
- buffFilter: See filter on Shared. (Default: "HELPFUL") |
- debuffFilter: See filter on Shared. (Default: "HARMFUL") |
- Variables set by .Auras: |
- visibleBuffs: Number of currently visible buff icons. |
- visibleDebuffs: Number of currently visible debuff icons. |
- visibleAuras: Total number of currently visible buffs + debuffs. |
.Buffs only: |
- num: The maximum number of buffs that should be shown. (Default: 32) |
- Variables set by .Buffs: |
- visibleBuffs: Number of currently visible buff icons. |
.Debuffs only: |
- num: The maximum number of debuffs that should be shown. (Default: 40) |
- Variables set by .Debuffs: |
- visibleDebuffs: Number of currently visible debuff icons. |
Functions that can be overridden from within a layout: |
- :PostCreateAuraIcon(icon, icons, index, isDebuff) |
- :CreateAuraIcon(icons, index, isDebuff) |
- :PostUpdateAuraIcon(icons, unit, icon, index, offset, filter, isDebuff) |
- :PreUpdateAura(event, unit) |
- :SetAuraPosition(auras, max) |
- :PostUpdateAura(event, unit) |
[1] http://www.wowwiki.com/API_UnitAura |
--]] |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
assert(global, 'X-oUF needs to be defined in the parent add-on.') |
local oUF = _G[global] |
local OnEnter = function(self) |
if(not self:IsVisible()) then return end |
GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT") |
GameTooltip:SetUnitAura(self.frame.unit, self:GetID(), self.filter) |
end |
local OnLeave = function() |
GameTooltip:Hide() |
end |
local createAuraIcon = function(self, icons, index, debuff) |
local button = CreateFrame("Frame", nil, icons) |
button:EnableMouse(true) |
button:SetWidth(icons.size or 16) |
button:SetHeight(icons.size or 16) |
local cd = CreateFrame("Cooldown", nil, button) |
cd:SetAllPoints(button) |
local icon = button:CreateTexture(nil, "BACKGROUND") |
icon:SetAllPoints(button) |
local count = button:CreateFontString(nil, "OVERLAY") |
count:SetFontObject(NumberFontNormal) |
count:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -1, 0) |
local overlay = button:CreateTexture(nil, "OVERLAY") |
overlay:SetTexture"Interface\\Buttons\\UI-Debuff-Overlays" |
overlay:SetAllPoints(button) |
overlay:SetTexCoord(.296875, .5703125, 0, .515625) |
button.overlay = overlay |
button:SetScript("OnEnter", OnEnter) |
button:SetScript("OnLeave", OnLeave) |
table.insert(icons, button) |
button.parent = icons |
button.frame = self |
button.debuff = debuff |
button.icon = icon |
button.count = count |
button.cd = cd |
if(self.PostCreateAuraIcon) then self:PostCreateAuraIcon(button, icons, index, debuff) end |
return button |
end |
local customFilter = function(icons, unit, icon, name, rank, texture, count, dtype, duration, timeLeft, caster) |
local isPlayer |
if(caster == 'player' or caster == 'vehicle') then |
isPlayer = true |
end |
if((icons.onlyShowPlayer and isPlayer) or (not icons.onlyShowPlayer and name)) then |
icon.isPlayer = isPlayer |
icon.owner = caster |
return true |
end |
end |
local updateIcon = function(self, unit, icons, index, offset, filter, isDebuff, max) |
if(index == 0) then index = max end |
local icon = icons[index + offset] |
if(not icon) then |
icon = (self.CreateAuraIcon or createAuraIcon) (self, icons, index, isDebuff) |
end |
local name, rank, texture, count, dtype, duration, timeLeft, caster = UnitAura(unit, index, filter) |
local show = (self.CustomAuraFilter or customFilter) (icons, unit, icon, name, rank, texture, count, dtype, duration, timeLeft, caster) |
if(show) then |
if(not icons.disableCooldown and duration and duration > 0) then |
icon.cd:SetCooldown(timeLeft - duration, duration) |
icon.duration = duration |
icon.timeLeft = timeLeft |
icon.cd:Show() |
else |
icon.cd:Hide() |
end |
if((isDebuff and icons.showDebuffType) or (not isDebuff and icons.showBuffType) or icons.showType) then |
local color = DebuffTypeColor[dtype] or DebuffTypeColor.none |
icon.overlay:SetVertexColor(color.r, color.g, color.b) |
icon.overlay:Show() |
else |
icon.overlay:Hide() |
end |
icon.icon:SetTexture(texture) |
icon.count:SetText((count > 1 and count)) |
icon.filter = filter |
icon.debuff = isDebuff |
icon:SetID(index) |
icon:Show() |
if(self.PostUpdateAuraIcon) then |
self:PostUpdateAuraIcon(icons, unit, icon, index, offset, filter, isDebuff) |
end |
return true |
else |
icon:Hide() |
end |
end |
local SetAuraPosition = function(self, icons, x) |
if(icons and x > 0) then |
local col = 0 |
local row = 0 |
local spacing = icons.spacing or 0 |
local gap = icons.gap |
local size = (icons.size or 16) + spacing |
local anchor = icons.initialAnchor or "BOTTOMLEFT" |
local growthx = (icons["growth-x"] == "LEFT" and -1) or 1 |
local growthy = (icons["growth-y"] == "DOWN" and -1) or 1 |
local cols = math.floor(icons:GetWidth() / size + .5) |
local rows = math.floor(icons:GetHeight() / size + .5) |
for i = 1, x do |
local button = icons[i] |
if(button and button:IsShown()) then |
if(gap and button.debuff) then |
if(col > 0) then |
col = col + 1 |
end |
gap = false |
end |
if(col >= cols) then |
col = 0 |
row = row + 1 |
end |
button:ClearAllPoints() |
button:SetPoint(anchor, icons, anchor, col * size * growthx, row * size * growthy) |
col = col + 1 |
end |
end |
end |
end |
local Update = function(self, event, unit) |
if(self.unit ~= unit) then return end |
if(self.PreUpdateAura) then self:PreUpdateAura(event, unit) end |
local auras, buffs, debuffs = self.Auras, self.Buffs, self.Debuffs |
if(auras) then |
local buffs = auras.numBuffs or 32 |
local debuffs = auras.numDebuffs or 40 |
local max = debuffs + buffs |
local visibleBuffs, visibleDebuffs = 0, 0 |
for index = 1, max do |
if(index > buffs) then |
if(updateIcon(self, unit, auras, index % debuffs, visibleBuffs, auras.debuffFilter or auras.filter or 'HARMFUL', true, debuffs)) then |
visibleDebuffs = visibleDebuffs + 1 |
end |
else |
if(updateIcon(self, unit, auras, index, 0, auras.buffFilter or auras.filter or 'HELPFUL')) then |
visibleBuffs = visibleBuffs + 1 |
end |
end |
end |
auras.visibleBuffs = visibleBuffs |
auras.visibleDebuffs = visibleDebuffs |
auras.visibleAuras = visibleBuffs + visibleDebuffs |
self:SetAuraPosition(auras, max) |
end |
if(buffs) then |
local filter = buffs.filter or 'HELPFUL' |
local max = buffs.num or 32 |
local visibleBuffs = 0 |
for index = 1, max do |
if(not updateIcon(self, unit, buffs, index, 0, filter)) then |
max = index - 1 |
while(buffs[index]) do |
buffs[index]:Hide() |
index = index + 1 |
end |
break |
end |
visibleBuffs = visibleBuffs + 1 |
end |
buffs.visibleBuffs = visibleBuffs |
self:SetAuraPosition(buffs, max) |
end |
if(debuffs) then |
local filter = debuffs.filter or 'HARMFUL' |
local max = debuffs.num or 40 |
local visibleDebuffs = 0 |
for index = 1, max do |
if(not updateIcon(self, unit, debuffs, index, 0, filter, true)) then |
max = index - 1 |
while(debuffs[index]) do |
debuffs[index]:Hide() |
index = index + 1 |
end |
break |
end |
visibleDebuffs = visibleDebuffs + 1 |
end |
debuffs.visibleDebuffs = visibleDebuffs |
self:SetAuraPosition(debuffs, max) |
end |
if(self.PostUpdateAura) then self:PostUpdateAura(event, unit) end |
end |
local Enable = function(self) |
if(self.Buffs or self.Debuffs or self.Auras) then |
if(not self.SetAuraPosition) then |
self.SetAuraPosition = SetAuraPosition |
end |
self:RegisterEvent("UNIT_AURA", Update) |
return true |
end |
end |
local Disable = function(self) |
if(self.Buffs or self.Debuffs or self.Auras) then |
self:UnregisterEvent("UNIT_AURA", Update) |
end |
end |
oUF:AddElement('Aura', Update, Enable, Disable) |
## Interface: 30100 |
## Title: oUF |
## Author: Haste |
## Version: 1.3.11 |
## X-eMail: troeks@gmail.com |
## X-oUF: oUF |
## Notes: Unit frame framework. Does nothing by itself. |
oUF.xml |
Copyright (c) 2006-2009 Trond A Ekseth |
Permission is hereby granted, free of charge, to any person |
obtaining a copy of this software and associated documentation |
files (the "Software"), to deal in the Software without |
restriction, including without limitation the rights to use, |
copy, modify, merge, publish, distribute, sublicense, and/or sell |
copies of the Software, and to permit persons to whom the |
Software is furnished to do so, subject to the following |
conditions: |
The above copyright notice and this permission notice shall be |
included in all copies or substantial portions of the Software. |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
OTHER DEALINGS IN THE SOFTWARE. |
<Ui xmlns="http://www.blizzard.com/wow/ui/"> |
<Script file='ouf.lua' /> |
<Script file='elements\power.lua' /> |
<Script file='elements\aura.lua' /> |
<Script file='elements\health.lua' /> |
<Script file='elements\cpoints.lua' /> |
<Script file='elements\ricons.lua' /> |
<Script file='elements\leader.lua' /> |
<Script file='elements\status.lua' /> |
<Script file='elements\pvp.lua' /> |
<Script file='elements\portraits.lua' /> |
<Script file='elements\range.lua' /> |
<Script file='elements\happiness.lua' /> |
<Script file='elements\castbar.lua' /> |
<Script file='elements\threat.lua' /> |
<Script file='elements\tags.lua' /> |
<Script file='elements\vehicle.lua' /> |
<Script file='elements\masterlooter.lua' /> |
<!-- |
This template requires the layout to set the anchoring positions from the |
sub-frame(s). These are feed to the layouts style functions as any other unit |
spawned by a header. The main difference is that they have the unitsuffix |
attribute set (and they are parented to their respective owener). |
--> |
<Button name="oUF_HeaderTargetTemplate" inherits="SecureUnitButtonTemplate" hidden="true" virtual="true"> |
<Frames> |
<Button name="$parentTarget" inherits="SecureUnitButtonTemplate"> |
<Attributes> |
<Attribute name="unitsuffix" type="string" value="target"/> |
<Attribute name="useparent-unit" type="boolean" value="true"/> |
<Attribute name="type1" type="string" value="target"/> |
<Attribute name="initial-unitWatch" type="boolean" value="true"/> |
</Attributes> |
</Button> |
</Frames> |
</Button> |
</Ui> |
<Include file="Libs\AceConsole-3.0\AceConsole-3.0.xml"/> |
<Include file="Libs\AceDB-3.0\AceDB-3.0.xml"/> |
<Include file="Libs\AceEvent-3.0\AceEvent-3.0.xml"/> |
<Include file="Libs\LibSharedMedia-3.0\lib.xml"/> |
<Include file="Libs\LibSharedMedia-3.0\lib.xml"/> |
<Script file="Libs\ LibHealComm-3.0.lua"/> |
</Ui> |
--============================================================================== |
-- |
-- oUF_HealComm |
-- |
-- Uses data from LibHealComm-3.0 to add incoming heal estimate bars onto units |
-- health bars. |
-- |
-- * currently won't update the frame if max HP is unknown (ie, restricted to |
-- players/pets in your group that are in range), hides the bar for these |
-- * can define frame.ignoreHealComm in layout to not have the bars appear on |
-- that frame |
-- |
--============================================================================= |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
local oUF = _G[global] or oUF |
assert(oUF, 'oUF not loaded') |
local oUF_HealComm = {} |
local healcomm = LibStub("LibHealComm-3.0") |
local playerName = UnitName("player") |
local playerIsCasting = false |
local playerHeals = 0 |
local playerTarget = "" |
oUF.debug=false |
function round(num, idp) |
if idp and idp>0 then |
local mult = 10^idp |
return math.floor(num * mult + 0.5) / mult |
end |
return math.floor(num + 0.5) |
end |
local numberize = function(val) |
if(val >= 1e3) then |
return ("%.1fk"):format(val / 1e3) |
elseif (val >= 1e6) then |
return ("%.1fm"):format(val / 1e6) |
else |
return round(val,1) |
end |
end |
local function Hex(r, g, b) |
if type(r) == "table" then |
if r.r then r, g, b = r.r, r.g, r.b else r, g, b = unpack(r) end |
end |
return string.format("|cff%02x%02x%02x", r*255, g*255, b*255) |
end |
--set texture and color here |
local color = { |
r = 0, |
g = 1, |
b = 0, |
a = .25, |
} |
--update a specific bar |
local updateHealCommBar = function(frame, unit) |
if not unit or unit == nil then return end |
local curHP = UnitHealth(unit) |
local maxHP = UnitHealthMax(unit) |
local percHP = curHP / maxHP |
local incHeals = select(2, healcomm:UnitIncomingHealGet(unit, GetTime())) or 0 |
local healCommBar = frame.HealCommBar |
local _,parentBar,_,_,_ = healCommBar:GetPoint() |
--add player's own heals if casting on this unit |
if playerIsCasting then |
for i = 1, select("#", playerTarget) do |
local target = select(i, playerTarget) |
if target == unit then |
incHeals = incHeals + playerHeals |
end |
end |
end |
local percInc = incHeals / maxHP |
--hide if unknown max hp or no heals inc |
if maxHP == 100 or incHeals == 0 then |
frame.HealCommBar:Hide() |
return |
else |
frame.HealCommBar:Show() |
end |
h = parentBar:GetHeight() |
w = frame:GetWidth()-2 |
orient = parentBar:GetOrientation() |
healCommBar:ClearAllPoints() |
healCommBar:SetFrameStrata("DIALOG") |
if(orient=="VERTICAL")then |
healCommBar:SetHeight(percInc * h) |
healCommBar:SetWidth(w) |
healCommBar:SetPoint("BOTTOM", parentBar, "BOTTOM", 0, h * percHP) |
else |
healCommBar:SetWidth(percInc * w) |
healCommBar:SetHeight(h) |
healCommBar:SetPoint("LEFT", parentBar, "LEFT", w * percHP,0) |
end |
if(healCommBar.Amount)then |
healCommBar.Amount:SetText(numberize(incHeals)) |
end |
end |
--used by library callbacks, arguments should be list of units to update |
local updateHealCommBars = function(...) |
for i = 1, select("#", ...) do |
local unit = select(i, ...) |
--search current oUF frames for this unit |
for frame in pairs(oUF.units) do |
local name, server = UnitName(frame) |
if server then name = strjoin("-",name,server) end |
if name == unit and not oUF.units[frame].ignoreHealComm then |
updateHealCommBar(oUF.units[frame],unit) |
end |
end |
end |
end |
local function hook(frame) |
if frame.ignoreHealComm then return end |
local parentBar = frame.Health |
--create heal bar here and set initial values |
local hcb = CreateFrame"StatusBar" |
if(parentBar:GetOrientation() =="VERTICAL")then |
hcb:SetWidth(parentBar:GetWidth()) -- same height as health bar |
hcb:SetHeight(4) --no initial width |
hcb:SetStatusBarTexture(parentBar:GetStatusBarTexture():GetTexture()) |
hcb:SetStatusBarColor(color.r, color.g, color.b, color.a) |
hcb:SetParent(frame) |
hcb:SetPoint("BOTTOMLEFT", parentBar, "TOPLEFT",0,0) --attach to immediate right of health bar to start |
hcb:Hide() --hide it for now |
else |
hcb:SetHeight(parentBar:GetHeight()) -- same height as health bar |
hcb:SetWidth(4) --no initial width |
hcb:SetStatusBarTexture(parentBar:GetStatusBarTexture():GetTexture()) |
hcb:SetStatusBarColor(color.r, color.g, color.b, color.a) |
hcb:SetParent(frame) |
hcb:SetPoint("LEFT", parentBar, "RIGHT",0,0) --attach to immediate right of health bar to start |
hcb:Hide() --hide it for now |
end |
healthBarTextObj = parentBar.value or parentBar.text |
if(healthBarTextObj)then |
fontName, fontHeight, fontFlags = healthBarTextObj:GetFont() |
else |
fontName, fontHeight, fontFlags = font, fontSize, "outline" |
end |
hcb.Amount = hcb:CreateFontString(nil, "OVERLAY") |
hcb.Amount:SetFont(fontName, fontHeight, fontFlags) |
hcb.Amount:SetPoint('CENTER',hcb, 0, 0) |
hcb.Amount:SetTextColor(1,1,1,.5) |
hcb.Amount:SetJustifyH("CENTER") |
if(frame.FontObjects ~= nil) then |
frame.FontObjects["incomingHeals"] = { |
name = "Incoming Heals", |
object = hcb.Amount |
} |
end |
frame.HealCommBar = hcb |
local o = frame.PostUpdateHealth |
frame.PostUpdateHealth = function(...) |
if o then o(...) end |
local name, server = UnitName(frame.unit) |
if server then name = strjoin("-",name,server) end |
updateHealCommBar(frame, name) --update the bar when unit's health is updated |
end |
end |
--hook into all existing frames |
for i, frame in ipairs(oUF.objects) do hook(frame) end |
--hook into new frames as they're created |
oUF:RegisterInitCallback(hook) |
--set up LibHealComm callbacks |
function oUF_HealComm:HealComm_DirectHealStart(event, healerName, healSize, endTime, ...) |
if healerName == playerName then |
playerIsCasting = true |
playerTarget = ... |
playerHeals = healSize |
end |
updateHealCommBars(...) |
end |
function oUF_HealComm:HealComm_DirectHealUpdate(event, healerName, healSize, endTime, ...) |
updateHealCommBars(...) |
end |
function oUF_HealComm:HealComm_DirectHealStop(event, healerName, healSize, succeeded, ...) |
if healerName == playerName then |
playerIsCasting = false |
end |
updateHealCommBars(...) |
end |
function oUF_HealComm:HealComm_HealModifierUpdate(event, unit, targetName, healModifier) |
updateHealCommBars(unit) |
end |
healcomm.RegisterCallback(oUF_HealComm, "HealComm_DirectHealStart") |
healcomm.RegisterCallback(oUF_HealComm, "HealComm_DirectHealUpdate") |
healcomm.RegisterCallback(oUF_HealComm, "HealComm_DirectHealStop") |
healcomm.RegisterCallback(oUF_HealComm, "HealComm_HealModifierUpdate") |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
local oUF = _G[global] or oUF |
assert(oUF, 'oUF not loaded') |
--[[ |
Elements handled: |
.RuneBar [fontstring or table] |
FontString only: |
- space: The space between each "counter". (Default: " ") |
- symbol: The symbol used when cooldowns are over. (Default: "*") |
- interval: The time offset used for the update script. (Default: 0.5) |
--]] |
local localized, class = UnitClass('player') |
local dummy = CreateFrame('Frame') |
local colors = { |
[1] = {0.77, 0.12, 0.23}, |
[2] = {0.3, 0.8, 0.1}, |
[3] = {0, 0.4, 0.7}, |
[4] = {0.8, 0.8, 0.8}, |
} |
local OnUpdateBar, OnUpdateText |
do |
local total = 0 |
function OnUpdateText(self, elapsed) |
total = total + elapsed |
if(total >= (self.bars.RuneBar.interval or 0.5)) then |
self:UpdateElement('RuneBar') |
total = 0 |
end |
end |
function OnUpdateBar(self, rune) |
local start, duration, ready = GetRuneCooldown(rune) |
if(ready) then |
self:SetValue(1) |
self:SetScript('OnUpdate', nil) |
else |
self:SetValue((GetTime() - start) / duration) |
end |
end |
end |
local function UpdateStatusBar(self, event, rune, usable) |
if(rune and not usable and GetRuneType(rune)) then |
self.bars.RuneBar.bars[rune]:SetScript('OnUpdate', function(self) OnUpdateBar(self, rune) end) |
end |
end |
local function Update(self, event, rune) |
local runebar = self.bars.RuneBar |
if(#runebar.bars == 0) then |
local text = '' |
for i = 1, 6 do |
local start, duration, ready, temp = GetRuneCooldown(i) |
local r, g, b = unpack(runebar.colors[GetRuneType(i)]) |
local temp = ready and (runebar.symbol or '*') or (duration - math.floor(GetTime() - start)) |
text = string.format('%s|cff%02x%02x%02x%s%s|r', text, r * 255, g * 255, b * 255, temp, runebar.space or ' ') |
end |
runebar:SetText(text) |
else |
for i = 1, 6 do |
local runetype = GetRuneType(i) |
if(runetype) then |
runebar.bars[i]:SetStatusBarColor(unpack(runebar.colors[runetype])) |
end |
end |
end |
end |
local function Enable(self, unit) |
if not (unit == 'player' and class == 'DEATHKNIGHT') then return end |
if(self.bars and self.bars.RuneBar)then |
local runebar = self.bars.RuneBar |
if(not runebar.colors) then |
runebar.colors = self.colors.runes or colors |
end |
self:RegisterEvent('RUNE_TYPE_UPDATE', Update) |
if(#runebar.bars == 0) then |
self:RegisterEvent('RUNE_POWER_UPDATE', Update) |
dummy:SetScript('OnUpdate', function(s, e) OnUpdateText(self, e) end) |
else |
self:RegisterEvent('RUNE_POWER_UPDATE', UpdateStatusBar) |
end |
RuneFrame:Hide() |
return true |
end |
end |
local function Disable(self) |
local runebar = self.bars.RuneBar |
if(runebar) then |
self:RegisterEvent('RUNE_TYPE_UPDATE', Update) |
if(#runebar == 0) then |
self:UnregisterEvent('RUNE_POWER_UPDATE', Update) |
dummy:SetScript('OnUpdate', nil) |
else |
self:UnregisterEvent('RUNE_POWER_UPDATE', UpdateStatusBar) |
end |
RuneFrame:Show() |
end |
end |
oUF:AddElement('RuneBar', Update, Enable, Disable) |
local parent = debugstack():match[[\AddOns\(.-)\]] |
local global = GetAddOnMetadata(parent, 'X-oUF') |
local oUF = _G[global] or oUF |
assert(oUF, 'oUF not loaded') |
oUF.TagEvents["[status]"] = "UNIT_HEALTH PLAYER_UPDATE_RESTING PLAYER_FLAGS_CHANGED" |
oUF.TagEvents["[afk]"] = "UNIT_HEALTH PLAYER_UPDATE_RESTING PLAYER_FLAGS_CHANGED" |
oUF.TagEvents["[shortName]"] = "UNIT_NAME_UPDATE" |
oUF.TagsLogicStrings = { |
["[class]"] = [[function(u) return UnitClass(u) end]], |
["[creature]"] = [[function(u) return UnitCreatureFamily(u) or UnitCreatureType(u) end]], |
["[curhp]"] = [[UnitHealth]], |
["[curpp]"] = [[UnitPower]], |
["[dead]"] = [[function(u) |
return UnitIsDead(u) and "Dead" or UnitIsGhost(u) and "Ghost" |
end]], |
["[difficulty]"] = [[function(u) |
if UnitCanAttack("player", u) then |
local l = UnitLevel(u); |
return Hex(GetDifficultyColor((l > 0) and l or 99)) |
end |
end]], |
["[faction]"] = [[function(u) return UnitFactionGroup(u) end]], |
["[leader]"] = [[function(u) return UnitIsPartyLeader(u) and "(L)" end]], |
["[leaderlong]"] = [[function(u) return UnitIsPartyLeader(u) and "(Leader)" end]], |
["[level]"] = [[function(u) |
local l = UnitLevel(u); |
return (l > 0) and l or "??" |
end]], |
["[maxhp]"] = [[UnitHealthMax]], |
["[maxpp]"] = [[UnitPowerMax]], |
["[missinghp]"] = [[function(u) m=UnitHealthMax(u) - UnitHealth(u); return m>0 and m.. " | " or "" end]], |
["[missingpp]"] = [[function(u) m=UnitPowerMax(u) - UnitPower(u); return m>0 and m.. " | " or "" end]], |
["[name]"] = [[function(u, r) return UnitName(r or u) end]], |
["[shortname]"] = [[function(u) return string.sub(UnitName(u),1,4) or '' end]], |
["[offline]"] = [[function(u) return (not UnitIsConnected(u) and "Offline") end]], |
["[perhp]"] = [[function(u) local m = UnitHealthMax(u); return m == 0 and 0 or math.floor(UnitHealth(u)/m*100+0.5) end]], |
["[perpp]"] = [[function(u) local m = UnitPowerMax(u); return m == 0 and 0 or math.floor(UnitPower(u)/m*100+0.5) end]], |
["[plus]"] = [[function(u) return UnitIsPlusMob(u) and "+" end]], |
["[pvp]"] = [[function(u) return UnitIsPVP(u) and "PvP" end]], |
["[race]"] = [[function(u) return UnitRace(u) end]], |
["[raidcolor]"] = [[function(u) |
local _, x = UnitClass(u); |
return x and Hex(RAID_CLASS_COLORS[x]) |
end]], |
["[rare]"] = [[function(u) |
local c = UnitClassification(u); |
return (c == "rare" or c == "rareelite") and "Rare" |
end]], |
["[resting]"] = [[function(u) return u == "player" and IsResting() and "zzz" end]], |
["[afk]"] = [[function(u) return UnitIsAFK(u) and "AFK" end]], |
["[sex]"] = [[function(u) local s = UnitSex(u) return s == 2 and "Male" or s == 3 and "Female" end]], |
["[smartclass]"] = [[function(u) return UnitIsPlayer(u) and oUF.Tags["[class]"](u) or oUF.Tags["[creature]"](u) end]], |
["[status]"] = [[function(u) return UnitIsDead(u) and "Dead" or UnitIsGhost(u) and "Ghost" or not UnitIsConnected(u) and "Offline" or oUF.Tags["[resting]"](u) end]], |
["[threat]"] = [[function(u) local s = UnitThreatSituation(u); return s == 1 and "++" or s == 2 and "--" or s == 3 and "Aggro" end]], |
["[threatplus]"] = [[function(u) |
local unitTarget = u.."target" |
if(UnitExists(unitTarget))then |
local_,_, threatpct, rawthreatpct, threatvalue = UnitDetailedThreatSituation(u, uTarget) |
return rawthreatpct |
else |
return '' |
end |
end]], |
["[threatcolor]"] = [[function(u) return Hex(GetThreatStatusColor(UnitThreatSituation(u))) end]], |
["[cpoints]"] = [[function(u) local cp = GetComboPoints(u, 'target') return (cp > 0) and cp end]], |
['[smartlevel]'] = [[function(u) |
local c = UnitClassification(u) |
if(c == "worldboss") then |
return "Boss" |
else |
local plus = oUF.Tags["[plus]"](u) |
local level = oUF.Tags["[level]"](u) |
if(plus) then |
return level .. plus |
else |
return level |
end |
end |
end]], |
["[classification]"] = [[function(u) |
local c = UnitClassification(u) |
return c == "rare" and "Rare" or c == "eliterare" and "Rare Elite" or c == "elite" and "Elite" or c == "worldboss" and "Boss" |
end]], |
["[shortclassification]"] = [[function(u) |
local c = UnitClassification(u) |
return c == "rare" and "R" or c == "eliterare" and "R+" or c == "elite" and "+" or c == "worldboss" and "B" |
end]], |
} |
function oUF:ReWriteTag(tag,events,logic) |
if logic then |
builder = assert(loadstring("return " .. logic)) |
self.Tags[tag] = builder() |
end |
if events then |
oUF.TagEvents[tag] = events |
end |
end |
function oUF:CompileTagStringLogic() |
for tag,logic in pairs(self.TagsLogicStrings)do |
oUF:ReWriteTag(tag,oUF.TagEvents[tag],logic) |
end |
end |