Thread Tools Display Modes
02-21-12, 08:37 AM   #1
lerb
A Frostmaul Preserver
 
lerb's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2008
Posts: 264
Creating a Shadow Orb element for oUF

Hey everyone! Requesting some more of your help I don't know if I'm supposed to post this here or in the actual oUF part of the forum, but I'm gonna give this place a try. It's LUA, after all

What I want to do is rather simple. I want a tracker that tracks a players shadow orbs, shown as 1-3 bars. I have an example here, this is soul shards on my warlock;



I'm using the soulshard-element for oUF to create this, using this code in my layout;

Code:
		if LeUI.Class == 'WARLOCK' then
		    self.SoulShards = CreateFrame('Frame', nil, self)
			for i = 1, 3 do
				self.SoulShards[i] = CreateFrame('StatusBar', self:GetName()..'_SoulShards'..i, self)
				self.SoulShards[i]:SetSize(60, 12)
				self.SoulShards[i]:SetStatusBarTexture(LeUI.media.texture)
				self.SoulShards[i]:SetStatusBarColor(LeUI.Classcolor.r, LeUI.Classcolor.g, LeUI.Classcolor.b)
				
				if(i == 1) then
					self.SoulShards[i]:SetPoint('CENTER', UIParent, 'BOTTOM', -70, 96)
				else
					self.SoulShards[i]:SetPoint('TOPLEFT', self.SoulShards[i-1], 'TOPRIGHT', 10, 0)
				end
				
				CreateBorderLight(self.SoulShards[i], LeUI.media.bordersize, LeUI.bordercolor, LeUI.bordercolor, LeUI.bordercolor, 4)
				
				self.SoulShards[i]:SetBackdrop(backdrop)
				self.SoulShards[i]:SetBackdropColor(unpack(LeUI.media.backdropcolor))
			end
		end
Now, I want the exact same thing but for Shadow Orbs when playing priest. I've been looking around but can't find an oUF element for Shadow Orbs, so I thought it wouldn't be so hard to write my own. I guess I was wrong

I thought it wouldn't be harder than to copy the Soulshard element lua-file and basically edit it for Shadow Orbs, but I can't seem to get it to work. Here's the code I ended up with _after_ editing soulshards.lua in oUF elements;

Code:
if(select(2, UnitClass('player')) ~= 'PRIEST') then return end

local parent, ns = ...
local oUF = ns.oUF

local SPELL_POWER_SHADOW_ORBS = SPELL_POWER_SHADOW_ORBS
local MAX_SHADOW_ORBS = MAX_SHADOW_ORBS

local Update = function(self, event, unit, powerType)
	if(self.unit ~= unit or (powerType and powerType ~= 'SHADOW_ORBS')) then return end

	local so = self.ShadowOrbs
	if(so.PreUpdate) then so:PreUpdate(unit) end

	local num = UnitPower('player', SPELL_POWER_SHADOW_ORBS)
	for i = 1, MAX_SHADOW_ORBS do
		if(i <= num) then
			so[i]:SetAlpha(1)
		else
			so[i]:SetAlpha(0)
		end
	end

	if(so.PostUpdate) then
		return so:PostUpdate(unit)
	end
end

local Path = function(self, ...)
	return (self.ShadowOrbs.Override or Update) (self, ...)
end

local ForceUpdate = function(element)
	return Path(element.__owner, 'ForceUpdate', element.__owner.unit, 'SHADOW_ORBS')
end

local function Enable(self)
	local so = self.ShadowOrbs
	if(so) then
		so.__owner = self
		so.ForceUpdate = ForceUpdate

		self:RegisterEvent('UNIT_POWER', Path)

		return true
	end
end

local function Disable(self)
	local so = self.ShadowOrbs
	if(so) then
		self:UnregisterEvent('UNIT_POWER', Path)
	end
end

oUF:AddElement('ShadowOrbs', Path, Enable, Disable)
Using this, I end up with this error;

Code:
...\LeUI\Modules\Unitframes\oUF\elements\shadoworbs.lua:16: 'for' limit must be a number

I'll have to point out that I'm no more than a rookie to LUA, and this is taking water over my head. But I really hope I can get it working with some help from you guys, like many times before
  Reply With Quote
02-21-12, 10:04 AM   #2
yj589794
A Rage Talon Dragon Guard
AddOn Author - Click to view addons
Join Date: Mar 2009
Posts: 314
When Blizzard implemented the Soul Shards / Holy Power / Eclipse as a new energy type they provided APIs and events to access the relevant information.

Unfortunately Shadow Orbs are buffs rather than a new energy type, so you cannot really base your oUF element on the existing Soul Shards element. Instead you would need to handle UNIT_AURA events and filter for the events associated with your own shadow orb buffs.

I use some custom elements within my own layout that would be closer to what you are trying to do with shadow orbs:
https://github.com/Evilpaul/oUF_EP/b...arthShield.lua
  Reply With Quote
02-21-12, 11:56 AM   #3
lerb
A Frostmaul Preserver
 
lerb's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2008
Posts: 264
Oh, sweet, that explains some things!

Thanks for that code, I'll see what I can do with it and report back later
  Reply With Quote
02-21-12, 11:02 PM   #4
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
I already implemented this in my oUF layout, but haven't published it yet. In my version, I display each Shadow Orb as an orb texture (kind of like combo point dots, but bigger), but you could easily make them look like bars instead. I use the same framework for combo points, Maelstrom Weapon stacks, holy power, and soul shards. It may be a bit more complex than what you need, but feel free to use some/all of it:

Code:
ns.CreateOrbs = function(parent, num, size)
	local orbs = {}
	for i = 1, num do
		local orb = CreateFrame("Frame", nil, parent)
		orb:SetSize(size or 20, size or 20)

		orb.bg = orb:CreateTexture(nil, "BACKGROUND")
		orb.bg:SetAllPoints(true)
		orb.bg:SetTexture("Interface\\AddOns\\oUF_Phanx\\media\\OrbBG")

		orb.fg = orb:CreateTexture(nil, "ARTWORK")
		orb.fg:SetAllPoints(true)
		orb.fg:SetTexture("Interface\\AddOns\\oUF_Phanx\\media\\OrbFG")

		orbs[i] = orb
	end
	return orbs
end
In the spawn function:

Code:
	if unit == "player" and (playerClass == "PALADIN" or playerClass == "PRIEST" or playerClass == "SHAMAN" or playerClass == "WARLOCK") then
		local color = (CUSTOM_CLASS_COLORS or RAID_CLASS_COLORS)[playerClass]

		local element, max, buff, power
		----------------
		-- Holy power --
		----------------
		if playerClass == "PALADIN" then
			element, max = "HolyPower", MAX_HOLY_POWER
			power = SPELL_POWER_HOLY_POWER
		----------------
		-- Shadow Orb --
		----------------
		elseif playerClass == "PRIEST" then
			element, max = "PowerStack", 3
			buff = GetSpellInfo(77487)
		----------------------
		-- Maelstrom Weapon --
		----------------------
		elseif playerClass == "SHAMAN" then
			element, max = "PowerStack", 5
			buff = GetSpellInfo(53817)
		-----------------
		-- Soul shards --
		-----------------
		elseif playerClass == "WARLOCK" then
			element, max = "SoulShards", SHARD_BAR_NUM_SHARDS
			power = SPELL_POWER_SOUL_SHARDS
		end

		local SetAlpha
		if power then
			SetAlpha = function(self, alpha)
				if alpha == 1 then
					self.bg:SetVertexColor(0.25, 0.25, 0.25)
					self.bg:SetAlpha(1)
					self.fg:Show()
				else
					local num = UnitPower("player", power)
					self.bg:SetVertexColor(0.4, 0.4, 0.4)
					self.bg:SetAlpha(num > 0 and 0.5 or 0)
					self.fg:Hide()
				end
			end
		else
			SetAlpha = function(orb, alpha)
				if alpha == 1 then
					orb.bg:SetVertexColor(0.25, 0.25, 0.25)
					orb.bg:SetAlpha(1)
					orb.fg:Show()
				else
					orb.bg:SetVertexColor(0.4, 0.4, 0.4)
					orb.bg:SetAlpha(0.5)
					orb.fg:Hide()
				end
			end
		end

		local t = ns.CreateOrbs(self.overlay, max, 20)
		for i = 1, max do
			local orb = t[i]
			if i == 1 then
				orb:SetPoint("BOTTOMRIGHT", self, "TOPRIGHT", 2, -5)
			else
				orb:SetPoint("BOTTOMRIGHT", t[i - 1], "BOTTOMLEFT", 2, 0)
			end
			orb.bg:SetVertexColor(0.25, 0.25, 0.25)
			orb.fg:SetVertexColor(color.r, color.g, color.b)
			orb.SetAlpha = SetAlpha
		end

		t.buff = buff
		self[element] = t
	end
The SetAlpha hook is optional, but allows you to do some niceties like hiding the combo points element completely when you have 0 combo points, but as soon as you get 1, not only does the first orb show up, but the other 4 (since you can have up to 5 combo points) show up as translucent, desaturated placeholders so you can easily see how close you are to the maximum without having to think about it.

If you're using bars this probably isn't necessary since presumably the element will be full-width, with each bar inside it being 1/3 of the width, but it's there if you want it.

The PowerStack element is a custom element I wrote for my layout to support treating stackable buffs like Shadow Orb and Maelstrom Weapon in basically the same way the core combo point, holy power, and soul shard elements work.

Code:
--[[
	oUF_PowerStack
	by Phanx <[email protected]>
	Adds a graphical counter element for Maelstrom Weapon or Shadow Orb.
--]]

local _, ns = ...
local oUF = ns.oUF or oUF
if not oUF then return end

local UnitBuff = UnitBuff

local prev

local Update = function(self, event, unit)
	if unit ~= "player" then return end

	local element = self.PowerStack
	local max = #element

	local _, _, _, count = UnitBuff("player", element.buff)
	if not count then count = 0 end

	-- print("PowerStack: Update", event, unit, element.buff, count, max)

	if count == prev then return end

	if count == 0 then
		for i = 1, max do
			element[i]:Hide()
		end
	else
		for i = 1, max do
			local obj = element[i]
			obj:Show()
			if i <= count then
				obj:SetAlpha(1)
			else
				obj:SetAlpha(0.25)
			end
		end
	end

	prev = count
end

local Path = function(self, ...)
	return (self.PowerStack.Override or Update)(self, ...)
end

local ForceUpdate = function(element)
	return Path(element.__owner, "ForceUpdate", element.__owner.unit)
end

local Enable = function(self)
	local element = self.PowerStack
	if not element then return end

	element.__owner = self
	element.ForceUpdate = ForceUpdate

	self:RegisterEvent("UNIT_AURA", Path)

	for i = 1, #element do
		local obj = element[i]
		if obj:IsObjectType("Texture") and not obj:GetTexture() then
			obj:SetTexture([[Interface\ComboFrame\ComboPoint]])
			obj:SetTexCoord(0, 0.375, 0, 1)
		end
	end

	return true
end

local Disable = function(self)
	local element = self.PowerStack
	if not element then return end

	self:UnregisterEvent("UNIT_AURA", Path)
end

oUF:AddElement("PowerStack", Path, Enable, Disable)
  Reply With Quote
02-22-12, 03:22 AM   #5
lerb
A Frostmaul Preserver
 
lerb's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2008
Posts: 264
Phanx, that's awesome! I'll have a look at this and I'm pretty sure I'll use most, if not all, of it if I manage to get it working! Thanks a lot Super nice
  Reply With Quote
02-22-12, 05:51 AM   #6
lerb
A Frostmaul Preserver
 
lerb's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2008
Posts: 264
I'm sorry Phanx but I'm not really sure in what LUA-files I should put these different codes. I guess some of it goes into oUF/elements/powerstack.lua and some of it into my oUF_LeUI layout, but having a hard time figuring out which goes where. Mind giving me a hint?
  Reply With Quote
02-22-12, 06:33 AM   #7
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
His last code snippet is the oUF plugin/module for maelstrom/shadow orbs. You can either embed it in your layout (as an embedded module) or use it to create an oUF module from it. (Check other oUF modules)

The first snippets are the createOrbs functions and the actual setup. Both have to be added to whereever you spawn your player frame.
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)
  Reply With Quote
02-22-12, 08:22 AM   #8
lerb
A Frostmaul Preserver
 
lerb's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2008
Posts: 264
I still can't seem to get it working, though I'm not getting any LUA errors.

I created a new LUA file and pasted the last snipped in it, and placed it inside my oUF_Plugins folder.

I put the first snippet in my layou, oUF_LeUI and changed the texture paths to my own, using a statusbar texture for testing only.

I pasted the second snippet in my oUF_LeUI too.

Nothing happens ingame :/
  Reply With Quote
02-22-12, 04:44 PM   #9
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Third snippet goes in its own file. Doesn't matter what you call it, as long as it gets loaded before your layout files.

Second snippet goes inside the function you pass to oUF:Spawn.

Third snippet goes in your layout file, in the main chunk (outside of any functions).

If you do not define your addon's private namespace table as "ns" then you will need to change the function definitions in the first snippet, and the calls to those functions in the second snippet.

Also, you probably need to define the "playerClass" variable for the second snippet.

Edit: If it doesn't work there's probably an error. Install BugSack if you don't already have it, and then check it for any errors.

Edit #2: I also don't have a priest, so I've never actually tested the Shadow Orb display, but it's basically the same codepath as the Maelstrom Weapon display, which definitely works.

Edit #3: Also, in my code, the orbs are parented to "self.overlay" which is an invisible frame I create over the top of the unit frame so I can attach text/icons to it without having to worry about frame layering even if I hide some elements. You probably need to change that also (second snippet, call to ns.CreateOrbs).

Last edited by Phanx : 02-22-12 at 06:12 PM.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Creating a Shadow Orb element for oUF


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off