From 07b87b2c127dec75a5536ebec8f6dacf341a1a05 Mon Sep 17 00:00:00 2001 From: Sumsebrum Date: Mon, 17 May 2021 16:49:54 +0200 Subject: [PATCH] init v1.0.3-Beta --- .gitignore | 8 + Bindings.xml | 38 + Constants.lua | 610 +++ EventListener.lua | 251 ++ Frame.lua | 287 ++ Gladdy.lua | 388 ++ Gladdy.toc | 35 + Images/BasicProfiles/Classic1.blp | Bin 0 -> 700220 bytes Images/BasicProfiles/Klimp1.blp | Bin 0 -> 700220 bytes Images/BasicProfiles/Knall1.blp | Bin 0 -> 700220 bytes Images/Border_Gloss.tga | Bin 0 -> 16428 bytes Images/Border_rounded_blp.blp | Bin 0 -> 23016 bytes Images/Border_squared_blp.blp | Bin 0 -> 23016 bytes Images/Classes/INV_Hammer_01.blp | Bin 0 -> 23016 bytes Images/Classes/INV_Jewelry_Talisman_04.blp | Bin 0 -> 3916 bytes Images/Classes/INV_Misc_MonsterClaw_04.blp | Bin 0 -> 3916 bytes Images/Classes/INV_Staff_13.blp | Bin 0 -> 6660 bytes Images/Classes/INV_Staff_30.blp | Bin 0 -> 6660 bytes Images/Classes/INV_Sword_27.blp | Bin 0 -> 23016 bytes Images/Classes/INV_ThrowingKnife_04.blp | Bin 0 -> 6660 bytes Images/Classes/INV_Weapon_Bow_07.blp | Bin 0 -> 3916 bytes Images/Classes/Spell_Nature_Drowsy.blp | Bin 0 -> 6660 bytes Images/Countdown/0.blp | Bin 0 -> 44900 bytes Images/Countdown/1.blp | Bin 0 -> 44900 bytes Images/Countdown/2.blp | Bin 0 -> 44900 bytes Images/Countdown/3.blp | Bin 0 -> 44900 bytes Images/Countdown/4.blp | Bin 0 -> 44900 bytes Images/Countdown/5.blp | Bin 0 -> 44900 bytes Images/Countdown/6.blp | Bin 0 -> 44900 bytes Images/Countdown/7.blp | Bin 0 -> 44900 bytes Images/Countdown/8.blp | Bin 0 -> 44900 bytes Images/Countdown/9.blp | Bin 0 -> 44900 bytes Images/DorisPP.TTF | Bin 0 -> 33980 bytes Images/Gloss.tga | Bin 0 -> 32812 bytes Images/LiteStep.tga | Bin 0 -> 32812 bytes Images/Minimalist.tga | Bin 0 -> 1304 bytes Images/Smooth.tga | Bin 0 -> 32812 bytes .../Spell_Nature_InvisibilityTotem_edit.blp | Bin 0 -> 23016 bytes .../Spell_Nature_ManaRegenTotem_edit.blp | Bin 0 -> 23016 bytes .../Totems/Spell_Nature_RemoveCurse_edit.blp | Bin 0 -> 23016 bytes .../Totems/Spell_Nature_SlowingTotem_edit.blp | Bin 0 -> 23016 bytes Images/Totems/Spell_Nature_Windfury_edit.blp | Bin 0 -> 23016 bytes Images/UI-Tooltip-Border_round_selfmade.blp | Bin 0 -> 12084 bytes Images/UI-Tooltip-Border_square_selfmade.blp | Bin 0 -> 12084 bytes LICENSE | 339 ++ Lang.lua | 480 +++ Libs/AceComm-3.0/AceComm-3.0.lua | 305 ++ Libs/AceComm-3.0/AceComm-3.0.xml | 5 + Libs/AceComm-3.0/ChatThrottleLib.lua | 534 +++ Libs/AceConfig-3.0/AceConfig-3.0.lua | 58 + Libs/AceConfig-3.0/AceConfig-3.0.xml | 8 + .../AceConfigCmd-3.0/AceConfigCmd-3.0.lua | 794 ++++ .../AceConfigCmd-3.0/AceConfigCmd-3.0.xml | 4 + .../AceConfigDialog-3.0.lua | 2015 ++++++++++ .../AceConfigDialog-3.0.xml | 4 + .../AceConfigRegistry-3.0.lua | 371 ++ .../AceConfigRegistry-3.0.xml | 4 + Libs/AceDB-3.0/AceDB-3.0.lua | 744 ++++ Libs/AceDB-3.0/AceDB-3.0.xml | 4 + Libs/AceDBOptions-3.0/AceDBOptions-3.0.lua | 460 +++ Libs/AceDBOptions-3.0/AceDBOptions-3.0.xml | 4 + .../AceGUI-3.0-SharedMediaWidgets.toc | 16 + .../AceGUI-3.0-SharedMediaWidgets.lua | 794 ++++ .../BackgroundWidget.lua | 235 ++ .../BorderWidget.lua | 230 ++ .../FontWidget.lua | 216 + .../SoundWidget.lua | 264 ++ .../StatusbarWidget.lua | 233 ++ .../prototypes.lua | 266 ++ .../AceGUI-3.0-SharedMediaWidgets/widget.xml | 9 + .../AceGUI-3.0-SharedMediaWidgets/CHANGES.txt | 12 + ...gelog-AceGUI-3.0-SharedMediaWidgets-r7.txt | 63 + Libs/AceGUI-3.0-SharedMediaWidgets/widget.xml | 4 + Libs/AceGUI-3.0/AceGUI-3.0.lua | 1026 +++++ Libs/AceGUI-3.0/AceGUI-3.0.xml | 28 + .../AceGUIContainer-BlizOptionsGroup.lua | 138 + .../widgets/AceGUIContainer-DropDownGroup.lua | 157 + .../widgets/AceGUIContainer-Frame.lua | 316 ++ .../widgets/AceGUIContainer-InlineGroup.lua | 103 + .../widgets/AceGUIContainer-ScrollFrame.lua | 215 + .../widgets/AceGUIContainer-SimpleGroup.lua | 69 + .../widgets/AceGUIContainer-TabGroup.lua | 349 ++ .../widgets/AceGUIContainer-TreeGroup.lua | 715 ++++ .../widgets/AceGUIContainer-Window.lua | 336 ++ .../widgets/AceGUIWidget-Button.lua | 103 + .../widgets/AceGUIWidget-CheckBox.lua | 296 ++ .../widgets/AceGUIWidget-ColorPicker.lua | 190 + .../widgets/AceGUIWidget-DropDown-Items.lua | 471 +++ .../widgets/AceGUIWidget-DropDown.lua | 737 ++++ .../widgets/AceGUIWidget-EditBox.lua | 263 ++ .../widgets/AceGUIWidget-Heading.lua | 78 + Libs/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua | 140 + .../widgets/AceGUIWidget-InteractiveLabel.lua | 94 + .../widgets/AceGUIWidget-Keybinding.lua | 249 ++ .../AceGUI-3.0/widgets/AceGUIWidget-Label.lua | 179 + .../widgets/AceGUIWidget-MultiLineEditBox.lua | 366 ++ .../widgets/AceGUIWidget-Slider.lua | 284 ++ Libs/AceHook-3.0/AceHook-3.0.lua | 511 +++ Libs/AceHook-3.0/AceHook-3.0.xml | 4 + Libs/AceSerializer-3.0/AceSerializer-3.0.lua | 287 ++ Libs/AceSerializer-3.0/AceSerializer-3.0.xml | 4 + Libs/AceTimer-3.0/AceTimer-3.0.lua | 278 ++ Libs/AceTimer-3.0/AceTimer-3.0.xml | 4 + .../CallbackHandler-1.0.lua | 239 ++ .../CallbackHandler-1.0.xml | 4 + Libs/DRData-1.0/DRData-1.0.lua | 427 ++ Libs/DRData-1.0/DRData-1.0.toc | 8 + Libs/DRData-1.0/DRData-1.0.xml | 4 + Libs/LibClassAuras-1.0/ClassBuffs.lua | 128 + Libs/LibClassAuras-1.0/ClassDebuffs.lua | 198 + Libs/LibClassAuras-1.0/LibClassAuras-1.0.lua | 74 + Libs/LibClassAuras-1.0/lib.xml | 6 + Libs/LibDeflate/LibDeflate.lua | 3536 +++++++++++++++++ Libs/LibDeflate/lib.xml | 4 + .../LibSharedMedia-3.0/LibSharedMedia-3.0.lua | 300 ++ Libs/LibSharedMedia-3.0/lib.xml | 4 + Libs/LibStub/LibStub.lua | 30 + Libs/LibStub/LibStub.toc | 9 + Modules/Announcements.lua | 282 ++ Modules/ArenaCountDown.lua | 180 + Modules/Auras.lua | 402 ++ Modules/BuffsDebuffs.lua | 1057 +++++ Modules/Castbar.lua | 827 ++++ Modules/Classicon.lua | 202 + Modules/Cooldowns.lua | 987 +++++ Modules/Diminishings.lua | 677 ++++ Modules/ExportImport.lua | 197 + Modules/Healthbar.lua | 449 +++ Modules/Highlight.lua | 242 ++ Modules/Pets.lua | 542 +++ Modules/Powerbar.lua | 442 +++ Modules/TotemPlates.lua | 606 +++ Modules/Trinket.lua | 364 ++ Modules/VersionCheck.lua | 46 + Modules/XiconProfiles.lua | 288 ++ Options.lua | 724 ++++ README.md | 129 + embeds.xml | 17 + 138 files changed, 31713 insertions(+) create mode 100644 .gitignore create mode 100644 Bindings.xml create mode 100644 Constants.lua create mode 100644 EventListener.lua create mode 100644 Frame.lua create mode 100644 Gladdy.lua create mode 100644 Gladdy.toc create mode 100644 Images/BasicProfiles/Classic1.blp create mode 100644 Images/BasicProfiles/Klimp1.blp create mode 100644 Images/BasicProfiles/Knall1.blp create mode 100644 Images/Border_Gloss.tga create mode 100644 Images/Border_rounded_blp.blp create mode 100644 Images/Border_squared_blp.blp create mode 100644 Images/Classes/INV_Hammer_01.blp create mode 100644 Images/Classes/INV_Jewelry_Talisman_04.blp create mode 100644 Images/Classes/INV_Misc_MonsterClaw_04.blp create mode 100644 Images/Classes/INV_Staff_13.blp create mode 100644 Images/Classes/INV_Staff_30.blp create mode 100644 Images/Classes/INV_Sword_27.blp create mode 100644 Images/Classes/INV_ThrowingKnife_04.blp create mode 100644 Images/Classes/INV_Weapon_Bow_07.blp create mode 100644 Images/Classes/Spell_Nature_Drowsy.blp create mode 100644 Images/Countdown/0.blp create mode 100644 Images/Countdown/1.blp create mode 100644 Images/Countdown/2.blp create mode 100644 Images/Countdown/3.blp create mode 100644 Images/Countdown/4.blp create mode 100644 Images/Countdown/5.blp create mode 100644 Images/Countdown/6.blp create mode 100644 Images/Countdown/7.blp create mode 100644 Images/Countdown/8.blp create mode 100644 Images/Countdown/9.blp create mode 100644 Images/DorisPP.TTF create mode 100644 Images/Gloss.tga create mode 100644 Images/LiteStep.tga create mode 100644 Images/Minimalist.tga create mode 100644 Images/Smooth.tga create mode 100644 Images/Totems/Spell_Nature_InvisibilityTotem_edit.blp create mode 100644 Images/Totems/Spell_Nature_ManaRegenTotem_edit.blp create mode 100644 Images/Totems/Spell_Nature_RemoveCurse_edit.blp create mode 100644 Images/Totems/Spell_Nature_SlowingTotem_edit.blp create mode 100644 Images/Totems/Spell_Nature_Windfury_edit.blp create mode 100644 Images/UI-Tooltip-Border_round_selfmade.blp create mode 100644 Images/UI-Tooltip-Border_square_selfmade.blp create mode 100644 LICENSE create mode 100644 Lang.lua create mode 100644 Libs/AceComm-3.0/AceComm-3.0.lua create mode 100644 Libs/AceComm-3.0/AceComm-3.0.xml create mode 100644 Libs/AceComm-3.0/ChatThrottleLib.lua create mode 100644 Libs/AceConfig-3.0/AceConfig-3.0.lua create mode 100644 Libs/AceConfig-3.0/AceConfig-3.0.xml create mode 100644 Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua create mode 100644 Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.xml create mode 100644 Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua create mode 100644 Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.xml create mode 100644 Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua create mode 100644 Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.xml create mode 100644 Libs/AceDB-3.0/AceDB-3.0.lua create mode 100644 Libs/AceDB-3.0/AceDB-3.0.xml create mode 100644 Libs/AceDBOptions-3.0/AceDBOptions-3.0.lua create mode 100644 Libs/AceDBOptions-3.0/AceDBOptions-3.0.xml create mode 100644 Libs/AceGUI-3.0-SharedMediaWidgets/AceGUI-3.0-SharedMediaWidgets.toc create mode 100644 Libs/AceGUI-3.0-SharedMediaWidgets/AceGUI-3.0-SharedMediaWidgets/AceGUI-3.0-SharedMediaWidgets.lua create mode 100644 Libs/AceGUI-3.0-SharedMediaWidgets/AceGUI-3.0-SharedMediaWidgets/BackgroundWidget.lua create mode 100644 Libs/AceGUI-3.0-SharedMediaWidgets/AceGUI-3.0-SharedMediaWidgets/BorderWidget.lua create mode 100644 Libs/AceGUI-3.0-SharedMediaWidgets/AceGUI-3.0-SharedMediaWidgets/FontWidget.lua create mode 100644 Libs/AceGUI-3.0-SharedMediaWidgets/AceGUI-3.0-SharedMediaWidgets/SoundWidget.lua create mode 100644 Libs/AceGUI-3.0-SharedMediaWidgets/AceGUI-3.0-SharedMediaWidgets/StatusbarWidget.lua create mode 100644 Libs/AceGUI-3.0-SharedMediaWidgets/AceGUI-3.0-SharedMediaWidgets/prototypes.lua create mode 100644 Libs/AceGUI-3.0-SharedMediaWidgets/AceGUI-3.0-SharedMediaWidgets/widget.xml create mode 100644 Libs/AceGUI-3.0-SharedMediaWidgets/CHANGES.txt create mode 100644 Libs/AceGUI-3.0-SharedMediaWidgets/Changelog-AceGUI-3.0-SharedMediaWidgets-r7.txt create mode 100644 Libs/AceGUI-3.0-SharedMediaWidgets/widget.xml create mode 100644 Libs/AceGUI-3.0/AceGUI-3.0.lua create mode 100644 Libs/AceGUI-3.0/AceGUI-3.0.xml create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIContainer-DropDownGroup.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIContainer-Frame.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIContainer-InlineGroup.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIContainer-ScrollFrame.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIContainer-SimpleGroup.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIContainer-TabGroup.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIContainer-TreeGroup.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIContainer-Window.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIWidget-Button.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIWidget-CheckBox.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIWidget-Heading.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIWidget-Icon.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIWidget-InteractiveLabel.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIWidget-Label.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua create mode 100644 Libs/AceGUI-3.0/widgets/AceGUIWidget-Slider.lua create mode 100644 Libs/AceHook-3.0/AceHook-3.0.lua create mode 100644 Libs/AceHook-3.0/AceHook-3.0.xml create mode 100644 Libs/AceSerializer-3.0/AceSerializer-3.0.lua create mode 100644 Libs/AceSerializer-3.0/AceSerializer-3.0.xml create mode 100644 Libs/AceTimer-3.0/AceTimer-3.0.lua create mode 100644 Libs/AceTimer-3.0/AceTimer-3.0.xml create mode 100644 Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua create mode 100644 Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml create mode 100644 Libs/DRData-1.0/DRData-1.0.lua create mode 100644 Libs/DRData-1.0/DRData-1.0.toc create mode 100644 Libs/DRData-1.0/DRData-1.0.xml create mode 100644 Libs/LibClassAuras-1.0/ClassBuffs.lua create mode 100644 Libs/LibClassAuras-1.0/ClassDebuffs.lua create mode 100644 Libs/LibClassAuras-1.0/LibClassAuras-1.0.lua create mode 100644 Libs/LibClassAuras-1.0/lib.xml create mode 100644 Libs/LibDeflate/LibDeflate.lua create mode 100644 Libs/LibDeflate/lib.xml create mode 100644 Libs/LibSharedMedia-3.0/LibSharedMedia-3.0.lua create mode 100644 Libs/LibSharedMedia-3.0/lib.xml create mode 100644 Libs/LibStub/LibStub.lua create mode 100644 Libs/LibStub/LibStub.toc create mode 100644 Modules/Announcements.lua create mode 100644 Modules/ArenaCountDown.lua create mode 100644 Modules/Auras.lua create mode 100644 Modules/BuffsDebuffs.lua create mode 100644 Modules/Castbar.lua create mode 100644 Modules/Classicon.lua create mode 100644 Modules/Cooldowns.lua create mode 100644 Modules/Diminishings.lua create mode 100644 Modules/ExportImport.lua create mode 100644 Modules/Healthbar.lua create mode 100644 Modules/Highlight.lua create mode 100644 Modules/Pets.lua create mode 100644 Modules/Powerbar.lua create mode 100644 Modules/TotemPlates.lua create mode 100644 Modules/Trinket.lua create mode 100644 Modules/VersionCheck.lua create mode 100644 Modules/XiconProfiles.lua create mode 100644 Options.lua create mode 100644 README.md create mode 100644 embeds.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f00ad52 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.idea +Gladdy +BuffLib +*.zip +*.psd +Ace-Libs +Images_Raw +Gladdy_old \ No newline at end of file diff --git a/Bindings.xml b/Bindings.xml new file mode 100644 index 0000000..2bd08d7 --- /dev/null +++ b/Bindings.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Constants.lua b/Constants.lua new file mode 100644 index 0000000..b6ad45c --- /dev/null +++ b/Constants.lua @@ -0,0 +1,610 @@ +local GetSpellInfo = GetSpellInfo + +local Gladdy = LibStub("Gladdy") +local L = Gladdy.L +local AURA_TYPE_DEBUFF, AURA_TYPE_BUFF = AURA_TYPE_DEBUFF, AURA_TYPE_BUFF + +function Gladdy:GetSpecBuffs() + return { + -- DRUID + [GetSpellInfo(45283)] = L["Restoration"], -- Natural Perfection + [GetSpellInfo(16880)] = L["Restoration"], -- Nature's Grace; Dreamstate spec in TBC equals Restoration + [GetSpellInfo(24858)] = L["Restoration"], -- Moonkin Form; Dreamstate spec in TBC equals Restoration + [GetSpellInfo(17007)] = L["Feral"], -- Leader of the Pack + [GetSpellInfo(16188)] = L["Restoration"], -- Nature's Swiftness + + -- HUNTER + [GetSpellInfo(34692)] = L["Beast Mastery"], -- The Beast Within + [GetSpellInfo(20895)] = L["Beast Mastery"], -- Spirit Bond + [GetSpellInfo(34455)] = L["Beast Mastery"], -- Ferocious Inspiration + [GetSpellInfo(27066)] = L["Marksmanship"], -- Trueshot Aura + + -- MAGE + [GetSpellInfo(33405)] = L["Frost"], -- Ice Barrier + [GetSpellInfo(11129)] = L["Fire"], -- Combustion + [GetSpellInfo(12042)] = L["Arcane"], -- Arcane Power + [GetSpellInfo(12043)] = L["Arcane"], -- Presence of Mind + [GetSpellInfo(12472)] = L["Frost"], -- Icy Veins + + -- PALADIN + [GetSpellInfo(31836)] = L["Holy"], -- Light's Grace + [GetSpellInfo(31842)] = L["Holy"], -- Divine Illumination + [GetSpellInfo(20216)] = L["Holy"], -- Divine Favor + [GetSpellInfo(20375)] = L["Retribution"], -- Seal of Command + [GetSpellInfo(20049)] = L["Retribution"], -- Vengeance + [GetSpellInfo(20218)] = L["Retribution"], -- Sanctity Aura + + -- PRIEST + [GetSpellInfo(15473)] = L["Shadow"], -- Shadowform + [GetSpellInfo(45234)] = L["Discipline"], -- Focused Will + [GetSpellInfo(27811)] = L["Discipline"], -- Blessed Recovery + [GetSpellInfo(33142)] = L["Holy"], -- Blessed Resilience + [GetSpellInfo(14752)] = L["Discipline"], -- Divine Spirit + [GetSpellInfo(27681)] = L["Discipline"], -- Prayer of Spirit + [GetSpellInfo(10060)] = L["Discipline"], -- Power Infusion + [GetSpellInfo(33206)] = L["Discipline"], -- Pain Suppression + [GetSpellInfo(14893)] = L["Discipline"], -- Inspiration + + -- ROGUE + [GetSpellInfo(36554)] = L["Subtlety"], -- Shadowstep + [GetSpellInfo(44373)] = L["Subtlety"], -- Shadowstep Speed + [GetSpellInfo(36563)] = L["Subtlety"], -- Shadowstep DMG + [GetSpellInfo(14278)] = L["Subtlety"], -- Ghostly Strike + [GetSpellInfo(31233)] = L["Assassination"], -- Find Weakness + + --Shaman + [GetSpellInfo(16190)] = L["Restoration"], -- Mana Tide Totem + [GetSpellInfo(32594)] = L["Restoration"], -- Earth Shield + [GetSpellInfo(30823)] = L["Enhancement"], -- Shamanistic Rage + + -- WARLOCK + [GetSpellInfo(19028)] = L["Demonology"], -- Soul Link + [GetSpellInfo(23759)] = L["Demonology"], -- Master Demonologist + [GetSpellInfo(30302)] = L["Destruction"], -- Nether Protection + [GetSpellInfo(34935)] = L["Destruction"], -- Backlash + + -- WARRIOR + [GetSpellInfo(29838)] = L["Arms"], -- Second Wind + [GetSpellInfo(12292)] = L["Arms"], -- Death Wish + + } +end + +function Gladdy:GetSpecSpells() + return { + -- DRUID + [GetSpellInfo(33831)] = L["Balance"], -- Force of Nature + [GetSpellInfo(33983)] = L["Feral"], -- Mangle (Cat) + [GetSpellInfo(33987)] = L["Feral"], -- Mangle (Bear) + [GetSpellInfo(18562)] = L["Restoration"], -- Swiftmend + [GetSpellInfo(16188)] = L["Restoration"], -- Nature's Swiftness + + -- HUNTER + [GetSpellInfo(19577)] = L["Beast Mastery"], -- Intimidation + [GetSpellInfo(34490)] = L["Marksmanship"], -- Silencing Shot + [GetSpellInfo(27068)] = L["Survival"], -- Wyvern Sting + [GetSpellInfo(19306)] = L["Survival"], -- Counterattack + [GetSpellInfo(27066)] = L["Marksmanship"], -- Trueshot Aura + + -- MAGE + [GetSpellInfo(12042)] = L["Arcane"], -- Arcane Power + [GetSpellInfo(33043)] = L["Fire"], -- Dragon's Breath + [GetSpellInfo(33933)] = L["Fire"], -- Blast Wave + [GetSpellInfo(33405)] = L["Frost"], -- Ice Barrier + [GetSpellInfo(31687)] = L["Frost"], -- Summon Water Elemental + [GetSpellInfo(12472)] = L["Frost"], -- Icy Veins + [GetSpellInfo(11958)] = L["Frost"], -- Cold Snap + + -- PALADIN + [GetSpellInfo(33072)] = L["Holy"], -- Holy Shock + [GetSpellInfo(20216)] = L["Holy"], -- Divine Favor + [GetSpellInfo(31842)] = L["Holy"], -- Divine Illumination + [GetSpellInfo(32700)] = L["Protection"], -- Avenger's Shield + [GetSpellInfo(27170)] = L["Retribution"], -- Seal of Command + [GetSpellInfo(35395)] = L["Retribution"], -- Crusader Strike + [GetSpellInfo(20066)] = L["Retribution"], -- Repentance + [GetSpellInfo(20218)] = L["Retribution"], -- Sanctity Aura + + -- PRIEST + [GetSpellInfo(10060)] = L["Discipline"], -- Power Infusion + [GetSpellInfo(33206)] = L["Discipline"], -- Pain Suppression + [GetSpellInfo(14752)] = L["Discipline"], -- Divine Spirit + [GetSpellInfo(33143)] = L["Holy"], -- Blessed Resilience + [GetSpellInfo(34861)] = L["Holy"], -- Circle of Healing + [GetSpellInfo(15473)] = L["Shadow"], -- Shadowform + [GetSpellInfo(34917)] = L["Shadow"], -- Vampiric Touch + + -- ROGUE + [GetSpellInfo(34413)] = L["Assassination"], -- Mutilate + [GetSpellInfo(14177)] = L["Assassination"], -- Cold Blood + [GetSpellInfo(13750)] = L["Combat"], -- Adrenaline Rush + [GetSpellInfo(14185)] = L["Subtlety"], -- Preparation + [GetSpellInfo(16511)] = L["Subtlety"], -- Hemorrhage + [GetSpellInfo(36554)] = L["Subtlety"], -- Shadowstep + [GetSpellInfo(14278)] = L["Subtlety"], -- Ghostly Strike + [GetSpellInfo(14183)] = L["Subtlety"], -- Premeditation + + -- SHAMAN + [GetSpellInfo(16166)] = L["Elemental"], -- Elemental Mastery + [GetSpellInfo(30823)] = L["Enhancement"], -- Shamanistic Rage + [GetSpellInfo(17364)] = L["Enhancement"], -- Stormstrike + [GetSpellInfo(16190)] = L["Restoration"], -- Mana Tide Totem + [GetSpellInfo(32594)] = L["Restoration"], -- Earth Shield + --[GetSpellInfo(16188)] = L["Restoration"], -- Nature's Swiftness + + -- WARLOCK + [GetSpellInfo(30405)] = L["Affliction"], -- Unstable Affliction + --[GetSpellInfo(30911)] = L["Affliction"], -- Siphon Life + [GetSpellInfo(30414)] = L["Destruction"], -- Shadowfury + + -- WARRIOR + [GetSpellInfo(30330)] = L["Arms"], -- Mortal Strike + [GetSpellInfo(12292)] = L["Arms"], -- Death Wish + [GetSpellInfo(30335)] = L["Fury"], -- Bloodthirst + [GetSpellInfo(12809)] = L["Protection"], -- Concussion Blow + [GetSpellInfo(30022)] = L["Protection"], -- Devastation + } +end + +function Gladdy:GetImportantAuras() + return { + -- Cyclone + [GetSpellInfo(33786)] = { + track = AURA_TYPE_DEBUFF, + duration = 6, + priority = 40, + spellID = 33786, + }, + -- Hibername + [GetSpellInfo(18658)] = { + track = AURA_TYPE_DEBUFF, + duration = 10, + priority = 40, + magic = true, + spellID = 18658, + }, + -- Entangling Roots + [GetSpellInfo(26989)] = { + track = AURA_TYPE_DEBUFF, + duration = 10, + priority = 30, + onDamage = true, + magic = true, + root = true, + spellID = 26989, + }, + -- Feral Charge + [GetSpellInfo(16979)] = { + track = AURA_TYPE_DEBUFF, + duration = 4, + priority = 30, + root = true, + spellID = 16979, + }, + -- Bash + [GetSpellInfo(8983)] = { + track = AURA_TYPE_DEBUFF, + duration = 4, + priority = 30, + spellID = 8983, + }, + -- Pounce + [GetSpellInfo(9005)] = { + track = AURA_TYPE_DEBUFF, + duration = 3, + priority = 40, + spellID = 9005, + }, + -- Maim + [GetSpellInfo(22570)] = { + track = AURA_TYPE_DEBUFF, + duration = 6, + priority = 40, + incapacite = true, + spellID = 22570, + }, + -- Innervate + [GetSpellInfo(29166)] = { + track = AURA_TYPE_BUFF, + duration = 20, + priority = 10, + spellID = 29166, + }, + -- Imp Starfire Stun + [GetSpellInfo(16922)] = { + track = AURA_TYPE_DEBUFF, + duration = 3, + priority = 40, + spellSchool = "physical", + spellID = 16922, + }, + + + -- Freezing Trap Effect + [GetSpellInfo(14309)] = { + track = AURA_TYPE_DEBUFF, + duration = 10, + priority = 40, + onDamage = true, + magic = true, + spellID = 14309, + }, + -- Wyvern Sting + [GetSpellInfo(19386)] = { + track = AURA_TYPE_DEBUFF, + duration = 10, + priority = 40, + onDamage = true, + poison = true, + sleep = true, + spellID = 19386, + }, + -- Scatter Shot + [GetSpellInfo(19503)] = { + track = AURA_TYPE_DEBUFF, + duration = 4, + priority = 40, + onDamage = true, + spellID = 19503, + }, + -- Silencing Shot + [GetSpellInfo(34490)] = { + track = AURA_TYPE_DEBUFF, + duration = 3, + priority = 15, + magic = true, + spellID = 34490, + }, + -- Intimidation + [GetSpellInfo(19577)] = { + track = AURA_TYPE_DEBUFF, + duration = 2, + priority = 40, + spellID = 19577, + }, + -- The Beast Within + [GetSpellInfo(34692)] = { + track = AURA_TYPE_BUFF, + duration = 18, + priority = 20, + spellID = 34692, + }, + + + -- Polymorph + [GetSpellInfo(12826)] = { + track = AURA_TYPE_DEBUFF, + duration = 10, + priority = 40, + onDamage = true, + magic = true, + spellID = 12826, + }, + -- Dragon's Breath + [GetSpellInfo(31661)] = { + track = AURA_TYPE_DEBUFF, + duration = 3, + priority = 40, + onDamage = true, + magic = true, + spellID = 31661, + }, + -- Frost Nova + [GetSpellInfo(27088)] = { + track = AURA_TYPE_DEBUFF, + duration = 8, + priority = 30, + onDamage = true, + magic = true, + root = true, + spellID = 27088, + }, + -- Freeze (Water Elemental) + [GetSpellInfo(33395)] = { + track = AURA_TYPE_DEBUFF, + duration = 8, + priority = 30, + onDamage = true, + magic = true, + root = true, + spellID = 33395, + }, + -- Counterspell - Silence + [GetSpellInfo(18469)] = { + track = AURA_TYPE_DEBUFF, + duration = 4, + priority = 15, + magic = true, + spellID = 18469, + }, + -- Ice Block + [GetSpellInfo(45438)] = { + track = AURA_TYPE_BUFF, + duration = 10, + priority = 20, + spellID = 45438, + }, + -- Impact + [GetSpellInfo(12355)] = { + track = AURA_TYPE_DEBUFF, + duration = 2, + priority = 40, + spellID = 12355, + }, + + -- Hammer of Justice + [GetSpellInfo(10308)] = { + track = AURA_TYPE_DEBUFF, + duration = 6, + priority = 40, + magic = true, + spellID = 10308, + }, + -- Repentance + [GetSpellInfo(20066)] = { + track = AURA_TYPE_DEBUFF, + duration = 6, + priority = 40, + onDamage = true, + magic = true, + incapacite = true, + spellID = 20066, + }, + -- Blessing of Protection + [GetSpellInfo(10278)] = { + track = AURA_TYPE_BUFF, + duration = 10, + priority = 10, + spellID = 10278, + }, + -- Blessing of Freedom + [GetSpellInfo(1044)] = { + track = AURA_TYPE_BUFF, + duration = 14, + priority = 10, + spellID = 1044, + }, + -- Divine Shield + [GetSpellInfo(642)] = { + track = AURA_TYPE_BUFF, + duration = 12, + priority = 20, + spellID = 642, + }, + + + -- Psychic Scream + [GetSpellInfo(8122)] = { + track = AURA_TYPE_DEBUFF, + duration = 8, + priority = 40, + onDamage = true, + fear = true, + magic = true, + spellID = 8122, + }, + -- Chastise + [GetSpellInfo(44047)] = { + track = AURA_TYPE_DEBUFF, + duration = 8, + priority = 30, + root = true, + spellID = 44047, + }, + -- Mind Control + [GetSpellInfo(605)] = { + track = AURA_TYPE_DEBUFF, + duration = 10, + priority = 40, + magic = true, + spellID = 605, + }, + -- Silence + [GetSpellInfo(15487)] = { + track = AURA_TYPE_DEBUFF, + duration = 5, + priority = 15, + magic = true, + spellID = 15487, + }, + -- Pain Suppression + [GetSpellInfo(33206)] = { + track = AURA_TYPE_BUFF, + duration = 8, + priority = 10, + spellID = 33206, + }, + + + -- Sap + [GetSpellInfo(6770)] = { + track = AURA_TYPE_DEBUFF, + duration = 10, + priority = 40, + onDamage = true, + incapacite = true, + spellID = 6770, + }, + -- Blind + [GetSpellInfo(2094)] = { + track = AURA_TYPE_DEBUFF, + duration = 10, + priority = 40, + onDamage = true, + spellID = 2094, + }, + -- Cheap Shot + [GetSpellInfo(1833)] = { + track = AURA_TYPE_DEBUFF, + duration = 4, + priority = 40, + spellID = 1833, + }, + -- Kidney Shot + [GetSpellInfo(8643)] = { + track = AURA_TYPE_DEBUFF, + duration = 6, + priority = 40, + spellID = 8643, + }, + -- Gouge + [GetSpellInfo(1776)] = { + track = AURA_TYPE_DEBUFF, + duration = 4, + priority = 40, + onDamage = true, + incapacite = true, + spellID = 1776, + }, + -- Kick - Silence + [GetSpellInfo(18425)] = { + track = AURA_TYPE_DEBUFF, + duration = 2, + priority = 15, + spellID = 18425, + }, + -- Garrote - Silence + [GetSpellInfo(1330)] = { + track = AURA_TYPE_DEBUFF, + duration = 3, + priority = 15, + spellID = 1330, + }, + -- Cloak of Shadows + [GetSpellInfo(31224)] = { + track = AURA_TYPE_BUFF, + duration = 5, + priority = 20, + spellID = 31224, + }, + + + -- Fear + [GetSpellInfo(5782)] = { + track = AURA_TYPE_DEBUFF, + duration = 10, + priority = 40, + onDamage = true, + fear = true, + magic = true, + spellID = 5782, + }, + -- Death Coil + [GetSpellInfo(27223)] = { + track = AURA_TYPE_DEBUFF, + duration = 3, + priority = 40, + spellID = 27223, + }, + -- Shadowfury + [GetSpellInfo(30283)] = { + track = AURA_TYPE_DEBUFF, + duration = 2, + priority = 40, + magic = true, + spellID = 30283, + }, + -- Seduction (Succubus) + [GetSpellInfo(6358)] = { + track = AURA_TYPE_DEBUFF, + duration = 10, + priority = 40, + onDamage = true, + fear = true, + magic = true, + spellID = 6358, + }, + -- Howl of Terror + [GetSpellInfo(5484)] = { + track = AURA_TYPE_DEBUFF, + duration = 8, + priority = 40, + onDamage = true, + fear = true, + magic = true, + spellID = 5484, + texture = select(3, GetSpellInfo(5484)) + }, + -- Spell Lock (Felhunter) + [GetSpellInfo(24259)] = { + track = AURA_TYPE_DEBUFF, + duration = 3, + priority = 15, + magic = true, + spellID = 24259, + }, + -- Unstable Affliction Silence + ["Unstable Affliction Silence"] = { -- GetSpellInfo returns "Unstable Affliction" + track = AURA_TYPE_DEBUFF, + duration = 5, + priority = 15, + magic = true, + spellID = 31117, + }, + + + -- Intimidating Shout + [GetSpellInfo(5246)] = { + track = AURA_TYPE_DEBUFF, + duration = 8, + priority = 15, + onDamage = true, + fear = true, + spellID = 5246, + }, + -- Concussion Blow + [GetSpellInfo(12809)] = { + track = AURA_TYPE_DEBUFF, + duration = 5, + priority = 40, + spellID = 12809, + }, + -- Intercept Stun + [GetSpellInfo(25274)] = { + track = AURA_TYPE_DEBUFF, + duration = 3, + priority = 40, + spellID = 25274, + }, + -- Spell Reflection + [GetSpellInfo(23920)] = { + track = AURA_TYPE_BUFF, + duration = 5, + priority = 50, + spellID = 23920, + }, + -- Shield Bash - Silenced + [GetSpellInfo(18498)] = { + track = AURA_TYPE_DEBUFF, + duration = 3, + priority = 15, + spellSchool = "magic", + spellID = 18498, + }, + + -- Grounding Totem Effect + [GetSpellInfo(8178)] = { + track = AURA_TYPE_BUFF, + duration = 0, + priority = 20, + spellID = 8178 + }, + + + -- War Stomp + [GetSpellInfo(20549)] = { + track = AURA_TYPE_DEBUFF, + duration = 2, + priority = 40, + spellID = 20549, + }, + -- Arcane Torrent + [GetSpellInfo(28730)] = { + track = AURA_TYPE_DEBUFF, + duration = 2, + priority = 15, + magic = true, + spellID = 28730, + }, + } +end \ No newline at end of file diff --git a/EventListener.lua b/EventListener.lua new file mode 100644 index 0000000..b16a00f --- /dev/null +++ b/EventListener.lua @@ -0,0 +1,251 @@ +local select, string_gsub = select, string.gsub + +local CombatLogGetCurrentEventInfo = CombatLogGetCurrentEventInfo +local RAID_CLASS_COLORS = RAID_CLASS_COLORS +local AURA_TYPE_DEBUFF = AURA_TYPE_DEBUFF +local AURA_TYPE_BUFF = AURA_TYPE_BUFF + +local UnitName, UnitAura, UnitRace, UnitClass, UnitGUID, UnitIsUnit = UnitName, UnitAura, UnitRace, UnitClass, UnitGUID, UnitIsUnit +local UnitCastingInfo, UnitChannelInfo = UnitCastingInfo, UnitChannelInfo +local GetSpellInfo = GetSpellInfo +local FindAuraByName = AuraUtil.FindAuraByName + +local Gladdy = LibStub("Gladdy") +local Cooldowns = Gladdy.modules["Cooldowns"] +local Diminishings = Gladdy.modules["Diminishings"] + +local EventListener = Gladdy:NewModule("EventListener", nil, { + test = true, +}) + +function EventListener:Initialize() + self:RegisterMessage("JOINED_ARENA") +end + +function EventListener.OnEvent(self, event, ...) + EventListener[event](self, ...) +end + +function EventListener:JOINED_ARENA() + self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") + self:RegisterEvent("ARENA_OPPONENT_UPDATE") + self:RegisterEvent("UNIT_AURA") + self:RegisterEvent("UNIT_SPELLCAST_START") + self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START") + self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED") + self:SetScript("OnEvent", EventListener.OnEvent) + Gladdy:SendCommMessage("GladdyVCheck", Gladdy.version, "RAID", UnitName("player")) +end + +function EventListener:Reset() + self:UnregisterAllEvents() + self:SetScript("OnEvent", nil) +end + +function Gladdy:DetectSpec(unit, specSpell) + if specSpell then + self.modules["Cooldowns"]:DetectSpec(unit, specSpell) + end +end + +function Gladdy:SpotEnemy(unit, auraScan) + local button = self.buttons[unit] + button.raceLoc = UnitRace(unit) + button.race = select(2, UnitRace(unit)) + button.classLoc = select(1, UnitClass(unit)) + button.class = select(2, UnitClass(unit)) + button.name = UnitName(unit) + button.stealthed = false + Gladdy.guids[UnitGUID(unit)] = unit + Gladdy:SendMessage("ENEMY_SPOTTED", unit) + if auraScan and not button.spec then + for n = 1, 30 do + local spellName,_,_,_,_,_,unitCaster = UnitAura(unit, n, "HELPFUL") + if ( not spellName ) then + break + end + if Gladdy.specBuffs[spellName] then + local unitPet = string_gsub(unit, "%d$", "pet%1") + if UnitIsUnit(unit, unitCaster) or UnitIsUnit(unitPet, unitCaster) then + Gladdy:DetectSpec(unit, Gladdy.specBuffs[spellName]) + end + end + end + end +end + +function EventListener:COMBAT_LOG_EVENT_UNFILTERED() + -- timestamp,eventType,hideCaster,sourceGUID,sourceName,sourceFlags,sourceRaidFlags,destGUID,destName,destFlags,destRaidFlags,spellId,spellName,spellSchool + local _,eventType,_,sourceGUID,_,_,_,destGUID,_,_,_,spellID,spellName = CombatLogGetCurrentEventInfo() + local srcUnit = Gladdy.guids[sourceGUID] + local destUnit = Gladdy.guids[destGUID] + + if Gladdy.specSpells[spellName] and srcUnit then + --Gladdy:Print(eventType, spellName, Gladdy.specSpells[spellName], srcUnit) + end + if (eventType == "UNIT_DIED" or eventType == "PARTY_KILL" or eventType == "SPELL_INSTAKILL") then + if destUnit then + --Gladdy:Print(eventType, "destUnit", destUnit) + elseif srcUnit then + --Gladdy:Print(eventType, "srcUnit", srcUnit) + end + end + + if destUnit then + -- diminish tracker + if (Gladdy.db.drEnabled and (eventType == "SPELL_AURA_REMOVED" or eventType == "SPELL_AURA_REFRESH")) then + Diminishings:AuraFade(destUnit, spellID) + end + -- death detection + if (eventType == "UNIT_DIED" or eventType == "PARTY_KILL" or eventType == "SPELL_INSTAKILL") then + Gladdy:SendMessage("UNIT_DEATH", destUnit) + end + -- spec detection + if not Gladdy.buttons[destUnit].class then + Gladdy:SpotEnemy(destUnit, true) + end + end + if srcUnit then + -- cooldown tracker + if Gladdy.db.cooldown and Cooldowns.cooldownSpellIds[spellName] then + local unitClass + local spellId = Cooldowns.cooldownSpellIds[spellName] -- don't use spellId from combatlog, in case of different spellrank + if (Cooldowns.cooldownSpells[Gladdy.buttons[srcUnit].class][spellId]) then + unitClass = Gladdy.buttons[srcUnit].class + else + unitClass = Gladdy.buttons[srcUnit].race + end + Cooldowns:CooldownUsed(srcUnit, unitClass, spellId, spellName) + Gladdy:DetectSpec(srcUnit, Gladdy.specSpells[spellName]) + end + + if not Gladdy.buttons[srcUnit].class then + Gladdy:SpotEnemy(srcUnit, true) + end + if not Gladdy.buttons[srcUnit].spec then + Gladdy:DetectSpec(srcUnit, Gladdy.specSpells[spellName]) + end + end +end + +function EventListener:ARENA_OPPONENT_UPDATE(unit, updateReason) + --[[ updateReason: seen, unseen, destroyed, cleared ]] + + local button = Gladdy.buttons[unit] + local pet = Gladdy.modules["Pets"].frames[unit] + if button or pet then + if updateReason == "seen" then + -- ENEMY_SPOTTED + if button and not button.class then + Gladdy:SpotEnemy(unit, true) + end + if button and button.stealthed then + local class = Gladdy.buttons[unit].class + button.healthBar.hp:SetStatusBarColor(RAID_CLASS_COLORS[class].r, RAID_CLASS_COLORS[class].g, RAID_CLASS_COLORS[class].b, 1) + end + if pet then + Gladdy:SendMessage("PET_SPOTTED", unit) + end + elseif updateReason == "unseen" then + -- STEALTH + if button then + Gladdy:SendMessage("ENEMY_STEALTH", unit) + button.healthBar.hp:SetStatusBarColor(0.66, 0.66, 0.66, 1) + button.stealthed = true + end + if pet then + Gladdy:SendMessage("PET_STEALTH", unit) + end + elseif updateReason == "destroyed" then + -- LEAVE + if button then + Gladdy:SendMessage("UNIT_DESTROYED", unit) + end + if pet then + Gladdy:SendMessage("PET_DESTROYED", unit) + end + elseif updateReason == "cleared" then + --Gladdy:Print("ARENA_OPPONENT_UPDATE", updateReason, unit) + end + end +end + +local exceptionNames = { + [31117] = GetSpellInfo(30405) .. " Silence", -- Unstable Affliction Silence + [43523] = GetSpellInfo(30405) .. " Silence", + [24131] = select(1, GetSpellInfo(19386)) .. " Dot", -- Wyvern Sting Dot + [24134] = select(1, GetSpellInfo(19386)) .. " Dot", + [24135] = select(1, GetSpellInfo(19386)) .. " Dot", + [27069] = select(1, GetSpellInfo(19386)) .. " Dot", + [19975] = select(1, GetSpellInfo(27010)) .. " " .. select(1, GetSpellInfo(16689)), -- Entangling Roots Nature's Grasp + [19974] = select(1, GetSpellInfo(27010)) .. " " .. select(1, GetSpellInfo(16689)), + [19973] = select(1, GetSpellInfo(27010)) .. " " .. select(1, GetSpellInfo(16689)), + [19972] = select(1, GetSpellInfo(27010)) .. " " .. select(1, GetSpellInfo(16689)), + [19971] = select(1, GetSpellInfo(27010)) .. " " .. select(1, GetSpellInfo(16689)), + [19971] = select(1, GetSpellInfo(27010)) .. " " .. select(1, GetSpellInfo(16689)), + [27010] = select(1, GetSpellInfo(27010)) .. " " .. select(1, GetSpellInfo(16689)), +} + +function EventListener:UNIT_AURA(unit) + local button = Gladdy.buttons[unit] + if not button then + return + end + for i = 1, 2 do + if not Gladdy.buttons[unit].class then + Gladdy:SpotEnemy(unit, false) + end + local filter = (i == 1 and "HELPFUL" or "HARMFUL") + local auraType = i == 1 and AURA_TYPE_BUFF or AURA_TYPE_DEBUFF + Gladdy:SendMessage("AURA_FADE", unit, auraType) + for n = 1, 30 do + local spellName, texture, count, debuffType, duration, expirationTime, unitCaster, _, shouldConsolidate, spellID = UnitAura(unit, n, filter) + if ( not spellID ) then + Gladdy:SendMessage("AURA_GAIN_LIMIT", unit, auraType, n - 1) + break + end + if not button.spec and Gladdy.specBuffs[spellName] then + local unitPet = string_gsub(unit, "%d$", "pet%1") + if UnitIsUnit(unit, unitCaster) or UnitIsUnit(unitPet, unitCaster) then + Gladdy:DetectSpec(unit, Gladdy.specBuffs[spellName]) + end + end + if exceptionNames[spellID] then + spellName = exceptionNames[spellID] + end + Gladdy:SendMessage("AURA_GAIN", unit, auraType, spellID, spellName, texture, duration, expirationTime, count, debuffType, i) + Gladdy:Call("Announcements", "CheckDrink", unit, spellName) + end + end +end + +function EventListener:UNIT_SPELLCAST_START(unit) + if Gladdy.buttons[unit] then + local spellName = UnitCastingInfo(unit) + if Gladdy.specSpells[spellName] and not Gladdy.buttons[unit].spec then + Gladdy:DetectSpec(unit, Gladdy.specSpells[spellName]) + end + end +end + +function EventListener:UNIT_SPELLCAST_CHANNEL_START(unit) + if Gladdy.buttons[unit] then + local spellName = UnitChannelInfo(unit) + if Gladdy.specSpells[spellName] and not Gladdy.buttons[unit].spec then + Gladdy:DetectSpec(unit, Gladdy.specSpells[spellName]) + end + end +end + +function EventListener:UNIT_SPELLCAST_SUCCEEDED(unit) + if Gladdy.buttons[unit] then + local spellName = UnitCastingInfo(unit) + if Gladdy.specSpells[spellName] and not Gladdy.buttons[unit].spec then + Gladdy:DetectSpec(unit, Gladdy.specSpells[spellName]) + end + end +end + +function EventListener:GetOptions() + return nil +end diff --git a/Frame.lua b/Frame.lua new file mode 100644 index 0000000..bd1cb9a --- /dev/null +++ b/Frame.lua @@ -0,0 +1,287 @@ +local CreateFrame = CreateFrame +local UIParent = UIParent +local InCombatLockdown = InCombatLockdown + +local Gladdy = LibStub("Gladdy") +local L = Gladdy.L + +Gladdy.BUTTON_DEFAULTS = { + name = "", + guid = "", + raceLoc = "", + classLoc = "", + class = "", + health = "", + healthMax = 0, + power = 0, + powerMax = 0, + powerType = 0, + spec = "", + testSpec = "", + spells = {}, + ns = false, + nf = false, + pom = false, + fd = false, + damaged = 0, + click = false, + stealthed = false, +} + +function Gladdy:CreateFrame() + self.frame = CreateFrame("Frame", "GladdyFrame", UIParent) + + self.frame:SetClampedToScreen(true) + self.frame:EnableMouse(true) + self.frame:SetMovable(true) + self.frame:RegisterForDrag("LeftButton") + + self.frame:SetScript("OnDragStart", function(f) + if (not InCombatLockdown() and not self.db.locked) then + f:StartMoving() + end + end) + self.frame:SetScript("OnDragStop", function(f) + if (not InCombatLockdown()) then + f:StopMovingOrSizing() + + local scale = f:GetEffectiveScale() + self.db.x = f:GetLeft() * scale + self.db.y = (self.db.growUp and f:GetBottom() or f:GetTop()) * scale + end + end) + + self.anchor = CreateFrame("Button", "GladdyAnchor", self.frame, BackdropTemplateMixin and "BackdropTemplate") + self.anchor:SetHeight(20) + self.anchor:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16 }) + self.anchor:SetBackdropColor(0, 0, 0, 1) + self.anchor:SetClampedToScreen(true) + self.anchor:EnableMouse(true) + self.anchor:SetMovable(true) + self.anchor:RegisterForDrag("LeftButton") + self.anchor:RegisterForClicks("RightButtonUp") + self.anchor:SetScript("OnDragStart", function() + if (not InCombatLockdown() and not self.db.locked) then + self.frame:StartMoving() + end + end) + self.anchor:SetScript("OnDragStop", function() + if (not InCombatLockdown()) then + self.frame:StopMovingOrSizing() + + local scale = self.frame:GetEffectiveScale() + self.db.x = self.frame:GetLeft() * scale + self.db.y = (self.db.growUp and self.frame:GetBottom() or self.frame:GetTop()) * scale + end + end) + self.anchor:SetScript("OnClick", function() + if (not InCombatLockdown()) then + self:ShowOptions() + end + end) + + self.anchor.text = self.anchor:CreateFontString("GladdyAnchorText", "ARTWORK", "GameFontHighlightSmall") + self.anchor.text:SetText(L["Gladdy - drag to move"]) + self.anchor.text:SetPoint("CENTER") + + self.anchor.button = CreateFrame("Button", "GladdyAnchorButton", self.anchor, "UIPanelCloseButton") + self.anchor.button:SetWidth(20) + self.anchor.button:SetHeight(20) + self.anchor.button:SetPoint("RIGHT", self.anchor, "RIGHT", 2, 0) + self.anchor.button:SetScript("OnClick", function(_, _, down) + if (not down) then + self.db.locked = true + self:UpdateFrame() + end + end) + + if (self.db.locked) then + self.anchor:Hide() + end + + self.frame:Hide() +end + +function Gladdy:UpdateFrame() + + if (not self.frame) then + self:CreateFrame() + end + local teamSize = self.curBracket or 0 + + local iconSize = self.db.healthBarHeight + local margin = 0 + local width = self.db.barWidth + self.db.padding * 2 + 5 + local height = self.db.healthBarHeight * teamSize + margin * (teamSize - 1) + self.db.padding * 2 + 5 + local extraBarWidth = 0 + local extraBarHeight = 0 + + -- Powerbar + iconSize = iconSize + self.db.powerBarHeight + margin = margin + self.db.powerBarHeight + height = height + self.db.powerBarHeight * teamSize + extraBarHeight = extraBarHeight + self.db.powerBarHeight + + -- Cooldown + margin = margin + 1 + self.db.highlightBorderSize * 2 + 1 -- + 1 space between health and power bar + height = height + self.db.highlightBorderSize * teamSize + + if (self.db.cooldownYPos == "TOP" or self.db.cooldownYPos == "BOTTOM") and self.db.cooldown then + margin = margin + self.db.cooldownSize + height = height + self.db.cooldownSize * teamSize + end + if (self.db.buffsCooldownPos == "TOP" or self.db.buffsCooldownPos == "BOTTOM") and self.db.buffsEnabled then + margin = margin + self.db.buffsIconSize + height = height + self.db.buffsIconSize * teamSize + end + if (self.db.buffsBuffsCooldownPos == "TOP" or self.db.buffsBuffsCooldownPos == "BOTTOM") and self.db.buffsEnabled then + margin = margin + self.db.buffsBuffsIconSize + height = height + self.db.buffsBuffsIconSize * teamSize + end + if self.db.buffsCooldownPos == "TOP" and self.db.cooldownYPos == "TOP" and self.db.cooldown and self.db.buffsEnabled then + margin = margin + 1 + end + if self.db.buffsCooldownPos == "BOTTOM" and self.db.cooldownYPos == "BOTTOM" and self.db.cooldown and self.db.buffsEnabled then + margin = margin + 1 + end + + -- Classicon + width = width + iconSize + extraBarWidth = extraBarWidth + iconSize + + -- Trinket + width = width + iconSize + + self.frame:SetScale(self.db.frameScale) + self.frame:SetWidth(width) + self.frame:SetHeight(height) + --self.frame:SetBackdropColor(self.db.frameColor.r, self.db.frameColor.g, self.db.frameColor.b, self.db.frameColor.a) + self.frame:ClearAllPoints() + if (self.db.x == 0 and self.db.y == 0) then + self.frame:SetPoint("CENTER") + else + local scale = self.frame:GetEffectiveScale() + if (self.db.growUp) then + self.frame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", self.db.x / scale, self.db.y / scale) + else + self.frame:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", self.db.x / scale, self.db.y / scale) + end + end + + self.anchor:SetWidth(width) + self.anchor:ClearAllPoints() + if (self.db.growUp) then + self.anchor:SetPoint("TOPLEFT", self.frame, "BOTTOMLEFT") + else + self.anchor:SetPoint("BOTTOMLEFT", self.frame, "TOPLEFT") + end + + if (self.db.locked) then + self.anchor:Hide() + self.anchor:Hide() + else + self.anchor:Show() + end + + for i = 1, teamSize do + local button = self.buttons["arena" .. i] + button:SetWidth(self.db.barWidth + extraBarWidth) + button:SetHeight(self.db.healthBarHeight) + button.secure:SetWidth(self.db.barWidth + extraBarWidth) + button.secure:SetHeight(self.db.healthBarHeight + extraBarHeight) + + button:ClearAllPoints() + button.secure:ClearAllPoints() + if (self.db.growUp) then + if (i == 1) then + button:SetPoint("BOTTOMLEFT", self.frame, "BOTTOMLEFT", self.db.padding + 2, 0) + button.secure:SetPoint("BOTTOMLEFT", self.frame, "BOTTOMLEFT", self.db.padding + 2, 0) + else + button:SetPoint("BOTTOMLEFT", self.buttons["arena" .. (i - 1)], "TOPLEFT", 0, margin + self.db.bottomMargin) + button.secure:SetPoint("BOTTOMLEFT", self.buttons["arena" .. (i - 1)], "TOPLEFT", 0, margin + self.db.bottomMargin) + end + else + if (i == 1) then + button:SetPoint("TOPLEFT", self.frame, "TOPLEFT", self.db.padding + 2, 0) + button.secure:SetPoint("TOPLEFT", self.frame, "TOPLEFT", self.db.padding + 2, 0) + else + button:SetPoint("TOPLEFT", self.buttons["arena" .. (i - 1)], "BOTTOMLEFT", 0, -margin - self.db.bottomMargin) + button.secure:SetPoint("TOPLEFT", self.buttons["arena" .. (i - 1)], "BOTTOMLEFT", 0, -margin - self.db.bottomMargin) + end + end + + + for k, v in self:IterModules() do + self:Call(v, "UpdateFrame", button.unit) + end + end + for k, v in self:IterModules() do + self:Call(v, "UpdateFrameOnce") + end +end + +function Gladdy:HideFrame() + if (self.frame) then + self.frame:Hide() + self.frame.testing = nil + end +end + +function Gladdy:ToggleFrame(i) + self:Reset() + + if (self.frame and self.frame:IsShown() and i == self.curBracket) then + self:HideFrame() + else + self.curBracket = i + + if (not self.frame) then + self:CreateFrame() + end + + for o = 1, self.curBracket do + local unit = "arena" .. o + if (not self.buttons[unit]) then + self:CreateButton(o) + end + end + self:UpdateFrame() + self:Test() + self.frame:Show() + end +end + +function Gladdy:CreateButton(i) + if (not self.frame) then + self:CreateFrame() + end + + local button = CreateFrame("Frame", "GladdyButtonFrame" .. i, self.frame) + button:SetAlpha(0) + + local secure = CreateFrame("Button", "GladdyButton" .. i, button, "SecureActionButtonTemplate") + secure:RegisterForClicks("AnyUp") + secure:RegisterForClicks("AnyUp") + secure:SetAttribute("*type1", "target") + secure:SetAttribute("*type2", "focus") + secure:SetAttribute("unit", "arena" .. i) + + button:RegisterEvent("UNIT_NAME_UPDATE") + button:RegisterEvent("ARENA_OPPONENT_UPDATE") + button:RegisterEvent("ARENA_COOLDOWNS_UPDATE") + button:RegisterEvent("ARENA_CROWD_CONTROL_SPELL_UPDATE") + button:RegisterUnitEvent("UNIT_CONNECTION", "arena" .. i) + + button.id = i + button.unit = "arena" .. i + button.secure = secure + + + self:ResetButton(button.unit) + + self.buttons[button.unit] = button + + for k, v in self:IterModules() do + self:Call(v, "CreateFrame", button.unit) + end +end \ No newline at end of file diff --git a/Gladdy.lua b/Gladdy.lua new file mode 100644 index 0000000..f4d39cc --- /dev/null +++ b/Gladdy.lua @@ -0,0 +1,388 @@ +local setmetatable = setmetatable +local type = type +local tostring = tostring +local select = select +local pairs = pairs +local tinsert = table.insert +local tsort = table.sort +local CreateFrame = CreateFrame +local DEFAULT_CHAT_FRAME = DEFAULT_CHAT_FRAME +local IsAddOnLoaded = IsAddOnLoaded +local IsInInstance = IsInInstance +local GetBattlefieldStatus = GetBattlefieldStatus +local IsActiveBattlefieldArena = IsActiveBattlefieldArena + +--------------------------- + +-- CORE + +--------------------------- + +local MAJOR, MINOR = "Gladdy", 4 +local Gladdy = LibStub:NewLibrary(MAJOR, MINOR) +local L +Gladdy.version_major = "TBC-Classic_v1" +Gladdy.version_minor = "0.3-Beta" +Gladdy.version = Gladdy.version_major .. "." .. Gladdy.version_minor + +LibStub("AceTimer-3.0"):Embed(Gladdy) +LibStub("AceComm-3.0"):Embed(Gladdy) +Gladdy.modules = {} +setmetatable(Gladdy, { + __tostring = function() + return MAJOR + end +}) + +function Gladdy:Print(...) + local text = "|cff0384fcGladdy|r:" + local val + for i = 1, select("#", ...) do + val = select(i, ...) + if (type(val) == 'boolean') then val = val and "true" or false end + text = text .. " " .. tostring(val) + end + DEFAULT_CHAT_FRAME:AddMessage(text) +end + +function Gladdy:Warn(...) + local text = "|cfffc0303Gladdy|r:" + local val + for i = 1, select("#", ...) do + val = select(i, ...) + if (type(val) == 'boolean') then val = val and "true" or false end + text = text .. " " .. tostring(val) + end + DEFAULT_CHAT_FRAME:AddMessage(text) +end + +Gladdy.events = CreateFrame("Frame") +Gladdy.events.registered = {} +Gladdy.events:RegisterEvent("PLAYER_LOGIN") +Gladdy.events:SetScript("OnEvent", function(self, event, ...) + if (event == "PLAYER_LOGIN") then + Gladdy:OnInitialize() + Gladdy:OnEnable() + else + local func = self.registered[event] + + if (type(Gladdy[func]) == "function") then + Gladdy[func](Gladdy, event, ...) + end + end +end) + +function Gladdy:RegisterEvent(event, func) + self.events.registered[event] = func or event + self.events:RegisterEvent(event) +end +function Gladdy:UnregisterEvent(event) + self.events.registered[event] = nil + self.events:UnregisterEvent(event) +end +function Gladdy:UnregisterAllEvents() + self.events.registered = {} + self.events:UnregisterAllEvents() +end + +--------------------------- + +-- MODULE FUNCTIONS + +--------------------------- + +local function pairsByPrio(t) + local a = {} + for k, v in pairs(t) do + tinsert(a, { k, v.priority }) + end + tsort(a, function(x, y) + return x[2] > y[2] + end) + + local i = 0 + return function() + i = i + 1 + + if (a[i] ~= nil) then + return a[i][1], t[a[i][1]] + else + return nil + end + end +end +function Gladdy:IterModules() + return pairsByPrio(self.modules) +end + +function Gladdy:Call(module, func, ...) + if (type(module) == "string") then + module = self.modules[module] + end + + if (type(module[func]) == "function") then + module[func](module, ...) + end +end +function Gladdy:SendMessage(message, ...) + for k, v in self:IterModules() do + self:Call(v, v.messages[message], ...) + end +end + +function Gladdy:NewModule(name, priority, defaults) + local module = CreateFrame("Frame") + module.name = name + module.priority = priority or 0 + module.defaults = defaults or {} + module.messages = {} + + module.RegisterMessage = function(self, message, func) + self.messages[message] = func or message + end + + module.GetOptions = function() + return nil + end + + for k, v in pairs(module.defaults) do + self.defaults.profile[k] = v + end + + self.modules[name] = module + + return module +end + +--------------------------- + +-- INIT + +--------------------------- + +function Gladdy:OnInitialize() + self.dbi = LibStub("AceDB-3.0"):New("GladdyXZ", self.defaults) + self.dbi.RegisterCallback(self, "OnProfileChanged", "OnProfileChanged") + self.dbi.RegisterCallback(self, "OnProfileCopied", "OnProfileChanged") + self.dbi.RegisterCallback(self, "OnProfileReset", "OnProfileChanged") + self.db = self.dbi.profile + + self.LSM = LibStub("LibSharedMedia-3.0") + self.LSM:Register("statusbar", "Gloss", "Interface\\AddOns\\Gladdy\\Images\\Gloss") + self.LSM:Register("statusbar", "Smooth", "Interface\\AddOns\\Gladdy\\Images\\Smooth") + self.LSM:Register("statusbar", "Minimalist", "Interface\\AddOns\\Gladdy\\Images\\Minimalist") + self.LSM:Register("statusbar", "LiteStep", "Interface\\AddOns\\Gladdy\\Images\\LiteStep.tga") + self.LSM:Register("border", "Gladdy Tooltip round", "Interface\\AddOns\\Gladdy\\Images\\UI-Tooltip-Border_round_selfmade") + self.LSM:Register("border", "Gladdy Tooltip squared", "Interface\\AddOns\\Gladdy\\Images\\UI-Tooltip-Border_square_selfmade") + self.LSM:Register("font", "DorisPP", "Interface\\AddOns\\Gladdy\\Images\\DorisPP.TTF") + + L = self.L + + self.testData = { + ["arena1"] = { name = "Swift", raceLoc = L["Tauren"], classLoc = L["Warrior"], class = "WARRIOR", health = 9635, healthMax = 14207, power = 76, powerMax = 100, powerType = 1, testSpec = L["Arms"], race = "Tauren" }, + ["arena2"] = { name = "Vilden", raceLoc = L["Undead"], classLoc = L["Mage"], class = "MAGE", health = 10969, healthMax = 11023, power = 7833, powerMax = 10460, powerType = 0, testSpec = L["Frost"], race = "Scourge" }, + ["arena3"] = { name = "Krymu", raceLoc = L["Human"], classLoc = L["Rogue"], class = "ROGUE", health = 1592, healthMax = 11740, power = 45, powerMax = 110, powerType = 3, testSpec = L["Subtlety"], race = "Human" }, + ["arena4"] = { name = "Talmon", raceLoc = L["Human"], classLoc = L["Warlock"], class = "WARLOCK", health = 10221, healthMax = 14960, power = 9855, powerMax = 9855, powerType = 0, testSpec = L["Demonology"], race = "Human" }, + ["arena5"] = { name = "Hydra", raceLoc = L["Undead"], classLoc = L["Priest"], class = "PRIEST", health = 11960, healthMax = 11960, power = 2515, powerMax = 10240, powerType = 0, testSpec = L["Discipline"], race = "Human" }, + } + + self.cooldownSpellIds = {} + self.spellTextures = {} + self.specBuffs = self:GetSpecBuffs() + self.specSpells = self:GetSpecSpells() + self.buttons = {} + self.guids = {} + self.curBracket = nil + self.curUnit = 1 + self.lastInstance = nil + + self:SetupOptions() + + for k, v in self:IterModules() do + self:Call(v, "Initialize") -- B.E > A.E :D + end +end + +function Gladdy:OnProfileChanged() + self.db = self.dbi.profile + + self:HideFrame() + self:ToggleFrame(3) +end + +function Gladdy:OnEnable() + self:RegisterEvent("UPDATE_BATTLEFIELD_STATUS") + self:RegisterEvent("PLAYER_ENTERING_WORLD") + + if (IsAddOnLoaded("Clique")) then + for i = 1, 5 do + self:CreateButton(i) + end + + ClickCastFrames = ClickCastFrames or {} + ClickCastFrames[self.buttons.arena1.secure] = true + ClickCastFrames[self.buttons.arena2.secure] = true + ClickCastFrames[self.buttons.arena3.secure] = true + ClickCastFrames[self.buttons.arena4.secure] = true + ClickCastFrames[self.buttons.arena5.secure] = true + end + + if (not self.db.locked and self.db.x == 0 and self.db.y == 0) then + self:Print(L["Welcome to Gladdy!"]) + self:Print(L["First run has been detected, displaying test frame."]) + self:Print(L["Valid slash commands are:"]) + self:Print(L["/gladdy ui"]) + self:Print(L["/gladdy test2-5"]) + self:Print(L["/gladdy hide"]) + self:Print(L["/gladdy reset"]) + self:Print(L["If this is not your first run please lock or move the frame to prevent this from happening."]) + + self:HideFrame() + self:ToggleFrame(3) + end +end + +function Gladdy:GetIconStyles() + return + { + ["Interface\\AddOns\\Gladdy\\Images\\Border_rounded_blp"] = L["Gladdy Tooltip round"], + ["Interface\\AddOns\\Gladdy\\Images\\Border_squared_blp"] = L["Gladdy Tooltip squared"], + ["Interface\\AddOns\\Gladdy\\Images\\Border_Gloss"] = L["Gloss (black border)"], + } +end + +--------------------------- + +-- TEST + +--------------------------- + +function Gladdy:Test() + Gladdy.frame.testing = true + for i = 1, self.curBracket do + local unit = "arena" .. i + if (not self.buttons[unit]) then + self:CreateButton(i) + end + local button = self.buttons[unit] + + for k, v in pairs(self.testData[unit]) do + button[k] = v + end + + for k, v in self:IterModules() do + self:Call(v, "Test", unit) + end + + button:SetAlpha(1) + end +end + +--------------------------- + +-- EVENT HANDLING + +--------------------------- + +function Gladdy:PLAYER_ENTERING_WORLD() + local instance = select(2, IsInInstance()) + if (instance ~= "arena" and self.frame and self.frame:IsVisible() and not self.frame.testing) then + self:Reset() + self:HideFrame() + end + if (instance == "arena") then + self:Reset() + self:HideFrame() + end + self.lastInstance = instance +end + +function Gladdy:UPDATE_BATTLEFIELD_STATUS(_, index) + local status, mapName, instanceID, levelRangeMin, levelRangeMax, teamSize, isRankedArena, suspendedQueue, bool, queueType = GetBattlefieldStatus(index) + if (status == "active" and teamSize > 0 and IsActiveBattlefieldArena()) then + self.curBracket = teamSize + self:JoinedArena() + end +end + +--------------------------- + +-- RESET FUNCTIONS (ARENA LEAVE) + +--------------------------- + +function Gladdy:Reset() + if type(self.guids) == "table" then + for k, v in pairs(self.guids) do + self.guids[k] = nil + end + end + self.guids = {} + self.curBracket = nil + self.curUnit = 1 + + for k1, v1 in self:IterModules() do + self:Call(v1, "Reset") + end + + for unit in pairs(self.buttons) do + self:ResetUnit(unit) + end +end + +function Gladdy:ResetUnit(unit) + local button = self.buttons[unit] + if (not button) then + return + end + + button:SetAlpha(0) + self:ResetButton(unit) + + for k2, v2 in self:IterModules() do + self:Call(v2, "ResetUnit", unit) + end +end + +function Gladdy:ResetButton(unit) + local button = self.buttons[unit] + if (not button) then + return + end + for k1, v1 in pairs(self.BUTTON_DEFAULTS) do + if (type(v1) == "string") then + button[k1] = nil + elseif (type(v1) == "number") then + button[k1] = 0 + elseif (type(v1) == "array") then + button[k1] = {} + elseif (type(v1) == "boolean") then + button[k1] = false + end + end +end + +--------------------------- + +-- ARENA JOINED + +--------------------------- + +function Gladdy:JoinedArena() + if not self.curBracket then + self.curBracket = 2 + end + + for i = 1, self.curBracket do + if (not self.buttons["arena" .. i]) then + self:CreateButton(i) + end + end + + self:SendMessage("JOINED_ARENA") + self:UpdateFrame() + self.frame:Show() + for i=1, self.curBracket do + self.buttons["arena" .. i]:SetAlpha(1) + end +end diff --git a/Gladdy.toc b/Gladdy.toc new file mode 100644 index 0000000..ca10f3f --- /dev/null +++ b/Gladdy.toc @@ -0,0 +1,35 @@ +## Interface: 20501 +## Title: Gladdy - Macumba/XiCoN Edit +## Version: 1.0.3-Beta +## Notes: The most powerful arena AddOn for WoW 2.5.1 +## Author: XiconQoo +## X-Email: +## SavedVariables: GladdyXZ +## OptionalDeps: SharedMedia, Blizzard_CombatLog, Blizzard_ArenaUI, Blizzard_CombatText + +embeds.xml + +Gladdy.lua +Lang.lua +Frame.lua +Options.lua +Constants.lua + +Modules\Announcements.lua +Modules\Healthbar.lua +Modules\Powerbar.lua +Modules\Auras.lua +Modules\Castbar.lua +Modules\Classicon.lua +Modules\Diminishings.lua +Modules\Highlight.lua +Modules\TotemPlates.lua +Modules\Trinket.lua +Modules\Cooldowns.lua +Modules\ArenaCountDown.lua +Modules\BuffsDebuffs.lua +Modules\VersionCheck.lua +Modules\XiconProfiles.lua +Modules\Pets.lua +Modules\ExportImport.lua +EventListener.lua diff --git a/Images/BasicProfiles/Classic1.blp b/Images/BasicProfiles/Classic1.blp new file mode 100644 index 0000000000000000000000000000000000000000..6b85095e73e4d30d52e5abe75efe58e64c1a49f3 GIT binary patch literal 700220 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