WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Tracking player's spell usage (https://www.wowinterface.com/forums/showthread.php?t=55320)

Layback_ 04-10-17 08:54 PM

Tracking player's spell usage
 
Hi all,

Yeah... it's me again :p

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!

Lombra 04-11-17 06:17 AM

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.

Seerah 04-11-17 09:15 AM

You don't go into combat (regen disabled) until after your first spell fires.

Layback_ 04-12-17 02:51 AM

Hi Lombra,

Quote:

Originally Posted by Lombra (Post 322909)
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 :p

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 :D

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 :banana:

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.

Quote:

Originally Posted by Lombra (Post 322909)
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 :D

Layback_ 04-12-17 03:04 AM

Quote:

Originally Posted by Seerah (Post 322913)
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 :(

Tim 04-12-17 03:34 PM

Perhaps have the destination target checked to see if it's attackable/hostile with the initial spell cast?

Layback_ 04-12-17 04:02 PM

Quote:

Originally Posted by Tim (Post 322925)
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.

Kakjens 05-13-17 10:07 AM

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.

jeruku 05-13-17 05:18 PM

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);


All times are GMT -6. The time now is 04:34 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI