Thread Tools Display Modes
04-10-17, 08:54 PM   #1
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Tracking player's spell usage

Hi all,

Yeah... it's me again

For this time, I am trying to make an addon that tracks player's spell usage and here is what I have got so far.

Lua Code:
  1. local SkillFlow = CreateFrame("Frame");
  2. SkillFlow:RegisterEvent("PLAYER_REGEN_ENABLED");
  3. SkillFlow:RegisterEvent("PLAYER_REGEN_DISABLED");
  4. SkillFlow:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
  5.  
  6. SkillFlow.regenEnabled = true;
  7. SkillFlow.queue = {};
  8. SkillFlow.queueSize = 10;
  9.  
  10. function SkillFlow:PLAYER_REGEN_ENABLED()
  11.     self.regenEnabled = true;
  12. end
  13.  
  14. function SkillFlow:PLAYER_REGEN_DISABLED()
  15.     self.regenEnabled = false;
  16. end
  17.  
  18. function SkillFlow:OnEvent(event, ...)
  19.     self[event](self, event, ...);
  20. end
  21.  
  22. function SkillFlow:COMBAT_LOG_EVENT_UNFILTERED(event, ...)
  23.     local _, subEvent, _, sourceGUID, _, _, _, _, _, _, _ = ...;
  24.  
  25.     if sourceGUID == UnitGUID("player") then
  26.         if subEvent == "SPELL_CAST_SUCCESS" and not self.regenEnabled then
  27.             local spellName = select(13, ...);
  28.            
  29.             if #self.queue < self.queueSize then
  30.                 table.insert(self.queue, spellName);
  31.             else
  32.                 for i = 1, #self.queue - 1 do
  33.                     self.queue[i] = self.queue[i + 1];
  34.                 end
  35.  
  36.                 self.queue[self.queueSize] = spellName;
  37.             end
  38.  
  39.             -- DUBUGGING ----------------------------------------
  40.             print("\n======== Skill Flow ========");
  41.             for i = 1, #self.queue do
  42.                 print(string.format("%d: %s", i, self.queue[i]));
  43.             end
  44.             print("============================");
  45.             -----------------------------------------------------
  46.         end
  47.     end
  48. end
  49.  
  50. SkillFlow:SetScript("OnEvent", SkillFlow.OnEvent);

There are basically two main problems that I am concerned:

1. The first spell fired before the combat won't be tracked and I know that is because of this line:

Code:
if type == "SPELL_CAST_SUCCESS" and not self.regenEnabled then
However, if I get rid of not self.regenEnabled, it even tracks for spell-casts done during non-combat situation.

2. Also tracks for spells fired via ExtraActionButton and so on. Since I am expecting to track player's spell only, I would like these kind of spells to be ignored.

In my personal opinion, COMBAT_LOG_EVENT (not COMBAT_LOG_EVENT_UNFILTERED) would do some job here, but I can't find further references regarding this.
(COMBAT_LOG_EVENT info page on wowwiki doesn't seem to cover this as well )

Any suggestions, please?

Thank you!
  Reply With Quote
04-11-17, 06:17 AM   #2
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
1. I don't understand. You say it won't track "before combat" due to the condition, and when you remove that, it does track out of combat. Isn't this working as intended?

2. COMBAT_LOG_EVENT is the same event, really. The difference is this one only fires for events that honors the filters set in your combat log frame. You can try a few things here, but neither are perfect, I think.

GetSpellInfo(spellName) should theoretically only return stuff for spells in your spellbook. I don't know how reliable that is, and there could be other spells with the same name as one of your own.

IsPlayerSpell(spellID), IsSpellKnown(spellID) or IsSpellKnownOrOverridesKnown(spellID) were not very reliable last time I tried. Incorrectly returned false for a bunch of spells. Could try.

Something that might work better is going through all your spell book spells and collecting their spell IDs.
__________________
Grab your sword and fight the Horde!
  Reply With Quote
04-11-17, 09:15 AM   #3
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
You don't go into combat (regen disabled) until after your first spell fires.
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
04-12-17, 02:51 AM   #4
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Hi Lombra,

Originally Posted by Lombra View Post
1. I don't understand. You say it won't track "before combat" due to the condition, and when you remove that, it does track out of combat. Isn't this working as intended?
I apologize that my word choice was awkward

What I actually meant was a spell that is fired before a combat, but that actually initiates a combat.

I know it still sounds weird

Let's take some example.

Say that you are a mage and cast a "Fireball" on a target. Once it hits a target, your health regen will be disabled (calls PLAYER_REGEN_DISABLED) and finally, you are in a combat

But, what if you cast a "Blink"? Casting a "Blink" won't directly initiate a combat unless you are in a range of mob or something (but still, that isn't considered as "direct"), and this is a case that I am trying to avoid tracking.

TL;DR - I'm trying to track a spell cast done 1) before a combat, but that initiates a combat and 2) during a combat.

+ the current code is conceptually wrong.

Originally Posted by Lombra View Post
2. COMBAT_LOG_EVENT is the same event, really. The difference is this one only fires for events that honors the filters set in your combat log frame. You can try a few things here, but neither are perfect, I think.

GetSpellInfo(spellName) should theoretically only return stuff for spells in your spellbook. I don't know how reliable that is, and there could be other spells with the same name as one of your own.

IsPlayerSpell(spellID), IsSpellKnown(spellID) or IsSpellKnownOrOverridesKnown(spellID) were not very reliable last time I tried. Incorrectly returned false for a bunch of spells. Could try.

Something that might work better is going through all your spell book spells and collecting their spell IDs.
Hm... I should do some further experiment with those functions.

Thanks a lot
  Reply With Quote
04-12-17, 03:04 AM   #5
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by Seerah View Post
You don't go into combat (regen disabled) until after your first spell fires.
You are totally right.

And this is why my code is conceptually wrong at the moment.

PLAYER_REGEN_DISABLED event is fired after COMBAT_LOG_EVENT_UNFILTERED event with SPELL_CAST_SUCCESS

Last edited by Layback_ : 04-12-17 at 03:09 AM.
  Reply With Quote
04-12-17, 03:34 PM   #6
Tim
A Rage Talon Dragon Guard
 
Tim's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2008
Posts: 308
Perhaps have the destination target checked to see if it's attackable/hostile with the initial spell cast?
  Reply With Quote
04-12-17, 04:02 PM   #7
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by Tim View Post
Perhaps have the destination target checked to see if it's attackable/hostile with the initial spell cast?
Yeah, I've used that method as well.

Code:
if subEvent == "SPELL_CAST_SUCCESS" and (UnitCanAttack("player", "target") or UnitAffectingCombat("player")) then
But, this also had some issue.

1. Still tracks any spell casts as long as unit is attackable.

2. Only "target" is considered. Even if you have a target exists, but is not attackable and you cast a spell on "focus", "targettarget" then this won't work.

3. AOE is not considered as well.
  Reply With Quote
05-13-17, 10:07 AM   #8
Kakjens
A Cliff Giant
Join Date: Apr 2017
Posts: 75
Knowing the last relevant spell before entering combat is not so easy. One thought on how to implement it.
During non-combat, store in local to the lua file variable with the last casted spell and timestamp. When entering combat, verify that it is relevant by checking that there's small time difference between timestamp and current time.
This way you would also be able to collect statistics about spells with which you initiate combat.
The other thing is whether you want to track only one spell preceding combat, or, for example, on use trinkets, racials (e.g, berserking), potion usage, etc. as well.
Does not solve extra action bar spell issue.
  Reply With Quote
05-13-17, 05:18 PM   #9
jeruku
A Cobalt Mageweaver
 
jeruku's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 223
Here is a sample of how it might be done, I threw it together real quick so it is without guarantee.

It will wait 1.5 seconds, global cooldown, after a spell cast waiting to see if you had entered combat.

Lua Code:
  1. local SkillFlow = CreateFrame("Frame");
  2. SkillFlow:RegisterEvent("PLAYER_REGEN_ENABLED");
  3. SkillFlow:RegisterEvent("PLAYER_REGEN_DISABLED");
  4. SkillFlow:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
  5.  
  6. SkillFlow.regenEnabled = true;
  7. SkillFlow.queue = {};
  8. SkillFlow.queueSize = 10;
  9.  
  10. local placeholderfunc
  11. local placeholdername
  12.  
  13. local function DoThis(self, spellName)
  14.     if #self.queue < self.queueSize then
  15.         table.insert(self.queue, spellName);
  16.     else
  17.         for i = 1, #self.queue - 1 do
  18.             self.queue[i] = self.queue[i + 1];
  19.         end
  20.  
  21.         self.queue[self.queueSize] = spellName;
  22.     end
  23.  
  24.     -- DUBUGGING ----------------------------------------
  25.     print("\n======== Skill Flow ========");
  26.     for i = 1, #self.queue do
  27.         print(string.format("%d: %s", i, self.queue[i]));
  28.     end
  29.     print("============================");
  30.     -----------------------------------------------------
  31. end
  32.  
  33. local function StopThis()
  34.     placeholderfunc = nil
  35.     placeholdername = nil
  36. end
  37.  
  38. function SkillFlow:PLAYER_REGEN_ENABLED()
  39.     self.regenEnabled = true;
  40.     -- safety measure
  41.     StopThis()
  42. end
  43.  
  44. function SkillFlow:PLAYER_REGEN_DISABLED()
  45.     self.regenEnabled = false;
  46.     if placeholderfunc then
  47.         placeholderfunc(self, placeholdername)
  48.     end
  49.     StopThis()
  50. end
  51.  
  52. function SkillFlow:OnEvent(event, ...)
  53.     self[event](self, event, ...);
  54. end
  55.  
  56. function SkillFlow:COMBAT_LOG_EVENT_UNFILTERED(event, _, subEvent, _, sourceGUID, _, _, _, _, _, _, _, _, spellName, ...)
  57.     if sourceGUID == UnitGUID("player") then
  58.         if subEvent == "SPELL_CAST_SUCCESS" and not self.regenEnabled then
  59.             DoThis(self, spellName)
  60.         elseif self.regenEnabled and not placeholderfunc then
  61.             placeholderfunc = DoThis
  62.             placeholdername = SpellName
  63.             C_Timer.After(1.5, StopThis) -- wait until after global cooldown I suppose.
  64.         end
  65.     end
  66. end
  67.  
  68. SkillFlow:SetScript("OnEvent", SkillFlow.OnEvent);
__________________
"I have not failed, I simply found 10,000 ways that did not work." - Thomas Edison

Last edited by jeruku : 05-13-17 at 05:19 PM. Reason: was incomplete
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Tracking player's spell usage

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