Thread Tools Display Modes
01-22-17, 09:05 AM   #1
Anaea
A Murloc Raider
Join Date: Jan 2007
Posts: 4
Tweaking an addon: associating a SpellID

Hi developers,

I'm looking to tweak a raid frame addon. The addon in question, PerfectRaid (written by Cladhaire) has reached the point of its life cycle where it's lightly supported by the author with feature additions largely contributed by the community. I've been using it since 2009/2010, and it still works great for 99% of what a raiding healer needs.

However, I'm running into issues with some of the newer mechanics. Specifically, on Chronomatic Anomaly, we're dealing with a healing absorb shield called Time Release that explodes unless it's healed through in time: whatever health remains on the Time Release will discharge for potentially wipe-worthy damage.

This spell, with the same name for all of them, is either:

http://www.wowhead.com/spell=219964/time-release (almost clear of the debuff)
http://www.wowhead.com/spell=219965/time-release (not safe)
http://www.wowhead.com/spell=219966/time-release (totally not clear of the debuff)

Default raid frames will show different colors for the different versions of the debuff, but because PerfectRaid calls (and caches) debuffs by the name it does not differentiate.

Step 1: Associate buffname with spellID
So I figure my first step is to associate the spell name ("buffname" in the PerfectRaid code) with the spell ID. I think I would do this in line 176, where I see:

Code:
for i=1,40 do
		local name,rank,texture,count,dispelType,duration,expires,caster,stealable = UnitBuff(unit, i)
		if not name then break end
		if caster == "player" then
			mybuffs[name] = true
			mystacks[name] = (mystacks[name] or 0) + count
			buffexpiry[name] = expires
		end

		buffcache[name] = (buffcache[name] or 0) + 1
		buffstacks[name] = (buffstacks[name] or 0) + count
	end
I think I can acquire the spellId just by adding the variable to the UnitBuff query (and the UnitDebuff query that follows in line 201).
Code:
for i=1,40 do
		local name,rank,texture,count,dispelType,duration,expires,caster,stealable,spellID = UnitBuff(unit, i)
		if not name then break end
		if caster == "player" then
			mybuffs[name] = true
			mystacks[name] = (mystacks[name] or 0) + count
			buffexpiry[name] = expires
		end

		buffcache[name] = (buffcache[name] or 0) + 1
		buffstacks[name] = (buffstacks[name] or 0) + count
	end
At this point, I have a few questions.
  1. Is this a valid query? Between stealable (isStealable I think is the new label) and spellID is another variable -- nameplateShowPersonal -- and I'm not sure if I'm allowed to just skip it in the query or not. I've seen some constructions where that blank variable is indicated with an underscore, but I'm not sure if that's required.
  2. Does this address the question of multiple spellIDs associated with one spell name? For example, will this request pull all three spellIDs for Time Release, or will something else need to be done to get that information?
  3. I know that if I were dealing with a database or a table, just tossing in a new variable would blow stuff up. But I think local cache spell information is saved as text? So it shouldn't be an issue? I'm a complete newbie to LUA so if I'm asking questions that make it sound like I'm missing really obvious things, that's probably because I am missing really obvious things.

I think if this was working, I could probably stop there for my purposes. I'd be able to add the specific spellIDs as default debuffs in the LUA file and move along. This would require editing the PerfectRaid files every time I wanted to add similar debuffs, but it would work. If I wanted to submit something more broadly useful though, I should probably also do Step 2.

Step 2: Allow either spellID or buffname entries
So, working on the assumption that the query for spellID is successful, I would then need to find a way to update the UI so that either the spell name or the spellID is a valid entry for setting up a buff check in PerfectRaid. I'm at much more of a loss on this one. I think that happens around line 322...

Code:
function Buffs:CreateBuffEntry(buffname, entry)
	local expires = buffexpiry[buffname]
	local num = buffcache[buffname]
	local stacks = buffstacks[buffname]
	local mine = mybuffs[buffname]

	-- show only my stacks
	if entry.onlymine then
		stacks = mystacks[buffname]
	end
	
	if ( ( num and num > 1 ) or ( stacks and stacks > 1 ) ) and not entry.onlymine then
		local num = num
		-- If the buff is mine, and it should be masked
		-- A buff is masked when there is a "mine" filter set for it
		if mine and not mymask[buffname] then
			num = num - 1
		end

		if (expires and entry.showexpiry) and (stacks > 1 and entry.showstacks) then
			work[#work + 1] = string.format("%s(%d,%d)", entry.colortext, stacks, -1 * (GetTime()-expires) )					
		elseif (stacks and stacks > 1 and entry.showstacks) then
			work[#work + 1] = string.format("%s(%d)", entry.colortext, stacks )				
		elseif ( num and expires and entry.showexpiry) then
			work[#work + 1] = string.format("%s(%d,%d)", entry.colortext, num, -1 * (GetTime() - expires))
		elseif ( num and num > 1 ) then
			work[#work + 1] = string.format("%s(%d)", entry.colortext, num)
		else
			work[#work + 1] = string.format("%s", entry.colortext)
		end
	else
		if (entry.onlymine and not mine) or (not entry.onlymine and mymask[buffname]) then
			-- Don't show
		else
			if (expires and entry.showexpiry) and (stacks > 1 and entry.showstacks) then
				work[#work + 1] = string.format("%s(%d,%d)", entry.colortext, stacks, -1 * (GetTime()-expires) )					
			elseif (stacks and stacks > 1 and entry.showstacks) then
				work[#work + 1] = string.format("%s(%d)", entry.colortext, stacks )							
			elseif (expires and entry.showexpiry) then
				work[#work + 1] = string.format("%s(%d)", entry.colortext, -1 * (GetTime()-expires))
			else
				work[#work + 1] = entry.colortext
			end
		end
	end
end
Or, it could happen at line 258?

Code:
		-- Determine which spell name we matched
		local buffname
		if buffcache[entry.buffname] then
			buffname = entry.buffname
		elseif buffcache[entry.groupname or "nil"] then
			buffname = entry.groupname
		elseif buffcache[entry.groupname2 or "nil"] then
			buffname = entry.groupname2		
		elseif buffcache[entry.groupname3 or "nil"] then
			buffname = entry.groupname3
		elseif buffcache[entry.groupname4 or "nil"] then
			buffname = entry.groupname4
		end
My questions are much more basic here, because I'm definitely at a loss in parsing this. Is there an obvious place here where I can incorporate a spellID? Or am I completely off base on this part?

I've attached the relevant LUA file (PerfectRaid_Buffs) as well as the full addon zip file.

Many, many thanks for anyone who helps out with this -- I realize my ignorance here, and know how much of a pain it can be helping someone with so little base knowledge to work with.
Attached Files
File Type: lua PerfectRaid_Buffs.lua (39.6 KB, 143 views)
File Type: zip PerfectRaid-v70000-1.0.0.zip (81.4 KB, 152 views)

Last edited by Anaea : 01-23-17 at 09:07 AM. Reason: noted that Step 1 is the crucial one
  Reply With Quote
02-02-17, 10:23 PM   #2
Jonisaurus
An Aku'mai Servant
 
Jonisaurus's Avatar
Join Date: Aug 2011
Posts: 35
This ability is technically a buff, correct? How is it displayed in PerfectRaid? I can't make it out on the addon page. Is it an icon?
Does it display one of the icons for all stages of the buff?

Does this address the question of multiple spellIDs associated with one spell name? For example, will this request pull all three spellIDs for Time Release, or will something else need to be done to get that information?
The addon loops over a unit's buffs 40 times (for i=1, 40 do). You can query spellID but you're gonna have to somehow alter the table that auras (buffs/debuffs) are stored in. Depending on how those are used further in addon, it might break if you use spellID (or 'name .. "_ " .. spellID').

I'll have a look tomorrow. It doesn't look too complicated but I don't see him using the texture that he queries for in that same UnitBuff() request.

local name,rank,texture,count,dispelType,duration,expires,caster = UnitDebuff(unit, i)

That's why it would be helpful if you described the addon's buff functionality in more detail.

Last edited by Jonisaurus : 02-02-17 at 10:55 PM.
  Reply With Quote
02-03-17, 07:12 AM   #3
Anaea
A Murloc Raider
Join Date: Jan 2007
Posts: 4
Originally Posted by Jonisaurus View Post
That's why it would be helpful if you described the addon's buff functionality in more detail.
I'd be happy to, though my perspective will be as a user.

In brief, PerfectRaid is a "classic" style unit frame. What it offers that many other raid frames don't is an extraordinary ability to customize how buffs and debuffs are presented on that raid frame.

Users go into a buff/debuff interface and set up how they want PRaid to display a particular buff. Here's an older screenshot of that interface:
https://i.ytimg.com/vi/x4AyIQLvT2M/maxresdefault.jpg

So for example, I might need to monitor how many stacks of a debuff my tanks have -- but not actually respond to that information. I enter the debuff name (e.g., Chronometric Particles) and check the option to "show stacks." I then tell Praid to display this debuff as "CP" and maybe I color it gray so I know it's just an FYI and not something I need to react to.

On the addon's side, I think that breaks down into the following general steps:
  • check to see if the user-entered debuff name matches a spell name
  • if it doesn't, end the process
  • if it does, get the spell name, some other stuff that i don't think is used, get stack information, get expiry information
  • store that spell information in the local cache
  • (it also looks like there's code to tell the addon when to refresh that spell information, but i don't really know enough to parse it)

All of this is working fine. I'm just hoping to extend it so that when, as a user, I enter the debuff GUI I can enter the specific spellID I need to deal with (e.g. Time Release version 3) and tell PRaid how to handle that differently from the debuff with which it shares a name (e.g. Time Release versions 2 and 1).

To the question about the information grabbed, you're right, I think there are some queries that maybe were used once and aren't anymore, or maybe they're just placeholders. I do know the addon uses:
- spellname
- debuff type
- stack/count
- expiration

I don't know if it uses the caster attribute, or the isStealable attribute (for buffs).

In combat, the addon (more specifically this module) does a lot of things that I don't need to change:
  • checks to see if any magic, disease, poison debuff is on a raid member
  • displays a colored highlight bar to indicate that there is some debuff on that raid member
  • (by default, this behavior is enabled by user class: so as a priest, I see magic and disease highlights but not poison)
  • (this behavior can be adjusted to show all the highlights, though I think that's done in another module)
  • using the list of user-entered buffs and debuffs, check to see if those debuffs are on a raid member
  • displays the buff, debuff status on the raid frame according to user specifications
  • (this can include expiration, if the user has enabled that for this particular debuff, but is not shown as a default)
  • (this can include stack count, if the user has enabled that for this particular debuff, but is not shown as a default)

Last edited by Anaea : 02-03-17 at 07:23 AM.
  Reply With Quote
02-06-17, 05:34 PM   #4
Jonisaurus
An Aku'mai Servant
 
Jonisaurus's Avatar
Join Date: Aug 2011
Posts: 35
Just letting you know that I'm working on it. The addon's 'buff component' has some very obtuse code. Weirdly named functions, barely any documentation and manipulating/passing data in strange ways. I spent a lot of time just trying to understand what each function does. I'm much more used to web development than WoW addon code so it takes a while to get used to it.

I've added a Spell ID entrybox into the buff entry options and have its content be inserted into the saved profile. Next step is reading the spell ID data into the proper 'buffs' variables (I haven't quite figured out how 'buffs', 'buffcache' and 'mybuffs' interact yet).

I can't spend great amounts of time on it right now but I will fix this for you, you just need to be patient with me a little, okay?

Last edited by Jonisaurus : 02-06-17 at 05:43 PM.
  Reply With Quote
02-07-17, 06:43 AM   #5
Anaea
A Murloc Raider
Join Date: Jan 2007
Posts: 4
Originally Posted by Jonisaurus View Post
Just letting you know that I'm working on it. The addon's 'buff component' has some very obtuse code. Weirdly named functions, barely any documentation and manipulating/passing data in strange ways. I spent a lot of time just trying to understand what each function does. I'm much more used to web development than WoW addon code so it takes a while to get used to it.

I've added a Spell ID entrybox into the buff entry options and have its content be inserted into the saved profile. Next step is reading the spell ID data into the proper 'buffs' variables (I haven't quite figured out how 'buffs', 'buffcache' and 'mybuffs' interact yet).

I can't spend great amounts of time on it right now but I will fix this for you, you just need to be patient with me a little, okay?
I am the last person to complain about free help! I appreciate you taking a look -- I was able to make some simpler updates but this was way beyond me. Thanks!
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Tweaking an addon: associating a SpellID


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