diff --git a/.gitignore b/.gitignore index 586299e..5cd0e19 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ Libs/ +Textures/ +!Textures/statusbar4.tga diff --git a/Auras.lua b/Auras.lua new file mode 100644 index 0000000..1bc2212 --- /dev/null +++ b/Auras.lua @@ -0,0 +1,243 @@ +--[[----------------------------------------------------------------------- + oUF: Stardust - a layout for the oUF framework + Copyright (c) 2016 Andrew Mordecai <armordecai@protonmail.ch> + This code is released under the zlib license; see LICENSE for details. +-------------------------------------------------------------------------]] + +local _, Stardust = ... + +local _, class = UnitClass("player") + +local b = { + ALL = 0, + SELF = 1, + MINE = 2, + FRIEND = 4, + FRIEND_OOC = 8, -- for long term buffs and non-combat effects + ENEMY = 16, +} + +local t = { + [ 2825] = b.ALL, -- Bloodlust + [ 32182] = b.ALL, -- Heroism + -- Crowd Control >= 10 seconds + [ 710] = b.ALL, -- Banish + [ 2094] = b.ALL, -- Blind + [ 33796] = b.ALL, -- Cyclone + [ 605] = b.ALL, -- Dominate Mind + [ 339] = b.ALL, -- Entangling Roots + [118699] = b.ALL, -- Fear + [ 3355] = b.ALL, -- Freezing Trap + [ 51514] = b.ALL, -- Hex + -- TODO: find spell ID for Hex with Glyph of the Compy + [ 5484] = b.ALL, -- Howl of Terror + [115078] = b.ALL, -- Paralysis + [ 118] = b.ALL, -- Polymorph + [161353] = b.ALL, -- Polymorph (bear cub) + [ 61305] = b.ALL, -- Polymorph (cat) + [161354] = b.ALL, -- Polymorph (monkey) + [161372] = b.ALL, -- Polymorph (peacock) + [161355] = b.ALL, -- Polymorph (penguin) + [ 28272] = b.ALL, -- Polymorph (pig) + [126819] = b.ALL, -- Polymorph (porcupine) + [ 61721] = b.ALL, -- Polymorph (rabbit) + [ 61780] = b.ALL, -- Polymorph (turkey) + [ 28271] = b.ALL, -- Polymorph (turtle) + [ 20066] = b.ALL, -- Repentance + [ 82691] = b.ALL, -- Ring of Frost + [ 6770] = b.ALL, -- Sap + [ 9484] = b.ALL, -- Shackle Undead + [ 10326] = b.ALL, -- Turn Evil + [ 19386] = b.ALL, -- Wyvern Sting + -- Racial Abilities + [ 25046] = b.MINE, -- Arcane Torrent (energy) + [ 28730] = b.MINE, -- Arcane Torrent (mana) + [ 50613] = b.MINE, -- Arcane Torrent (runic power) + [ 69179] = b.MINE, -- Arcane Torrent (rage) + [ 80483] = b.MINE, -- Arcane Torrent (focus) + [129597] = b.MINE, -- Arcane Torrent (chi) + [155145] = b.MINE, -- Arcane Torrent (holy power) + [ 26297] = b.MINE, -- Berserking + [ 20572] = b.MINE, -- Blood Fury (attack power) + [ 33697] = b.MINE, -- Blood Fury (melee attack power + spell power) + [ 33702] = b.MINE, -- Blood Fury (spell power) + [ 68992] = b.MINE, -- Darkflight + [107079] = b.MINE, -- Quaking Palm + [ 58984] = b.MINE, -- Shadowmeld + [ 20594] = b.MINE, -- Stoneform + [ 20549] = b.MINE, -- War Stomp +} +if class == "DEATHKNIGHT" then +elseif class == "DEMONHUNTER" then +elseif class == "DRUID" then + t[ 22812] = b.MINE -- Barkskin + t[ 50334] = b.MINE -- Berserk (bear) + t[106951] = b.MINE -- Berserk (cat) + t[155835] = b.MINE -- Bristling Fur + t[112071] = b.MINE -- Celestial Alignment + t[102351] = b.MINE -- Cenarion Ward (buff) + t[102352] = b.MINE -- Cenarion Ward (heal) + t[ 16870] = b.MINE -- Clearcasting + t[135700] = b.MINE -- Clearcasting (from Omen of Clarity) + t[ 1850] = b.MINE -- Dash + t[137452] = b.MINE -- Displacer Beast + t[145162] = b.MINE -- Dream of Cenarius + t[157228] = b.MINE -- Empowered Moonkin + t[ 6795] = b.MINE -- Growl + t[108291] = b.MINE -- Heart of the Wild (balance) + t[108292] = b.MINE -- Heart of the Wild (feral) + t[108293] = b.MINE -- Heart of the Wild (guardian) + t[108294] = b.MINE -- Heart of the Wild (restoration) + t[ 99] = b.MINE -- Incapacitating Roar + t[102560] = b.MINE -- Incarnation: Chosen of Elune + t[102543] = b.MINE -- Incarnation: King of the Jungle + t[102558] = b.MINE -- Incarnation: Son of Ursoc + t[ 33891] = b.MINE -- Incarnation: Tree of Life + t[102342] = b.MINE -- Ironbark + t[ 33745] = b.MINE -- Lacerate + t[ 33763] = b.MINE -- Lifebloom + t[164547] = b.MINE -- Lunar Empowerment (from Starsurge) + t[ 22570] = b.MINE -- Maim + -- TODO: find spell ID for mangle slow debuff + t[ 1126] = b.FRIEND_OOC -- Mark of the Wild + t[102359] = b.MINE -- Mass Entanglement + t[ 5211] = b.MINE -- Mighty Bash + t[164812] = b.MINE -- Moonfire (TODO?) + t[132158] = b.MINE -- Nature's Swiftness + t[124974] = b.MINE -- Nature's Vigil + t[ 69369] = b.MINE -- Predatory Swiftness + t[ 5215] = b.MINE -- Prowl + t[158792] = b.MINE -- Pulverize + t[155722] = b.MINE -- Rake + t[ 8936] = b.MINE -- Regrowth + t[ 774] = b.MINE -- Rejuvenation + t[ 1079] = b.MINE -- Rip + t[132402] = b.MINE -- Savage Defense + t[ 52610] = b.MINE -- Savage Roar + t[164545] = b.MINE -- Solar Empowerment (from Starsurge) + t[114108] = b.MINE -- Soul of the Forest + t[106989] = b.MINE -- Stampeding Roar + t[184989] = b.MINE -- Starfall + t[152221] = b.MINE -- Stellar Flare + t[164815] = b.MINE -- Sunfire + t[ 61336] = b.MINE -- Survival Instincts + t[ 77758] = b.MINE -- Thrash (bear) + t[106830] = b.MINE -- Thrash (cat) + t[ 5217] = b.MINE -- Tiger's Fury + t[102416] = b.MINE -- Wild Charge (aquatic) + t[ 16979] = b.MINE -- Wild Charge (bear) + t[ 49376] = b.MINE -- Wild Charge (cat) + t[ 48438] = b.MINE -- Wild Growth +elseif class == "HUNTER" then +elseif class == "MAGE" then +elseif class == "MONK" then +elseif class == "PALADIN" then +elseif class == "PRIEST" then +elseif class == "ROGUE" then +elseif class == "SHAMAN" then + t[108281] = b.MINE -- Ancestral Guidance + t[ 16188] = b.MINE -- Ancestral Swiftness + t[114050] = b.MINE -- Ascendance (elemental) + t[114051] = b.MINE -- Ascendance (enhancement) + t[114052] = b.MINE -- Ascendance (restoration) + t[108271] = b.MINE -- Astral Shift + t[ 974] = b.MINE -- Earth Shield + t[ 3600] = b.MINE -- Earthbind (Totem) + t[ 64695] = b.MINE -- Earthgrab (Totem) + t[157174] = b.MINE -- Elemental Fusion + t[ 16166] = b.MINE -- Elemental Mastery +-- t[162557] = b.MINE -- Enhanced Unleash + t[ 8050] = b.MINE -- Flame Shock + t[ 8056] = b.MINE -- Frost Shock + t[ 63685] = b.MINE -- Frozen Power (from Frost Shock with talent) + t[ 8178] = b.SELF -- Grounding Totem Effect + t[ 89523] = b.SELF -- Grounding Totem (with Glyph of Grounding Totem) + t[ 77762] = b.MINE -- Lava Surge +-- t[ 31616] = b.SELF -- Nature's Guardian + t[ 61295] = b.MINE -- Riptide + t[ 30823] = b.MINE -- Shamanistic Rage + t[ 98007] = b.FRIEND -- Spirit Link Totem (TODO?) + t[151175] = b.FRIEND -- Spirit Link Totem (TODO?) + t[ 58875] = b.MINE -- Spirit Walk + t[ 79206] = b.MINE -- Spiritwalker's Grace + t[118905] = b.MINE -- Static Charge (from Capacitor Totem) + t[114893] = b.MINE -- Stone Bulwark + t[ 17364] = b.MINE -- Stormstrike + t[ 53390] = b.MINE -- Tidal Waves + t[165462] = b.MINE -- Unleash Flame + t[ 73685] = b.MINE -- Unleash Life + t[118470] = b.MINE -- Unleashed Fury (elemental) + t[118473] = b.MINE -- Unleashed Fury (restoration) + t[ 546] = b.FRIEND_OOC -- Water Walking +-- t[114896] = b.MINE -- Windwalk Totem + t[115356] = b.MINE -- Windstrike (replaces Stormstrike during Ascendance) +elseif class == "WARLOCK" then + t[ 980] = b.MINE -- Agony + t[117828] = b.MINE -- Backdraft + t[111397] = b.MINE -- Blood Horror (self buff) + t[137143] = b.MINE -- Blood Horror (debuff) + t[111400] = b.MINE -- Burning Rush + t[124915] = b.MINE -- Chaos Wave + t[ 17962] = b.MINE -- Conflagrate + t[146739] = b.MINE -- Corruption + t[110913] = b.MINE -- Dark Bargain (absorb) + t[110914] = b.MINE -- Dark Bargain (dot) + t[109773] = b.FRIEND_OOC -- Dark Intent + t[108359] = b.MINE -- Dark Regeneration + t[113858] = b.MINE -- Dark Soul: Instability + t[113861] = b.MINE -- Dark Soul: Knowledge + t[113860] = b.MINE -- Dark Soul: Misery + t[ 603] = b.MINE -- Doom + t[114635] = b.MINE -- Ember Tap (with glyph) + t[ 1098] = b.ALL -- Enslave Demon + t[108683] = b.MINE -- Fire and Brimstone + t[ 47960] = b.MINE -- Hand of Gul'dan + t[ 48181] = b.MINE -- Haunt + t[ 80240] = b.MINE -- Havoc + t[ 6262] = b.MINE -- Healthstone (with glyph) (TODO?) + t[157736] = b.MINE -- Immolate + t[108686] = b.MINE -- Immolate (with Fire and Brimstone) + t[137587] = b.MINE -- Kil'jaeden's Cunning + t[ 1454] = b.MINE -- Life Tab (with glyph) (TODO?) + t[171018] = b.MINE -- Meteor Strike + t[ 6789] = b.MINE -- Mortal Coil + t[122355] = b.MINE -- Molten Core + t[104232] = b.MINE -- Rain of Fire + t[108416] = b.MINE -- Sacrificial Pact + t[ 27243] = b.MINE -- Seed of Corruption + t[114790] = b.MINE -- Seed of Corruption (with Soulburn) + t[ 30283] = b.MINE -- Shadowfury + t[ 86211] = b.MINE -- Soul Swap + t[ 74434] = b.MINE -- Soulburn + t[ 20707] = b.FRIEND -- Soulstone + t[ 5697] = b.FRIEND_OOC -- Unending Breath + t[104773] = b.MINE -- Unending Resolve + t[ 30108] = b.MINE -- Unstable Affliction +elseif class == "WARRIOR" then +end + +--------------------------- +-- Functions +--------------------------- + +local UnitAffectingCombat = UnitAffectingCombat +local UnitIsUnit = UnitIsUnit +local UnitReaction = UnitReaction + +function Stardust.AuraFilter(element, unit, icon, name, _, _, count, dispelType, duration, expires, caster, isStealable, _, spellID, canApplyAura, isBossDebuff) + local x = t[spellID] + if isBossDebuff or caster == "vehicle" or x == b.ALL then + return true + elseif x == b.MINE then + return icon.isPlayer or caster == "pet" + elseif x == b.FRIEND then + return UnitReaction(unit, "player") >= 4 + elseif x == b.FRIEND_OOC then + return UnitReaction(unit, "player") >= 4 and not UnitAffectingCombat("player") + elseif x == b.ENEMY then + return UnitReaction(unit, "player") < 4 + elseif x == b.SELF then + return UnitIsUnit(unit, "player") + end +end + diff --git a/Config.lua b/Config.lua index 1f58cee..862dfe7 100644 --- a/Config.lua +++ b/Config.lua @@ -6,16 +6,23 @@ local _, Stardust = ... +local LibSharedMedia = LibStub("LibSharedMedia-3.0") +LibSharedMedia:Register("font", "Lato Bold", "Interface\\AddOns\\oUF_Stardust\\Fonts\\LatoBold.ttf", bit.bor(LibSharedMedia.LOCALE_BIT_western, LibSharedMedia.LOCALE_BIT_ruRU)) +--LibSharedMedia:Register("statusbar", "Qulight", "Interface\\AddOns\\oUF_Stardust\\Textures\\statusbar4") + Stardust.config = { -- Style barTexture = "Qulight", bgMultiplier = 0.35, - numberFont = "Blizzard Bold", - textFont = "Blizzard", + numberFont = "Lato Bold", + numberLarge = 26, + numberSmall = 14, + textFont = "Lato Bold", + textSize = 16, -- Layout width = 220, - height = 32, + height = 38, power = true, powerHeight = 5, @@ -42,18 +49,12 @@ Stardust.config = { } } -Stardust.colors = { - power = { - MANA = { 0, 0.8, 1 } - }, - totems = { - [1] = { 0.6, 1, 0.2 }, -- Earth - [2] = { 1, 0.6, 0.2 }, -- Fire - [3] = { 0.2, 0.8, 1 }, -- Water - [4] = { 0.8, 0.4, 1 }, -- Air - } -} +oUF.colors.power.MANA = { 0, 0.8, 1 } -setmetatable(Stardust.colors, { __index = oUF.colors }) -setmetatable(Stardust.colors.power, { __index = oUF.colors.power }) +oUF.colors.totems = { + [1] = { 0.6, 1, 0.2 }, -- Earth + [2] = { 1, 0.6, 0.2 }, -- Fire + [3] = { 0.2, 0.8, 1 }, -- Water + [4] = { 0.8, 0.4, 1 }, -- Air +} diff --git a/Elements/AFK.lua b/Elements/AFK.lua new file mode 100644 index 0000000..d6a9cad --- /dev/null +++ b/Elements/AFK.lua @@ -0,0 +1,101 @@ +--[[----------------------------------------------------------------------- + oUF_Phanx/Elements/AFK.lua + Element to display AFK times on oUF frames. + Based on code from oUF_Smurf by Merl@chainweb.net. + Written and distributed by Phanx with permission. + + Additional changes for oUF Stardust: + - Added PreUpdate and PostUpdate callbacks. + + Usage: + self.AFK = self:CreateFontString(nil, "OVERLAY") + self.AFK:SetPoint("CENTER") +----------------------------------------------------------------------]] + +if select(4, GetAddOnInfo("oUF_AFK")) then return end + +local _, ns = ... +local oUF = ns.oUF or oUF +assert(oUF, "AFK element requires oUF") + +local times = {} +local elements = {} + +local updater = CreateFrame("Frame") +updater:Hide() + +local lastUpdate = 0 +local floor, mod, next, pairs, GetTime = floor, mod, next, pairs, GetTime +updater:SetScript("OnUpdate", function(self, elapsed) + lastUpdate = lastUpdate + elapsed + if lastUpdate > 0.2 then + lastUpdate = 0 + if not next(times) then + self:Hide() + end + for element, unit in pairs(elements) do + local t = times[unit] + if t then + t = GetTime() - t + element:SetFormattedText("AFK %d:%02.0f", floor(t / 60), mod(t, 60)) + else + elements[element] = nil + element:SetText("") -- nil gives it 0 height which might disturb the layout + end + end + end +end) + +local function Update(self, event, unit) + if unit ~= self.unit then return end + + local element = self.AFK + if element.PreUpdate then + element:PreUpdate() + end + + local afk = UnitIsAFK(unit) + + if afk and not times[unit] then + times[unit] = GetTime() + elements[element] = unit + updater:Show() + elseif times[unit] and not afk then + times[unit] = nil + element:SetText("") + end + + if element.PostUpdate then + element:PostUpdate(afk) + end +end + +local ForceUpdate = function(element) + return Update(element.__owner, "ForceUpdate", element.__owner.unit) +end + +local function Enable(self) + local element = self.AFK + if not element then return end + + element.__owner = self + element.ForceUpdate = Update + + if not element:GetFont() then + element:SetFontObject("GameFontHighlightSmall") + end + + self:RegisterEvent("PLAYER_FLAGS_CHANGED", Update) + return true +end + +local function Disable(self) + local element = self.AFK + if not element then return end + + self:UnregisterEvent("PLAYER_FLAGS_CHANGED", Update) + element:Hide() +end + +oUF:AddElement("AFK", Update, Enable, Disable) + diff --git a/Elements/AuraStack.lua b/Elements/AuraStack.lua new file mode 100755 index 0000000..fe25d14 --- /dev/null +++ b/Elements/AuraStack.lua @@ -0,0 +1,150 @@ +--[[-------------------------------------------------------------------- + oUF_Phanx/Elements/AuraStack.lua + Element to track stacking self-(de)buffs like combo points. + Copyright (c) 2008-2015 Phanx <addons@phanx.net>. All rights reserved. + + You may embed this module in your own layout, but please do not + distribute it as a standalone plugin. + + Modified for oUF Stardust: + - Added .spec key to hide in wrong specs +------------------------------------------------------------------------ + Usage: + + self.AuraStack = { + aura = GetSpellInfo(53817) -- Localized spell name for Maelstrom Weapon + filter = "HELPFUL", -- Optional filter to pass to UnitAura, defaults to "HELPFUL" + } + for i = 1, 5 do + self.AuraStack[i] = CreateTexture(nil, "OVERLAY") + self.AuraStack[i]:SetSize(20, 20) + if i == 1 then + self.AuraStack[i]:SetPoint("LEFT", self, "BOTTOMLEFT", 5, 0) + else + self.AuraStack[i]:SetPoint("LEFT", self.AuraStack[i-1], "RIGHT", 0, 0) + end + end +------------------------------------------------------------------------ + Notes: + + Only supports one aura per frame. + + Supports Override or PreUpdate/PostUpdate. + + Does not support spell IDs, as the WoW API cannot look up a buff + directly by its ID and looping is not desirable here. + + The buff to track can be changed dynamically (for example, when + the player's spec changes) by the layout. + + The individual objects do not have to be textures. They can be + frames, fontstrings, or even basic tables, as long as they have + Show, Hide, SetAlpha, and IsObjectType methods. +----------------------------------------------------------------------]] + +local _, ns = ... +local oUF = ns.oUF or oUF +assert(oUF, "AuraStack element requires oUF") + +local UnitBuff = UnitBuff + +local UpdateVisibility, Update, Path, ForceUpdate, Enable, Disable + +function UpdateVisibility(self, event) + local element = self.AuraStack + + if UnitHasVehicleUI(self.unit) or (element.spec and element.spec ~= GetSpecialization()) then + element.__disabled = true + for i = 1, #element do + element[i]:Hide() + end + return self:UnregisterEvent("UNIT_AURA", Path) + end + + element.__disabled = false + self:RegisterEvent("UNIT_AURA", Path) + return Path(self, "UpdateVisibility", self.unit) +end + +function Update(self, event, unit) + if unit ~= self.unit then return end + local element = self.AuraStack + if element.__disabled or not element.aura then return end + + local _, _, _, count = UnitAura(unit, element.aura, nil, element.filter or "HELPFUL") + count = count or 0 + + if count == element.__count then return end + + if element.PreUpdate then + element:PreUpdate() + end + + element.__count = count + + for i = 1, #element do + local obj = element[i] + obj:SetShown(count > 0 and i <= element.__max) + end + + if element.PostUpdate then + element:PostUpdate(count) + end +end + +function Path(self, ...) + return (self.AuraStack.Override or Update)(self, ...) +end + +function ForceUpdate(element) + return Path(element.__owner, "ForceUpdate", element.__owner.unit) +end + +function Enable(self) + local element = self.AuraStack + if not element then return end + + element.__name = "AuraStack" + element.__owner = self + element.ForceUpdate = ForceUpdate + + if not element.__max then + element.__max = #element + end + + for i = 1, #element do + local obj = element[i] + obj.__owner = self + if obj:IsObjectType("Texture") and not obj:GetTexture() then + obj:SetTexture([[Interface\ComboFrame\ComboPoint]]) + obj:SetTexCoord(0, 0.375, 0, 1) + end + end + + self:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED", UpdateVisibility) + self:RegisterEvent("UNIT_ENTERING_VEHICLE", UpdateVisibility) + self:RegisterEvent("UNIT_EXITED_VEHICLE", UpdateVisibility) + + UpdateVisibility(self, "Enable") + + return true +end + +function Disable(self) + local element = self.AuraStack + if not element then return end + + self:UnregisterEvent("UNIT_AURA", Path) + self:UnregisterEvent("UNIT_ENTERING_VEHICLE", UpdateVisibility) + self:UnregisterEvent("UNIT_EXITED_VEHICLE", UpdateVisibility) + + for i = 1, #element do + element[i]:Hide() + end + if element.SetShown then + element:SetShown(false) + end +end + +oUF:AddElement("AuraStack", Path, Enable, Disable) + diff --git a/Elements/BurningEmbers.lua b/Elements/BurningEmbers.lua index 395dfe2..9c5de26 100644 --- a/Elements/BurningEmbers.lua +++ b/Elements/BurningEmbers.lua @@ -1,12 +1,7 @@ --[[-------------------------------------------------------------------- - oUF_Phanx - Fully-featured PVE-oriented layout for oUF. - Copyright (c) 2008-2015 Phanx <addons@phanx.net>. All rights reserved. - http://www.wowinterface.com/downloads/info13993-oUF_Phanx.html - http://www.curse.com/addons/wow/ouf-phanx - https://github.com/Phanx/oUF_Phanx ------------------------------------------------------------------------- + oUF_Phanx/Elements/BurningEmbers.lua Element to display burning embers on oUF frames. + Copyright (c) 2008-2015 Phanx <addons@phanx.net>. All rights reserved. You may embed this module in your own layout, but please do not distribute it as a standalone plugin. diff --git a/Elements/DemonicFury.lua b/Elements/DemonicFury.lua index ef8c32a..9bf39a4 100644 --- a/Elements/DemonicFury.lua +++ b/Elements/DemonicFury.lua @@ -1,12 +1,7 @@ --[[-------------------------------------------------------------------- - oUF_Phanx - Fully-featured PVE-oriented layout for oUF. - Copyright (c) 2008-2015 Phanx <addons@phanx.net>. All rights reserved. - http://www.wowinterface.com/downloads/info13993-oUF_Phanx.html - http://www.curse.com/addons/wow/ouf-phanx - https://github.com/Phanx/oUF_Phanx ------------------------------------------------------------------------- + oUF_Phanx/Elements/DemonicFury.lua Element to display demonic fury on oUF frames. + Copyright (c) 2008-2015 Phanx <addons@phanx.net>. All rights reserved. You may embed this module in your own layout, but please do not distribute it as a standalone plugin. diff --git a/Elements/DispelIcon.lua b/Elements/DispelIcon.lua new file mode 100644 index 0000000..b6271e0 --- /dev/null +++ b/Elements/DispelIcon.lua @@ -0,0 +1,87 @@ +--[[----------------------------------------------------------------------- + oUF: Stardust - a layout for the oUF framework + Copyright (c) 2016 Andrew Mordecai <armordecai@protonmail.ch> + This code is released under the zlib license; see LICENSE for details. +--------------------------------------------------------------------------- + This file provides a "DispelIcon" element, which may be used in any + oUF layout and does not depend on any other files in this addon. + + self.DispelIcon = self:CreateTexture(nil, "OVERLAY") + self.DispelIcon:SetPoint("CENTER") + self.DispelIcon:SetSize(16, 16) + + To use Blizzard's graphical icons for each debuff type, set + .showIcons = true on the element. Otherwise, the element's existing + texture will be colored according to the debuff type. +-------------------------------------------------------------------------]] + +local _, ns = ... +local oUF = ns.oUF or oUF +assert(oUF, "DispelIcon element requires oUF") + +function Update(self, event, unit) + local element = self.DispelIcon + if element.PreUpdate then + element:PreUpdate() + end + + local _, _, _, _, dispelType = UnitDebuff(unit, 1, "RAID") + if dispelType == "" then dispelType = nil end + + local color, r, g, b = dispelType and DebuffTypeColor[dispelType] + if element.showIcons then + if dispelType then + element:SetTexture("Interface\\RAIDFRAME\\Raid-Icon-Debuff"..dispelType) + element:SetVertexColor(1, 1, 1) + element:Show() + else + element:SetTexture("") + element:Hide() + end + else + if dispelType then + r, g, b = color.r, color.g, color.b + element:SetVertexColor(r, g, b) + element:Show() + else + element:SetVertexColor(1, 1, 1) + element:Hide() + end + end + + if element.PostUpdate then + element:PostUpdate(dispelType, r, g, b) + end +end + +function Path(self, ...) + return (self.DispelIcon.Override or Update)(self, ...) +end + +function ForceUpdate(element) + return Path(element.__owner, "ForceUpdate", element.__owner.unit) +end + +function Enable(self, unit) + local element = self.DispelIcon + if not element then return end + + element.__owner = self + element.ForceUpdate = ForceUpdate + + self:RegisterEvent("UNIT_AURA", Path) + + return true +end + +function Disable(self) + local element = self.DispelIcon + if not element then return end + + self:UnregisterEvent("UNIT_AURA", Path) + + element:Hide() +end + +oUF:AddElement("DispelIcon", Path, Enable, Disable) + diff --git a/Fonts/LatoBold.ttf b/Fonts/LatoBold.ttf new file mode 100644 index 0000000..9aa2d0c Binary files /dev/null and b/Fonts/LatoBold.ttf differ diff --git a/Functions.lua b/Functions.lua index 6ffe6e6..aff1d5b 100644 --- a/Functions.lua +++ b/Functions.lua @@ -5,21 +5,21 @@ -------------------------------------------------------------------------]] local _, Stardust = ... +local config = Stardust.config ---------------------------- --- General utility functions ---------------------------- +local LibSharedMedia = LibStub("LibSharedMedia-3.0") local function abbrev(n) - if n > 1000000000 then + local v = abs(n) + if v > 1000000000 then return format("%.0fb", n / 1000000000) - elseif n > 10000000 then + elseif v > 10000000 then return format("%.0fm", n / 1000000) - elseif n > 1000000 then + elseif v > 1000000 then return format("%.1fm", n / 1000000) - elseif n > 10000 then + elseif v > 10000 then return format("%.0fk", n / 1000) - elseif n > 1000 then + elseif v > 1000 then return format("%.1fk", n / 1000) else return n @@ -27,24 +27,56 @@ local function abbrev(n) end --------------------------- +-- Frames +--------------------------- + +function Stardust.OnEnter(self) + self.isMouseOver = true + UnitFrame_OnEnter(self) + self:UpdateAllElements("OnEnter") +end + +function Stardust.OnLeave(self) + self.isMouseOver = false + UnitFrame_OnLeave(self) + self:UpdateAllElements("OnLeave") +end + +--------------------------- -- Health --------------------------- -function Stardust.PostUpdateHealth(self, unit, cur, max) - self:SetValue(max - cur) - self.value:SetText(cur < max and abbrev(-max + cur) or "") - self.bg:SetVertexColor(0.15, 0.15, 0.15) +function Stardust.PostUpdateHealth(element, unit, cur, max) + element:SetValue(max - cur) + element.value:SetText(element.__owner.isMouseOver and abbrev(cur) or cur < max and abbrev(-max + cur) or "") end --------------------------- --- Power --- DruidMana --- DemonicFury +-- Power / DruidMana / DemonicFury --------------------------- -function Stardust.PostUpdatePower(self, unit, cur, max) - self:SetShown(max > 0) - self.value:SetText(abbrev(cur)) +local UnitIsDead = UnitIsDead + +function Stardust.PostUpdatePower(element, unit, cur, max) + if UnitIsDead(unit) then + local t = oUF.colors.disconnected + local r, g, b = t[1], t[2], t[3] + local mu = element.bg.multiplier or 1 + element:SetStatusBarColor(r, g, b) + element.bg:SetVertexColor(r * mu, g * mu, b * mu) + element.value:SetText("") + element:SetValue(0) + else + element.value:SetText(max > 0 and element.__owner.isMouseOver and abbrev(cur) or "") + end +end + +--------------------------- +-- Stagger +--------------------------- + +function Stardust.PostUpdateStagger(element, maxHealth, stagger, staggerPercent, r, g, b) + element.value:SetFormattedText("%d%%", staggerPercent) end --------------------------- @@ -53,8 +85,7 @@ end function Stardust.ResizeClassIcons(element) local COUNT = element.__max - local SPACING = 3 - local widthTotal = ((Stardust.config.width - SPACING - SPACING) * 0.6) - (COUNT * SPACING) + local widthTotal = ((Stardust.config.width - 6) * 0.7) - (COUNT * 3) local widthEach = floor(widthTotal / COUNT + 0.5) for i = 1, COUNT do element[i]:SetWidth(widthEach) @@ -64,20 +95,35 @@ end function Stardust.PostUpdateClassIcons(element, cur, max, maxChanged, event) if maxChanged then Stardust.ResizeClassIcons(element) + if element.__owner.Stagger then + element.__owner.Stagger:SetPoint("TOPLEFT", element[max], 3, 0) + end end end --------------------------- --- CPoints --- BurningEmbers +-- CPoints / AuraStack / BurningEmbers --------------------------- -function Stardust.PostUpdateCPoints(element, cur) - -- The number of combo points isn't dynamic, so they only need to be resized once per frame. - element.PostUpdate = nil +function Stardust.PreUpdateCPoints(element) + element.PreUpdate = nil Stardust.ResizeClassIcons(element) end +function Stardust.PostUpdateCPoints(element, cur) + if cur == 0 or element.__disabled then return end + + for i = 1, element.__max or #element do + local bar = element[i] + if i > cur then + bar:SetValue(0) + bar:Show() + else + bar:SetValue(1) + end + end +end + --------------------------- -- Runes --------------------------- @@ -98,25 +144,41 @@ end -- Partly adapted from oUF_Phanx --------------------------- -local function OnUpdateTotem(bar, elapsed) - local t = bar.duration - elapsed - if t > 0 then - bar.duration = t - bar:SetValue(t) - else - bar:SetValue(0) +local OnUpdateTotem +do + local ceil = ceil + local unpack = unpack + local SMOOTH_COLORS = oUF.colors.smooth + local ColorGradient = oUF.ColorGradient + + function OnUpdateTotem(bar, elapsed) + local t = bar.remaining - elapsed + if t > 0 then + bar.remaining = t + bar:SetValue(t) + if bar.__owner.isMouseOver then + bar.value:SetText(ceil(t)) + bar.value:SetTextColor(ColorGradient(t, bar.max, unpack(SMOOTH_COLORS))) + else + bar.value:SetText("") + end + else + bar:SetValue(0) + bar.value:SetText("") + end end end function Stardust.PostUpdateTotem(element, index, _, name, start, duration) local bar = element[index] - bar.duration, bar.max = duration, duration + bar.remaining, bar.max = start + duration - GetTime(), duration if duration > 0 then bar:SetMinMaxValues(0, duration) bar:SetScript("OnUpdate", OnUpdateTotem) else bar:SetScript("OnUpdate", nil) bar:SetValue(0) + bar.value:SetText("") end end @@ -130,43 +192,121 @@ end -- Status icons --------------------------- -function Stardust.PostUpdateStatusIcon(self) - if not self:IsShown() then return end - local icons, x = self.__owner.StatusIcons, 2 +function Stardust.PostUpdateStatusIcon(element) + if not element:IsShown() then return end + local icons, x = element.__owner.StatusIcons, 2 for i = 1, #icons do local icon = icons[i] - if icon == self then + if icon == element then break elseif icon:IsShown() and icon:GetTexture() then x = x + icon:GetWidth() end end - self:SetPoint("LEFT", self.__owner.Health, "TOPLEFT", x + self.offsetX, 0 + self.offsetY) + element:SetPoint("LEFT", element.__owner.Health, "TOPLEFT", x + element.offsetX, 0 + element.offsetY) end local updatingCombatOrResting -function Stardust.PostUpdateCombat(self) +function Stardust.PostUpdateCombat(element) if not updatingCombatOrResting then updatingCombatOrResting = true - self.__owner.Resting:ForceUpdate() + element.__owner.Resting:ForceUpdate() updatingCombatOrResting = nil end end -function Stardust.PostUpdateResting(self) +function Stardust.PostUpdateResting(element) if not updatingCombatOrResting then updatingCombatOrResting = true - self.__owner.Combat:ForceUpdate() + element.__owner.Combat:ForceUpdate() updatingCombatOrResting = nil end end --------------------------- --- Glow +-- AFK text +--------------------------- + +function Stardust.PostUpdateAFK(element, isAFK) + local Power = element.__owner.Power + if Power and Power.value then + Power.value:SetShown(not isAFK) + end +end + +--------------------------- +-- DispelIcon (redirected to frame.Shadows) --------------------------- -local GLOW_SEGMENTS = { +Stardust.DispelIconStub = { + SetTexture = nop, + SetVertexColor = nop, + Show = nop, + Hide = nop, +} + +function Stardust.PostUpdateDispelIcon(element, dispelType, r, g, b) + local frame = element.__owner + if not frame.__shadowSize then + frame.__shadowSize = frame.Shadows[1]:GetWidth() + end + if dispelType then + frame:SetShadowColor(r, g, b) + frame:SetShadowSize(frame.__shadowSize * 2) + else + frame:SetShadowColor() + frame:SetShadowSize(frame.__shadowSize) + end +end + +--------------------------- +-- Auras +--------------------------- + +function Stardust.PostCreateAuraIcon(element, button) + button.cd:SetDrawBling(false) + button.cd:SetDrawEdge(false) + button.cd:SetReverse(true) + + button.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93) + + button.count:SetFont(LibSharedMedia:Fetch("font", config.numberFont), config.numberSmall, "OUTLINE") + button.count:SetShadowOffset(0, 0) + button.count:SetTextColor(1, 1, 1) + + button.backdrop = button:CreateTexture(nil, "BACKGROUND") + button.backdrop:SetPoint("BOTTOMLEFT", -1, -1) + button.backdrop:SetPoint("TOPRIGHT", 1, 1) + button.backdrop:SetTexture("Interface\\BUTTONS\\WHITE8X8") + + Stardust.AddShadow(button, 6) +end + +function Stardust.PostUpdateAuraIcon(element, unit, button, index, offset) + local _, _, _, _, dispelType, duration, timeLeft, _, isStealable, _, spellID, canApplyAura, isBossDebuff = UnitAura(unit, index, button.filter) + + if timeLeft > 600 then + button.cd:Hide() + end + + local color = button.isDebuff and dispelType and DebuffTypeColor[dispelType] + if color then + button.backdrop:SetVertexColor(color.r, color.g, color.b) + else + button.backdrop:SetVertexColor(0, 0, 0) + end +end + +--------------------------- +-- Shadow +--------------------------- + +local SHADOW_SIZE = 3 +local SHADOW_COLOR = { 0, 0, 0 } + +local SHADOW_SEGMENTS = { + -- 1 point, 2 coordLeft, 3 coordRight, 4 coordTop, 5 coordBottom, 6 offsetMultiplierX, 7 offsetMultiplierY { "TOPLEFT", 0, 1/3, 0, 1/3, -1, 1 }, { "TOPRIGHT", 2/3, 1, 0, 1/3, 1, 1 }, { "BOTTOMRIGHT", 2/3, 1, 2/3, 1, 1, -1 }, @@ -177,63 +317,72 @@ local GLOW_SEGMENTS = { { "LEFT", 0, 1/3, 1/3, 2/3, -1, 0 }, } -local function SetGlowColor(self, r, g, b, a) - for i = 1, #self.Glow do - self.Glow[i]:SetVertexColor(r, g, b, a) +local function SetShadowColor(self, r, g, b, a) + if not r or not g or not b then + r, g, b = unpack(SHADOW_COLOR) + end + for i = 1, #self.Shadows do + self.Shadows[i]:SetVertexColor(r, g, b, a or 1) end end -local function SetGlowSize(self, size, offset) - local Glow = self.Glow - for i = 1, #Glow do - Glow[i]:SetSize(size, size) +local function SetShadowSize(self, size, offset) + if not size then size = SHADOW_SIZE end + + local Shadows = self.Shadows + for i = 1, #Shadows do + Shadows[i]:SetSize(size, size) end local d = offset or floor(size * 2 / 3 + 0.5) - Glow[1]:SetPoint("TOPLEFT", -d, d) - Glow[2]:SetPoint("TOPRIGHT", d, d) - Glow[3]:SetPoint("BOTTOMRIGHT", d, -d) - Glow[4]:SetPoint("BOTTOMLEFT", -d, -d) ---[[ - Glow[5]:SetShown(Glow[2]:GetLeft() > Glow[1]:GetRight()) - Glow[6]:SetShown(Glow[2]:GetBottom() > Glow[3]:GetTop()) - Glow[7]:SetShown(Glow[3]:GetLeft() > Glow[4]:GetLeft()) - Glow[8]:SetShown(Glow[1]:GetBottom() > Glow[4]:GetTop()) -]] -end - -function Stardust.CreateGlow(self) - local Glow = {} - for i = 1, #GLOW_SEGMENTS do - local seg = GLOW_SEGMENTS[i] + Shadows[1]:SetPoint("TOPLEFT", -d, d) + Shadows[2]:SetPoint("TOPRIGHT", d, d) + Shadows[3]:SetPoint("BOTTOMRIGHT", d, -d) + Shadows[4]:SetPoint("BOTTOMLEFT", -d, -d) + + local showH = self:GetWidth() > (2 * (size - d)) + local showV = self:GetHeight() > (2 * (size - d)) + Shadows[5]:SetShown(showH) + Shadows[6]:SetShown(showV) + Shadows[7]:SetShown(showH) + Shadows[8]:SetShown(showV) +end + +function Stardust.AddShadow(self, size, r, g, b, a) + local Shadows = {} + for i = 1, #SHADOW_SEGMENTS do + local seg = SHADOW_SEGMENTS[i] local tex = self:CreateTexture(nil, "BACKGROUND") - tex:SetTexture("Interface\\AddOns\\oUF_Stardust\\textures\\glow") + tex:SetTexture("Interface\\AddOns\\oUF_Stardust\\Textures\\glow") tex:SetTexCoord(seg[2], seg[3], seg[4], seg[5]) tex:SetVertexColor(0, 0, 0) - Glow[i] = tex + Shadows[i] = tex end -- TOP - Glow[5]:SetPoint("LEFT", Glow[1], "RIGHT") - Glow[5]:SetPoint("RIGHT", Glow[2], "LEFT") + Shadows[5]:SetPoint("LEFT", Shadows[1], "RIGHT") + Shadows[5]:SetPoint("RIGHT", Shadows[2], "LEFT") -- RIGHT - Glow[6]:SetPoint("TOP", Glow[2], "BOTTOM") - Glow[6]:SetPoint("BOTTOM", Glow[3], "TOP") + Shadows[6]:SetPoint("TOP", Shadows[2], "BOTTOM") + Shadows[6]:SetPoint("BOTTOM", Shadows[3], "TOP") -- BOTTOM - Glow[7]:SetPoint("LEFT", Glow[4], "RIGHT") - Glow[7]:SetPoint("RIGHT", Glow[3], "LEFT") + Shadows[7]:SetPoint("LEFT", Shadows[4], "RIGHT") + Shadows[7]:SetPoint("RIGHT", Shadows[3], "LEFT") -- LEFT - Glow[8]:SetPoint("TOP", Glow[1], "BOTTOM") - Glow[8]:SetPoint("BOTTOM", Glow[4], "TOP") + Shadows[8]:SetPoint("TOP", Shadows[1], "BOTTOM") + Shadows[8]:SetPoint("BOTTOM", Shadows[4], "TOP") + + self.Shadows = Shadows + self.SetBackdropBorderColor = SetShadowColor + self.SetShadowColor = SetShadowColor + self.SetShadowSize = SetShadowSize - self.Glow = Glow - self.SetBackdropBorderColor = SetGlowColor - self.SetGlowColor = SetGlowColor - self.SetGlowSize = SetGlowSize + self:SetShadowColor(r, g, b, a) + self:SetShadowSize(size) - return Glow + return Shadows end diff --git a/Layout.lua b/Layout.lua index 7f7828a..001e248 100644 --- a/Layout.lua +++ b/Layout.lua @@ -6,7 +6,7 @@ local _, Stardust = ... local config = Stardust.config -local colors = Stardust.colors +local colors = oUF.colors local _, class = UnitClass("player") local LibSharedMedia = LibStub("LibSharedMedia-3.0") @@ -15,15 +15,17 @@ local LibSharedMedia = LibStub("LibSharedMedia-3.0") -- Widget creation --------------------------- -local function NewStatusBar(parent, textFont, textSize, noBG, noBackdrop) +local function NewStatusBar(parent, textSize, noBG, noBorder, noShadow) local TEXTURE = LibSharedMedia:Fetch("statusbar", config.barTexture) local bar = CreateFrame("StatusBar", nil, parent) bar:SetStatusBarTexture(TEXTURE) - if textFont and textSize then - bar.value = bar:CreateFontString(nil, "OVERLAY", "GameFontHighlight") - bar.value:SetFont(LibSharedMedia:Fetch("font", config.textFont), textSize) + if textSize then + bar.value = bar:CreateFontString(nil, "OVERLAY") + bar.value:SetFont(LibSharedMedia:Fetch("font", config.numberFont), textSize, "OUTLINE") + bar.value:SetShadowOffset(0, 0) + bar.value:SetTextColor(1, 1, 1) bar.value:SetPoint("CENTER") end @@ -34,34 +36,31 @@ local function NewStatusBar(parent, textFont, textSize, noBG, noBackdrop) bar.bg.multiplier = config.bgMultiplier end - if not noBackdrop then + if not noBorder then bar.backdrop = bar:CreateTexture(nil, "BACKGROUND") bar.backdrop:SetPoint("BOTTOMLEFT", -1, -1) bar.backdrop:SetPoint("TOPRIGHT", 1, 1) bar.backdrop:SetTexture(0, 0, 0) end + if not noShadow then + Stardust.AddShadow(bar, 3) + end + return bar end -local function NewBarGroup(parent, count, width, height) - local group = { __max = count } - - local color = Stardust.colors.class[class] - local r, g, b = color[1], color[2], color[3] +local function NewBarGroup(parent, count, width, height, textSize) + local group = { + __max = count + } for i = 1, count do - local bar = NewStatusBar(parent) + local bar = NewStatusBar(parent, textSize) bar:SetSize(width, height) bar:SetMinMaxValues(0, 1) bar:SetValue(1) - if not noColor then - local mu = bar.bg.multiplier - bar:SetStatusBarColor(r, g, b) - bar.bg:SetVertexColor(r * mu, g * mu, b * mu) - end - -- ClassIcons expects texture objects bar.SetVertexColor = bar.SetStatusBarColor @@ -97,178 +96,284 @@ end local function ApplyStyle(self, unit, isSingle) unit = unit:gsub("%d+", "") - local uconfig = config.units[unit] + local unitConfig = config.units[unit] + local classColor = oUF.colors.class[class] + local classR, classG, classB = classColor[1], classColor[2], classColor[3] --------------------------- -- Frame --------------------------- - self:SetScript("OnEnter", UnitFrame_OnEnter) - self:SetScript("OnLeave", UnitFrame_OnLeave) + self:SetScript("OnEnter", Stardust.OnEnter) + self:SetScript("OnLeave", Stardust.OnLeave) self:RegisterForClicks("AnyUp") if (isSingle) then - self:SetSize(config.width * (uconfig and uconfig.width or 1), config.height * (uconfig and uconfig.height or 1)) + self:SetSize(config.width * (unitConfig and unitConfig.width or 1), config.height * (unitConfig and unitConfig.height or 1)) end - --------------------------- - -- Outer glow - --------------------------- - - self.Glow = Stardust.CreateGlow(self) + Stardust.AddShadow(self, 6) --------------------------- -- Health bar --------------------------- - local Health = NewStatusBar(self, config.numberFont, 25) + local Health = NewStatusBar(self, config.numberLarge) Health:SetPoint("BOTTOMLEFT") Health:SetPoint("TOPRIGHT") Health:SetReverseFill(true) + Health:SetStatusBarColor(0.3, 0.3, 0.3) + Health.bg:SetVertexColor(0.15, 0.15, 0.15) + Health.value:ClearAllPoints() - Health.value:SetPoint("RIGHT", Health, "TOPRIGHT", 0, 3) + Health.value:SetPoint("BOTTOMRIGHT", 0, 3 + config.powerHeight + 2) - Health.colorClass = true - Health.colorDisconnected = true - Health.colorReaction = true - Health.colorTapping = true Health.frequentUpdates = true + Health.PostUpdate = Stardust.PostUpdateHealth + + self:SmoothBar(Health) self.Health = Health --------------------------- + -- Name text + --------------------------- + + local Name = self.Health:CreateFontString(nil, "OVERLAY") + Name:SetPoint("BOTTOMLEFT", 2, 3 + config.powerHeight + 2) + Name:SetPoint("RIGHT", self.Health.value, "LEFT") + Name:SetJustifyH("LEFT") + Name:SetFont(LibSharedMedia:Fetch("font", config.textFont), config.textSize, "OUTLINE") + Name:SetShadowOffset(0, 0) + Name:SetTextColor(1, 1, 1) + self:Tag(Name, "[unitcolor][name]") + self.Name = Name + + --------------------------- -- Power bar --------------------------- - local Power = NewStatusBar(Health, config.numberFont, 15) + local Power = NewStatusBar(Health, config.numberSmall) Power:SetPoint("BOTTOMLEFT", 3, 3) Power:SetPoint("BOTTOMRIGHT", -3, 3) Power:SetHeight(config.powerHeight) + Power.colorClass = true Power.colorDisconnected = true - Power.colorPower = true + Power.colorReaction = true + Power.colorTapping = true Power.frequentUpdates = true + Power.PostUpdate = Stardust.PostUpdatePower + + self:SmoothBar(Power) self.Power = Power + Stardust.AddShadow(Power, 3) + --------------------------- - -- Secondary resources + -- AFK text --------------------------- - if class == "WARLOCK" then - local BurningEmbers = NewBarGroup(self.Health, 4, 30, config.powerHeight) - BurningEmbers[1]:SetPoint("TOPLEFT", self.Health, 3, -3) - BurningEmbers.PostUpdate = Stardust.PostUpdateCPoints - self.BurningEmbers = BurningEmbers + if unit == "player" or unit == "party" then + local AFK = self:CreateFontString(nil, "OVERLAY") + AFK:SetPoint("CENTER", self.Power) + AFK:SetFont(LibSharedMedia:Fetch("font", config.numberFont), config.numberSmall, "OUTLINE") + AFK:SetShadowOffset(0, 0) + AFK:SetTextColor(1, 1, 1) + AFK.PostUpdate = Stardust.PostUpdateAFK + self.AFK = AFK end - if class == "PALADIN" or class == "PRIEST" or class == "WARLOCK" then - local ClassIcons = NewBarGroup(self.Health, 6, 30, config.powerHeight) - ClassIcons[1]:SetPoint("TOPLEFT", self.Health, 3, -3) - ClassIcons.PostUpdate = Stardust.PostUpdateClassIcons - self.ClassIcons = ClassIcons - end + --------------------------- + -- Secondary resources + --------------------------- - if class == "DRUID" or class == "ROGUE" then - local CPoints = NewBarGroup(self.Health, 5, 30, config.powerHeight) - CPoints[1]:SetPoint("TOPLEFT", self.Health, 3, -3) - CPoints.PostUpdate = Stardust.PostUpdateCPoints - self.CPoints = CPoints - end + if unit == "player" then - if class == "DEATHKNIGHT" then - local Runes = NewBarGroup(self.Health, 6, 30, config.powerHeight) - Runes[1]:SetPoint("TOPLEFT", self.Health, 3, -3) - Runes.PostUpdateRune = Stardust.PostUpdateRune - Runes.PostUpdateRuneType = Stardust.PostUpdateRuneType - self.Runes = Runes - end + --------------------------- + -- Runes @ TOPLEFT + --------------------------- + + if class == "DEATHKNIGHT" then + local Runes = NewBarGroup(self.Health, 6, 30, config.powerHeight) + Runes[1]:SetPoint("TOPLEFT", self.Health, 3, -3) + Runes.PostUpdateRune = Stardust.PostUpdateRune + Runes.PostUpdateRuneType = Stardust.PostUpdateRuneType + self.Runes = Runes + end + + --------------------------- + -- Combo Points @ TOPLEFT + --------------------------- + + if class == "DRUID" or class == "ROGUE" then + local CPoints = NewBarGroup(self.Health, 5, 30, config.powerHeight) + CPoints[1]:SetPoint("TOPLEFT", self.Health, 3, -3) + CPoints.PreUpdate = Stardust.PreUpdateCPoints + self.CPoints = CPoints + + for i = 1, #CPoints do + local bar = CPoints[i] + local mu = bar.bg.multiplier + bar:SetStatusBarColor(classR, classG, classB) + bar.bg:SetVertexColor(classR * mu, classG * mu, classB * mu) + end + end + + --------------------------- + -- Totems @ TOPLEFT + --------------------------- - if class == "DRUID" or class == "SHAMAN" then - -- TODO: This can also show death knight ghouls. - -- How do these work? Are they important? - -- How to show them at the same time as runes? - local Totems = NewBarGroup(self.Health, 4, 30, config.powerHeight) - Totems[1]:SetPoint("TOPLEFT", self.Health, 3, -3) if class == "SHAMAN" then - local mu = config.bgMultiplier + local Totems = NewBarGroup(self.Health, 4, 30, config.powerHeight, config.numberSmall) + Totems[1]:SetPoint("TOPLEFT", self.Health, 3, -3) + Totems.PreUpdate = Stardust.PreUpdateTotems + Totems.PostUpdate = Stardust.PostUpdateTotem + self.Totems = Totems + for i = 1, 4 do - local totem = Totems[i] - totem:EnableMouse(true) + local bar = Totems[i] + bar:EnableMouse(true) + bar:SetHitRectInsets(0, 0, -6, -3) + bar.__owner = self -- oUF sets it on Totems, but not Totems[i] - local color = Stardust.colors.totems[i] + local color = oUF.colors.totems[i] local r, g, b = color[1], color[2], color[3] - totem:SetStatusBarColor(r, g, b) - totem.bg:SetVertexColor(r * mu, b * mu, g * mu) + local mu = bar.bg.multiplier + bar:SetStatusBarColor(r, g, b) + bar.bg:SetVertexColor(r * mu, g * mu, b * mu) - local value = totem:CreateFontString(nil, "OVERLAY", "GameFontHighlight") - value:SetFont(LibSharedMedia:Fetch("font", config.numberFont), 15) - value:SetPoint("CENTER") + bar.value:SetPoint("CENTER", 0, 3) end end - Totems.PreUpdate = Stardust.PreUpdateTotems - self.Totems = Totems - end - -- TODO: burning embers + --------------------------- + -- Chi / Holy Power / Shadow Orbs / Soul Shards @ TOPLEFT + --------------------------- - --------------------------- - -- Druid mana - -- Warlock demonic fury - --------------------------- + if class == "MONK" or class == "PALADIN" or class == "PRIEST" or class == "WARLOCK" then + local ClassIcons = NewBarGroup(self.Health, 6, 30, config.powerHeight) + ClassIcons[1]:SetPoint("TOPLEFT", self.Health, 3, -3) + ClassIcons.PostUpdate = Stardust.PostUpdateClassIcons + self.ClassIcons = ClassIcons + end - if class == "DRUID" or class == "WARLOCK" then - local bar = NewStatusBar(Health) - bar:SetPoint("TOPLEFT", 3, -3) - bar:SetPoint("TOPRIGHT", -3, -3) - bar:SetHeight(config.powerHeight) - if class == "DRUID" then - bar:SetPoint("TOPLEFT", self.Totems[4], 3, 0) - bar.colorPower = true - bar.PostUpdate = PostUpdatePower - self.DruidMana = bar - else - bar.colorPower = true - bar.PostUpdate = PostUpdatePower - self.DemonicFury = bar + --------------------------- + -- Druid Mana @ TOP / Stagger @ TOPRIGHT / Demonic Fury @ TOP + --------------------------- + + if class == "DRUID" or class == "MONK" or class == "WARLOCK" then + local bar = NewStatusBar(Health, config.numberSmall) + bar:SetPoint("TOPLEFT", 3, -3) + bar:SetPoint("TOPRIGHT", -3, -3) + bar:SetHeight(config.powerHeight) + self:SmoothBar(bar) + if class == "DRUID" then + bar.colorPower = true + bar.PostUpdate = PostUpdatePower + self.DruidMana = bar + elseif class == "MONK" then + bar:SetPoint("TOPLEFT", self.ClassIcons[4], 3, 0) + bar.PostUpdate = PostUpdateStagger + self.Stagger = bar + elseif class == "WARLOCK" then + bar.colorPower = true + bar.PostUpdate = PostUpdatePower + self.DemonicFury = bar + end end + + --------------------------- + -- Maelstrom Weapon @ TOPRIGHT + --------------------------- + + if class == "SHAMAN" then + local AuraStack = NewBarGroup(self.Health, 5, config.powerHeight * 2, config.powerHeight) + AuraStack[1]:SetPoint("TOPRIGHT", self.Health, -3, -3) + AuraStack.PostUpdate = Stardust.PostUpdateCPoints + self.AuraStack = AuraStack + + AuraStack.aura = GetSpellInfo(51530) -- Maelstrom Weapon + AuraStack.spec = 2 -- Enhancement + + for i = 1, #AuraStack do + local bar = AuraStack[i] + + local mu = bar.bg.multiplier + bar:SetStatusBarColor(classR, classG, classB) + bar.bg:SetVertexColor(classR * mu, classG * mu, classB * mu) + + if i > 1 then + bar:ClearAllPoints() + bar:SetPoint("RIGHT", AuraStack[i-1], "LEFT", -3, 0) + end + end + end + + --------------------------- + -- Burning Embers @ TOPLEFT + --------------------------- + + if class == "WARLOCK" then + local BurningEmbers = NewBarGroup(self.Health, 4, 30, config.powerHeight) + BurningEmbers[1]:SetPoint("TOPLEFT", self.Health, 3, -3) + BurningEmbers.PreUpdate = Stardust.PreUpdateCPoints + self.BurningEmbers = BurningEmbers + + for i = 1, #BurningEmbers do + local bar = BurningEmbers[i] + local mu = bar.bg.multiplier + bar:SetStatusBarColor(classR, classG, classB) + bar.bg:SetVertexColor(classR * mu, classG * mu, classB * mu) + self:SmoothBar(bar) + end + end + end --------------------------- - -- TODO + -- Alternate Power Bar + -- TODO: layout --------------------------- - -- AltPowerBar - -- EclipseBar - -- HealPrediction - -- Stagger + local AltPowerBar = NewStatusBar(self.Health, config.numberSmall) + AltPowerBar:SetPoint("TOPLEFT", self.Power, "BOTTOMLEFT", 0, -3) + AltPowerBar:SetPoint("TOPRIGHT", self.Power, "BOTTOMRIGHT", 0, 3) + AltPowerBar:SetHeight(config.powerHeight) + AltPowerBar:EnableMouse(true) - -- Castbar + AltPowerBar.colorTexture = true + AltPowerBar.PostUpdate = Stardust.PostUpdatePower - -- Auras + self:SmoothBar(AltPowerBar) + self.AltPowerBar = AltPowerBar + + Stardust.AddShadow(AltPowerBar, 3) --------------------------- - -- Name text + -- TODO --------------------------- - local Name = self:CreateFontString(nil, "OVERLAY", "GameFontNormal") - Name:SetPoint("BOTTOMLEFT", Power, "TOPLEFT", 0, 3) - Name:SetFont(LibSharedMedia:Fetch("font", config.valueFont), 14) - self:Tag(Name, "[unitcolor][name]") - self.Name = Name + -- EclipseBar + -- HealPrediction + + -- Castbar --------------------------- -- Group status icons --------------------------- - AddStatusIcon(self, "LFDRole", 24) - AddStatusIcon(self, "RaidRole") -- maintank, mainassist - AddStatusIcon(self, "Leader") - AddStatusIcon(self, "Assistant") - AddStatusIcon(self, "MasterLooter", nil, 0, 1) - AddStatusIcon(self, "PvP", 32, 0, -5) -- TODO: move it somewhere else? + if not unit:match("pet") and not unit:match(".+target") then + AddStatusIcon(self, "LFDRole", 24) + AddStatusIcon(self, "RaidRole") -- maintank, mainassist + AddStatusIcon(self, "Leader") + AddStatusIcon(self, "Assistant") + AddStatusIcon(self, "MasterLooter", nil, 0, 1) + AddStatusIcon(self, "PvP", 32, 0, -5) -- TODO: move it somewhere else? + end --------------------------- -- Combat icon @@ -276,13 +381,13 @@ local function ApplyStyle(self, unit, isSingle) if unit == "player" then local Combat = self.Health:CreateTexture(nil, "OVERLAY") - Combat:SetSize(16, 16) + Combat:SetSize(32, 32) Combat:SetPoint("RIGHT", self.Health, "TOPRIGHT", -3, 0) Combat.PostUpdate = Stardust.PostUpdateCombat self.Combat = Combat local Resting = self.Health:CreateTexture(nil, "OVERLAY") - Resting:SetSize(16, 16) + Resting:SetSize(32, 32) Resting:SetPoint("RIGHT", self.Health, "TOPRIGHT", -3, 0) Resting.PostUpdate = Stardust.PostUpdateResting self.Resting = Resting @@ -292,7 +397,7 @@ local function ApplyStyle(self, unit, isSingle) -- Phasing icon --------------------------- - if not unit:match(".+target$") and not unit:match(".+pet") then + if not unit:match("pet") and not unit:match(".+target") then local PhaseIcon = self.Health:CreateTexture(nil, "OVERLAY") PhaseIcon:SetPoint("TOP") PhaseIcon:SetPoint("BOTTOM") @@ -312,8 +417,8 @@ local function ApplyStyle(self, unit, isSingle) if unit == "target" then local QuestIcon = self.Health:CreateTexture(nil, "OVERLAY") - QuestIcon:SetSize(16, 16) - QuestIcon:SetPoint("RIGHT", self.Health, "TOPRIGHT", -3, 0) + QuestIcon:SetSize(32, 32) + QuestIcon:SetPoint("CENTER", self.Health, "LEFT", -3, 0) self.QuestIcon = QuestIcon end @@ -324,7 +429,7 @@ local function ApplyStyle(self, unit, isSingle) if unit == "player" or unit == "target" or unit == "party" then local RaidIcon = self.Health:CreateTexture(nil, "OVERLAY") RaidIcon:SetSize(24, 24) - RaidIcon:SetPoint("CENTER", 0, 3) -- TODO + RaidIcon:SetPoint("CENTER", self.Health, "TOP", 0, 6) -- TODO self.RaidIcon = RaidIcon end @@ -343,7 +448,7 @@ local function ApplyStyle(self, unit, isSingle) -- Resurrection icon --------------------------- - if not unit:match(".+target$") and not unit:match("pet") then + if not unit:match("pet") and not unit:match(".+target") then local ResurrectIcon = self.Health:CreateTexture(nil, "OVERLAY") ResurrectIcon:SetSize(24, 24) ResurrectIcon:SetPoint("CENTER", 0, 3) -- TODO @@ -352,6 +457,7 @@ local function ApplyStyle(self, unit, isSingle) --------------------------- -- Threat level icon + -- TODO: colorize and enlarge frame shadow for aggro --------------------------- if unit == "target" or unit == "focus" then @@ -362,28 +468,48 @@ local function ApplyStyle(self, unit, isSingle) end --------------------------- - -- Range + -- DispelIcon (redirected to frame glow) --------------------------- - self.Range = { - insideAlpha = 1, - outsideAlpha = 0.5 - } + if not unit:match(".+target$") then + local DispelIcon = setmetatable({}, { __index = Stardust.DispelIconStub }) + DispelIcon.PostUpdate = Stardust.PostUpdateDispelIcon + self.DispelIcon = DispelIcon + end --------------------------- - -- oUF_SmoothUpdate plugin support + -- Auras --------------------------- - if self.SmoothBar then - self:SmoothBar(self.Health) - self:SmoothBar(self.Power) - if self.DemonicFury then - self:SmoothBar(self.DemonicFury) - end - if self.DruidMana then - self:SmoothBar(self.DruidMana) - end + if unit == "player" or unit == "target" then + local Auras = CreateFrame("Frame", nil, self) + Auras:SetPoint("BOTTOMLEFT", self, "TOPLEFT", 0, 9) + Auras:SetSize(config.width, 16) + + Auras.gap = true + Auras['growth-x'] = "LEFT" + Auras['growth-y'] = "UP" + Auras.initialAnchor = "BOTTOMRIGHT" + Auras.showDebuffType = true + Auras.showStealableBuffs = true + Auras.size = 24 + Auras.spacing = 6 + + Auras.CustomFilter = Stardust.AuraFilter + Auras.PostCreateIcon = Stardust.PostCreateAuraIcon + Auras.PostUpdateIcon = Stardust.PostUpdateAuraIcon + + self.Auras = Auras end + + --------------------------- + -- Range + --------------------------- + + self.Range = { + insideAlpha = 1, + outsideAlpha = 0.5 + } end oUF:Factory(function(self) diff --git a/Textures/statusbar4.tga b/Textures/statusbar4.tga new file mode 100755 index 0000000..e2fc1fa Binary files /dev/null and b/Textures/statusbar4.tga differ diff --git a/oUF_Stardust.toc b/oUF_Stardust.toc index 3cf61c6..7ddd773 100644 --- a/oUF_Stardust.toc +++ b/oUF_Stardust.toc @@ -1,11 +1,13 @@ ## Interface: 60200 ## Dependencies: oUF +## Version: 6.2.4.0 ## Title: oUF: Stardust ## Author: Akkorian ## X-Credits: Phanx, Qulight ## X-Email: armordecai@protonmail.ch ## X-License: zlib/libpng License +## X-Website: https://gitlab.com/akkorian/ouf-stardust Libs/LibStub.lua Libs/CallbackHandler-1.0.lua @@ -13,11 +15,17 @@ Libs/LibSharedMedia-3.0.lua Plugins/Smooth.lua +Elements/AFK.lua +Elements/AuraStack.lua Elements/BurningEmbers.lua Elements/DemonicFury.lua +Elements/DispelIcon.lua Config.lua + +Auras.lua Functions.lua Tags.lua Layout.lua +