From 766093fde11257e47e680caf983c148d4b3fc2e2 Mon Sep 17 00:00:00 2001 From: Tercioo Date: Fri, 19 Feb 2016 12:26:38 -0200 Subject: [PATCH] - added a plugin for Streamers and Youtubers. --- .pkgmeta | 3 +- boot.lua | 8 +- core/parser.lua | 6 +- functions/hooks.lua | 7 + functions/profiles.lua | 3 +- plugins/Details_Streamer/Details_Streamer.lua | 1565 +++++++++++++++++ plugins/Details_Streamer/Details_Streamer.toc | 10 + .../Details_Streamer/Libs/LibStub/LibStub.lua | 51 + .../Details_Streamer/Libs/LibStub/LibStub.toc | 13 + .../Libs/LibStub/tests/test.lua | 41 + .../Libs/LibStub/tests/test2.lua | 27 + .../Libs/LibStub/tests/test3.lua | 14 + .../Libs/LibStub/tests/test4.lua | 41 + plugins/Details_Streamer/embeds.xml | 6 + 14 files changed, 1788 insertions(+), 7 deletions(-) create mode 100644 plugins/Details_Streamer/Details_Streamer.lua create mode 100644 plugins/Details_Streamer/Details_Streamer.toc create mode 100644 plugins/Details_Streamer/Libs/LibStub/LibStub.lua create mode 100644 plugins/Details_Streamer/Libs/LibStub/LibStub.toc create mode 100644 plugins/Details_Streamer/Libs/LibStub/tests/test.lua create mode 100644 plugins/Details_Streamer/Libs/LibStub/tests/test2.lua create mode 100644 plugins/Details_Streamer/Libs/LibStub/tests/test3.lua create mode 100644 plugins/Details_Streamer/Libs/LibStub/tests/test4.lua create mode 100644 plugins/Details_Streamer/embeds.xml diff --git a/.pkgmeta b/.pkgmeta index 382a2128..1908afeb 100644 --- a/.pkgmeta +++ b/.pkgmeta @@ -11,4 +11,5 @@ move-folders: Details/plugins/Details_DungeonInfo-Warlords: Details_DungeonInfo-Warlords Details/plugins/Details_3DModelsPaths: Details_3DModelsPaths Details/plugins/Details_RaidCheck: Details_RaidCheck - Details/plugins/Details_DpsTuning: Details_DpsTuning \ No newline at end of file + Details/plugins/Details_DpsTuning: Details_DpsTuning + Details/plugins/Details_Streamer: Details_Streamer \ No newline at end of file diff --git a/boot.lua b/boot.lua index e75c0bc7..70a7fd53 100644 --- a/boot.lua +++ b/boot.lua @@ -4,7 +4,7 @@ _ = nil _detalhes = LibStub("AceAddon-3.0"):NewAddon("_detalhes", "AceTimer-3.0", "AceComm-3.0", "AceSerializer-3.0", "NickTag-1.0") _detalhes.build_counter = 2466 --it's 2466 for release - _detalhes.userversion = "v4.2.10" + _detalhes.userversion = "v4.3" _detalhes.realversion = 80 --core version _detalhes.version = _detalhes.userversion .. " (core " .. _detalhes.realversion .. ")" Details = _detalhes @@ -21,13 +21,13 @@ do local Loc = LibStub ("AceLocale-3.0"):GetLocale ( "Details" ) --[[ -|cFFFFFF00v4.2.10 (|cFFFFCC00Feb 10, 2016|r|cFFFFFF00)|r:\n\n -|cFFFFFF00-|r Major fixes on the Weakaura creator tool.\n\n +|cFFFFFF00v4.3 (|cFFFFCC00Feb 19, 2016|r|cFFFFFF00)|r:\n\n +|cFFFFFF00-|r Added Details!: Streamer plugin, if you are a streamer or youtuber, enable it at the Plugins Management on Options Panel.\n\n --]] -- - Loc ["STRING_VERSION_LOG"] = "|cFFFFFF00v4.2.10 (|cFFFFCC00Feb 11, 2016|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Major fixes on the Weakaura creator tool.\n\n|cFFFFFF00v4.2.9a (|cFFFFCC00Feb 10, 2016|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Global profiles got a revamp, now you can select which profile is used on all characters.\n\n|cFFFFFF00-|r You also can overwrite the global profile on any ton by just selecting a profile for that character.\n\n|cFFFFFF00-|r Added two new custom displays: Damage Done on targets marked with skull and Damage Done on targets marked with any other mark.\n\n|cFFFFFF00-|r Bookmark now also supports Plugins.\n\n|cFFFFFF00-|r Warlock's Burning Rush won't be counted when the player is out of combat.\n\n|cFFFFFF00-|r Added a Scale options to Encounter Details plugin window.\n\n|cFFFFFF00-|r Added a report button for targets of targets at the Player Details Window.\n\n|cFFFFFF00-|r Fixed the click to switch segment through segment button: left click changes up, right click changes down, middle mouse switch back to current segment.\n\n|cFFFFFF00-|r Advanced Damage Taken now also makes the damage Taken by tanks always be post-mitigated by shields.\n\n|cFFFFFF00-|r Fixed a gap when setting the bars to 'bottom to top' grow direction.\n\n|cFFFFFF00-|r Fixed an issue with the window size when hiding borders.\n\n|cFFFFFF00v4.1.6 (|cFFFFCC00Jan 14, 2016|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fixed the size of the right margin on tooltips.\n\n|cFFFFFF00v4.1.5 (|cFFFFCC00Jan 10, 2016|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fix for the weakauras creator for DBM and BidWigs Timers.\n\n|cFFFFFF00-|r Fix for an issue with dungeon bosses where sometimes Details! throw some error messages.\n\n|cFFFFFF00-|r Fixed the background color of All Displays window (right click the title bar).\n\n|cFFFFFF00-|r Attempt to fix a 'class undefined' bug.\n\n|cFFFFFF00v4.1.4 (|cFFFFCC00Jan 03, 2016|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fixed an issue with the segment plugin for the statusbar.\n\n|cFFFFFF00v4.1.3 (|cFFFFCC00Jan 01, 2016|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Small visual improvement on tooltips.\n\n|cFFFFFF00-|r Fixed an issue when closing solo plugins with the red X button.\n\n|cFFFFFF00v4.1.2 (|cFFFFCC00Dec 31, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fix for item level tracker.\n\n|cFFFFFF00v4.1.1 (|cFFFFCC00Dec 23, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Using LibItemUpgradeInfo library to retrive the item level of upgraded items.\n\n|cFFFFFF00v4.1.0 (|cFFFFCC00Dec 18, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Added new skin preset: 'New Gray'.\n\n|cFFFFFF00-|r Added a Dark skin for the Options Panel.\n\n|cFFFFFF00-|r Fixed an issue with the Plugin DPS Tuning when reseting data on Details!.\n\n|cFFFFFF00-|r Removed realm names from player at the Comparison Panel.\n\n|cFFFFFF00v4.0.8 (|cFFFFCC00Dec 13, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Framework and functions update for the next version of the Advanced Death Logs plugin.\n\n|cFFFFFF00v4.0.7 (|cFFFFCC00Dec 07, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fixed some corner border for elvui skins.\n\n|cFFFFFF00-|r /run Details.death_tooltip_width = 500 makes the deathlog tooltip be 500 width.\n\n|cFFFFFF00v4.0.6e (|cFFFFCC00Nov 23, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fixed an issue where sometimes some actors are duplicated at the end of an encounter.\n\n|cFFFFFF00-|r Fixed bookmark for segments (shift+right click).\n\n|cFFFFFF00-|r Fixed an issue with Chat Tab Embed when embeding only one window.\n\n|cFFFFFF00v4.0.6c (|cFFFFCC00Nov 04, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Added an option for numeral system: Western/East Asian.\n\n|cFFFFFF00v4.0.5c (|cFFFFCC00Oct 24, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Added an option to disable the all-displays window (right click on title bar).\n\n|cFFFFFF00-|r Added an option to suppress segment changes after killing a boss encounter (experimental).\n\n|cFFFFFF00-|r Fixed pet battles auto hide.\n\n|cFFFFFF00-|r Fixed an issue with bar animations starting from the middle of the bar.\n\n|cFFFFFF00-|r Fixed buffs and spell cast start on weakauras creator tool.\n\n|cFFFFFF00v4.0.3a (|cFFFFCC00Set 29, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fix for an error on Damage Taken By Spell display.\n\n|cFFFFFF00v4.0.3 (|cFFFFCC00Set 27, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Some improvements on Plugin's icon at the title bar.\n\n|cFFFFFF00v4.0.2 (|cFFFFCC00Set 26, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Added 'ShielTronic Shield' on HealthPotion & Stone display.\n\n|cFFFFFF00-|r Improvements done on Vanguard Plugin.\n\n|cFFFFFF00-|r Fixed an alignment issue which was happening with few tooltips.\n\n|cFFFFFF00-|r Fixed a problem where sometimes the addon crashes while doing a /reload during raid.\n\n|cFFFFFF00-|r Fixed the creation of auras for weakauras from the Forge (/details forge).\n\n|cFFFFFF00v4.0.1 (|cFFFFCC00Set 21, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Added an options to use a customized skin file.\n\n|cFFFFFF00-|r Added an options to use a customized bar texture file.\n\n|cFFFFFF00-|r A Package with photoshop files with examples and the skin file for Minimalistic skin are available at WoW Interface.\n\n|cFFFFFF00-|r Added 'API Custom Displays.txt' on Details! folder, this file explain how to create scripts for custom displays.\n\n|cFFFFFF00v4.0h (|cFFFFCC00Set 19, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Created new plugin 'Target Caller' for RBGs, it's available at Curse.com.\n\n|cFFFFFF00-|r Fixed death display color when not using colored by the player class.\n\n|cFFFFFF00-|r Fixed a rare bug where the window for Encounter Details Plugin won't open when clicking on its icon.\n\n|cFFFFFF00-|r Added officer channel to 'Announce Death' feature.\n\n|cFFFFFF00v4.0f (|cFFFFCC00Set 16, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fix for the title bar encounter timer.\n\n|cFFFFFF00v4.0e (|cFFFFCC00Set 14, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Added a custom display for Crowd Control Received.\n\n|cFFFFFF00-|r Weak Aura Creator Tool, now has full support for BigWigs and Dbm time bars.\n\n|cFFFFFF00-|r Auras for interrupt and dispelling has been added on the Weak Aura Creator Tool.\n\n|cFFFFFF00-|r Details! Forge now has support for DBM and BigWigs time bars.\n\n|cFFFFFF00-|r Solo Plugins now has a close button on their panels.\n\n|cFFFFFF00-|r Fixed damage/healing score message after a boss kill.\n\n|cFFFFFF00-|r Now, an alert to open the history panel is shown after killing a boss.\n\n|cFFFFFF00-|r Added a 'all-displays' menu when right clicking title bar.\n\n|cFFFFFF00-|r Removed few texture from bookmarks panel, now it has a more clean appearance.\n\n|cFFFFFF00-|r Updated Details! Framework.\n\n|cFFFFFF00-|r Added option in order to change the bar orientation.\n\n|cFFFFFF00-|r Added an option to make the menus on title bar work with clicks instead of hovering over them.\n\n|cFFFFFF00-|r Healing for battleground enemies is now placed on healing done instead of enemy healing done.\n\n|cFFFFFF00-|r Improvements on our support for Arena battles.\n\n|cFFFFFF00-|r Fixed some issues on the Player Detail Window.\n\n|cFFFFFF00-|r Fixed encounter time on title bar text.\n\n|cFFFFFF00-|r Fixed death display tooltip, wasn't respecting the font and size set on options panel." + Loc ["STRING_VERSION_LOG"] = "|cFFFFFF00v4.3 (|cFFFFCC00Feb 19, 2016|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Added Details!: Streamer plugin, if you are a streamer or youtuber, enable it at the Plugins Management on Options Panel.\n\n|cFFFFFF00v4.2.10 (|cFFFFCC00Feb 11, 2016|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Major fixes on the Weakaura creator tool.\n\n|cFFFFFF00v4.2.9a (|cFFFFCC00Feb 10, 2016|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Global profiles got a revamp, now you can select which profile is used on all characters.\n\n|cFFFFFF00-|r You also can overwrite the global profile on any ton by just selecting a profile for that character.\n\n|cFFFFFF00-|r Added two new custom displays: Damage Done on targets marked with skull and Damage Done on targets marked with any other mark.\n\n|cFFFFFF00-|r Bookmark now also supports Plugins.\n\n|cFFFFFF00-|r Warlock's Burning Rush won't be counted when the player is out of combat.\n\n|cFFFFFF00-|r Added a Scale options to Encounter Details plugin window.\n\n|cFFFFFF00-|r Added a report button for targets of targets at the Player Details Window.\n\n|cFFFFFF00-|r Fixed the click to switch segment through segment button: left click changes up, right click changes down, middle mouse switch back to current segment.\n\n|cFFFFFF00-|r Advanced Damage Taken now also makes the damage Taken by tanks always be post-mitigated by shields.\n\n|cFFFFFF00-|r Fixed a gap when setting the bars to 'bottom to top' grow direction.\n\n|cFFFFFF00-|r Fixed an issue with the window size when hiding borders.\n\n|cFFFFFF00v4.1.6 (|cFFFFCC00Jan 14, 2016|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fixed the size of the right margin on tooltips.\n\n|cFFFFFF00v4.1.5 (|cFFFFCC00Jan 10, 2016|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fix for the weakauras creator for DBM and BidWigs Timers.\n\n|cFFFFFF00-|r Fix for an issue with dungeon bosses where sometimes Details! throw some error messages.\n\n|cFFFFFF00-|r Fixed the background color of All Displays window (right click the title bar).\n\n|cFFFFFF00-|r Attempt to fix a 'class undefined' bug.\n\n|cFFFFFF00v4.1.4 (|cFFFFCC00Jan 03, 2016|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fixed an issue with the segment plugin for the statusbar.\n\n|cFFFFFF00v4.1.3 (|cFFFFCC00Jan 01, 2016|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Small visual improvement on tooltips.\n\n|cFFFFFF00-|r Fixed an issue when closing solo plugins with the red X button.\n\n|cFFFFFF00v4.1.2 (|cFFFFCC00Dec 31, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fix for item level tracker.\n\n|cFFFFFF00v4.1.1 (|cFFFFCC00Dec 23, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Using LibItemUpgradeInfo library to retrive the item level of upgraded items.\n\n|cFFFFFF00v4.1.0 (|cFFFFCC00Dec 18, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Added new skin preset: 'New Gray'.\n\n|cFFFFFF00-|r Added a Dark skin for the Options Panel.\n\n|cFFFFFF00-|r Fixed an issue with the Plugin DPS Tuning when reseting data on Details!.\n\n|cFFFFFF00-|r Removed realm names from player at the Comparison Panel.\n\n|cFFFFFF00v4.0.8 (|cFFFFCC00Dec 13, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Framework and functions update for the next version of the Advanced Death Logs plugin.\n\n|cFFFFFF00v4.0.7 (|cFFFFCC00Dec 07, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fixed some corner border for elvui skins.\n\n|cFFFFFF00-|r /run Details.death_tooltip_width = 500 makes the deathlog tooltip be 500 width.\n\n|cFFFFFF00v4.0.6e (|cFFFFCC00Nov 23, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fixed an issue where sometimes some actors are duplicated at the end of an encounter.\n\n|cFFFFFF00-|r Fixed bookmark for segments (shift+right click).\n\n|cFFFFFF00-|r Fixed an issue with Chat Tab Embed when embeding only one window.\n\n|cFFFFFF00v4.0.6c (|cFFFFCC00Nov 04, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Added an option for numeral system: Western/East Asian.\n\n|cFFFFFF00v4.0.5c (|cFFFFCC00Oct 24, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Added an option to disable the all-displays window (right click on title bar).\n\n|cFFFFFF00-|r Added an option to suppress segment changes after killing a boss encounter (experimental).\n\n|cFFFFFF00-|r Fixed pet battles auto hide.\n\n|cFFFFFF00-|r Fixed an issue with bar animations starting from the middle of the bar.\n\n|cFFFFFF00-|r Fixed buffs and spell cast start on weakauras creator tool.\n\n|cFFFFFF00v4.0.3a (|cFFFFCC00Set 29, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fix for an error on Damage Taken By Spell display.\n\n|cFFFFFF00v4.0.3 (|cFFFFCC00Set 27, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Some improvements on Plugin's icon at the title bar.\n\n|cFFFFFF00v4.0.2 (|cFFFFCC00Set 26, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Added 'ShielTronic Shield' on HealthPotion & Stone display.\n\n|cFFFFFF00-|r Improvements done on Vanguard Plugin.\n\n|cFFFFFF00-|r Fixed an alignment issue which was happening with few tooltips.\n\n|cFFFFFF00-|r Fixed a problem where sometimes the addon crashes while doing a /reload during raid.\n\n|cFFFFFF00-|r Fixed the creation of auras for weakauras from the Forge (/details forge).\n\n|cFFFFFF00v4.0.1 (|cFFFFCC00Set 21, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Added an options to use a customized skin file.\n\n|cFFFFFF00-|r Added an options to use a customized bar texture file.\n\n|cFFFFFF00-|r A Package with photoshop files with examples and the skin file for Minimalistic skin are available at WoW Interface.\n\n|cFFFFFF00-|r Added 'API Custom Displays.txt' on Details! folder, this file explain how to create scripts for custom displays.\n\n|cFFFFFF00v4.0h (|cFFFFCC00Set 19, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Created new plugin 'Target Caller' for RBGs, it's available at Curse.com.\n\n|cFFFFFF00-|r Fixed death display color when not using colored by the player class.\n\n|cFFFFFF00-|r Fixed a rare bug where the window for Encounter Details Plugin won't open when clicking on its icon.\n\n|cFFFFFF00-|r Added officer channel to 'Announce Death' feature.\n\n|cFFFFFF00v4.0f (|cFFFFCC00Set 16, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Fix for the title bar encounter timer.\n\n|cFFFFFF00v4.0e (|cFFFFCC00Set 14, 2015|r|cFFFFFF00)|r:\n\n|cFFFFFF00-|r Added a custom display for Crowd Control Received.\n\n|cFFFFFF00-|r Weak Aura Creator Tool, now has full support for BigWigs and Dbm time bars.\n\n|cFFFFFF00-|r Auras for interrupt and dispelling has been added on the Weak Aura Creator Tool.\n\n|cFFFFFF00-|r Details! Forge now has support for DBM and BigWigs time bars.\n\n|cFFFFFF00-|r Solo Plugins now has a close button on their panels.\n\n|cFFFFFF00-|r Fixed damage/healing score message after a boss kill.\n\n|cFFFFFF00-|r Now, an alert to open the history panel is shown after killing a boss.\n\n|cFFFFFF00-|r Added a 'all-displays' menu when right clicking title bar.\n\n|cFFFFFF00-|r Removed few texture from bookmarks panel, now it has a more clean appearance.\n\n|cFFFFFF00-|r Updated Details! Framework.\n\n|cFFFFFF00-|r Added option in order to change the bar orientation.\n\n|cFFFFFF00-|r Added an option to make the menus on title bar work with clicks instead of hovering over them.\n\n|cFFFFFF00-|r Healing for battleground enemies is now placed on healing done instead of enemy healing done." Loc ["STRING_DETAILS1"] = "|cffffaeaeDetails!:|r " diff --git a/core/parser.lua b/core/parser.lua index 185f67bc..10800b2d 100644 --- a/core/parser.lua +++ b/core/parser.lua @@ -2672,7 +2672,11 @@ for _, func in _ipairs (_hook_deaths_container) do local new_death_table = table_deepcopy (esta_morte) - func (nil, token, time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, new_death_table, este_jogador.last_cooldown, death_at, max_health) + local successful, errortext = pcall (func, nil, token, time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, new_death_table, este_jogador.last_cooldown, death_at, max_health) + if (not successful) then + _detalhes:Msg ("error occurred on a death hook function:", errortext) + end + --func (nil, token, time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, new_death_table, este_jogador.last_cooldown, death_at, max_health) end end diff --git a/functions/hooks.lua b/functions/hooks.lua index c008f637..c328af46 100644 --- a/functions/hooks.lua +++ b/functions/hooks.lua @@ -29,6 +29,13 @@ return false, "Invalid hook type." end + for _, this_func in ipairs (_detalhes.hooks [hook_type]) do + if (this_func == func) then + --> already installed + return + end + end + _detalhes.hooks [hook_type] [#_detalhes.hooks [hook_type] + 1] = func _detalhes.hooks [hook_type].enabled = true diff --git a/functions/profiles.lua b/functions/profiles.lua index 9fd95eb6..bb579403 100644 --- a/functions/profiles.lua +++ b/functions/profiles.lua @@ -610,6 +610,7 @@ end local default_profile = { --> spec coords +-- /run Details.class_specs_coords = nil class_specs_coords = { [250] = {0, 64/512, 0, 64/512}, --> blood dk [251] = {64/512, 128/512, 0, 64/512}, --> frost dk @@ -638,7 +639,7 @@ local default_profile = { [256] = {192/512, 256/512, 128/512, 192/512}, --> priest disc [257] = {256/512, 320/512, 128/512, 192/512}, --> priest holy - [258] = {(320/512) + 0.001953125, 384/512, 128/512, 192/512}, --> priest shadow + [258] = {(320/512) + (0.001953125 * 4), 384/512, 128/512, 192/512}, --> priest shadow [259] = {384/512, 448/512, 128/512, 192/512}, --> rogue assassination [260] = {448/512, 512/512, 128/512, 192/512}, --> rogue combat diff --git a/plugins/Details_Streamer/Details_Streamer.lua b/plugins/Details_Streamer/Details_Streamer.lua new file mode 100644 index 00000000..27449a8d --- /dev/null +++ b/plugins/Details_Streamer/Details_Streamer.lua @@ -0,0 +1,1565 @@ +local Loc = LibStub ("AceLocale-3.0"):GetLocale ( "Details" ) +local SharedMedia = LibStub:GetLibrary ("LibSharedMedia-3.0") +local LDB = LibStub ("LibDataBroker-1.1", true) +local LDBIcon = LDB and LibStub ("LibDBIcon-1.0", true) + +--> create the plugin object +local StreamOverlay = _detalhes:NewPluginObject ("Details_StreamOverlay", DETAILSPLUGIN_ALWAYSENABLED) +tinsert (UISpecialFrames, "Details_StreamOverlays") +--> main frame (shortcut) +local SOF = StreamOverlay.Frame +--> shortcut for details framework +local fw = StreamOverlay.gump + +StreamOverlay.CurrentVersion = "v1.0" + +--> mantaing the tables for casts, has hash indexes of numbers pointing to tables, tables inside store data of the UNIT_CAST events +--> also mantain information about the cast, if is done, interrupted, channeled, instant. +--Target = the target of the spell casted or the spellname if is a death table +--Id = the CastId from UNIT_CAST events. +--CastStart = GetTime from the cast start. +--HasCastTime = if true, isn't a instant cast. +--Interrupted = if the cast has been interrupted (any interrupt even walk). +--Done = the cast is done and isn't more relevant to track updates. +--Percent = cast percentage, used to update the statusbar. +--Death = this is a event from death tables. +local CastsTable = {} + +--> store bars references +StreamOverlay.battle_lines = {} +--> store the information to be shown on bars, like text, icon, colors +StreamOverlay.battle_content = {} + +-- StreamOverlay:UpdateLines() = update the bar text, icons and statusbar. Uses battle_lines and battle_content tables. +-- StreamOverlay:NewText() = adds a new line to battle_content and call update. +-- StreamOverlay:CreateBattleLine() = create a new line on the frame and add to battle_lines table. +-- StreamOverlay:SetBattleLineStyle (row, index) = update bar config like font size, bar height, etc, +-- StreamOverlay:RefreshInUse (line) = check if the bar still need to be shown in the screen or if can the hide. Runs every 1 minutes. +-- StreamOverlay:Refresh() = check if need to create more lines after a resize. +-- StreamOverlay:GetSpellInformation (spellid) = get information about the spell, if is a cooldown, defense, neutral, class, etc. +-- StreamOverlay:CastStart (castid) = called from the UNIT_CAST parser, it starts a cast when isn't a instant cast. +-- StreamOverlay:CastFinished (castid) = called from the UNIT_CAST parser, finish a cast. + +-- track_spell_cast() runs on tick, check CastsTables updating ongoing spell casting, updates cast percentage. + +-- StreamOverlay.OnDeath hook deaths from details! and show here (if player only). + +--frame listening to UNIT_CAST events +local listener = CreateFrame ("frame") +--max left and right text sizes, is updated later in a function +local text1_size, text2_size = 200, 200 +--icon size, is updated later in a function +local icon_size = 16 +--default icon for an attack on a monster +local default_attack_icon = [[Interface\CURSOR\UnableAttack]] + +local function CreatePluginFrames() + + --> shortcut for details fade function + local fader = StreamOverlay.gump.Fade + + + function StreamOverlay:OnDetailsEvent (event, ...) + if (event == "HIDE") then --> plugin hidded, disabled + self.open = false + + elseif (event == "SHOW") then --> plugin hidded, disabled + self.open = true + + elseif (event == "PLUGIN_DISABLED") then + StreamOverlay:OnDisablePlugin() + + elseif (event == "DETAILS_STARTED") then + StreamOverlay:OnEnablePlugin() + + elseif (event == "PLUGIN_ENABLED") then + StreamOverlay:OnEnablePlugin() + + end + end + + function StreamOverlay:OnEnablePlugin() + --> show the frame and restore position + SOF:Show() + local LibWindow = LibStub ("LibWindow-1.1") + LibWindow.RegisterConfig (SOF, StreamOverlay.db) + LibWindow.RestorePosition (SOF) + LibWindow.SavePosition (SOF) + + --> refresh the frame + StreamOverlay:Refresh() + StreamOverlay:SetBackgroundColor() + StreamOverlay:CreateMinimapIcon() + + --> enable the minimap icon + LDBIcon:Refresh ("DetailsStreamer", StreamOverlay.db.minimap) + StreamOverlay:SetLocked() + + --> install the death hook + Details:InstallHook (DETAILS_HOOK_DEATH, StreamOverlay.OnDeath) + + --> enable event listener + listener:RegisterMyEvents() + + --> enable the tick update + listener:SetScript ("OnUpdate", listener.track_spell_cast) + end + + function StreamOverlay:OnDisablePlugin() + --> shutdown the tick update + listener:SetScript ("OnUpdate", nil) + + --> disable the event listener + listener:UnregisterMyEvents() + + --> unistall the death hook + Details:UnInstallHook (DETAILS_HOOK_DEATH, StreamOverlay.OnDeath) + + --> shutdown minimap icon + StreamOverlay:CreateMinimapIcon() + local realstate = StreamOverlay.db.minimap.hide + StreamOverlay.db.minimap.hide = true + LDBIcon:Refresh ("DetailsStreamer", StreamOverlay.db.minimap) + StreamOverlay.db.minimap.hide = realstate + + --> save position and hide the frame + local LibWindow = LibStub ("LibWindow-1.1") + LibWindow.RegisterConfig (SOF, StreamOverlay.db) + LibWindow.SavePosition (SOF) + SOF:Hide() + end + + --> title bar, only shown when the frame isn't locked + local titlebar = CreateFrame ("frame", "DetailsStreamerTitlebar", SOF) + titlebar:SetHeight (20) + titlebar:SetPoint ("bottomleft", SOF, "topleft") + titlebar:SetPoint ("bottomright", SOF, "topright") + titlebar:SetBackdrop ({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tile = true, tileSize = 16, insets = {left = 0, right = 0, top = 0, bottom = 0}}) + titlebar:SetBackdropColor (.1, .1, .1, .9) + titlebar.text = titlebar:CreateFontString (nil, "overlay", "GameFontNormal") + titlebar.text:SetPoint ("center", titlebar, "center") + titlebar.text:SetText ("Details!: Streamer") + titlebar:SetScript ("OnEnter", function (self) + GameTooltip:SetOwner (self) + GameTooltip:SetOwner (self, "ANCHOR_TOPLEFT") + GameTooltip:AddLine ("|cFFFF7700Left Click|r: Open Options\n|cFFFF7700Right Click|r: Lock the Frame\n|cFFFF7700Slash Command|r: /streamer") + GameTooltip:Show() + end) + titlebar:SetScript ("OnLeave", function() + GameTooltip:Hide() + end) + + titlebar:SetScript ("OnMouseUp", function (self, button) + if (button == "LeftButton") then + --open options + StreamOverlay.OpenOptionsPanel() + elseif (button == "RightButton") then + --lock the frame + StreamOverlay:SetLocked (not StreamOverlay.db.main_frame_locked) + end + end) + + --> main frame parameters + SOF:SetPoint ("center", UIParent, "center") + SOF:SetSize (300, 500) + SOF:SetBackdrop ({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tile = true, tileSize = 16, insets = {left = 0, right = 0, top = 0, bottom = 0}}) + SOF:EnableMouse (true) + SOF:SetMovable (true) + SOF:SetResizable (true) + SOF:SetClampedToScreen (true) + SOF:SetMinResize (150, 40) + SOF:SetMaxResize (800, 1024) + + --> two resizers + local left_resize = CreateFrame ("button", "DetailsStreamerLeftResizer", SOF) + local right_resize = CreateFrame ("button", "DetailsStreamerRightResizer", SOF) + left_resize:SetPoint ("bottomleft", SOF, "bottomleft") + right_resize:SetPoint ("bottomright", SOF, "bottomright") + left_resize:SetSize (16, 16) + right_resize:SetSize (16, 16) + right_resize:SetNormalTexture ([[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Up]]) + right_resize:SetHighlightTexture ([[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Highlight]]) + right_resize:SetPushedTexture ([[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Down]]) + left_resize:SetNormalTexture ([[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Up]]) + left_resize:SetHighlightTexture ([[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Highlight]]) + left_resize:SetPushedTexture ([[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Down]]) + left_resize:GetNormalTexture():SetTexCoord (1, 0, 0, 1) + left_resize:GetHighlightTexture():SetTexCoord (1, 0, 0, 1) + left_resize:GetPushedTexture():SetTexCoord (1, 0, 0, 1) + + left_resize:SetScript ("OnMouseDown", function (self) + if (not SOF.resizing and not StreamOverlay.db.main_frame_locked) then + SOF.resizing = true + SOF:StartSizing ("bottomleft") + end + end) + left_resize:SetScript ("OnMouseUp", function (self) + if (SOF.resizing) then + SOF.resizing = false + SOF:StopMovingOrSizing() + StreamOverlay:Refresh() + local LibWindow = LibStub ("LibWindow-1.1") + LibWindow.SavePosition (SOF) + end + end) + right_resize:SetScript ("OnMouseDown", function (self) + if (not SOF.resizing and not StreamOverlay.db.main_frame_locked) then + SOF.resizing = true + SOF:StartSizing ("bottomright") + end + end) + right_resize:SetScript ("OnMouseUp", function (self) + if (SOF.resizing) then + SOF.resizing = false + SOF:StopMovingOrSizing() + StreamOverlay:Refresh() + local LibWindow = LibStub ("LibWindow-1.1") + LibWindow.SavePosition (SOF) + end + end) + + SOF:SetScript ("OnSizeChanged", function (self) + StreamOverlay:Refresh() + end) + + SOF:SetScript ("OnMouseDown", function (self) + if (not SOF.moving and not StreamOverlay.db.main_frame_locked) then + SOF:StartMoving() + SOF.moving = true + end + end) + SOF:SetScript ("OnMouseUp", function (self) + if (SOF.moving) then + SOF.moving = false + SOF:StopMovingOrSizing() + local LibWindow = LibStub ("LibWindow-1.1") + LibWindow.SavePosition (SOF) + end + end) + + + + + + --> scroll frame + local autoscroll = CreateFrame ("scrollframe", "Details_StreamOverlayScrollFrame", SOF, "FauxScrollFrameTemplate") + autoscroll:SetScript ("OnVerticalScroll", function (self, offset) FauxScrollFrame_OnVerticalScroll (self, offset, 20, StreamOverlay.UpdateLines) end) + + --> looks like this isn't working + function StreamOverlay:ClearAll() + for index = 1, #StreamOverlay.battle_lines do + local line = StreamOverlay.battle_lines [index] + if (line) then + line.in_use = 1 + end + end + StreamOverlay:UpdateLines() + end + + + + --> iterate each bar and update its text, icons and statusbar + function StreamOverlay:UpdateLines() + + FauxScrollFrame_Update (autoscroll, StreamOverlay.total_lines, StreamOverlay.total_lines, 20) + + for index = 1, StreamOverlay.total_lines do + + --> here gets the bar and the table with the information to shown on the bar + local data = StreamOverlay.battle_content [index] + local line = StreamOverlay.battle_lines [index] + if (data) then + + --> left + line.icon1:SetTexture (data [1]) + line.icon1:SetTexCoord (5/64, 59/64, 5/64, 59/64) + + local text = data [2] + line.text1:SetText (text) + local loops = 20 + while (line.text1:GetStringWidth() > text1_size and loops > 0) do + text = strsub (text, 1, #text-1) + line.text1:SetText (text) + loops = loops - 1 --just to be safe + end + + --> right + local text = data [6] + line.text2:SetText (text) + local loops = 20 + while (line.text2:GetStringWidth() > text2_size and loops > 0) do + text = strsub (text, 1, #text-1) + line.text2:SetText (text) + loops = loops - 1 --just to be safe + end + + if (text == "") then + line.icon2:Hide() + line.arrow:Hide() + else + line.icon2:Show() + line.arrow:Show() + end + + if (data[7]) then + line.text2:SetTextColor (data[7].r, data[7].g, data[7].b) + else + line.text2:SetTextColor (1, 1, 1) + end + + line.icon2:SetTexture (data [4]) + line.icon2:SetTexCoord (unpack (data [5])) + if (data [4] == default_attack_icon) then + line.icon2:SetSize (icon_size*0.8, icon_size*0.8) + line.icon2:SetPoint ("left", line, "center", 8, 0) + line.text2:SetPoint ("left", line.icon2, "right", 5, 0) + else + line.icon2:SetSize (icon_size, icon_size) + line.icon2:SetPoint ("left", line, "center", 8, 0) + line.text2:SetPoint ("left", line.icon2, "right", 5, 0) + end + + --> background + line:SetBackdropColor (unpack (data [8])) + + if (data [9]) then + line:SetBackdropBorderColor (unpack (data [9])) + else + line:SetBackdropBorderColor (0, 0, 0, 0) + end + + --> percentage + local castinfo = CastsTable [data.CastID] + local percent = castinfo and castinfo.Percent or 0 + if (percent > 100) then + percent = 100 + end + + line.statusbar:SetValue (percent) + line.spark:Show() + if (castinfo.Success) then + line.spark:SetVertexColor (1, 1, 1, 0.4) + line.spark:SetPoint ("left", line.statusbar, "left", (line.statusbar:GetWidth() / 100 * percent) - 8, 0) + elseif (castinfo.Interrupted) then + line.spark:SetVertexColor (1, 0, 0, 0.4) + line.spark:SetPoint ("left", line.statusbar, "left", (line.statusbar:GetWidth() / 100 * percent) - 8, 0) + end + + line.in_use = data.CastStart + StreamOverlay:RefreshInUse (line) + else + line.in_use = 1 + StreamOverlay:RefreshInUse (line) + end + end + end + + function StreamOverlay:NewText (icon1, text1, color1, icon2, icon2coords, text2, color2, backgroundcolor, bordercolor, ID, CastStart) + + if (StreamOverlay.ShowingDeath) then + StreamOverlay.ShowingDeath = nil + StreamOverlay:ClearAll() + end + + table.insert (StreamOverlay.battle_content, 1, {icon1, text1, color1, icon2, icon2coords, text2, color2, backgroundcolor, bordercolor, CastID = ID, CastStart = CastStart}) + table.remove (StreamOverlay.battle_content, StreamOverlay.total_lines+1) + StreamOverlay:UpdateLines (autoscroll) + end + + function StreamOverlay:CreateBattleLine() + + local index = #StreamOverlay.battle_lines+1 + + local f = CreateFrame ("frame", "StreamOverlayBar" .. index, SOF) + local statusbar = CreateFrame ("StatusBar", "StreamOverlayBar" .. index .. "StatusBar", f) + local statusbar_texture = statusbar:CreateTexture (nil, "border") + statusbar_texture:SetTexture (1, 1, 1, 0.15) + statusbar:SetStatusBarColor (0, 0, 0, 0) + statusbar:SetStatusBarTexture (statusbar_texture) + statusbar:SetMinMaxValues (0, 100) + statusbar:SetValue (0) + local statusbar_spark = statusbar:CreateTexture (nil, "artwork") + statusbar_spark:SetTexture ([[Interface\CastingBar\UI-CastingBar-Spark]]) + statusbar_spark:SetSize (16, 50) + statusbar_spark:SetBlendMode ("ADD") + statusbar_spark:Hide() + + local h = (index-1) * StreamOverlay.db.row_spacement * -1 + + f:SetPoint ("topleft", SOF, "topleft", 0, h) + f:SetPoint ("topright", SOF, "topright", 0, h) + + f:SetBackdrop ({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, tile = true, tileSize = 16, insets = {left = 0, right = 0, top = 0, bottom = 0}}) + f:SetBackdropBorderColor (0, 0, 0, 0) + + local icon1 = statusbar:CreateTexture (nil, "overlay") + local icon2 = statusbar:CreateTexture (nil, "overlay") + + local arrow = statusbar:CreateTexture (nil, "overlay") + + local text1 = statusbar:CreateFontString (nil, "overlay", "GameFontNormal") + local text2 = statusbar:CreateFontString (nil, "overlay", "GameFontNormal") + + icon1:SetPoint ("left", f, "left", 2, 0) --> player spell icon + text1:SetPoint ("left", icon1, "right", 2, 0) --> player spell name + + arrow:SetPoint ("center", f, "center") --> separate player spell and targets + + icon2:SetPoint ("left", f, "center", 10, 0) + text2:SetPoint ("left", icon2, "right", 3, 0) + + statusbar:SetPoint ("topleft", f, "topleft", 0, 0) + statusbar:SetPoint ("bottomright", f, "bottomright", 0, 0) + + f.icon1 = icon1 + f.icon2 = icon2 + f.text1 = text1 + f.text2 = text2 + f.arrow = arrow + f.statusbar = statusbar + f.statusbar_texture = statusbar_texture + f.spark = statusbar_spark + + StreamOverlay.battle_lines [#StreamOverlay.battle_lines+1] = f + + f.in_use = 1 + f:Hide() + + StreamOverlay:SetBattleLineStyle (f) + + end + + + function StreamOverlay:RefreshAllBattleLineStyle() + for i, row in ipairs (StreamOverlay.battle_lines) do + StreamOverlay:SetBattleLineStyle (row, i) + end + end + + function StreamOverlay:SetBattleLineStyle (row, index) + local options = StreamOverlay.db + + row:SetHeight (StreamOverlay.db.row_height) + + if (index) then + local h = (index-1) * StreamOverlay.db.row_spacement * -1 + row:SetPoint ("topleft", SOF, "topleft", 0, h) + row:SetPoint ("topright", SOF, "topright", 0, h) + end + + StreamOverlay:SetFontSize (row.text1, StreamOverlay.db.font_size) + StreamOverlay:SetFontSize (row.text2, StreamOverlay.db.font_size) + + local font = SharedMedia:Fetch ("font", StreamOverlay.db.font_face) + StreamOverlay:SetFontFace (row.text1, font) + StreamOverlay:SetFontFace (row.text2, font) + + StreamOverlay:SetFontColor (row.text1, StreamOverlay.db.font_color) + StreamOverlay:SetFontColor (row.text2, StreamOverlay.db.font_color) + + icon_size = StreamOverlay.db.row_height-4 + row.icon1:SetSize (icon_size, icon_size) + row.icon2:SetSize (icon_size, icon_size) + + local current_texture = row.icon2:GetTexture() + if (current_texture == default_attack_icon) then + row.icon2:SetSize (icon_size*0.8, icon_size*0.8) + row.icon2:SetPoint ("left", row, "center", 8, 0) + row.text2:SetPoint ("left", row.icon2, "right", 5, 0) + else + row.icon2:SetPoint ("left", row, "center", 8, 0) + row.text2:SetPoint ("left", row.icon2, "right", 5, 0) + end + + if (row.text2:GetText() == "") then + row.icon2:Hide() + row.arrow:Hide() + else + row.icon2:Show() + row.arrow:Show() + end + + local texture = SharedMedia:Fetch ("statusbar", StreamOverlay.db.row_texture) + row.statusbar_texture:SetTexture (texture) + row.statusbar_texture:SetVertexColor (unpack (StreamOverlay.db.row_color)) + + row.arrow:SetTexture (StreamOverlay.db.arrow_texture) + row.arrow:SetSize (StreamOverlay.db.arrow_size, StreamOverlay.db.arrow_size) + row.arrow:SetVertexColor (unpack (StreamOverlay.db.arrow_color)) + row.arrow:SetPoint ("center", row, "center", StreamOverlay.db.arrow_anchor_x, StreamOverlay.db.arrow_anchor_y) + + end + + function StreamOverlay:RefreshInUse (line) + local now = GetTime() + if (line) then + local line_in_use = line.in_use or 1 + local content_in_use = StreamOverlay.battle_content [i] and StreamOverlay.battle_content [i].CastStart or 1 + + if (max (line_in_use, content_in_use) + 60 < now) then + fader (nil, line, "in") + else + fader (nil, line, "out") + end + else + for i = 1, #StreamOverlay.battle_lines do + local line = StreamOverlay.battle_lines[i] + + local line_in_use = line.in_use or 1 + local content_in_use = StreamOverlay.battle_content [i] and StreamOverlay.battle_content [i].CastStart or 1 + + if (max (line_in_use, content_in_use) + 60 < now) then + fader (nil, StreamOverlay.battle_lines [i], "in") + else + fader (nil, StreamOverlay.battle_lines [i], "out") + end + end + end + end + + C_Timer.NewTicker (60, StreamOverlay.RefreshInUse) + + function StreamOverlay:Refresh() + + --> how many lines fit in the frame + local amt = math.floor (SOF:GetHeight() / StreamOverlay.db.row_spacement) + + if (amt < 0) then + amt = 0 + end + + StreamOverlay.total_lines = amt + + if (amt == 0) then + for i = 1, #StreamOverlay.battle_lines do + StreamOverlay.battle_lines [i]:Hide() + end + return + end + + --> need create more lines + if (amt > #StreamOverlay.battle_lines) then + for i = #StreamOverlay.battle_lines+1, amt do + StreamOverlay:CreateBattleLine() + end + for i = 1, amt do + StreamOverlay.battle_lines [i]:Show() + end + + elseif (#StreamOverlay.battle_lines > amt) then + for i = #StreamOverlay.battle_lines, amt+1, -1 do + StreamOverlay.battle_lines [i]:Hide() + end + for i = 1, amt do + StreamOverlay.battle_lines [i]:Show() + end + else + for i = 1, amt do + StreamOverlay.battle_lines [i]:Show() + end + end + + local width = SOF:GetWidth() / 2 + text1_size, text2_size = width - 28, width - 30 + + --for i = 1, #StreamOverlay.battle_lines do + -- StreamOverlay.battle_lines [i].text1:SetWidth (text1_size) + -- StreamOverlay.battle_lines [i].text2:SetWidth (text2_size) + --end + + StreamOverlay:UpdateLines() + StreamOverlay:RefreshInUse() + end + + function StreamOverlay:SetBackgroundColor (r, g, b, a) + if (not r) then + r, g, b, a = unpack (StreamOverlay.db.main_frame_color) + else + local c = StreamOverlay.db.main_frame_color + c[1], c[2], c[3], c[4] = r, g, b, a + end + SOF:SetBackdropColor (r, g, b, a) + end + +end + +local playername = UnitName ("player") + +local COLOR_HARMFUL = {.9, .5, .5, .4} +local COLOR_HELPFUL = {.1, .9, .1, .4} +local COLOR_ATTKCOOLDOWN = {1, 1, 0, .6} +local COLOR_DEFECOOLDOWN = {1, 1, 1, .6} +local COLOR_BORDER_DEFAULT = {0, 0, 0, 0} +local COLOR_BORDER_ABSORB = {1, 1, 0, 0.5} + +local HarmfulSpellsTable = StreamOverlay.HarmfulSpells +local HelpfulSpellsTable = StreamOverlay.HelpfulSpells +local AttackCooldownSpellsTable = StreamOverlay.AttackCooldownSpells +local ClassSpellsTable = StreamOverlay.MiscClassSpells +local CooldownTable1 = StreamOverlay.DefensiveCooldownSpells +local CooldownTable2 = StreamOverlay.DefensiveCooldownSpellsNoBuff +local ClassColorsTable = StreamOverlay.class_colors +local ClassSpellList = StreamOverlay.ClassSpellList +local AbsorbSpellsTable = StreamOverlay.AbsorbSpells + +local ban_spells = { + [49821] = true, --mind sear ticks + [121557] = true, --angelic feather walkon +} + +function StreamOverlay:GetSpellInformation (spellid) + + local spellname, _, icon = GetSpellInfo (spellid) + + local backgroundcolor + + if (HarmfulSpellsTable [spellid]) then + backgroundcolor = COLOR_HARMFUL + + elseif (HelpfulSpellsTable [spellid]) then + backgroundcolor = COLOR_HELPFUL + + elseif (AttackCooldownSpellsTable [spellid]) then + backgroundcolor = COLOR_ATTKCOOLDOWN + + elseif (CooldownTable1 [spellid] or CooldownTable2 [spellid]) then + backgroundcolor = COLOR_DEFECOOLDOWN + + elseif (ClassSpellsTable [spellid]) then + local class = ClassSpellList [spellid] + backgroundcolor = ClassColorsTable [class] + + else + backgroundcolor = COLOR_HARMFUL + + end + + if (AbsorbSpellsTable [spellid]) then + bordercolor = COLOR_BORDER_ABSORB + else + bordercolor = COLOR_BORDER_DEFAULT + end + + return icon, backgroundcolor, bordercolor + +end + +local RoleIcons = "Interface\\LFGFRAME\\UI-LFG-ICON-PORTRAITROLES" +local RoleIconsCoord = { + ["TANK"] = {0, 0.28125, 0.328125, 0.625}, + ["HEALER"] = {0.3125, 0.59375, 0, 0.296875}, + ["DAMAGER"] = {0.3125, 0.59375, 0.328125, 0.625}, + ["NONE"] = {0.3125, 0.59375, 0.328125, 0.625} +} +local DefaultCoords = {0, 1, 0, 1} +local DefaultColor = {r=1, g=1, b=1} +local PetCoords = {0.25, 0.49609375, 0.75, 1} + +local parse_target_name = function (target) + return StreamOverlay:GetOnlyName (target) +end + +local parse_target_icon = function (targetObject, target) + local icon2, icon2coords, pclass + if (targetObject) then + local role = targetObject.role + pclass = targetObject.classe + if (role) then + icon2 = RoleIcons + icon2coords = RoleIconsCoord [role] + else + local class = targetObject.classe + if (class == "PET") then + icon2 = [[Interface\AddOns\Details\images\classes_small_alpha]] + icon2coords = PetCoords + elseif (class and RAID_CLASS_COLORS [class]) then + if (targetObject.spec) then + icon2 = [[Interface\AddOns\Details\images\spec_icons_normal_alpha]] + icon2coords = Details.class_specs_coords [targetObject.spec] + else + local spec_from_cache = Details.cached_specs [targetObject.serial] + if (spec_from_cache) then + icon2 = [[Interface\AddOns\Details\images\spec_icons_normal_alpha]] + icon2coords = Details.class_specs_coords [spec_from_cache] + else + icon2 = [[Interface\AddOns\Details\images\classes_small_alpha]] + icon2coords = Details.class_coords [class] + end + end + else + local _, class = UnitClass (targetObject.nome) + if (class) then + icon2 = [[Interface\AddOns\Details\images\classes_small_alpha]] + icon2coords = Details.class_coords [class] + else + icon2 = "" + icon2coords = DefaultCoords + end + end + end + else + local _, class = UnitClass (target) + if (class) then + icon2 = [[Interface\AddOns\Details\images\classes_small_alpha]] + icon2coords = Details.class_coords [class] + pclass = class + else + icon2 = "" + icon2coords = DefaultCoords + end + end + + if (icon2 == "") then + icon2 = [[Interface\CURSOR\Attack]] + icon2 = [[Interface\CURSOR\UnableAttack]] + icon2coords = {1, 0, 0, 1} + end + return icon2, icon2coords, pclass +end + +local parse_target_color = function (class) + local color2 = RAID_CLASS_COLORS [class] + return color2 +end + +function StreamOverlay:CastStart (castid) + local spellid = CastsTable [castid].SpellId + local target = CastsTable [castid].Target + local caststart = CastsTable [castid].CastStart + + if (ban_spells [spellid]) then + return + end + + local icon, backgroundcolor, bordercolor = StreamOverlay:GetSpellInformation (spellid) + local spellname, _, spellicon = GetSpellInfo (spellid) + + local targetObject = Details:GetActor ("current", 1, target) or Details:GetActor ("current", 2, target) + local icon2, icon2coords, class = parse_target_icon (targetObject, target) + + local color2 + if (icon2 == RoleIcons) then + color2 = parse_target_color (class) + if (not color2) then + color2 = DefaultColor + end + else + color2 = DefaultColor + end + + target = parse_target_name (target) + + StreamOverlay:NewText (spellicon, spellname, color1, icon2, icon2coords, target, color2, backgroundcolor, bordercolor, castid, caststart) + +end + +function StreamOverlay:CastFinished (castid) + local spellid = CastsTable [castid].SpellId + local target = CastsTable [castid].Target + local caststart = CastsTable [castid].CastStart + local hascasttime = CastsTable [castid].HasCastTime + + if (ban_spells [spellid]) then + return + end + + if (hascasttime) then + --just finished a casted cast + CastsTable [castid].Success = true + + else + --just casted a instant spell + + local icon, backgroundcolor, bordercolor = StreamOverlay:GetSpellInformation (spellid) + local spellname, _, spellicon = GetSpellInfo (spellid) + + local targetObject = Details:GetActor ("current", 1, target) or Details:GetActor ("current", 2, target) + + local icon2, icon2coords, class = parse_target_icon (targetObject, target) + + local color2 + if (icon2 == RoleIcons) then + color2 = parse_target_color (class) + if (not color2) then + color2 = DefaultColor + end + else + color2 = DefaultColor + end + + target = parse_target_name (target) + + StreamOverlay:NewText (spellicon, spellname, color1, icon2, icon2coords, target, color2, backgroundcolor, bordercolor, castid, caststart) + end +end + +listener.track_spell_cast = function() + + for i = 1, #StreamOverlay.battle_content do + + local content = StreamOverlay.battle_content [i] + local line = StreamOverlay.battle_lines [i] + local castinfo = CastsTable [content.CastID] + + if (not castinfo.Done) then + + --> is being casted? + if (castinfo.HasCastTime) then + if (castinfo.Success) then + --> okey it's done + castinfo.Done = true + castinfo.Percent = 100 + line.statusbar:SetValue (100) + line.spark:SetPoint ("left", line.statusbar, "left", (line.statusbar:GetWidth() / 100 * 100) - 8, 0) + --line.spark:Hide() + + elseif (castinfo.Interrupted) then + --> has been interrupted + castinfo.Done = true + line.spark:SetVertexColor (1, 0.7, 0) + + elseif (castinfo.IsChanneled) then + --> casting a channeled spell + local name, subText, text, texture, startTime, endTime, isTradeSkill, notInterruptible = UnitChannelInfo ("player") + + if (name) then + startTime = startTime / 1000 + endTime = endTime / 1000 + + local diff = endTime - startTime + local current = GetTime() - startTime + local percent = current / diff * 100 + percent = math.abs (percent - 100) + castinfo.Percent = percent + line.statusbar:SetValue (percent) + line.spark:Show() + line.spark:SetVertexColor (1, 1, 1, 0.5 + (percent/100)) + line.spark:SetVertexColor (1, 1, 1, 1) + line.spark:SetPoint ("left", line.statusbar, "left", (line.statusbar:GetWidth() / 100 * percent) - 6, 0) + end + + else + --> still casting + local spell, rank, displayName, icon, startTime, endTime, isTradeSkill, castID, interrupt = UnitCastingInfo ("player") + if (spell) then + startTime = startTime / 1000 + endTime = endTime / 1000 + + local diff = endTime - startTime + local current = GetTime() - startTime + + local percent = current / diff * 100 + castinfo.Percent = percent + line.statusbar:SetValue (percent) + line.spark:Show() + line.spark:SetVertexColor (1, 1, 1, 0.5 + (percent/100)) + line.spark:SetPoint ("left", line.statusbar, "left", (line.statusbar:GetWidth() / 100 * percent) - 6, 0) + end + end + + else + --> it's instant cast + if (castinfo.CastStart+1.2 < GetTime()) then + castinfo.Done = true + castinfo.Percent = 100 + line.statusbar:SetValue (100) + line.spark:SetPoint ("left", line.statusbar, "left", (line.statusbar:GetWidth() / 100 * 100) - 8, 0) + --line.spark:Hide() + else + local startTime = castinfo.CastStart + local endTime = (castinfo.CastStart + 1.2) + + local diff = endTime - startTime + local current = GetTime() - startTime + + local percent = current / diff * 100 + castinfo.Percent = percent + line.statusbar:SetValue (percent) + line.spark:Show() + line.spark:SetVertexColor (1, 1, 1, 0.5 + (percent/100)) + line.spark:SetPoint ("left", line.statusbar, "left", (line.statusbar:GetWidth() / 100 * percent) - 6, 0) + end + + end + + line.in_use = GetTime() + end + + end +end + +function listener:RegisterMyEvents() + listener:RegisterEvent ("UNIT_SPELLCAST_START") + listener:RegisterEvent ("UNIT_SPELLCAST_SENT") + listener:RegisterEvent ("UNIT_SPELLCAST_SUCCEEDED") + listener:RegisterEvent ("UNIT_SPELLCAST_INTERRUPTED") + + listener:RegisterEvent ("UNIT_SPELLCAST_FAILED_QUIET") + listener:RegisterEvent ("UNIT_SPELLCAST_FAILED") + listener:RegisterEvent ("UNIT_SPELLCAST_NOT_INTERRUPTIBLE") + listener:RegisterEvent ("UNIT_SPELLCAST_INTERRUPTIBLE") + listener:RegisterEvent ("UNIT_SPELLCAST_DELAYED") + listener:RegisterEvent ("UNIT_SPELLCAST_CHANNEL_START") + listener:RegisterEvent ("UNIT_SPELLCAST_CHANNEL_STOP") + listener:RegisterEvent ("UNIT_SPELLCAST_CHANNEL_UPDATE") + listener:RegisterEvent ("UNIT_SPELLCAST_STOP") +end + +function listener:UnregisterMyEvents() + listener:UnregisterEvent ("UNIT_SPELLCAST_START") + listener:UnregisterEvent ("UNIT_SPELLCAST_SENT") + listener:UnregisterEvent ("UNIT_SPELLCAST_SUCCEEDED") + listener:UnregisterEvent ("UNIT_SPELLCAST_INTERRUPTED") + + listener:UnregisterEvent ("UNIT_SPELLCAST_FAILED_QUIET") + listener:UnregisterEvent ("UNIT_SPELLCAST_FAILED") + listener:UnregisterEvent ("UNIT_SPELLCAST_NOT_INTERRUPTIBLE") + listener:UnregisterEvent ("UNIT_SPELLCAST_INTERRUPTIBLE") + listener:UnregisterEvent ("UNIT_SPELLCAST_DELAYED") + listener:UnregisterEvent ("UNIT_SPELLCAST_CHANNEL_START") + listener:UnregisterEvent ("UNIT_SPELLCAST_CHANNEL_STOP") + listener:UnregisterEvent ("UNIT_SPELLCAST_CHANNEL_UPDATE") + listener:UnregisterEvent ("UNIT_SPELLCAST_STOP") +end + +local lastspell, lastcastid, lastchannelid, ischanneling +local channelspells = {} +listener:SetScript ("OnEvent", function (self, event, ...) + + --print (event, ...) + + if (event == "UNIT_SPELLCAST_SENT") then + local unitID, spell, rank, target, id = ... + + if (unitID == "player") then + CastsTable [id] = {Target = target, Id = id, CastStart = GetTime()} + lastspell = spell + lastcastid = id + end + + elseif (event == "UNIT_SPELLCAST_START") then + local unitID, spell, rank, id, spellID = ... + + if (unitID == "player" and CastsTable [id]) then + CastsTable [id].SpellId = spellID + CastsTable [id].HasCastTime = true + StreamOverlay:CastStart (id) + end + + elseif (event == "UNIT_SPELLCAST_INTERRUPTED") then + local unitID, spell, rank, id, spellID = ... + + if (unitID == "player" and CastsTable [id]) then + CastsTable [id].Interrupted = true + end + + --> channels isn't passing the CastID / cast id for channels is always Zero. + elseif (event == "UNIT_SPELLCAST_CHANNEL_STOP") then + local unitID, spell, rank, id, spellID = ... + + if (unitID == "player") then + id = lastchannelid + CastsTable [id].Interrupted = true + ischanneling = false + lastchannelid = nil + end + + elseif (event == "UNIT_SPELLCAST_CHANNEL_START") then + local unitID, spell, rank, id, spellID = ... + if (unitID == "player" and (CastsTable [id] or spell == lastspell)) then + if (id == 0) then + id = lastcastid + end + + if (ischanneling) then + --> channel updated + CastsTable [lastchannelid].Interrupted = true + end + + CastsTable [id].HasCastTime = true + CastsTable [id].IsChanneled = true + CastsTable [id].SpellId = spellID + lastchannelid = id + ischanneling = true + + channelspells [spell] = true + + StreamOverlay:CastStart (id) + end + + elseif (event == "UNIT_SPELLCAST_SUCCEEDED") then + local unitID, spell, rank, id, spellID = ... + + if (unitID == "player" and CastsTable[id] and not channelspells [spell]) then + if (CastsTable[id].HasCastTime and not CastsTable[id].IsChanneled) then + --> a cast (non channeled) just successful finished + CastsTable [id].Success = true + StreamOverlay:CastFinished (id) + + elseif (not CastsTable[id].HasCastTime) then + --> instant cast finished + CastsTable [id].SpellId = spellID + CastsTable [id].Success = true + StreamOverlay:CastFinished (id) + end + end + end + + --print (event, ...) + +end) + +local format_time = function (v) return "-" .. format ("%.2f", v) end + +--when the player die, show the events before the death +function StreamOverlay.OnDeath (_, token, time, who_serial, who_name, who_flags, alvo_serial, alvo_name, alvo_flags, death_table, last_cooldown, death_at_combattime, max_health) + + if (alvo_serial ~= UnitGUID ("player")) then + return + end + + StreamOverlay:ClearAll() + + for i = 1, #death_table do + local ev = death_table [i] + if (ev[1] and type (ev[1]) == "boolean") then + --> it's a damage + local spellid = ev[2] + local amount = ev[3] + local attime = ev[4] + local health = ev[5] + local source = ev[6] + local absorbed = ev[7] + + --get the actor from details + local sourceObject = Details:GetActor ("current", 1, source) + local classIcon, l, r, t, b + if (sourceObject) then + classIcon, l, r, t, b = StreamOverlay:GetClassIcon (sourceObject.classe) + else + classIcon, l, r, t, b = default_attack_icon, 0, 1, 0, 1 + end + + --spellname + local spellname, _, spellicon = StreamOverlay.getspellinfo (spellid) + source = StreamOverlay:GetOnlyName (source) + + local CastInfoIndex = i * -1 + + local percent = health / max_health * 100 + percent = math.min (percent, 100) + --HasCastTime has to be true, this can't be considered a instant cast + --Done = won't be touch during cast bar updates + --Percent is used on the bar text updates + --Interrupted / Death is irrelevant at this point because the bar is flagged as Done + CastsTable [CastInfoIndex] = {Target = spellname, Id = CastInfoIndex, CastStart = GetTime(), HasCastTime = true, Interrupted = true, Done = true, Percent = percent, Death = true} + + local at = format_time (time - attime) + + local damage_color = "|cFFFFFFFF" + if (amount > 100000) then + damage_color = "|cFFFF3300" + elseif (amount > 75000) then + damage_color = "|cFFFF6600" + elseif (amount > 50000) then + damage_color = "|cFFFF9900" + elseif (amount > 25000) then + damage_color = "|cFFFFAA00" + elseif (amount > 10000) then + damage_color = "|cFFFFFF66" + elseif (amount > 5000) then + damage_color = "|cFFFFFFAA" + end + + --adds the text to the line + StreamOverlay:NewText (spellicon, at .. " | " .. damage_color .. StreamOverlay:ToK2 (amount) .. "|r (" .. spellname .. ")", {1, 1, 1, 1}, classIcon, {l, r, t, b}, source, {r=1, g=1, b=1}, {1, 1, 1, 0.6}, {0, 0, 0}, CastInfoIndex, GetTime()) + +-- :NewText (icon1, text1, color1, icon2, icon2coords, text2, color2, backgroundcolor, bordercolor, ID, CastStart) + end + end + + StreamOverlay.ShowingDeath = true + +end + +--> passes the new lock state +--the window is click throught when locked +function StreamOverlay:SetLocked (state) + + if (state == nil) then + state = StreamOverlay.db.main_frame_locked + end + + if (state) then + --> is locked + StreamOverlay.db.main_frame_locked = true + DetailsStreamerTitlebar:Hide() + DetailsStreamerLeftResizer:Hide() + DetailsStreamerRightResizer:Hide() + SOF:EnableMouse (false) + else + --> not locked + StreamOverlay.db.main_frame_locked = false + DetailsStreamerTitlebar:Show() + DetailsStreamerLeftResizer:Show() + DetailsStreamerRightResizer:Show() + SOF:EnableMouse (true) + end + +end + + +function StreamOverlay.OpenOptionsPanel() + + if (not StreamOverlayOptionsPanel) then + + local fw = Details:GetFramework() + + local options_text_template = fw:GetTemplate ("font", "OPTIONS_FONT_TEMPLATE") + local options_dropdown_template = fw:GetTemplate ("dropdown", "OPTIONS_DROPDOWN_TEMPLATE") + local options_switch_template = fw:GetTemplate ("switch", "OPTIONS_CHECKBOX_TEMPLATE") + local options_slider_template = fw:GetTemplate ("slider", "OPTIONS_SLIDER_TEMPLATE") + local options_button_template = fw:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE") + + local options_frame = StreamOverlay:CreatePluginOptionsFrame ("StreamOverlayOptionsPanel", "Details!: Streamer", 1) + options_frame:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}) + options_frame:SetBackdropColor (0, 0, 0, 0.5) + options_frame:SetBackdropBorderColor (0, 0, 0, 1) + options_frame:SetHeight (340) + + -- select texture + local set_row_texture = function (_, _, value) + StreamOverlay.db.row_texture = value + StreamOverlay:RefreshAllBattleLineStyle() + end + local textures = SharedMedia:HashTable ("statusbar") + local textureTable = {} + for name, texturePath in pairs (textures) do + textureTable[#textureTable+1] = {value = name, label = name, statusbar = texturePath, onclick = set_row_texture} + end + table.sort (textureTable, function (t1, t2) return t1.label < t2.label end) + + -- select font + local set_font_face= function (_, _, value) + StreamOverlay.db.font_face = value + StreamOverlay:RefreshAllBattleLineStyle() + end + local fontObjects = SharedMedia:HashTable ("font") + local fontTable = {} + for name, fontPath in pairs (fontObjects) do + fontTable[#fontTable+1] = {value = name, label = name, onclick = set_font_face, font = fontPath, descfont = name} + end + table.sort (fontTable, function (t1, t2) return t1.label < t2.label end) + + -- select arrow + local arrows = { + [[Interface\CHATFRAME\ChatFrameExpandArrow]], + [[Interface\CHATFRAME\UI-InChatFriendsArrow]], + [[Interface\MONEYFRAME\Arrow-Right-Disabled]], + [[Interface\OPTIONSFRAME\VoiceChat-Play]], + [[Interface\MINIMAP\TrapInactive_HammerGold]], + [[Interface\MINIMAP\Vehicle-HammerGold-1]], + [[Interface\GossipFrame\BattleMasterGossipIcon]], + [[Interface\GROUPFRAME\UI-GROUP-MAINASSISTICON]], + [[Interface\GROUPFRAME\UI-GROUP-MAINTANKICON]], + [[Interface\HELPFRAME\HelpIcon-ItemRestoration]], + [[Interface\PetBattles\DeadPetIcon]], + [[Interface\BattlefieldFrame\Battleground-Alliance]], + [[Interface\BattlefieldFrame\Battleground-Horde]], + [[Interface\Buttons\UI-SliderBar-Button-Vertical]], + [[Interface\Buttons\UI-SpellbookIcon-NextPage-Up]], + [[Interface\Buttons\UI-StopButton]], + [[Interface\COMMON\friendship-heart]], + [[Interface\COMMON\friendship-FistHuman]], + [[Interface\COMMON\VOICECHAT-MUTED]], + [[Interface\Glues\LOGIN\Glues-CheckBox-Check]], + [[Interface\PvPRankBadges\PvPRank06]], + [[Interface\Scenarios\ScenarioIcon-Boss]], + [[Interface\Tooltips\ReforgeGreenArrow]], + } + + local set_arrow_texture = function (_, _, value) + StreamOverlay.db.arrow_texture = value + StreamOverlay:RefreshAllBattleLineStyle() + end + + local arrowIconTable = {} + for _, arrow in ipairs (arrows) do + arrowIconTable[#arrowIconTable+1] = {value = arrow, label = arrow:gsub ("Interface(.*)\\", ""), onclick = set_arrow_texture, icon = arrow} + end + -- + local options = { + + { + type = "toggle", + name = "Locked", + desc = "Can't move or interact within the frame when it's locked.", + order = 1, + get = function() return StreamOverlay.db.main_frame_locked end, + set = function (self, val) + StreamOverlay:SetLocked (not StreamOverlay.db.main_frame_locked) + end, + }, + + { + type = "color", + get = function() return StreamOverlay.db.main_frame_color end, + set = function (self, r, g, b, a) + StreamOverlay:SetBackgroundColor (r, g, b, a) + end, + desc = "Color used on the background.", + name = "Background Color" + }, + + {type = "space"}, + + { + type = "range", + get = function() return StreamOverlay.db.row_height end, + set = function (self, fixedparam, value) StreamOverlay.db.row_height = value; StreamOverlay:RefreshAllBattleLineStyle() end, + min = 10, + max = 30, + step = 1, + desc = "How hight is each bar.", + name = "Bar Height", + }, + + { + type = "range", + get = function() return StreamOverlay.db.row_spacement end, + set = function (self, fixedparam, value) StreamOverlay.db.row_spacement = value; StreamOverlay:RefreshAllBattleLineStyle() end, + min = 8, + max = 31, + step = 1, + desc = "How much space each bar use.", + name = "Bar Space", + }, + + { + type = "select", + get = function() return StreamOverlay.db.row_texture end, + values = function() return textureTable end, + desc = "Which texture is used on bars.", + name = "Bar Texture" + }, + + { + type = "color", + get = function() return StreamOverlay.db.row_color end, + set = function (self, r, g, b, a) + local c = StreamOverlay.db.row_color + c[1], c[2], c[3], c[4] = r, g, b, a + StreamOverlay:RefreshAllBattleLineStyle() + end, + desc = "Color used on the background.", + name = "Bar Color" + }, + + {type = "space"}, + + { + type = "range", + get = function() return StreamOverlay.db.font_size end, + set = function (self, fixedparam, value) StreamOverlay.db.font_size = value; StreamOverlay:RefreshAllBattleLineStyle() end, + min = 8, + max = 32, + step = 1, + desc = "The size of the text.", + name = "Text Size", + }, + + { + type = "select", + get = function() return StreamOverlay.db.font_face end, + values = function() return fontTable end, + desc = "Font used on texts.", + name = "Text Font" + }, + + { + type = "color", + get = function() return StreamOverlay.db.font_color end, + set = function (self, r, g, b, a) + local c = StreamOverlay.db.font_color + c[1], c[2], c[3], c[4] = r, g, b, a + StreamOverlay:RefreshAllBattleLineStyle() + end, + desc = "Color used on texts.", + name = "Text Color" + }, + + {type = "space"}, + + { + type = "toggle", + name = "Minimap Icon", + desc = "Show/Hide minimap icon.", + order = 1, + get = function() return not StreamOverlay.db.minimap.hide end, + set = function (self, val) + StreamOverlay.db.minimap.hide = not StreamOverlay.db.minimap.hide + if (LDBIcon) then + LDBIcon:Refresh ("DetailsStreamer", StreamOverlay.db.minimap) + end + end, + }, + + {type = "space"}, + + { + type = "select", + get = function() return StreamOverlay.db.arrow_texture end, + values = function() return arrowIconTable end, + desc = "The icon used on the middle of the bar", + name = "Arrow Icon" + }, + + { + type = "range", + get = function() return StreamOverlay.db.arrow_size end, + set = function (self, fixedparam, value) StreamOverlay.db.arrow_size = value; StreamOverlay:RefreshAllBattleLineStyle() end, + min = 6, + max = 32, + step = 1, + desc = "The size of the arrow.", + name = "Arrow Size", + }, + + { + type = "color", + get = function() return StreamOverlay.db.arrow_color end, + set = function (self, r, g, b, a) + local c = StreamOverlay.db.arrow_color + c[1], c[2], c[3], c[4] = r, g, b, a + StreamOverlay:RefreshAllBattleLineStyle() + end, + desc = "The color used on the arrow.", + name = "Arrow Color" + }, + + { + type = "range", + get = function() return StreamOverlay.db.arrow_anchor_x end, + set = function (self, fixedparam, value) StreamOverlay.db.arrow_anchor_x = value; StreamOverlay:RefreshAllBattleLineStyle() end, + min = -16, + max = 16, + step = 1, + desc = "Adjust the arrow positioning on X axis.", + name = "Arrow Anchor X", + }, + + { + type = "range", + get = function() return StreamOverlay.db.arrow_anchor_y end, + set = function (self, fixedparam, value) StreamOverlay.db.arrow_anchor_y = value; StreamOverlay:RefreshAllBattleLineStyle() end, + min = -16, + max = 16, + step = 1, + desc = "Adjust the arrow positioning on Y axis.", + name = "Arrow Anchor Y", + }, + } + + + + fw:BuildMenu (options_frame, options, 15, -77, 340, true, options_text_template, options_dropdown_template, options_switch_template, true, options_slider_template, options_button_template) + end + + StreamOverlayOptionsPanel:Show() + +end + + +function StreamOverlay:OnEvent (_, event, ...) + + if (event == "ADDON_LOADED") then + local AddonName = select (1, ...) + if (AddonName == "Details_Streamer") then + + if (_G._detalhes) then + + --> create widgets + CreatePluginFrames() + + --> core version required + local MINIMAL_DETAILS_VERSION_REQUIRED = 80 + + local default_options_table = { + main_frame_locked = false, + main_frame_color = {0, 0, 0, .2}, + row_height = 20, + row_spacement = 21, + row_texture = "Details Serenity", + row_color = {.1, .1, .1, 0.4}, + font_size = 10, + font_face = "Friz Quadrata TT", + font_color = {1, 1, 1, 1}, + + arrow_texture = [[Interface\CHATFRAME\ChatFrameExpandArrow]], + arrow_size = 10, + arrow_color = {1, 1, 1, .5}, + arrow_anchor_x = 0, + arrow_anchor_y = 0, + + minimap = {hide = false, radius = 160, minimapPos = 160}, + + is_first_run = true, + } + + --> Install + local install, saveddata = _G._detalhes:InstallPlugin ("TOOLBAR", "Streamer", [[Interface\MINIMAP\MOVIERECORDINGICON]], StreamOverlay, "DETAILS_PLUGIN_STREAM_OVERLAY", MINIMAL_DETAILS_VERSION_REQUIRED, "Details! Team", StreamOverlay.CurrentVersion, default_options_table) + if (type (install) == "table" and install.error) then + print (install.error) + end + + StreamOverlay:CreateMinimapIcon() + + StreamOverlay:SetPluginDescription ("Show in real time the spells you are casting.\n\nThe viewer can now follow what you are doing, what spells you are casting, learn your rotation.\n\nAlso tells who is the target and its class/spec on raiding or role if you are in arena.\n\nWhen you die, the panel is filled with your death log.") + + if (StreamOverlay.db.is_first_run) then + Details:DisablePlugin ("DETAILS_PLUGIN_STREAM_OVERLAY") + end + + if (StreamOverlay.db.is_first_run and not Details:GetTutorialCVar ("STREAMER_PLUGIN_FIRSTRUN")) then + + local show_frame = function() + + if ((DetailsWelcomeWindow and DetailsWelcomeWindow:IsShown()) or not Details:GetTutorialCVar ("MEMORY_USAGE_ALERT1") or not StreamOverlay.db.is_first_run) then + return + end + + StreamOverlay.ShowWelcomeFrame:Cancel() + + local welcome_window = CreateFrame ("frame", "StreamOverlayWelcomeWindow", UIParent) + welcome_window:SetPoint ("center", UIParent, "center") + welcome_window:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}) + welcome_window:SetBackdropColor (0, 0, 0, 0.5) + welcome_window:SetBackdropBorderColor (0, 0, 0, 1) + welcome_window:SetSize (800, 270) + + local icon = welcome_window:CreateTexture (nil, "overlay") + icon:SetTexture ([[Interface\MINIMAP\MOVIERECORDINGICON]]) + local title = welcome_window:CreateFontString (nil, "overlay", "GameFontNormal") + title:SetText ("Details!: Streamer (plugin)") + StreamOverlay:SetFontSize (title, 20) + + local text1 = welcome_window:CreateFontString (nil, "overlay", "GameFontNormal") + text1:SetText ("If you are a Streamer or Youtuber, you might want to take a look at the Details! Streamer plugin.") + local text2 = welcome_window:CreateFontString (nil, "overlay", "GameFontNormal") + text2:SetText ("Go to Options Panel -> Plugin Management and enable the Streamer plugin.") + + icon:SetPoint ("topleft", welcome_window, "topleft", 10, -60) + + title:SetPoint ("left", icon, "right", 10, 0) + + text1:SetPoint ("topleft", welcome_window, "topleft", 10, -120) + text2:SetPoint ("topleft", welcome_window, "topleft", 10, -140) + + local close_func = function() + StreamOverlay.db.is_first_run = false + Details:SetTutorialCVar ("STREAMER_PLUGIN_FIRSTRUN", true) + welcome_window:Hide() + end + + local close = Details.gump:CreateButton (welcome_window, close_func, 127, 20, Loc ["STRING_MEMORY_ALERT_BUTTON"], nil, nil, nil, nil, nil, nil, Details.gump:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE")) + close:SetPoint ("topleft", welcome_window, "topleft", 10, -200) + end + + StreamOverlay.ShowWelcomeFrame = C_Timer.NewTicker (5, show_frame) + + end + + --wipe (StreamOverlay.db) + + end + end + end +end + +--> create minimap icon +function StreamOverlay:CreateMinimapIcon() + + if (StreamOverlay.minimap_icon_created) then + return + end + + StreamOverlay.minimap_icon_created = true + + local LDB = LibStub ("LibDataBroker-1.1", true) + local LDBIcon = LDB and LibStub ("LibDBIcon-1.0", true) + + if LDB then + local minimapIcon = LDB:NewDataObject ("DetailsStreamer", { + type = "data source", + icon = [[Interface\MINIMAP\MOVIERECORDINGICON]], + + OnClick = function (self, button) + if (button == "LeftButton") then + StreamOverlay.OpenOptionsPanel() + elseif (button == "RightButton") then + StreamOverlay.db.minimap.hide = not StreamOverlay.db.minimap.hide + if (LDBIcon) then + LDBIcon:Refresh ("DetailsStreamer", StreamOverlay.db.minimap) + end + end + end, + + OnTooltipShow = function (tooltip) + tooltip:AddLine ("Details!: Streamer", 1, 1, 1) + tooltip:AddLine ("|cFFFF7700Left Click|r: open options.") + tooltip:AddLine ("|cFFFF7700Right Click|r: hide this icon.") + end, + }) + + if (minimapIcon and not LDBIcon:IsRegistered ("DetailsStreamer")) then + LDBIcon:Register ("DetailsStreamer", minimapIcon, StreamOverlay.db.minimap) + end + end +end + +SLASH_STREAMER1, SLASH_STREAMER2 = "/streamer", "/detailsstreamer" +function SlashCmdList.STREAMER (msg, editbox) + local command, rest = msg:match ("^(%S*)%s*(.-)$") + + --> open options panel + StreamOverlay.OpenOptionsPanel() +end + +--[[ extrair lista das magias +local editbox = CreateFrame ("editbox", nil, UIParent) +editbox:SetSize (300, 700) +editbox:SetPoint ("topleft", UIParent, "topleft") +editbox:SetBackdrop ({bgFile = "Interface\\AddOns\\Details\\images\\background", tile = true, tileSize = 16, insets = {left = 0, right = 0, top = 0, bottom = 0}}) +editbox:SetBackdropColor (0, 0, 0, .2) +editbox:SetAutoFocus (false) +editbox:ClearFocus() +editbox:SetMultiLine (true) +editbox:SetFontObject (GameFontHighlightSmall) +editbox:SetJustifyH("CENTER") +editbox:EnableMouse(true) +editbox:SetText ("") +editbox:SetScript ("OnEscapePressed", function() editbox:ClearFocus() end) +editbox:SetScript ("OnEditFocusGained", function() editbox:HighlightText() end) + +local list = "" + +local harmful_spells = StreamOverlay.HarmfulSpells +local helpful_spells = StreamOverlay.HelpfulSpells + +if (not harmful_spells [spellid] and not helpful_spells [spellid]) then + if (bit.band (who_flags, 0x00000400) ~= 0 and who_name) then + local text = editbox:GetText() + if (not list:find (spellid) and not text:find (spellid)) then + + local class = _detalhes:GetClass (who_name) or "unknow" + + if (class ~= "unknow") then + text = text .. "\n"..spellid .. " " .. spellname .. " " .. class + editbox:SetText (text) + end + end + end +end +--]] +--endd +--doo \ No newline at end of file diff --git a/plugins/Details_Streamer/Details_Streamer.toc b/plugins/Details_Streamer/Details_Streamer.toc new file mode 100644 index 00000000..23820f01 --- /dev/null +++ b/plugins/Details_Streamer/Details_Streamer.toc @@ -0,0 +1,10 @@ +## Interface: 60200 +## Title: Details!: Streamer (plugin) +## Notes: Show which spells you are casting, viewers can see what are you doing and follow your steps. +## RequiredDeps: Details + +#@no-lib-strip@ +embeds.xml +#@end-no-lib-strip@ + +Details_Streamer.lua \ No newline at end of file diff --git a/plugins/Details_Streamer/Libs/LibStub/LibStub.lua b/plugins/Details_Streamer/Libs/LibStub/LibStub.lua new file mode 100644 index 00000000..f5fc9192 --- /dev/null +++ b/plugins/Details_Streamer/Libs/LibStub/LibStub.lua @@ -0,0 +1,51 @@ +-- $Id: LibStub.lua 76 2007-09-03 01:50:17Z mikk $ +-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info +-- LibStub is hereby placed in the Public Domain +-- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! +local LibStub = _G[LIBSTUB_MAJOR] + +-- Check to see is this version of the stub is obsolete +if not LibStub or LibStub.minor < LIBSTUB_MINOR then + LibStub = LibStub or {libs = {}, minors = {} } + _G[LIBSTUB_MAJOR] = LibStub + LibStub.minor = LIBSTUB_MINOR + + -- LibStub:NewLibrary(major, minor) + -- major (string) - the major version of the library + -- minor (string or number ) - the minor version of the library + -- + -- returns nil if a newer or same version of the lib is already present + -- returns empty library object or old library object if upgrade is needed + function LibStub:NewLibrary(major, minor) + assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") + minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") + + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + -- LibStub:GetLibrary(major, [silent]) + -- major (string) - the major version of the library + -- silent (boolean) - if true, library is optional, silently return nil if its not found + -- + -- throws an error if the library can not be found (except silent is set) + -- returns the library object if found + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(("Cannot find a library instance of %q."):format(tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + -- LibStub:IterateLibraries() + -- + -- Returns an iterator for the currently registered libraries + function LibStub:IterateLibraries() + return pairs(self.libs) + end + + setmetatable(LibStub, { __call = LibStub.GetLibrary }) +end diff --git a/plugins/Details_Streamer/Libs/LibStub/LibStub.toc b/plugins/Details_Streamer/Libs/LibStub/LibStub.toc new file mode 100644 index 00000000..c3dc3656 --- /dev/null +++ b/plugins/Details_Streamer/Libs/LibStub/LibStub.toc @@ -0,0 +1,13 @@ +## Interface: 40200 +## Title: Lib: LibStub +## Notes: Universal Library Stub +## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel +## X-Website: http://www.wowace.com/addons/libstub/ +## X-Category: Library +## X-License: Public Domain +## X-Curse-Packaged-Version: r95 +## X-Curse-Project-Name: LibStub +## X-Curse-Project-ID: libstub +## X-Curse-Repository-ID: wow/libstub/mainline + +LibStub.lua diff --git a/plugins/Details_Streamer/Libs/LibStub/tests/test.lua b/plugins/Details_Streamer/Libs/LibStub/tests/test.lua new file mode 100644 index 00000000..645a08b1 --- /dev/null +++ b/plugins/Details_Streamer/Libs/LibStub/tests/test.lua @@ -0,0 +1,41 @@ +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + +local lib, oldMinor = LibStub:NewLibrary("Pants", 1) -- make a new thingy +assert(lib) -- should return the library table +assert(not oldMinor) -- should not return the old minor, since it didn't exist + +-- the following is to create data and then be able to check if the same data exists after the fact +function lib:MyMethod() +end +local MyMethod = lib.MyMethod +lib.MyTable = {} +local MyTable = lib.MyTable + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 1) -- try to register a library with the same version, should silently fail +assert(not newLib) -- should not return since out of date + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 0) -- try to register a library with a previous, should silently fail +assert(not newLib) -- should not return since out of date + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 2) -- register a new version +assert(newLib) -- library table +assert(rawequal(newLib, lib)) -- should be the same reference as the previous +assert(newOldMinor == 1) -- should return the minor version of the previous version + +assert(rawequal(lib.MyMethod, MyMethod)) -- verify that values were saved +assert(rawequal(lib.MyTable, MyTable)) -- verify that values were saved + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 3 Blah") -- register a new version with a string minor version (instead of a number) +assert(newLib) -- library table +assert(newOldMinor == 2) -- previous version was 2 + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 4 and please ignore 15 Blah") -- register a new version with a string minor version (instead of a number) +assert(newLib) +assert(newOldMinor == 3) -- previous version was 3 (even though it gave a string) + +local newLib, newOldMinor = LibStub:NewLibrary("Pants", 5) -- register a new library, using a normal number instead of a string +assert(newLib) +assert(newOldMinor == 4) -- previous version was 4 (even though it gave a string) \ No newline at end of file diff --git a/plugins/Details_Streamer/Libs/LibStub/tests/test2.lua b/plugins/Details_Streamer/Libs/LibStub/tests/test2.lua new file mode 100644 index 00000000..af431dd3 --- /dev/null +++ b/plugins/Details_Streamer/Libs/LibStub/tests/test2.lua @@ -0,0 +1,27 @@ +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + +for major, library in LibStub:IterateLibraries() do + -- check that MyLib doesn't exist yet, by iterating through all the libraries + assert(major ~= "MyLib") +end + +assert(not LibStub:GetLibrary("MyLib", true)) -- check that MyLib doesn't exist yet by direct checking +assert(not pcall(LibStub.GetLibrary, LibStub, "MyLib")) -- don't silently fail, thus it should raise an error. +local lib = LibStub:NewLibrary("MyLib", 1) -- create the lib +assert(lib) -- check it exists +assert(rawequal(LibStub:GetLibrary("MyLib"), lib)) -- verify that :GetLibrary("MyLib") properly equals the lib reference + +assert(LibStub:NewLibrary("MyLib", 2)) -- create a new version + +local count=0 +for major, library in LibStub:IterateLibraries() do + -- check that MyLib exists somewhere in the libraries, by iterating through all the libraries + if major == "MyLib" then -- we found it! + count = count +1 + assert(rawequal(library, lib)) -- verify that the references are equal + end +end +assert(count == 1) -- verify that we actually found it, and only once diff --git a/plugins/Details_Streamer/Libs/LibStub/tests/test3.lua b/plugins/Details_Streamer/Libs/LibStub/tests/test3.lua new file mode 100644 index 00000000..01aabb8d --- /dev/null +++ b/plugins/Details_Streamer/Libs/LibStub/tests/test3.lua @@ -0,0 +1,14 @@ +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + +local proxy = newproxy() -- non-string + +assert(not pcall(LibStub.NewLibrary, LibStub, proxy, 1)) -- should error, proxy is not a string, it's userdata +local success, ret = pcall(LibStub.GetLibrary, proxy, true) +assert(not success or not ret) -- either error because proxy is not a string or because it's not actually registered. + +assert(not pcall(LibStub.NewLibrary, LibStub, "Something", "No number in here")) -- should error, minor has no string in it. + +assert(not LibStub:GetLibrary("Something", true)) -- shouldn't've created it from the above statement \ No newline at end of file diff --git a/plugins/Details_Streamer/Libs/LibStub/tests/test4.lua b/plugins/Details_Streamer/Libs/LibStub/tests/test4.lua new file mode 100644 index 00000000..15a9c9cd --- /dev/null +++ b/plugins/Details_Streamer/Libs/LibStub/tests/test4.lua @@ -0,0 +1,41 @@ +debugstack = debug.traceback +strmatch = string.match + +loadfile("../LibStub.lua")() + + +-- Pretend like loaded libstub is old and doesn't have :IterateLibraries +assert(LibStub.minor) +LibStub.minor = LibStub.minor - 0.0001 +LibStub.IterateLibraries = nil + +loadfile("../LibStub.lua")() + +assert(type(LibStub.IterateLibraries)=="function") + + +-- Now pretend that we're the same version -- :IterateLibraries should NOT be re-created +LibStub.IterateLibraries = 123 + +loadfile("../LibStub.lua")() + +assert(LibStub.IterateLibraries == 123) + + +-- Now pretend that a newer version is loaded -- :IterateLibraries should NOT be re-created +LibStub.minor = LibStub.minor + 0.0001 + +loadfile("../LibStub.lua")() + +assert(LibStub.IterateLibraries == 123) + + +-- Again with a huge number +LibStub.minor = LibStub.minor + 1234567890 + +loadfile("../LibStub.lua")() + +assert(LibStub.IterateLibraries == 123) + + +print("OK") \ No newline at end of file diff --git a/plugins/Details_Streamer/embeds.xml b/plugins/Details_Streamer/embeds.xml new file mode 100644 index 00000000..ee157111 --- /dev/null +++ b/plugins/Details_Streamer/embeds.xml @@ -0,0 +1,6 @@ + + +