Thread Tools Display Modes
04-06-17, 04:21 AM   #1
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Roll the Bones addon for Rogue

Hi all,

I am currently trying to create Roll the Bones indicator for Outlaw Rogue and here is a draft for what I have done so far.
(Pretty sure I made something similar to this before, but w/e...)

Lua Code:
  1. if select(2, UnitClass("player")) ~= "ROGUE" then
  2.     return;
  3. end
  4.  
  5. -----------------------------------------------------
  6. -- Variables
  7. -----------------------------------------------------
  8. local RolltheBonesID = {
  9.     193356, -- Broadsides
  10.     193357, -- Shark Infested Waters
  11.     193358, -- Grand Melee
  12.     199603, -- Jolly Roger
  13.     199600, -- Buried Treasure
  14.     193359, -- True Bearing
  15. }
  16.  
  17. local UpdateRolltheBonesBuff, CheckPlayerSpec;
  18.  
  19. -----------------------------------------------------
  20. -- Frames
  21. -----------------------------------------------------
  22. local RolltheBones = CreateFrame("Frame", "RolltheBones", UIParent);
  23. RolltheBones:RegisterEvent("PLAYER_ENTERING_WORLD");
  24. RolltheBones:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED");
  25. RolltheBones:RegisterUnitEvent("UNIT_AURA", "player");
  26. RolltheBones:SetSize(180, 180);
  27. RolltheBones:SetPoint("CENTER", 0, -200);
  28.  
  29. RolltheBones.Dice = {};
  30. for i = 1, 6 do
  31.     local Dice = CreateFrame("Button", "$parentDice" .. i, RolltheBones);
  32.     Dice:SetSize(40, 40);
  33.     Dice:SetPoint("CENTER", 60 * math.cos(i * math.pi / 3), 60 * math.sin(i * math.pi / 3));
  34.  
  35.     local Cooldown = CreateFrame("Cooldown", "$parentCooldown", Dice, "CooldownFrameTemplate");
  36.     Cooldown:SetAllPoints(true);
  37.  
  38.     local Icon = Dice:CreateTexture("$parentIcon", "OVERLAY");
  39.     Icon:SetAllPoints(true);
  40.     Icon:SetTexture(GetSpellTexture(RolltheBonesID[i]));
  41.  
  42.     Dice.Cooldown = Cooldown;
  43.     Dice.Icon = Icon;
  44.  
  45.     RolltheBones.Dice[i] = Dice;
  46. end
  47.  
  48. -----------------------------------------------------
  49. -- Functions
  50. -----------------------------------------------------
  51. -- Update the buff frame based on its status
  52. function UpdateRolltheBonesBuff()
  53.     for i = 1, #RolltheBonesID do
  54.         local spellName = GetSpellInfo(RolltheBonesID[i]);
  55.         local _, _, _, _, _, duration, expires = UnitAura("player", spellName);
  56.  
  57.         -- TO-DO: Condition check needed to prevent :SetCooldown being called on UNIT_AURA event by irrelevant aura
  58.         if duration then
  59.             RolltheBones.Dice[i].Cooldown:SetCooldown(expires - duration, duration);
  60.         else
  61.             -- Resets the duration to 0 when the buff is removed before it is expired
  62.             -- (when 'Roll the bones' is fired again)
  63.             RolltheBones.Dice[i].Cooldown:SetCooldown(0, 0);
  64.         end
  65.     end
  66. end
  67.  
  68. -- Check player's spec and returns bool value
  69. function CheckPlayerSpec()
  70.     local playerSpecID = GetSpecializationInfo(GetSpecialization());
  71.  
  72.     if playerSpecID ~= 260 then
  73.         RolltheBones:Hide();
  74.         RolltheBones:SetScript("OnEvent", nil);
  75.         RolltheBones:UnregisterEvent("UNIT_AURA");
  76.  
  77.         return false;
  78.     else
  79.         RolltheBones:Show();
  80.         RolltheBones:SetScript("OnEvent", RolltheBones.OnEvent);
  81.         RolltheBones:RegisterEvent("UNIT_AURA");
  82.  
  83.         return true;
  84.     end
  85. end
  86.  
  87. function RolltheBones:OnEvent(event, ...)
  88.     self[event](self);
  89. end
  90.  
  91. function RolltheBones:PLAYER_ENTERING_WORLD()
  92.     if CheckPlayerSpec() then
  93.         UpdateRolltheBonesBuff();
  94.     end
  95.  
  96.     self:UnregisterEvent("PLAYER_ENTERING_WORLD");
  97. end
  98.  
  99. function RolltheBones:PLAYER_SPECIALIZATION_CHANGED()
  100.     if CheckPlayerSpec() then
  101.         UpdateRolltheBonesBuff();
  102.     end
  103. end
  104.  
  105. function RolltheBones:UNIT_AURA(unitID)
  106.     UpdateRolltheBonesBuff();
  107. end
  108.  
  109. RolltheBones:SetScript("OnEvent", RolltheBones.OnEvent);

There are two things that I am unhappy with.

1. Structure of local functions, CheckPlayerSpec & UpdateRolltheBonesBuff

2. Their usage

I don't know why, but they just don't feel right to me and both their structure and usage seems soooooooooooooooooooo awkward to me.

Could I get some advice, please?

Also, any recommendation or criticism are welcomed !!

Thank you.
  Reply With Quote
04-06-17, 10:41 AM   #2
pas06
A Theradrim Guardian
Join Date: Apr 2009
Posts: 62
You don't have to do frame:SetScript("OnEvent", xxxxx) more than once. You set that Script once and whenever a event thats registered to that frame fires the function(xxxxx) gets called.

Lua Code:
  1. local RolltheBonesID = {
  2.     193356, -- Broadsides
  3.     193357, -- Shark Infested Waters
  4.     193358, -- Grand Melee
  5.     199603, -- Jolly Roger
  6.     199600, -- Buried Treasure
  7.     193359, -- True Bearing
  8. }
what about saving the spellnames like this:
Lua Code:
  1. local RolltheBonesBuffNames = {
  2.     GetSpellInfo(193356), -- Broadsides
  3.     GetSpellInfo(193357), -- Shark Infested Waters
  4.     GetSpellInfo(193358), -- Grand Melee
  5.     GetSpellInfo(199603), -- Jolly Roger
  6.     GetSpellInfo(199600), -- Buried Treasure
  7.     GetSpellInfo(193359), -- True Bearing
  8. }
Then you don't have to run the function GetSpellInfo that often, you don't have to access the spellID anyways in the current state.

Another problem is that you use SetCooldown a lot. Maybe something like this would be better:
Lua Code:
  1. function RolltheBones:UNIT_AURA(unitID)
  2.     for i, #RolltheBonesBuffNames do
  3.         local name, _, _, _, _, duration, expires = UnitBuff(unitID, RolltheBonesBuffNames[i])
  4.         if name then
  5.             if not HasBuff[i] then --player just got the buff
  6.                 HasBuff[i] = true
  7.                 RolltheBones.Dice[i].Cooldown:SetCooldown(expires - duration, duration)
  8.             end
  9.         elseif HasBuff[i] thenH
  10.             HasBuff[i] = false
  11.             RolltheBones.Dice[i].Cooldown:SetCooldown(0, 0)
  12.         end
  13.     end
  14. end
But i am not sure what happens if you reroll the bones and replace buff 1 with buff 1. The Code should work if it works the following: reroll > UNIT_AURA fires > buff disappears for a short peroid of time(gets replaced by the same buff) > UNIT_AURA fires > only new buff exists. Feel free to test it.

The whole code:
Lua Code:
  1. if select(2, UnitClass("player")) ~= "ROGUE" then
  2.     return
  3. end
  4.  
  5. -----------------------------------------------------
  6. -- Variables
  7. -----------------------------------------------------
  8. local RolltheBonesBuffNames = {
  9.     GetSpellInfo(193356), -- Broadsides
  10.     GetSpellInfo(193357), -- Shark Infested Waters
  11.     GetSpellInfo(193358), -- Grand Melee
  12.     GetSpellInfo(199603), -- Jolly Roger
  13.     GetSpellInfo(199600), -- Buried Treasure
  14.     GetSpellInfo(193359), -- True Bearing
  15. }
  16. local HasBuff = {}
  17. -----------------------------------------------------
  18. -- Frames
  19. -----------------------------------------------------
  20. local RolltheBones = CreateFrame("Frame", "RolltheBones", UIParent)
  21. RolltheBones:SetScript("OnEvent", function(self, event, ...) self[event](self, ...))
  22. RolltheBones:RegisterEvent("PLAYER_ENTERING_WORLD")
  23. RolltheBones:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
  24. RolltheBones:SetSize(180, 180)
  25. RolltheBones:SetPoint("CENTER", 0, -200)
  26.  
  27. RolltheBones.Dice = {}
  28. for i = 1, 6 do
  29.     local Dice = CreateFrame("Button", "$parentDice" .. i, RolltheBones)
  30.     Dice:SetSize(40, 40)
  31.     Dice:SetPoint("CENTER", 60 * math.cos(i * math.pi / 3), 60 * math.sin(i * math.pi / 3))
  32.  
  33.     local Cooldown = CreateFrame("Cooldown", "$parentCooldown", Dice, "CooldownFrameTemplate")
  34.     Cooldown:SetAllPoints(true)
  35.  
  36.     local Icon = Dice:CreateTexture("$parentIcon", "OVERLAY")
  37.     Icon:SetAllPoints(true)
  38.     Icon:SetTexture(GetSpellTexture(RolltheBonesID[i]))
  39.  
  40.     Dice.Cooldown = Cooldown
  41.     Dice.Icon = Icon
  42.  
  43.     RolltheBones.Dice[i] = Dice
  44. end
  45.  
  46. -----------------------------------------------------
  47. -- Functions
  48. -----------------------------------------------------
  49.  
  50. -- Check player's spec and returns bool value
  51. function RolltheBones:CheckPlayerSpec()
  52.     local playerSpecID = GetSpecializationInfo(GetSpecialization())
  53.  
  54.     if playerSpecID ~= 260 then
  55.         self:Hide()
  56.         self:UnregisterEvent("UNIT_AURA")
  57.     else
  58.         self:Show()
  59.         self:RegisterUnitEvent("UNIT_AURA", "player")
  60.     end
  61. end
  62.  
  63. function RolltheBones:PLAYER_ENTERING_WORLD()
  64.     self:CheckPlayerSpec()
  65.     self:UnregisterEvent("PLAYER_ENTERING_WORLD")
  66. end
  67.  
  68. function RolltheBones:PLAYER_SPECIALIZATION_CHANGED()
  69.     self:CheckPlayerSpec()
  70. end
  71.  
  72. function RolltheBones:UNIT_AURA(unitID)
  73.     for i, #RolltheBonesBuffNames do
  74.         local name, _, _, _, _, duration, expires = UnitBuff(unitID, RolltheBonesBuffNames[i])
  75.         if name then
  76.             if not HasBuff[i] then --player just got the buff
  77.                 HasBuff[i] = true
  78.                 RolltheBones.Dice[i].Cooldown:SetCooldown(expires - duration, duration)
  79.             end
  80.         elseif HasBuff[i] thenH
  81.             HasBuff[i] = false
  82.             RolltheBones.Dice[i].Cooldown:SetCooldown(0, 0)
  83.         end
  84.     end
  85. end
Feel free to test it. i am pretty sure that someone comes up with a better idea afterwards

Last edited by pas06 : 04-06-17 at 10:49 AM.
  Reply With Quote
04-06-17, 04:28 PM   #3
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Hi pas06,

Thank you for your reply.

1. For :SetScript("OnEvent", ...), I was trying to minimize the memory usage when it is not needed, but I definitely should have called RegisterUnitEvent, not RegisterEvent for UNIT_AURA

2. I also tried that approach for Roll the Bones id table, but the way you've done it will insert the rest of GetSpellInfo(193359) data into the table (like rank, icon, castingTime, minRange, maxRange, spellID) as well.

3. Same for UNIT_AURA function. I've tried a same approach and as you've guessed, there was a small taint which I really didn't like
  Reply With Quote
04-06-17, 04:41 PM   #4
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Here's a fix for UpdateRolltheBonesBuff function.

Lua Code:
  1. function UpdateRolltheBonesBuff(i)
  2.     local spellName = GetSpellInfo(RolltheBonesID[i]);
  3.     local _, _, _, _, _, duration, expires = UnitAura("player", spellName);
  4.  
  5.     if duration then
  6.         -- Prevents from redundant SetCooldown function called on UNIT_AURA event
  7.         if not RolltheBones.Dice[i].IsRunning then
  8.             RolltheBones.Dice[i].Cooldown:SetCooldown(expires - duration, duration);
  9.  
  10.             RolltheBones.Dice[i].IsRunning = true;
  11.         else
  12.             local startTime = RolltheBones.Dice[i].Cooldown:GetCooldownTimes();
  13.  
  14.             if startTime / 1000 < expires - duration then
  15.                 RolltheBones.Dice[i].Cooldown:SetCooldown(expires - duration, duration);
  16.             end
  17.         end
  18.     else
  19.         -- Resets the duration to 0 when the buff is removed before it is expired
  20.         -- e.g. When Roll the dice is fired again
  21.         RolltheBones.Dice[i].Cooldown:SetCooldown(0, 0);
  22.  
  23.         RolltheBones.Dice[i].IsRunning = false;
  24.     end
  25. end

Currently it is working as I expected
  Reply With Quote
04-09-17, 03:47 AM   #5
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Your function UpdateRolltheBonesBuff should be local.
  Reply With Quote
04-09-17, 03:50 PM   #6
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Yeap, it is declared as local on variables section (L#17) !!
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Roll the Bones addon for Rogue

Thread Tools
Display Modes

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