After getting some inspiration from the post made by fmagretto here:
http://www.ownedcore.com/forums/worl...ml#post2159020 ([BETA] PQRotation - an automated ability priority queue.)
I decided to start playing around with the concept of hooking into the combatlog to attach an event listener to grab key entries relevant to a rotation. Once I finally managed to create a custom frame element and get it implemented into the game I started to get the first feedback from wow that everything was working. After some filtering and testing the first thing I thought of doing was to create a smarter, faster and more efficient decurse script that would no longer rely on the current repeated looping of the raid group.
And that is what I'm releasing here for the current profile authors to start playing with. In this first preview I've managed to hook an event listener into the combat log to grab debuffs being applied to the current raid or party members aswell as the player. With this method we can instantly decurse a spell in the allowed list without the need to repeatedly cycle through the raid group, checking their debuffs.
Below are the two XML files, to get started you'll need to change a few things:
- The class the rotation is designed for (currently Druid)
- The list of spells you'd like to decurse
- And the spell IDs of your decurse spell
Abilities:
Code:
<?xml version="1.0" encoding="utf-8" ?><DRUID><Ability><Name>-- Loader --</Name><Default>false</Default><SpellID>0</SpellID><Actions></Actions><Lua>-- Make sure we&apos;re only loading once
if not loaded then
-- Global Variable
Perform = { }
-- Create our event handler function
function EventHandler(self, event, ...)
-- Check for a combat log event
if event == &quot;COMBAT_LOG_EVENT_UNFILTERED&quot; then
-- Check for a debuff addition on a member of the raid, party or player
if select(2, ...) == &quot;SPELL_AURA_APPLIED&quot; and
select(15, ...) == &quot;DEBUFF&quot; and
bit.band(select(10, ...), COMBATLOG_OBJECT_AFFILIATION_OUTSIDER) ~= 8
then
Perform[&quot;action&quot;] = &quot;Decurse&quot;
Perform[&quot;spell&quot;] = select(13, ...)
Perform[&quot;spellid&quot;] = select(12, ...)
PQR_CustomTarget = select(9, ...)
end
end
end
-- Create our frame and bind combat log events
frame = CreateFrame(&quot;FRAME&quot;, &quot;OurFrame&quot;)
frame:RegisterEvent(&quot;COMBAT_LOG_EVENT_UNFILTERED&quot;)
frame:SetScript(&quot;OnEvent&quot;, EventHandler)
-- Stop multiple loads
loaded = true
end</Lua><RecastDelay>0</RecastDelay><Target>Player</Target><CancelChannel>False</CancelChannel><LuaBefore></LuaBefore><LuaAfter></LuaAfter></Ability><Ability><Name>Decurse</Name><Default>false</Default><SpellID>2782</SpellID><Actions></Actions><Lua>-- Define what we&apos;d like to decurse
Decurse = { &quot;Living Bomb&quot; }
-- Define the spell, just for range etc. checks
DecurseSpell = 2782
-- Check we&apos;ve got something to decurse
if Perform[&quot;action&quot;] == &quot;Decurse&quot; then
-- Get debuff details
local Name,_,_,_,Type,Duration,Expires = UnitDebuff(PQR_CustomTarget, Perform[&quot;spell&quot;])
-- Check the debuff is something we can deal with
if Name ~= nil and
tableFind(Decurse, Perform[&quot;spell&quot;]) ~= false and
Expires - GetTime() &gt;= 2 and
spellCheck(DecurseSpell, PQR_CustomTarget) ~= false
then
-- Debug messages
local spell = &quot;|cff71d5ff|Hspell:&quot;..Perform[&quot;spellid&quot;]..&quot;|h[&quot;..Perform[&quot;spell&quot;]..&quot;]|h|r&quot;
print(&quot;Removing&quot;, spell, &quot;from&quot;, classColor(UnitName(PQR_CustomTarget), true)..&quot;.&quot;)
-- Reset perform
Perform = { }
-- Cast It!
return true
end
end</Lua><RecastDelay>1000</RecastDelay><Target>Custom</Target><CancelChannel>False</CancelChannel><LuaBefore></LuaBefore><LuaAfter></LuaAfter></Ability><Ability><Name>-- Functions --</Name><Default>false</Default><SpellID>0</SpellID><Actions></Actions><Lua>-- Make sure we&apos;re only declaring once
if not functions then
-- FUNCTION: spellCheck
-- ACCEPTS: SpellID or Name and Unit
-- PERFORMS: Various range, afinity and other checks to ensure a spell should be cast
-- RETURNS: 1 or 0 depending on the check results
function spellCheck(spell, target)
local Cast = true;
local SpellName = GetSpellInfo(spell)
if UnitExists(target) == nil or
UnitIsDeadOrGhost(target) or
UnitCanCooperate(&quot;player&quot;, target) == nil or
IsSpellInRange(SpellName, target) == 0 or
UnitChannelInfo(&quot;player&quot;) ~= nil or
PQR_IsOutOfSight(target)
then Cast = false end
return Cast
end
-- FUNCTION: classColor
-- ACCEPTS: String Name, Boolean use [ ] around name?
-- PERFORMS: Builds a class coloured hyperlink to be used in chat
-- RETURNS: A hyperlink string
function classColor(name, brackets)
local str = name
if UnitExists(name) then
local playerClass, englishClass = UnitClass(name)
local color = RAID_CLASS_COLORS[englishClass]
str = Hex(color)..&quot;|Hplayer:&quot;..name..&quot;|h&quot;
if brackets == true then str = str..&quot;[&quot;..name..&quot;]|h|r&quot; else str = str..name..&quot;|h|r&quot; end
end
return str
end
-- FUNCTION: Hex
-- ACCEPTS: table r of r,g,b colors, or seperate r,g,b values
-- PERFORMS: takes the input colours and turns them into a hex value for coloring chat
-- RETURNS: Hex string
function Hex(r, g, b)
if(type(r) == &quot;table&quot;) then if(r.r) then r, g, b = r.r, r.g, r.b else r, g, b = unpack(r) end end
if(not r or not g or not b) then r, g, b = 1, 1, 1 end
return format(&quot;|cff%02x%02x%02x&quot;, tonumber(r*255), tonumber(g*255), tonumber(b*255))
end
-- FUNCTION: table.find
-- ACCEPTS: table name, value to find
-- PERFORMS: Searches the given table for the value
-- RETURNS: position if found, false on not
function tableFind(table, value)
if type(table) == &quot;table&quot; and value then
for k, val in pairs(table) do
if val:lower() == value:lower() then return true end
end
end
return false
end
-- Stop multiple loads
functions = true
end</Lua><RecastDelay>0</RecastDelay><Target>Player</Target><CancelChannel>False</CancelChannel><LuaBefore></LuaBefore><LuaAfter></LuaAfter></Ability></DRUID>
Rotation:
Code:
<?xml version="1.0" encoding="utf-8" ?><DRUID><Rotation><RotationName>Decurse</RotationName><RotationDefault>false</RotationDefault><RotationList>-- Loader --|-- Functions --|Decurse</RotationList><RequireCombat>false</RequireCombat><RotationNotes>This is a small Proof-of-Concept rotation and the beginnings of an event-driven profile framework. In this first preview I&apos;ve managed to hook an event listener into the combat log to grab debuffs being applied to the current raid or party members aswell as the player. With this method we can instantly decurse a spell in the allowed list without the need to repeatedly cycle through the raid group, checking their debuffs.
With this preview you&apos;ll get a small idea of what is now possible and how easy it is to upgrade and merge into a smarter, faster and more efficient rotation.</RotationNotes></Rotation></DRUID>
The eventlisener function can easily be scaled to add more events and I can't wait to see some of the ideas and possibilites that you guys come up with for this.
Now it's most definately not perfect, given that multiple debuffs can be applied at once, the GCD means we can't remove them as and when they happen and this is the first thing I intent to overcome by queing events and putting them into a stack system. When a new event is fired it will be put into the end of the current stack, which is moved through one by one and items are removed as and when they are dispelled in this case, moving the next item to the top to be dealt with. A set of functions will be created to easily manage these and enable a very easy way to move throguh, reorder and remove items from the stack.
I'd love to hear your thoughts on the concept as well as any proposed changes